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 }