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