1 /** 2 Cursor translations 3 */ 4 module dpp.translation.translation; 5 6 import dpp.from; 7 8 9 alias Translator = string[] function( 10 in from!"clang".Cursor cursor, 11 ref from!"dpp.runtime.context".Context context, 12 ) @safe; 13 14 string translateTopLevelCursor(in from!"clang".Cursor cursor, 15 ref from!"dpp.runtime.context".Context context, 16 in string file = __FILE__, 17 in size_t line = __LINE__) 18 @safe 19 { 20 import std.array: join; 21 import std.algorithm: map; 22 23 return cursor.skipTopLevel 24 ? "" 25 : translate(cursor, context, file, line).map!(a => " " ~ a).join("\n"); 26 } 27 28 private bool skipTopLevel(in from!"clang".Cursor cursor) @safe pure { 29 import dpp.translation.aggregate: isAggregateC; 30 import clang: Cursor; 31 import std.algorithm: startsWith, canFind; 32 33 // We want to ignore anonymous structs and unions but not enums. See #54 34 if(cursor.spelling == "" && cursor.kind == Cursor.Kind.EnumDecl) 35 return false; 36 37 // don't bother translating top-level anonymous aggregates 38 if(isAggregateC(cursor) && cursor.spelling == "") 39 return true; 40 41 static immutable forbiddenSpellings = 42 [ 43 "ulong", "ushort", "uint", 44 "va_list", "__gnuc_va_list", 45 "_IO_2_1_stdin_", "_IO_2_1_stdout_", "_IO_2_1_stderr_", 46 ]; 47 48 return forbiddenSpellings.canFind(cursor.spelling) || 49 cursor.isPredefined || 50 cursor.kind == Cursor.Kind.MacroExpansion 51 ; 52 } 53 54 55 string[] translate(in from!"clang".Cursor cursor, 56 ref from!"dpp.runtime.context".Context context, 57 in string file = __FILE__, 58 in size_t line = __LINE__) 59 @safe 60 { 61 import dpp.runtime.context: Language; 62 import dpp.translation.exception: UntranslatableException; 63 import std.conv: text; 64 import std.algorithm: canFind; 65 66 debugCursor(cursor, context); 67 68 if(context.language == Language.Cpp && ignoredCppCursorSpellings.canFind(cursor.spelling)) { 69 return []; 70 } 71 72 if(cursor.kind !in translators) { 73 if(context.options.hardFail) 74 throw new Exception(text("Cannot translate unknown cursor kind ", cursor.kind), 75 file, 76 line); 77 else 78 return []; 79 } 80 81 const indentation = context.indentation; 82 scope(exit) context.setIndentation(indentation); 83 context.indent; 84 85 try 86 return translators[cursor.kind](cursor, context); 87 catch(UntranslatableException e) { 88 89 debug { 90 import std.stdio: stderr; 91 () @trusted { 92 stderr.writeln("\nUntranslatable cursor ", cursor, 93 " sourceRange: ", cursor.sourceRange, 94 " children: ", cursor.children, "\n"); 95 }(); 96 } 97 98 if(context.options.hardFail) 99 throw e; 100 else 101 return []; 102 103 } catch(Exception e) { 104 105 debug { 106 import std.stdio: stderr; 107 () @trusted { 108 stderr.writeln("\nCould not translate cursor ", cursor, 109 " sourceRange: ", cursor.sourceRange, 110 " children: ", cursor.children, "\n"); 111 }(); 112 } 113 114 throw e; 115 } 116 } 117 118 void debugCursor(in from!"clang".Cursor cursor, 119 in from!"dpp.runtime.context".Context context) 120 @safe 121 { 122 import clang: Cursor; 123 import std.algorithm: startsWith, canFind; 124 125 version(unittest) {} 126 else if(!context.debugOutput) return; 127 128 const isMacro = cursor.kind == Cursor.Kind.MacroDefinition; 129 const isOkMacro = 130 !cursor.spelling.startsWith("__") && 131 !["_LP64", "unix", "linux"].canFind(cursor.spelling); 132 const canonical = cursor.isCanonical ? " CAN" : ""; 133 const definition = cursor.isDefinition ? " DEF" : ""; 134 135 if(!isMacro || isOkMacro) { 136 context.log(cursor, canonical, definition, " @ ", cursor.sourceRange); 137 } 138 } 139 140 Translator[from!"clang".Cursor.Kind] translators() @safe { 141 import dpp.translation; 142 import clang: Cursor; 143 144 static string[] ignore( 145 in Cursor cursor, 146 ref from!"dpp.runtime.context".Context context) 147 { 148 return []; 149 } 150 151 static string[] translateUnexposed( 152 in Cursor cursor, 153 ref from!"dpp.runtime.context".Context context) 154 { 155 import clang: Type; 156 import std.conv: text; 157 158 switch(cursor.type.kind) with(Type.Kind) { 159 default: 160 throw new Exception(text("Unknown unexposed declaration type ", cursor.type)); 161 case Invalid: 162 return []; 163 } 164 assert(0); 165 } 166 167 static string[] translateAccess( 168 in Cursor cursor, 169 ref from!"dpp.runtime.context".Context context) 170 { 171 import clang: AccessSpecifier; 172 173 final switch(cursor.accessSpecifier) with(AccessSpecifier) { 174 case InvalidAccessSpecifier: assert(0); 175 case Public: return [" public:"]; 176 case Protected: return [" protected:"]; 177 case Private: return [" private:"]; 178 } 179 180 assert(0); 181 } 182 183 with(Cursor.Kind) { 184 return [ 185 ClassDecl: &translateClass, 186 StructDecl: &translateStruct, 187 UnionDecl: &translateUnion, 188 EnumDecl: &translateEnum, 189 FunctionDecl: &translateFunction, 190 FieldDecl: &translateField, 191 TypedefDecl: &translateTypedef, 192 MacroDefinition: &translateMacro, 193 InclusionDirective: &ignore, 194 EnumConstantDecl: &translateEnumConstant, 195 VarDecl: &translateVariable, 196 UnexposedDecl: &translateUnexposed, 197 CXXAccessSpecifier: &translateAccess, 198 CXXMethod: &translateFunction, 199 Constructor: &translateFunction, 200 Destructor: &translateFunction, 201 TypeAliasDecl: &translateTypedef, 202 ClassTemplate: &translateClass, 203 TemplateTypeParameter: &ignore, 204 NonTypeTemplateParameter: &ignore, 205 ConversionFunction: &translateFunction, 206 Namespace: &translateNamespace, 207 VisibilityAttr: &ignore, // ??? 208 FirstAttr: &ignore, // ??? 209 ClassTemplatePartialSpecialization: &translateClass, 210 ]; 211 } 212 } 213 214 // blacklist of cursors in the C++ standard library that dpp can't handle 215 string[] ignoredCppCursorSpellings() @safe pure nothrow { 216 return 217 [ 218 "is_function", // dmd bug 219 "__is_referenceable", 220 "__is_convertible_helper", 221 "aligned_union", 222 "__expanded_common_type_wrapper", 223 "underlying_type", 224 "__result_of_memfun_ref", 225 "__result_of_memfun_deref", 226 "__result_of_memfun", 227 "__result_of_impl", 228 "result_of", 229 "__detector", 230 "__is_swappable_with_impl", 231 "__is_nothrow_swappable_with_impl", 232 "is_rvalue_reference", 233 "__is_member_pointer_helper", 234 "__do_is_implicitly_default_constructible_impl", 235 "remove_reference", 236 "remove_extent", // FIXME 237 "remove_all_extents", // FIXME 238 "__remove_pointer_helper", // FIXME 239 "__result_of_memobj", 240 "piecewise_construct_t", // FIXME (@disable ctor) 241 "piecewise_construct", // FIXME (piecewise_construct_t) 242 243 "hash", // FIXME (stl_bvector.h partial template specialisation) 244 "__is_fast_hash", // FIXME (hash) 245 246 "move_iterator", // FIXME (extra type parameters) 247 "__replace_first_arg", // FIXME 248 "pointer_traits", // FIXME 249 "pair", // FIXME 250 "iterator_traits", // FIXME 251 252 "_Hash_bytes", // FIXME (std.size_t) 253 "_Fnv_hash_bytes", // FIXME (std.size_t) 254 "allocator_traits", // FIXME 255 "__allocator_traits_base", // FIXME 256 ]; 257 }