1 /**
2 	Contains definitions of the syntax tree elements.
3 
4 	Copyright: © 2012 RejectedSoftware e.K.
5 	License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
6 	Authors: Sönke Ludwig
7 */
8 module ddox.entities;
9 
10 import ddox.ddoc;
11 import std.algorithm : countUntil, joiner, map;
12 import std.range;
13 import std.string;
14 import std.typecons;
15 
16 
17 class Entity {
18 	Entity parent;
19 	string name;
20 	DocGroup docGroup;
21 
22 	this(Entity parent, string name)
23 	{
24 		this.parent = parent;
25 		this.name = name;
26 	}
27 
28 	@property string qualifiedName()
29 	const {
30 		string s = name;
31 		Rebindable!(const(Entity)) e = parent;
32 		while( e && e.parent ){
33 			s = e.name ~ "." ~ s;
34 			e = e.parent;
35 		}
36 		return s;
37 	}
38 
39 	@property string moduleName()
40 	const {
41 		Rebindable!(const(Entity)) e = this;
42 		while( e && !cast(Module)e ) e = e.parent;
43 		if( e ) return e.qualifiedName;
44 		return null;
45 	}
46 
47 	@property string nestedName()
48 	const {
49 		string s = name;
50 		Rebindable!(const(Entity)) e = parent;
51 		while( e && e.parent ){
52 			if( cast(Module)e ) break;
53 			s = e.name ~ "." ~ s;
54 			e = e.parent;
55 		}
56 		return s;
57 	}
58 
59 	@property string kindCaption() const { return "Entity"; }
60 
61 	bool isAncestorOf(in Entity node)
62 	const {
63 		auto n = rebindable(node);
64 		while( n ){
65 			if( n.parent is this ) return true;
66 			n = n.parent;
67 		}
68 		return false;
69 	}
70 
71 	abstract void iterateChildren(bool delegate(Entity) del);
72 
73 	final T findChild(T = Entity)(string name)
74 	{
75 		T ret;
76 		iterateChildren((ch){ if( ch.name == name ){ ret = cast(T)ch; return ret is null; } return true; });
77 		return ret;
78 	}
79 
80 	final T[] findChildren(T = Entity)(string name)
81 	{
82 		T[] ret;
83 		iterateChildren((ch){ if( ch.name == name ){ auto t = cast(T)ch; if( t ) ret ~= t; } return true; });
84 		return ret;
85 	}
86 
87 	final T lookup(T = Entity)(string qualified_name, bool recurse = true)
88 	{
89 		auto parts = split(qualified_name, ".");
90 		Entity e = this;
91 		foreach( i, p; parts ){
92 			if( i+1 < parts.length ){
93 				e = e.findChild(p);
94 				if( !e ) break;
95 			} else {
96 				auto r = e.findChild!T(p);
97 				if( r ) return r;
98 			}
99 		}
100 		static if (is(T == Declaration)) {
101 			if (auto decl = cast(Declaration)this) {
102 				auto idx = decl.templateArgs.countUntil!(p => p.name == qualified_name);
103 				if (idx >= 0) return decl.templateArgs[idx];
104 			}
105 		}
106 		if( recurse && parent ) return parent.lookup!T(qualified_name);
107 		return null;
108 	}
109 
110 	final T[] lookupAll(T = Entity)(string qualified_name)
111 	{
112 		auto parts = split(qualified_name, ".");
113 		Entity e = this;
114 		foreach( i, p; parts ){
115 			if( i+1 < parts.length ) e = e.findChild(p);
116 			else return e.findChildren!T(p);
117 			if( !e ) return null;
118 		}
119 		return null;
120 	}
121 
122 	final Entity lookdown(string qualified_name, bool stop_at_module_level = false)
123 	{
124 		auto parts = split(qualified_name, ".");
125 		Entity e = this;
126 		foreach( p; parts ){
127 			e = e.findChild(p);
128 			if( !e ){
129 				if( stop_at_module_level && cast(Module)this ) return null;
130 				Entity ret;
131 				iterateChildren((ch){
132 					if( auto res = (cast()ch).lookdown(qualified_name) ){
133 						ret = res;
134 						return false;
135 					}
136 					return true; 
137 				});
138 				return ret;
139 			}
140 		}
141 		return e;
142 	}
143 
144 	void visit(T)(void delegate(T) del)
145 	{
146 		if( auto t = cast(T)this ) del(t);
147 		iterateChildren((ch){ ch.visit!T(del); return true; });
148 	}
149 }
150 
151 final class DocGroup {
152 	Entity[] members;
153 	string text;
154 	DdocComment comment;
155 
156 	this(Entity entity, string text)
157 	{
158 		this.members = [entity];
159 		this.text = text;
160 		this.comment = new DdocComment(text);
161 	}
162 
163 	this(Entity entity, string text, DdocComment comment)
164 	{
165 		this.members = [entity];
166 		this.text = text;
167 		this.comment = comment;
168 	}
169 }
170 
171 final class Package : Entity {
172 	Package[] packages;
173 	Module[] modules;
174 
175 	this(Entity parent, string name){ super(parent, name); }
176 
177 	override @property string kindCaption() const { return "Package"; }
178 
179 	Module createModule(string name)
180 	{
181 		assert(findChild!Module(name) is null, "Module already present");
182 		auto mod = new Module(this, name);
183 		modules ~= mod;
184 		return mod;
185 	}
186 
187 	Package getOrAddPackage(string name)
188 	{
189 		foreach( p; packages )
190 			if( p.name == name )
191 				return p;
192 		auto pack = new Package(this, name);
193 		pack.docGroup = new DocGroup(pack, null);
194 		packages ~= pack;
195 		return pack;
196 	}
197 
198 	override void iterateChildren(bool delegate(Entity) del)
199 	{
200 		foreach( p; packages ) if( !del(p) ) return;
201 		foreach( m; modules ) if( !del(m) ) return;
202 	}
203 }
204 
205 final class Module : Entity{
206 	Declaration[] members;
207 	string file;
208 
209 	this(Entity parent, string name){ super(parent, name); }
210 
211 	override @property string kindCaption() const { return "Module"; }
212 
213 	override void iterateChildren(bool delegate(Entity) del)
214 	{
215 		foreach( m; members ) if( !del(m) ) return;
216 	}
217 }
218 
219 enum DeclarationKind {
220 	Variable,
221 	Function,
222 	Struct,
223 	Union,
224 	Class,
225 	Interface,
226 	Enum,
227 	EnumMember,
228 	Alias,
229 	Template,
230 	TemplateParameter
231 }
232 
233 enum Protection {
234 	Private,
235 	Package,
236 	Protected,
237 	Public
238 }
239 
240 class Declaration : Entity {
241 	Declaration inheritingDecl;
242 	Protection protection = Protection.Public;
243 	int line;
244 	bool isTemplate;
245 	TemplateParameterDeclaration[] templateArgs;
246 
247 	override @property string kindCaption() const { return "Declaration"; }
248 	abstract @property Declaration dup();
249 	abstract @property DeclarationKind kind();
250 	@property inout(Declaration) parentDeclaration() inout { return cast(inout(Declaration))parent; }
251 	@property Module module_() {
252 		Entity e = parent;
253 		while(e){
254 			if( auto m = cast(Module)e ) return m;
255 			e = e.parent;
256 		}
257 		assert(false, "Declaration without module?");
258 	}
259 	@property const(Module) module_() const {
260 		Rebindable!(const(Entity)) e = parent;
261 		while(e){
262 			if( auto m = cast(const(Module))e ) return m;
263 			e = e.parent;
264 		}
265 		assert(false, "Declaration without module?");
266 	}
267 
268 	@property string templateArgsString() const {
269 		if (!isTemplate) return null;
270 		return format("(%s)", (cast(string[])templateArgs.map!(a => a.name).array).join(", "));
271 	}
272 
273 	this(Entity parent, string name){ super(parent, name); }
274 
275 	abstract override void iterateChildren(bool delegate(Entity) del);
276 
277 	protected void copyFrom(Declaration src)
278 	{
279 		this.docGroup = src.docGroup;
280 		this.inheritingDecl = src.inheritingDecl;
281 		this.protection = src.protection;
282 		this.line = src.line;
283 		this.templateArgs = src.templateArgs;
284 	}
285 }
286 
287 class TypedDeclaration : Declaration {
288 	Type type;
289 
290 	this(Entity parent, string name){ super(parent, name); }
291 
292 	override @property string kindCaption() const { return "Typed declaration"; }
293 
294 	abstract override @property DeclarationKind kind() const;
295 
296 	abstract override void iterateChildren(bool delegate(Entity) del);
297 
298 	protected override void copyFrom(Declaration src)
299 	{
300 		super.copyFrom(src);
301 		if (auto tsrc = cast(TypedDeclaration)src)
302 			this.type = tsrc.type;
303 	}
304 }
305 
306 final class VariableDeclaration : TypedDeclaration {
307 	Value initializer;
308 
309 	override @property string kindCaption() const { return "Variable"; }
310 	override @property VariableDeclaration dup() { auto ret = new VariableDeclaration(parent, name); ret.copyFrom(this); ret.initializer = initializer; return ret; }
311 	override @property DeclarationKind kind() const { return DeclarationKind.Variable; }
312 
313 	this(Entity parent, string name){ super(parent, name); }
314 
315 	override void iterateChildren(bool delegate(Entity) del) {}
316 }
317 
318 final class FunctionDeclaration : TypedDeclaration {
319 	Type returnType;
320 	VariableDeclaration[] parameters;
321 	string[] attributes;
322 
323 	override @property string kindCaption() const { return "Function"; }
324 	override @property FunctionDeclaration dup() { auto ret = new FunctionDeclaration(parent, name); ret.copyFrom(this); ret.returnType = returnType; ret.parameters = parameters.dup; ret.attributes = attributes; return ret; }
325 	override @property DeclarationKind kind() const { return DeclarationKind.Function; }
326 
327 	this(Entity parent, string name){ super(parent, name); }
328 
329 	bool hasAttribute(string att) const { foreach( a; attributes ) if( a == att ) return true; return false; }
330 
331 	override void iterateChildren(bool delegate(Entity) del)
332 	{
333 		foreach( p; parameters ) del(p);
334 	}
335 }
336 
337 class CompositeTypeDeclaration : Declaration {
338 	Declaration[] members;
339 
340 	override @property string kindCaption() const { return "Composite type"; }
341 	override abstract @property DeclarationKind kind() const;
342  
343 	this(Entity parent, string name){ super(parent, name); }
344 
345 	override void iterateChildren(bool delegate(Entity) del)
346 	{
347 		foreach( m; members ) if( !del(m) ) return;
348 	}
349 }
350 
351 final class StructDeclaration : CompositeTypeDeclaration {
352 	override @property string kindCaption() const { return "Struct"; }
353 	override @property StructDeclaration dup() { auto ret = new StructDeclaration(parent, name); ret.copyFrom(this); ret.members = members; return ret; }
354 	override @property DeclarationKind kind() const { return DeclarationKind.Struct; }
355 
356 	this(Entity parent, string name){ super(parent, name); }
357 }
358 
359 final class UnionDeclaration : CompositeTypeDeclaration {
360 	override @property string kindCaption() const { return "Union"; }
361 	override @property UnionDeclaration dup() { auto ret = new UnionDeclaration(parent, name); ret.copyFrom(this); ret.members = members; return ret; }
362 	override @property DeclarationKind kind() const { return DeclarationKind.Union; }
363 
364 	this(Entity parent, string name){ super(parent, name); }
365 }
366 
367 final class InterfaceDeclaration : CompositeTypeDeclaration {
368 	Type[] derivedInterfaces;
369 
370 	override @property string kindCaption() const { return "Interface"; }
371 	override @property InterfaceDeclaration dup() { auto ret = new InterfaceDeclaration(parent, name); ret.copyFrom(this); ret.members = members; ret.derivedInterfaces = derivedInterfaces.dup; return ret; }
372 	override @property DeclarationKind kind() const { return DeclarationKind.Interface; }
373 
374 	this(Entity parent, string name){ super(parent, name); }
375 }
376 
377 final class ClassDeclaration : CompositeTypeDeclaration {
378 	Type baseClass;
379 	Type[] derivedInterfaces;
380 
381 	override @property string kindCaption() const { return "Class"; }
382 	override @property ClassDeclaration dup() { auto ret = new ClassDeclaration(parent, name); ret.copyFrom(this); ret.members = members; ret.baseClass = baseClass; ret.derivedInterfaces = derivedInterfaces.dup; return ret; }
383 	override @property DeclarationKind kind() const { return DeclarationKind.Class; }
384 
385 	this(Entity parent, string name){ super(parent, name); }
386 }
387 
388 final class EnumDeclaration : CompositeTypeDeclaration {
389 	Type baseType;
390 
391 	override @property string kindCaption() const { return "Enum"; }
392 	override @property EnumDeclaration dup() { auto ret = new EnumDeclaration(parent, name); ret.copyFrom(this); ret.members = members; ret.baseType = baseType; return ret; }
393 	override @property DeclarationKind kind() const { return DeclarationKind.Enum; }
394 
395 	this(Entity parent, string name){ super(parent, name); }
396 }
397 
398 final class EnumMemberDeclaration : Declaration {
399 	Value value;
400 
401 	override @property string kindCaption() const { return "Enum member"; }
402 	override @property EnumMemberDeclaration dup() { auto ret = new EnumMemberDeclaration(parent, name); ret.copyFrom(this); ret.value = value; return ret; }
403 	override @property DeclarationKind kind() const { return DeclarationKind.EnumMember; }
404 	@property Type type() { if( !value ) return null; return value.type; }
405 
406 	this(Entity parent, string name){ super(parent, name); }
407 
408 	override void iterateChildren(bool delegate(Entity) del) {}
409 }
410 
411 final class AliasDeclaration : Declaration {
412 	string[] attributes;
413 	Declaration targetDecl;
414 	Type targetType;
415 
416 	override @property string kindCaption() const { return "Alias"; }
417 	override @property AliasDeclaration dup() { auto ret = new AliasDeclaration(parent, name); ret.copyFrom(this); ret.targetDecl = targetDecl; ret.targetType = targetType; return ret; }
418 	override @property DeclarationKind kind() const { return DeclarationKind.Alias; }
419 	@property Type type() { return targetType; }
420 
421 	this(Entity parent, string name){ super(parent, name); }
422 
423 	override void iterateChildren(bool delegate(Entity) del) {}
424 }
425 
426 final class TemplateDeclaration : Declaration {
427 	Declaration[] members;
428 
429 	override @property string kindCaption() const { return "Template"; }
430 	override @property TemplateDeclaration dup() { auto ret = new TemplateDeclaration(parent, name); ret.copyFrom(this); ret.members = members.dup; return ret; }
431 	override @property DeclarationKind kind() const { return DeclarationKind.Template; }
432 
433 	this(Entity parent, string name){ super(parent, name); isTemplate = true; }
434 
435 	override void iterateChildren(bool delegate(Entity) del)
436 	{
437 		foreach( m; members ) del(m);
438 	}
439 }
440 
441 final class TemplateParameterDeclaration : TypedDeclaration {
442 	override @property string kindCaption() const { return "Template parameter"; }
443 	override @property TemplateParameterDeclaration dup() { auto ret = new TemplateParameterDeclaration(parent, name); ret.copyFrom(this); ret.type = type; return ret; }
444 	override @property DeclarationKind kind() const { return DeclarationKind.TemplateParameter; }
445 
446 	this(Entity parent, string name){ super(parent, name); type = new Type(this); }
447 
448 	override void iterateChildren(bool delegate(Entity) del) {}
449 }
450 
451 final class Value {
452 	Type type;
453 	string valueString;
454 }
455 
456 enum TypeKind {
457 	Primitive,
458 	Pointer,
459 	Array,
460 	StaticArray,
461 	AssociativeArray,
462 	Function,
463 	Delegate
464 }
465 
466 final class Type {
467 	TypeKind kind;
468 	string[] attributes;
469 	string[] modifiers;
470 	string templateArgs;
471 	string text; // original text as in DMDs JSON output
472 	// Primitive
473 	string typeName;
474 	Declaration typeDecl;
475 	// P, A, SA, AA
476 	Type elementType;
477 	// SA
478 	string arrayLength;
479 	// AA
480 	Type keyType;
481 	// Function/Delegate
482 	Type returnType;
483 	Type[] parameterTypes;
484 	string[] _parameterNames;
485 	Value[] _parameterDefaultValues;
486 
487 	this() {}
488 	this(Declaration decl) { kind = TypeKind.Primitive; text = decl.nestedName; typeName = text; typeDecl = decl; }
489 
490 	override equals_t opEquals(Object other_)
491 	{
492 		auto other = cast(Type)other_;
493 		if( !other ) return false;
494 		if( kind != other.kind ) return false;
495 		if( attributes != other.attributes ) return false; // TODO use set comparison instead
496 		if( modifiers != other.modifiers ) return false; // TODO: use set comparison instead
497 
498 		final switch( kind ){
499 			case TypeKind.Primitive: return typeName == other.typeName && typeDecl == other.typeDecl;
500 			case TypeKind.Pointer: 
501 			case TypeKind.Array: return elementType == other.elementType;
502 			case TypeKind.StaticArray: return elementType == other.elementType && arrayLength == other.arrayLength;
503 			case TypeKind.AssociativeArray: return elementType == other.elementType && keyType == other.keyType;
504 			case TypeKind.Function:
505 			case TypeKind.Delegate:
506 				if( returnType != other.returnType ) return false;
507 				if( parameterTypes.length != other.parameterTypes.length ) return false;
508 				foreach( i, p; parameterTypes )
509 					if( p != other.parameterTypes[i] )
510 						return false;
511 		}
512 		return true;
513 	}
514 }