1 module dpp.translation.macro_; 2 3 import dpp.from; 4 5 string[] translateMacro(in from!"clang".Cursor cursor, 6 ref from!"dpp.runtime.context".Context context) 7 @safe 8 { 9 import dpp.translation.dlang: maybeRename; 10 import clang: Cursor; 11 import std.algorithm: map; 12 import std..string: join; 13 import std.file: exists; 14 import std.stdio: File; 15 import std.algorithm: startsWith; 16 import std.conv: text; 17 18 assert(cursor.kind == Cursor.Kind.MacroDefinition); 19 20 // we want non-built-in macro definitions to be defined and then preprocessed 21 // again 22 23 auto range = cursor.sourceRange; 24 25 if(range.path == "" || !range.path.exists || 26 cursor.isPredefined || cursor.spelling.startsWith("__STDC_")) { //built-in macro 27 return []; 28 } 29 30 // now we read the header where the macro comes from and copy the text inline 31 32 const startPos = range.start.offset; 33 const endPos = range.end.offset; 34 35 auto file = File(range.path); 36 file.seek(startPos); 37 const chars = () @trusted { return file.rawRead(new char[endPos - startPos]); }(); 38 39 // the only sane way for us to be able to see a macro definition 40 // for a macro that has already been defined is if an #undef happened 41 // in the meanwhile. Unfortunately, libclang has no way of passing 42 // that information to us 43 string maybeUndef; 44 if(context.macroAlreadyDefined(cursor)) 45 maybeUndef = "#undef " ~ cursor.spelling ~ "\n"; 46 47 context.rememberMacro(cursor); 48 const spelling = maybeRename(cursor, context); 49 const body_ = chars.text[cursor.spelling.length .. $]; 50 51 return [maybeUndef ~ "#define " ~ spelling ~ translateToD(body_, context) ~ "\n"]; 52 } 53 54 55 // Some macros define snippets of C code that aren't valid D 56 private string translateToD(in string line, in from!"dpp.runtime.context".Context context) @safe { 57 import std.array: replace; 58 import std.regex: regex, replaceAll; 59 60 auto sizeofRegex = regex(`sizeof *?\(([^)]+)\)`); 61 62 return line 63 .replace("->", ".") 64 .replaceNull 65 .replaceAll(sizeofRegex, "$1.sizeof") 66 .replaceAll(context.castRegex, "cast($1)") 67 ; 68 } 69 70 private string replaceNull(in string str) @safe pure nothrow { 71 import std.array: replace; 72 import std.algorithm: startsWith; 73 // we don't want to translate the definition of NULL itself 74 return str.startsWith("NULL") ? str : str.replace("NULL", "null"); 75 }