1 /**
2  * Copyright: Copyright (c) 2012 Jacob Carlborg. All rights reserved.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: Jan 29, 2012
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module clang.Visitor;
8 
9 import clang.c.index;
10 import clang.Cursor;
11 
12 struct Visitor
13 {
14 	alias int delegate (ref Cursor, ref Cursor) Delegate;
15 	alias int delegate (Delegate dg) OpApply;
16 	
17 	private CXCursor cursor;
18 	
19 	this (CXCursor cursor)
20 	{
21 		this.cursor = cursor;
22 	}
23 	
24 	this (Cursor cursor)
25 	{
26 		this.cursor = cursor.cx;
27 	}
28 
29 	int opApply (Delegate dg)
30 	{
31 		auto data = OpApplyData(dg);
32 		clang_visitChildren(cursor, &visitorFunction, cast(CXClientData) &data);
33 
34 		return data.returnCode;
35 	}
36 
37 private:
38 
39 	extern (C) static CXChildVisitResult visitorFunction (CXCursor cursor, CXCursor parent, CXClientData data)
40 	{
41 		auto tmp = cast(OpApplyData*) data;
42 
43 		with (CXChildVisitResult)
44 		{
45 			auto dCursor = Cursor(cursor);
46 			auto dParent = Cursor(parent);
47 			auto r = tmp.dg(dCursor, dParent);
48 			tmp.returnCode = r;
49 			return r ? CXChildVisit_Break : CXChildVisit_Continue;
50 		}
51 	}
52 
53 	static struct OpApplyData
54 	{
55 		int returnCode;
56 		Delegate dg;
57 
58 		this (Delegate dg)
59 		{
60 			this.dg = dg;
61 		}
62 	}
63 	
64 	template Constructors ()
65 	{
66 		private Visitor visitor;
67 
68 		this (Visitor visitor)
69 		{
70 			this.visitor = visitor;
71 		}
72 
73 		this (CXCursor cursor)
74 		{
75 			visitor = Visitor(cursor);
76 		}
77 		
78 		this (Cursor cursor)
79 		{
80 			visitor = Visitor(cursor);
81 		}
82 	}
83 }
84 
85 struct DeclarationVisitor
86 {
87 	mixin Visitor.Constructors;
88 
89 	int opApply (Visitor.Delegate dg)
90 	{
91 		foreach (cursor, parent ; visitor)
92 			if (cursor.isDeclaration)
93 				if (auto result = dg(cursor, parent))
94 					return result;
95 				
96 		return 0;
97 	}
98 }
99 
100 struct TypedVisitor (CXCursorKind kind)
101 {
102 	private Visitor visitor;
103 	
104 	this (Visitor visitor)
105 	{
106 		this.visitor = visitor;
107 	}
108 
109 	this (CXCursor cursor)
110 	{
111 		this(Visitor(cursor));
112 	}
113 	
114 	this (Cursor cursor)
115 	{
116 		this(cursor.cx);
117 	}
118 
119 	int opApply (Visitor.Delegate dg)
120 	{
121 		foreach (cursor, parent ; visitor)
122 			if (cursor.kind == kind)
123 				if (auto result = dg(cursor, parent))
124 					return result;
125 				
126 		return 0;
127 	}
128 }
129 
130 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCInstanceMethodDecl) ObjCInstanceMethodVisitor;
131 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCClassMethodDecl) ObjCClassMethodVisitor;
132 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCPropertyDecl) ObjCPropertyVisitor;
133 alias TypedVisitor!(CXCursorKind.CXCursor_ObjCProtocolRef) ObjCProtocolVisitor;
134 
135 struct ParamVisitor
136 {
137 	mixin Visitor.Constructors;
138 	
139 	int opApply (int delegate (ref ParamCursor) dg)
140 	{
141 		foreach (cursor, parent ; visitor)
142 			if (cursor.kind == CXCursorKind.CXCursor_ParmDecl)
143 			{
144 				auto paramCursor = ParamCursor(cursor);
145 
146 				if (auto result = dg(paramCursor))
147 					return result;
148 			}
149 
150 		return 0;
151 	}
152 
153 	@property size_t length ()
154 	{
155 		auto type = Cursor(visitor.cursor).type;
156 
157 		if (type.isValid)
158 			return type.func.arguments.length;
159 
160 		else
161 		{
162 			size_t i;
163 
164 			foreach (_ ; this)
165 				i++;
166 
167 			return i;
168 		}
169 	}
170 
171 	@property bool any ()
172 	{
173 	    return length > 0;
174 	}
175 
176 	@property bool isEmpty ()
177 	{
178 		return !any;
179 	}
180 
181 	@property ParamCursor first ()
182 	{
183 		assert(any, "Cannot get the first parameter of an empty parameter list");
184 
185 		foreach (c ; this)
186 			return c;
187 
188 		assert(0, "Cannot get the first parameter of an empty parameter list");
189 	}
190 }