1 // This file is part of Visual D 2 // 3 // Visual D integrates the D programming language into Visual Studio 4 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved 5 // 6 // Distributed under the Boost Software License, Version 1.0. 7 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 8 9 module vdc.ast.mod; 10 11 import vdc.util; 12 import vdc.semantic; 13 import vdc.lexer; 14 15 import vdc.ast.node; 16 import vdc.ast.decl; 17 import vdc.ast.expr; 18 import vdc.ast.misc; 19 import vdc.ast.aggr; 20 import vdc.ast.tmpl; 21 import vdc.ast.writer; 22 23 import vdc.parser.engine; 24 import vdc.interpret; 25 26 import stdext.util; 27 28 import std.conv; 29 import std.path; 30 import std.array; 31 import std.algorithm; 32 33 //////////////////////////////////////////////////////////////// 34 35 //Module: 36 // [ModuleDeclaration_opt DeclDef...] 37 class Module : Node 38 { 39 mixin ForwardCtor!(); 40 41 string filename; 42 bool imported; 43 Options options; 44 45 override Module clone() 46 { 47 Module n = static_cast!Module(super.clone()); 48 n.filename = filename; 49 n.imported = imported; 50 return n; 51 } 52 53 override bool compare(const(Node) n) const 54 { 55 if(!super.compare(n)) 56 return false; 57 58 auto tn = static_cast!(typeof(this))(n); 59 return tn.filename == filename 60 && tn.imported == imported; 61 } 62 63 64 Project getProject() { return static_cast!Project(parent); } 65 66 override void toD(CodeWriter writer) 67 { 68 foreach(m; members) 69 writer(m); 70 } 71 72 override void toC(CodeWriter writer) 73 { 74 if(members.length > 0 && cast(ModuleDeclaration) getMember(0)) 75 { 76 auto fqn = getMember(0).getMember!ModuleFullyQualifiedName(0); 77 78 foreach(m; fqn.members) 79 { 80 writer("namespace ", m, " {"); 81 writer.nl; 82 } 83 writer.nl; 84 foreach(m; members[1..$]) 85 writer(m); 86 87 writer.nl(false); 88 foreach_reverse(m; fqn.members) 89 { 90 writer("} // namespace ", m); 91 writer.nl; 92 } 93 } 94 else 95 { 96 writer("namespace ", baseName(filename), " {"); 97 writer.nl; 98 foreach(m; members) 99 writer(m); 100 writer.nl(false); 101 writer("} // namespace ", baseName(filename)); 102 writer.nl; 103 } 104 } 105 106 void writeNamespace(CodeWriter writer) 107 { 108 if(members.length > 0 && cast(ModuleDeclaration) getMember(0)) 109 { 110 auto fqn = getMember(0).getMember!ModuleFullyQualifiedName(0); 111 112 foreach(m; fqn.members) 113 writer("::", m); 114 } 115 else 116 writer("::", baseName(filename)); 117 writer("::"); 118 } 119 120 string getModuleName() 121 { 122 if(auto md = cast(ModuleDeclaration) getMember(0)) 123 { 124 auto mfqn = md.getMember!ModuleFullyQualifiedName(0); 125 string name = mfqn.getName(); 126 return name; 127 } 128 return stripExtension(baseName(filename)); 129 } 130 131 override bool createsScope() const { return true; } 132 133 override Scope enterScope(Scope sc) 134 { 135 initScope(); 136 return super.enterScope(sc); 137 } 138 139 override Scope getScope() 140 { 141 initScope(); 142 return scop; 143 } 144 145 void initScope() 146 { 147 if(!scop) 148 { 149 scop = new Scope; 150 scop.mod = this; 151 scop.node = this; 152 153 // add implicite import of module object 154 if(auto prj = getProject()) 155 if(auto objmod = prj.getObjectModule(this)) 156 if(objmod !is this) 157 { 158 auto imp = Import.create(objmod); // only needs module name 159 scop.addImport(imp); 160 } 161 162 super.addMemberSymbols(scop); 163 } 164 } 165 166 override void addMemberSymbols(Scope sc) 167 { 168 initScope(); 169 } 170 171 Scope.SearchSet search(string ident) 172 { 173 initScope(); 174 return scop.search(ident, false, false, true); 175 } 176 177 override void _semantic(Scope sc) 178 { 179 if(imported) // no full semantic on imports 180 return; 181 182 // the order in which lazy semantic analysis takes place: 183 // - evaluate/expand version/debug 184 // - evaluate mixins and static if conditionals in lexical order 185 // - analyze declarations: 186 // - instantiate templates 187 // - evaluate compile time expression 188 // to resolve identifiers: 189 // look in current scope, module 190 // if not found, search all imports 191 initScope(); 192 193 sc = sc.push(scop); 194 scope(exit) sc.pop(); 195 196 foreach(m; members) 197 { 198 m.semantic(scop); 199 } 200 } 201 202 public /* debug & version handling */ { 203 VersionDebug debugIds; 204 VersionDebug versionIds; 205 206 Options getOptions() 207 { 208 if(options) 209 return options; 210 if(auto prj = getProject()) 211 return prj.options; 212 return null; 213 } 214 215 void specifyVersion(string ident, TextPos pos) 216 { 217 if(Options opt = getOptions()) 218 if(opt.versionPredefined(ident) != 0) 219 semanticError("cannot define predefined version identifier " ~ ident); 220 versionIds.define(ident, pos); 221 } 222 223 void specifyVersion(int level) 224 { 225 versionIds.level = max(level, versionIds.level); 226 } 227 228 bool versionEnabled(string ident, TextPos pos) 229 { 230 if(Options opt = getOptions()) 231 if(opt.versionEnabled(ident)) 232 return true; 233 if(versionIds.defined(ident, pos)) 234 return true; 235 return false; 236 } 237 238 bool versionEnabled(int level) 239 { 240 if(Options opt = getOptions()) 241 if(opt.versionEnabled(level)) 242 return true; 243 return level <= versionIds.level; 244 } 245 246 void specifyDebug(string ident, TextPos pos) 247 { 248 debugIds.define(ident, pos); 249 } 250 251 void specifyDebug(int level) 252 { 253 debugIds.level = max(level, debugIds.level); 254 } 255 256 bool debugEnabled(string ident, TextPos pos) 257 { 258 if(Options opt = getOptions()) 259 { 260 if(!opt.debugOn) 261 return false; 262 if(opt.debugEnabled(ident)) 263 return true; 264 } 265 if(debugIds.defined(ident, pos)) 266 return true; 267 return false; 268 } 269 270 bool debugEnabled(int level) 271 { 272 if(Options opt = getOptions()) 273 { 274 if(!opt.debugOn) 275 return false; 276 if(opt.debugEnabled(level)) 277 return true; 278 } 279 return level <= debugIds.level; 280 } 281 bool debugEnabled() 282 { 283 if(Options opt = getOptions()) 284 return opt.debugOn; 285 return false; 286 } 287 288 } 289 } 290 291 //ModuleDeclaration: 292 // [ModuleFullyQualifiedName] 293 class ModuleDeclaration : Node 294 { 295 mixin ForwardCtor!(); 296 297 override void toD(CodeWriter writer) 298 { 299 writer("module ", getMember(0), ";"); 300 writer.nl; 301 } 302 } 303 304 class PackageIdentifier : Node 305 { 306 mixin ForwardCtor!(); 307 308 override void toD(CodeWriter writer) 309 { 310 assert(false); 311 } 312 } 313 314 //ModuleFullyQualifiedName: 315 // [Identifier...] 316 class ModuleFullyQualifiedName : Node 317 { 318 PackageIdentifier[] pkgs; 319 320 mixin ForwardCtor!(); 321 322 override void toD(CodeWriter writer) 323 { 324 writer.writeArray(members, "."); 325 } 326 327 override bool createsScope() const { return true; } 328 329 override void addSymbols(Scope sc) 330 { 331 for(int m = 0; m < members.length; m++) 332 { 333 auto id = getMember!Identifier(m); 334 string name = id.ident; 335 Scope.SearchSet syms = sc.search(name, false, false, false); 336 if(syms.length > 1) 337 { 338 semanticError("ambiguous use of package/module name ", name); 339 break; 340 } 341 else if(syms.length == 1) 342 { 343 Node n = syms.first(); 344 345 if(auto pkg = cast(PackageIdentifier)n) 346 { 347 sc = pkg.enterScope(sc); 348 pkgs ~= pkg; 349 } 350 else 351 { 352 semanticError("package/module name ", name, " also used as ", n); 353 break; 354 } 355 } 356 else 357 { 358 auto pkg = new PackageIdentifier(id.span); 359 sc.addSymbol(name, pkg); 360 sc = pkg.enterScope(sc); 361 pkgs ~= pkg; 362 } 363 } 364 } 365 366 string getName() 367 { 368 string name = getMember!Identifier(0).ident; 369 foreach(m; 1..members.length) 370 name ~= "." ~ getMember!Identifier(m).ident; 371 return name; 372 } 373 } 374 375 //EmptyDeclDef: 376 // [] 377 class EmptyDeclDef : Node 378 { 379 mixin ForwardCtor!(); 380 381 override void toD(CodeWriter writer) 382 { 383 writer(";"); 384 writer.nl; 385 } 386 } 387 388 //AttributeSpecifier: 389 // attributes annotations [DeclarationBlock_opt] 390 class AttributeSpecifier : Node 391 { 392 mixin ForwardCtor!(); 393 394 override void toD(CodeWriter writer) 395 { 396 writer.writeAttributesAndAnnotations(attr, annotation); 397 398 switch(id) 399 { 400 case TOK_colon: 401 assert(members.length == 0); 402 writer(":"); 403 writer.nl; 404 break; 405 case TOK_lcurly: 406 writer.nl; 407 //writer("{"); 408 //writer.nl; 409 //{ 410 // CodeIndenter indent = CodeIndenter(writer); 411 writer(getMember(0)); 412 //} 413 //writer("}"); 414 //writer.nl; 415 break; 416 default: 417 writer(getMember(0)); 418 break; 419 } 420 } 421 422 void applyAttributes(Node m) 423 { 424 m.attr = combineAttributes(attr, m.attr); 425 m.annotation = combineAnnotations(annotation, m.annotation); 426 } 427 428 override Node[] expandNonScopeBlock(Scope sc, Node[] athis) 429 { 430 switch(id) 431 { 432 case TOK_colon: 433 combineAttributes(sc.attributes, attr); 434 combineAnnotations(sc.attributes, annotation); 435 return []; 436 case TOK_lcurly: 437 auto db = getMember!DeclarationBlock(0); 438 foreach(m; db.members) 439 applyAttributes(m); 440 return db.removeAll(); 441 default: 442 applyAttributes(getMember(0)); 443 return removeAll(); 444 } 445 } 446 } 447 448 //UserAttributeSpecifier: 449 // ident [ArgumentList_opt] 450 class UserAttributeSpecifier : Node 451 { 452 mixin ForwardCtor!(); 453 454 string ident; 455 456 ArgumentList getArgumentList() { return getMember!ArgumentList(0); } 457 458 override void toD(CodeWriter writer) 459 { 460 writer(ident); 461 if(members.length) 462 { 463 writer("("); 464 writer.writeArray(members); 465 writer(")"); 466 } 467 } 468 469 override void addSymbols(Scope sc) 470 { 471 addMemberSymbols(sc); 472 } 473 override void _semantic(Scope sc) 474 { 475 } 476 } 477 478 //DeclarationBlock: 479 // [DeclDef...] 480 class DeclarationBlock : Node 481 { 482 mixin ForwardCtor!(); 483 484 override void toD(CodeWriter writer) 485 { 486 if(id == TOK_lcurly) 487 { 488 writer("{"); 489 writer.nl; 490 { 491 CodeIndenter indent = CodeIndenter(writer); 492 foreach(m; members) 493 writer(m); 494 } 495 writer("}"); 496 writer.nl; 497 } 498 else 499 foreach(m; members) 500 writer(m); 501 } 502 503 override Node[] expandNonScopeBlock(Scope sc, Node[] athis) 504 { 505 return removeAll(); 506 } 507 } 508 509 //LinkageAttribute: 510 // attribute 511 class LinkageAttribute : AttributeSpecifier 512 { 513 mixin ForwardCtor!(); 514 515 override Node[] expandNonScopeBlock(Scope sc, Node[] athis) 516 { 517 return super.expandNonScopeBlock(sc, athis); 518 } 519 } 520 521 //AlignAttribute: 522 // attribute 523 class AlignAttribute : AttributeSpecifier 524 { 525 mixin ForwardCtor!(); 526 } 527 528 //Pragma: 529 // ident [TemplateArgumentList] 530 class Pragma : Node 531 { 532 mixin ForwardCtor!(); 533 534 string ident; 535 536 TemplateArgumentList getTemplateArgumentList() { return getMember!TemplateArgumentList(0); } 537 538 override Pragma clone() 539 { 540 Pragma n = static_cast!Pragma(super.clone()); 541 n.ident = ident; 542 return n; 543 } 544 override bool compare(const(Node) n) const 545 { 546 if(!super.compare(n)) 547 return false; 548 549 auto tn = static_cast!(typeof(this))(n); 550 return tn.ident == ident; 551 } 552 553 override void toD(CodeWriter writer) 554 { 555 writer("pragma(", ident, ", ", getMember(0), ")"); 556 } 557 558 override void _semantic(Scope sc) 559 { 560 if(ident == "msg") 561 { 562 string msg; 563 auto alst = getTemplateArgumentList(); 564 alst.semantic(sc); 565 566 foreach(m; alst.members) 567 { 568 Value val = m.interpretCatch(nullContext); 569 msg ~= val.toMixin(); 570 } 571 semanticMessage(msg); 572 } 573 } 574 } 575 576 577 //ImportDeclaration: 578 // [ImportList] 579 class ImportDeclaration : Node 580 { 581 mixin ForwardCtor!(); 582 583 override void toD(CodeWriter writer) 584 { 585 writer("import ", getMember(0), ";"); 586 writer.nl(); 587 } 588 override void toC(CodeWriter writer) 589 { 590 } 591 592 override void _semantic(Scope sc) 593 { 594 getMember(0).annotation = annotation; // copy protection attributes 595 getMember(0).semantic(sc); 596 } 597 598 override void addSymbols(Scope sc) 599 { 600 getMember(0).addSymbols(sc); 601 } 602 603 } 604 605 //ImportList: 606 // [Import...] 607 class ImportList : Node 608 { 609 mixin ForwardCtor!(); 610 611 override void toD(CodeWriter writer) 612 { 613 writer.writeArray(members); 614 } 615 616 override void _semantic(Scope sc) 617 { 618 foreach(m; members) 619 { 620 m.annotation = annotation; // copy protection attributes 621 m.semantic(sc); 622 } 623 } 624 625 override void addSymbols(Scope sc) 626 { 627 foreach(m; members) 628 m.addSymbols(sc); 629 } 630 } 631 632 //Import: 633 // aliasIdent_opt [ModuleFullyQualifiedName ImportBindList_opt] 634 class Import : Node 635 { 636 mixin ForwardCtor!(); 637 638 string aliasIdent; 639 ImportBindList getImportBindList() { return members.length > 1 ? getMember!ImportBindList(1) : null; } 640 641 Annotation getProtection() 642 { 643 if(parent && parent.parent) 644 return parent.parent.annotation & Annotation_ProtectionMask; 645 return Annotation_Private; 646 } 647 648 // semantic data 649 Module mod; 650 int countLookups; 651 int countFound; 652 653 override Import clone() 654 { 655 Import n = static_cast!Import(super.clone()); 656 n.aliasIdent = aliasIdent; 657 return n; 658 } 659 660 override bool compare(const(Node) n) const 661 { 662 if(!super.compare(n)) 663 return false; 664 665 auto tn = static_cast!(typeof(this))(n); 666 return tn.aliasIdent == aliasIdent; 667 } 668 669 override void toD(CodeWriter writer) 670 { 671 if(aliasIdent.length) 672 writer(aliasIdent, " = "); 673 writer(getMember(0)); 674 if(auto bindList = getImportBindList()) 675 writer(" : ", bindList); 676 } 677 678 override void addSymbols(Scope sc) 679 { 680 sc.addImport(this); 681 if(aliasIdent.length > 0) 682 sc.addSymbol(aliasIdent, this); 683 684 auto mfqn = getMember!ModuleFullyQualifiedName(0); 685 mfqn.addSymbols(sc); 686 } 687 688 Scope.SearchSet search(Scope sc, string ident) 689 { 690 if(!mod) 691 if(auto prj = sc.mod.getProject()) 692 mod = prj.importModule(getModuleName(), this); 693 694 if(!mod) 695 return Scope.SearchSet(); 696 697 return mod.search(ident); 698 } 699 700 string getModuleName() 701 { 702 auto mfqn = getMember!ModuleFullyQualifiedName(0); 703 return mfqn.getName(); 704 } 705 706 static Import create(Module mod) 707 { 708 // TODO: no location info 709 auto id = new Identifier; 710 id.ident = mod.getModuleName(); // TODO: incorrect for modules in packages 711 auto mfqm = new ModuleFullyQualifiedName; 712 mfqm.addMember(id); 713 auto imp = new Import; 714 imp.addMember(mfqm); 715 return imp; 716 } 717 } 718 719 unittest 720 { 721 verifyParseWrite(q{ import test; }); 722 verifyParseWrite(q{ import ntest = pkg.test; }); 723 verifyParseWrite(q{ import io = std.stdio : writeln, write; }); 724 } 725 726 727 //ImportBindList: 728 // ImportBind 729 // ImportBind , ImportBindList 730 class ImportBindList : Node 731 { 732 mixin ForwardCtor!(); 733 734 override void toD(CodeWriter writer) 735 { 736 writer.writeArray(members); 737 } 738 } 739 740 741 //ImportBind: 742 // Identifier 743 // Identifier = Identifier 744 class ImportBind : Node 745 { 746 mixin ForwardCtor!(); 747 748 override void toD(CodeWriter writer) 749 { 750 writer(getMember(0)); 751 if(members.length > 1) 752 writer(" = ", getMember(1)); 753 } 754 } 755 756 //MixinDeclaration: 757 // mixin ( AssignExpression ) ; 758 class MixinDeclaration : Node 759 { 760 mixin ForwardCtor!(); 761 762 override void toD(CodeWriter writer) 763 { 764 writer("mixin(", getMember(0), ");"); 765 writer.nl; 766 } 767 768 override Node[] expandNonScopeInterpret(Scope sc, Node[] athis) 769 { 770 Context ctx = new Context(nullContext); 771 ctx.scop = sc; 772 Value v = getMember(0).interpret(ctx); 773 string s = v.toMixin(); 774 Parser parser = new Parser; 775 if(auto prj = sc.getProject()) 776 parser.saveErrors = prj.saveErrors; 777 return parser.parseDeclarations(s, span); 778 } 779 780 } 781 782 //Unittest: 783 // unittest BlockStatement 784 class Unittest : Node 785 { 786 mixin ForwardCtor!(); 787 788 override void toD(CodeWriter writer) 789 { 790 writer("unittest"); 791 writer.nl; 792 writer(getMember(0)); 793 } 794 795 override void toC(CodeWriter writer) 796 { 797 } 798 }