1 /** 2 Cursor translations 3 */ 4 module dpp.cursor.translation; 5 6 import dpp.from; 7 8 alias Translator = string[] function( 9 in from!"clang".Cursor cursor, 10 ref from!"dpp.runtime.context".Context context, 11 ) @safe; 12 13 string translateTopLevelCursor(in from!"clang".Cursor cursor, 14 ref from!"dpp.runtime.context".Context context, 15 in string file = __FILE__, 16 in size_t line = __LINE__) 17 @safe 18 { 19 import std.array: join; 20 import std.algorithm: map; 21 22 return cursor.skipTopLevel 23 ? "" 24 : translate(cursor, context, file, line).map!(a => " " ~ a).join("\n"); 25 } 26 27 private bool skipTopLevel(in from!"clang".Cursor cursor) @safe pure { 28 import dpp.cursor.aggregate: isAggregateC; 29 import clang: Cursor; 30 import std.algorithm: startsWith, canFind; 31 32 // don't bother translating top-level anonymous aggregates 33 if(isAggregateC(cursor) && cursor.spelling == "") 34 return true; 35 36 static immutable forbiddenSpellings = 37 [ 38 "ulong", "ushort", "uint", 39 "va_list", "__gnuc_va_list", 40 "_IO_2_1_stdin_", "_IO_2_1_stdout_", "_IO_2_1_stderr_", 41 ]; 42 43 return forbiddenSpellings.canFind(cursor.spelling) || 44 cursor.isPredefined || 45 cursor.kind == Cursor.Kind.MacroExpansion 46 ; 47 } 48 49 50 string[] translate(in from!"clang".Cursor cursor, 51 ref from!"dpp.runtime.context".Context context, 52 in string file = __FILE__, 53 in size_t line = __LINE__) 54 @safe 55 { 56 import std.conv: text; 57 58 debugCursor(cursor, context); 59 60 if(cursor.kind !in translators) 61 throw new Exception(text("Cannot translate unknown cursor kind ", cursor.kind), 62 file, 63 line); 64 65 const indentation = context.indentation; 66 scope(exit) context.setIndentation(indentation); 67 context.indent; 68 69 try 70 return translators[cursor.kind](cursor, context); 71 catch(Exception e) { 72 import std.stdio: stderr; 73 debug { 74 () @trusted { 75 stderr.writeln("\nCould not translate cursor ", cursor, 76 " sourceRange: ", cursor.sourceRange, 77 " children: ", cursor.children, "\n"); 78 }(); 79 } 80 throw e; 81 } 82 } 83 84 void debugCursor(in from!"clang".Cursor cursor, 85 in from!"dpp.runtime.context".Context context) 86 @safe 87 { 88 import clang: Cursor; 89 import std.algorithm: startsWith, canFind; 90 91 version(unittest) {} 92 else if(!context.debugOutput) return; 93 94 const isMacro = cursor.kind == Cursor.Kind.MacroDefinition; 95 const isOkMacro = 96 !cursor.spelling.startsWith("__") && 97 !["_LP64", "unix", "linux"].canFind(cursor.spelling); 98 const canonical = cursor.isCanonical ? " CAN" : ""; 99 const definition = cursor.isDefinition ? " DEF" : ""; 100 101 if(!isMacro || isOkMacro) { 102 context.log(cursor, canonical, definition, " @ ", cursor.sourceRange); 103 } 104 } 105 106 Translator[from!"clang".Cursor.Kind] translators() @safe { 107 import dpp.cursor; 108 import clang: Cursor; 109 import dpp.expansion: expand; 110 111 static string[] ignore( 112 in Cursor cursor, 113 ref from!"dpp.runtime.context".Context context) 114 { 115 return []; 116 } 117 118 static string[] translateUnexposed( 119 in Cursor cursor, 120 ref from!"dpp.runtime.context".Context context) 121 { 122 import clang: Type; 123 import std.conv: text; 124 125 switch(cursor.type.kind) with(Type.Kind) { 126 default: 127 throw new Exception(text("Unknown unexposed declaration type ", cursor.type)); 128 case Invalid: 129 return []; 130 } 131 assert(0); 132 } 133 134 static string[] translateAccess( 135 in Cursor cursor, 136 ref from!"dpp.runtime.context".Context context) 137 { 138 import clang: AccessSpecifier; 139 140 final switch(cursor.accessSpecifier) with(AccessSpecifier) { 141 case InvalidAccessSpecifier: assert(0); 142 case Public: return ["public:"]; 143 case Protected: return ["protected:"]; 144 case Private: return ["private:"]; 145 } 146 147 assert(0); 148 } 149 150 with(Cursor.Kind) { 151 return [ 152 ClassDecl: &translateClass, 153 StructDecl: &translateStruct, 154 UnionDecl: &translateUnion, 155 EnumDecl: &translateEnum, 156 FunctionDecl: &translateFunction, 157 FieldDecl: &translateField, 158 TypedefDecl: &translateTypedef, 159 MacroDefinition: &translateMacro, 160 InclusionDirective: &ignore, 161 EnumConstantDecl: &translateEnumConstant, 162 VarDecl: &translateVariable, 163 UnexposedDecl: &translateUnexposed, 164 CXXAccessSpecifier: &translateAccess, 165 CXXMethod: &translateFunction, 166 Constructor: &translateFunction, 167 Destructor: &translateFunction, 168 TypeAliasDecl: &translateTypedef, 169 ClassTemplate: &translateClass, 170 TemplateTypeParameter: &ignore, 171 NonTypeTemplateParameter: &ignore, 172 ]; 173 } 174 }