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 std.conv: text; 63 import std.algorithm: canFind; 64 65 debugCursor(cursor, context); 66 67 if(context.language == Language.Cpp && ignoredCppCursorSpellings.canFind(cursor.spelling)) { 68 return []; 69 } 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(Exception e) { 88 import std.stdio: stderr; 89 debug { 90 () @trusted { 91 stderr.writeln("\nCould not translate cursor ", cursor, 92 " sourceRange: ", cursor.sourceRange, 93 " children: ", cursor.children, "\n"); 94 }(); 95 } 96 throw e; 97 } 98 } 99 100 void debugCursor(in from!"clang".Cursor cursor, 101 in from!"dpp.runtime.context".Context context) 102 @safe 103 { 104 import clang: Cursor; 105 import std.algorithm: startsWith, canFind; 106 107 version(unittest) {} 108 else if(!context.debugOutput) return; 109 110 const isMacro = cursor.kind == Cursor.Kind.MacroDefinition; 111 const isOkMacro = 112 !cursor.spelling.startsWith("__") && 113 !["_LP64", "unix", "linux"].canFind(cursor.spelling); 114 const canonical = cursor.isCanonical ? " CAN" : ""; 115 const definition = cursor.isDefinition ? " DEF" : ""; 116 117 if(!isMacro || isOkMacro) { 118 context.log(cursor, canonical, definition, " @ ", cursor.sourceRange); 119 } 120 } 121 122 Translator[from!"clang".Cursor.Kind] translators() @safe { 123 import dpp.translation; 124 import clang: Cursor; 125 126 static string[] ignore( 127 in Cursor cursor, 128 ref from!"dpp.runtime.context".Context context) 129 { 130 return []; 131 } 132 133 static string[] translateUnexposed( 134 in Cursor cursor, 135 ref from!"dpp.runtime.context".Context context) 136 { 137 import clang: Type; 138 import std.conv: text; 139 140 switch(cursor.type.kind) with(Type.Kind) { 141 default: 142 throw new Exception(text("Unknown unexposed declaration type ", cursor.type)); 143 case Invalid: 144 return []; 145 } 146 assert(0); 147 } 148 149 static string[] translateAccess( 150 in Cursor cursor, 151 ref from!"dpp.runtime.context".Context context) 152 { 153 import clang: AccessSpecifier; 154 155 final switch(cursor.accessSpecifier) with(AccessSpecifier) { 156 case InvalidAccessSpecifier: assert(0); 157 case Public: return [" public:"]; 158 case Protected: return [" protected:"]; 159 case Private: return [" private:"]; 160 } 161 162 assert(0); 163 } 164 165 with(Cursor.Kind) { 166 return [ 167 ClassDecl: &translateClass, 168 StructDecl: &translateStruct, 169 UnionDecl: &translateUnion, 170 EnumDecl: &translateEnum, 171 FunctionDecl: &translateFunction, 172 FieldDecl: &translateField, 173 TypedefDecl: &translateTypedef, 174 MacroDefinition: &translateMacro, 175 InclusionDirective: &ignore, 176 EnumConstantDecl: &translateEnumConstant, 177 VarDecl: &translateVariable, 178 UnexposedDecl: &translateUnexposed, 179 CXXAccessSpecifier: &translateAccess, 180 CXXMethod: &translateFunction, 181 Constructor: &translateFunction, 182 Destructor: &translateFunction, 183 TypeAliasDecl: &translateTypedef, 184 ClassTemplate: &translateClass, 185 TemplateTypeParameter: &ignore, 186 NonTypeTemplateParameter: &ignore, 187 ConversionFunction: &translateFunction, 188 Namespace: &translateNamespace, 189 VisibilityAttr: &ignore, // ??? 190 FirstAttr: &ignore, // ??? 191 ClassTemplatePartialSpecialization: &translateClass, 192 ]; 193 } 194 } 195 196 // blacklist of cursors in the C++ standard library that dpp can't handle 197 string[] ignoredCppCursorSpellings() @safe pure nothrow { 198 return 199 [ 200 "is_function", 201 "__is_referenceable", 202 "__is_convertible_helper", 203 "aligned_union", 204 "__expanded_common_type_wrapper", 205 "underlying_type", 206 "__result_of_memfun_ref", 207 "__result_of_memfun_deref", 208 "__result_of_memfun", 209 "__result_of_impl", 210 "result_of", 211 "__detector", 212 "__is_swappable_with_impl", 213 "__is_nothrow_swappable_with_impl", 214 "is_rvalue_reference", 215 "__is_member_pointer_helper", 216 "__do_is_implicitly_default_constructible_impl", 217 "remove_reference", 218 "remove_extent", // FIXME 219 "remove_all_extents", // FIXME 220 "__remove_pointer_helper", // FIXME 221 "__result_of_memobj", 222 "__nonesuch", // FIXME (struct default ctor) 223 ]; 224 }