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