1 module clang;
2 
3 import clang.c.index;
4 import clang.c.util: EnumD;
5 
6 mixin EnumD!("TranslationUnitFlags", CXTranslationUnit_Flags, "CXTranslationUnit_");
7 
8 
9 TranslationUnit parse(in string fileName, in TranslationUnitFlags translUnitflags)
10     @safe
11 {
12     return parse(fileName, [], translUnitflags);
13 }
14 
15 
16 TranslationUnit parse(in string fileName, in string[] commandLineArgs, in TranslationUnitFlags translUnitflags)
17     @trusted
18 {
19 
20     import std.string: toStringz;
21     import std.algorithm: map;
22     import std.array: array;
23 
24     auto index = clang_createIndex(0, 0);
25     CXUnsavedFile[] unsavedFiles;
26     const commandLineArgz = commandLineArgs.map!(a => a.toStringz).array;
27 
28     auto cx = clang_parseTranslationUnit(
29         index,
30         fileName.toStringz,
31         commandLineArgz.ptr,
32         cast(int)commandLineArgz.length,
33         unsavedFiles.ptr,
34         cast(uint)unsavedFiles.length,
35         CXTranslationUnit_None,
36     );
37 
38     return TranslationUnit(cx);
39 }
40 
41 mixin EnumD!("ChildVisitResult", CXChildVisitResult, "CXChildVisit_");
42 
43 alias CursorVisitor = ChildVisitResult delegate(Cursor cursor, Cursor parent);
44 
45 struct TranslationUnit {
46 
47     CXTranslationUnit _cx;
48 
49     Cursor cursor() @trusted {
50         return Cursor(clang_getTranslationUnitCursor(_cx));
51     }
52 
53     void visitChildren(CursorVisitor visitor) @safe {
54         cursor.visitChildren(visitor);
55     }
56 
57     int opApply(scope int delegate(Cursor cursor, Cursor parent) block) @safe {
58         return cursor.opApply(block);
59     }
60 
61     int opApply(scope int delegate(Cursor cursor) block) @safe {
62         return cursor.opApply(block);
63     }
64 }
65 
66 string toString(CXString cxString) @trusted {
67     import std.conv: to;
68     auto cstr = clang_getCString(cxString);
69     auto str = cstr.to!string;
70     clang_disposeString(cxString);
71     return str;
72 }
73 
74 struct Cursor {
75 
76     mixin EnumD!("Kind", CXCursorKind, "CXCursor_");
77 
78     private CXCursor _cx;
79     Kind kind;
80     string spelling;
81 
82     this(CXCursor cx) @trusted {
83         _cx = cx;
84         kind = cast(Kind)clang_getCursorKind(_cx);
85         spelling = clang_getCursorSpelling(_cx).toString;
86     }
87 
88     void visitChildren(CursorVisitor visitor) @trusted {
89         clang_visitChildren(_cx, &cvisitor, new ClientData(visitor));
90     }
91 
92     SourceRange sourceRange() @safe nothrow const {
93         return typeof(return).init;
94     }
95 
96     bool isPredefined() @safe @nogc pure nothrow const {
97         return false;
98     }
99 
100     int opApply(scope int delegate(Cursor cursor, Cursor parent) block) @safe {
101         return opApplyN(block);
102     }
103 
104     int opApply(scope int delegate(Cursor cursor) block) @safe {
105         return opApplyN(block);
106     }
107 
108     private int opApplyN(T...)(int delegate(T args) block) {
109         int stop = 0;
110 
111         visitChildren((cursor, parent) {
112 
113             static if(T.length == 2)
114                 stop = block(cursor, parent);
115             else static if(T.length == 1)
116                 stop = block(cursor);
117             else
118                 static assert(false);
119 
120             return stop
121                 ? ChildVisitResult.Break
122                 : ChildVisitResult.Recurse;
123         });
124 
125         return stop;
126     }
127 }
128 
129 struct SourceRange {
130     string path;
131     SourceLocation start;
132     SourceLocation end;
133 }
134 
135 struct SourceLocation {
136     uint offset;
137 }
138 
139 private struct ClientData {
140     CursorVisitor dvisitor;
141 }
142 
143 private extern(C) CXChildVisitResult cvisitor(CXCursor cursor, CXCursor parent, void* clientData_) {
144     auto clientData = cast(ClientData*)clientData_;
145     return cast(CXChildVisitResult)clientData.dvisitor(Cursor(cursor), Cursor(parent));
146 }