1 /** 2 * Defines a package and module. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/module.html, Modules) 5 * 6 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmodule.d, _dmodule.d) 10 * Documentation: https://dlang.org/phobos/dmd_dmodule.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmodule.d 12 */ 13 14 module dmd.dmodule; 15 16 import core.stdc.stdio; 17 import core.stdc.stdlib; 18 import core.stdc.string; 19 import dmd.aggregate; 20 import dmd.arraytypes; 21 import dmd.astcodegen; 22 import dmd.compiler; 23 import dmd.gluelayer; 24 import dmd.dimport; 25 import dmd.dmacro; 26 import dmd.doc; 27 import dmd.dscope; 28 import dmd.dsymbol; 29 import dmd.dsymbolsem; 30 import dmd.errors; 31 import dmd.expression; 32 import dmd.expressionsem; 33 import dmd.globals; 34 import dmd.id; 35 import dmd.identifier; 36 import dmd.parse; 37 import dmd.root.array; 38 import dmd.root.file; 39 import dmd.root.filename; 40 import dmd.root.outbuffer; 41 import dmd.root.port; 42 import dmd.root.rmem; 43 import dmd.root.rootobject; 44 import dmd.root.string; 45 import dmd.semantic2; 46 import dmd.semantic3; 47 import dmd.utils; 48 import dmd.visitor; 49 50 version(Windows) { 51 extern (C) char* getcwd(char* buffer, size_t maxlen); 52 } else { 53 import core.sys.posix.unistd : getcwd; 54 } 55 56 /* =========================== ===================== */ 57 /******************************************** 58 * Look for the source file if it's different from filename. 59 * Look for .di, .d, directory, and along global.path. 60 * Does not open the file. 61 * Input: 62 * filename as supplied by the user 63 * global.path 64 * Returns: 65 * NULL if it's not different from filename. 66 */ 67 private const(char)[] lookForSourceFile(const(char)[] filename) 68 { 69 /* Search along global.path for .di file, then .d file. 70 */ 71 const sdi = FileName.forceExt(filename, global.hdr_ext); 72 if (FileName.exists(sdi) == 1) 73 return sdi; 74 scope(exit) FileName.free(sdi.ptr); 75 const sd = FileName.forceExt(filename, global.mars_ext); 76 if (FileName.exists(sd) == 1) 77 return sd; 78 scope(exit) FileName.free(sd.ptr); 79 if (FileName.exists(filename) == 2) 80 { 81 /* The filename exists and it's a directory. 82 * Therefore, the result should be: filename/package.d 83 * iff filename/package.d is a file 84 */ 85 const ni = FileName.combine(filename, "package.di"); 86 if (FileName.exists(ni) == 1) 87 return ni; 88 FileName.free(ni.ptr); 89 const n = FileName.combine(filename, "package.d"); 90 if (FileName.exists(n) == 1) 91 return n; 92 FileName.free(n.ptr); 93 } 94 if (FileName.absolute(filename)) 95 return null; 96 if (!global.path) 97 return null; 98 for (size_t i = 0; i < global.path.dim; i++) 99 { 100 const p = (*global.path)[i].toDString(); 101 const(char)[] n = FileName.combine(p, sdi); 102 if (FileName.exists(n) == 1) { 103 return n; 104 } 105 FileName.free(n.ptr); 106 n = FileName.combine(p, sd); 107 if (FileName.exists(n) == 1) { 108 return n; 109 } 110 FileName.free(n.ptr); 111 const b = FileName.removeExt(filename); 112 n = FileName.combine(p, b); 113 FileName.free(b.ptr); 114 if (FileName.exists(n) == 2) 115 { 116 const n2i = FileName.combine(n, "package.di"); 117 if (FileName.exists(n2i) == 1) 118 return n2i; 119 FileName.free(n2i.ptr); 120 const n2 = FileName.combine(n, "package.d"); 121 if (FileName.exists(n2) == 1) { 122 return n2; 123 } 124 FileName.free(n2.ptr); 125 } 126 FileName.free(n.ptr); 127 } 128 return null; 129 } 130 131 // function used to call semantic3 on a module's dependencies 132 void semantic3OnDependencies(Module m) 133 { 134 if (!m) 135 return; 136 137 if (m.semanticRun > PASS.semantic3) 138 return; 139 140 m.semantic3(null); 141 142 foreach (i; 1 .. m.aimports.dim) 143 semantic3OnDependencies(m.aimports[i]); 144 } 145 146 /** 147 * Remove generated .di files on error and exit 148 */ 149 void removeHdrFilesAndFail(ref Param params, ref Modules modules) 150 { 151 if (params.doHdrGeneration) 152 { 153 foreach (m; modules) 154 { 155 if (m.isHdrFile) 156 continue; 157 File.remove(m.hdrfile.toChars()); 158 } 159 } 160 161 fatal(); 162 } 163 164 /** 165 * Converts a chain of identifiers to the filename of the module 166 * 167 * Params: 168 * packages = the names of the "parent" packages 169 * ident = the name of the child package or module 170 * 171 * Returns: 172 * the filename of the child package or module 173 */ 174 private const(char)[] getFilename(Identifier[] packages, Identifier ident) 175 { 176 const(char)[] filename = ident.toString(); 177 178 if (packages.length == 0) 179 return filename; 180 181 OutBuffer buf; 182 OutBuffer dotmods; 183 auto modAliases = &global.params.modFileAliasStrings; 184 185 void checkModFileAlias(const(char)[] p) 186 { 187 /* Check and replace the contents of buf[] with 188 * an alias string from global.params.modFileAliasStrings[] 189 */ 190 dotmods.writestring(p); 191 foreach_reverse (const m; *modAliases) 192 { 193 const q = strchr(m, '='); 194 assert(q); 195 if (dotmods.length == q - m && memcmp(dotmods.peekChars(), m, q - m) == 0) 196 { 197 buf.setsize(0); 198 auto rhs = q[1 .. strlen(q)]; 199 if (rhs.length > 0 && (rhs[$ - 1] == '/' || rhs[$ - 1] == '\\')) 200 rhs = rhs[0 .. $ - 1]; // remove trailing separator 201 buf.writestring(rhs); 202 break; // last matching entry in ms[] wins 203 } 204 } 205 dotmods.writeByte('.'); 206 } 207 208 foreach (pid; packages) 209 { 210 const p = pid.toString(); 211 buf.writestring(p); 212 if (modAliases.dim) 213 checkModFileAlias(p); 214 version (Windows) 215 enum FileSeparator = '\\'; 216 else 217 enum FileSeparator = '/'; 218 buf.writeByte(FileSeparator); 219 } 220 buf.writestring(filename); 221 if (modAliases.dim) 222 checkModFileAlias(filename); 223 buf.writeByte(0); 224 filename = buf.extractSlice()[0 .. $ - 1]; 225 226 return filename; 227 } 228 229 enum PKG : int 230 { 231 unknown, // not yet determined whether it's a package.d or not 232 module_, // already determined that's an actual package.d 233 package_, // already determined that's an actual package 234 } 235 236 /*********************************************************** 237 */ 238 extern (C++) class Package : ScopeDsymbol 239 { 240 PKG isPkgMod = PKG.unknown; 241 uint tag; // auto incremented tag, used to mask package tree in scopes 242 Module mod; // !=null if isPkgMod == PKG.module_ 243 244 final extern (D) this(const ref Loc loc, Identifier ident) 245 { 246 super(loc, ident); 247 __gshared uint packageTag; 248 this.tag = packageTag++; 249 } 250 251 override const(char)* kind() const 252 { 253 return "package"; 254 } 255 256 override bool equals(const RootObject o) const 257 { 258 // custom 'equals' for bug 17441. "package a" and "module a" are not equal 259 if (this == o) 260 return true; 261 auto p = cast(Package)o; 262 return p && isModule() == p.isModule() && ident.equals(p.ident); 263 } 264 265 /**************************************************** 266 * Input: 267 * packages[] the pkg1.pkg2 of pkg1.pkg2.mod 268 * Returns: 269 * the symbol table that mod should be inserted into 270 * Output: 271 * *pparent the rightmost package, i.e. pkg2, or NULL if no packages 272 * *ppkg the leftmost package, i.e. pkg1, or NULL if no packages 273 */ 274 extern (D) static DsymbolTable resolve(Identifier[] packages, Dsymbol* pparent, Package* ppkg) 275 { 276 DsymbolTable dst = Module.modules; 277 Dsymbol parent = null; 278 //printf("Package::resolve()\n"); 279 if (ppkg) 280 *ppkg = null; 281 foreach (pid; packages) 282 { 283 Package pkg; 284 Dsymbol p = dst.lookup(pid); 285 if (!p) 286 { 287 pkg = new Package(Loc.initial, pid); 288 dst.insert(pkg); 289 pkg.parent = parent; 290 pkg.symtab = new DsymbolTable(); 291 } 292 else 293 { 294 pkg = p.isPackage(); 295 assert(pkg); 296 // It might already be a module, not a package, but that needs 297 // to be checked at a higher level, where a nice error message 298 // can be generated. 299 // dot net needs modules and packages with same name 300 // But we still need a symbol table for it 301 if (!pkg.symtab) 302 pkg.symtab = new DsymbolTable(); 303 } 304 parent = pkg; 305 dst = pkg.symtab; 306 if (ppkg && !*ppkg) 307 *ppkg = pkg; 308 if (pkg.isModule()) 309 { 310 // Return the module so that a nice error message can be generated 311 if (ppkg) 312 *ppkg = cast(Package)p; 313 break; 314 } 315 } 316 317 if (pparent) 318 *pparent = parent; 319 return dst; 320 } 321 322 override final inout(Package) isPackage() inout 323 { 324 return this; 325 } 326 327 /** 328 * Checks if pkg is a sub-package of this 329 * 330 * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3', 331 * this function returns 'true'. If it is other way around or qualified 332 * package paths conflict function returns 'false'. 333 * 334 * Params: 335 * pkg = possible subpackage 336 * 337 * Returns: 338 * see description 339 */ 340 final bool isAncestorPackageOf(const Package pkg) const 341 { 342 if (this == pkg) 343 return true; 344 if (!pkg || !pkg.parent) 345 return false; 346 return isAncestorPackageOf(pkg.parent.isPackage()); 347 } 348 349 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 350 { 351 //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); 352 flags &= ~SearchLocalsOnly; // searching an import is always transitive 353 if (!isModule() && mod) 354 { 355 // Prefer full package name. 356 Dsymbol s = symtab ? symtab.lookup(ident) : null; 357 if (s) 358 return s; 359 //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars()); 360 return mod.search(loc, ident, flags); 361 } 362 return ScopeDsymbol.search(loc, ident, flags); 363 } 364 365 override void accept(Visitor v) 366 { 367 v.visit(this); 368 } 369 370 final Module isPackageMod() 371 { 372 if (isPkgMod == PKG.module_) 373 { 374 return mod; 375 } 376 return null; 377 } 378 379 /** 380 * Checks for the existence of a package.d to set isPkgMod appropriately 381 * if isPkgMod == PKG.unknown 382 */ 383 final void resolvePKGunknown() 384 { 385 if (isModule()) 386 return; 387 if (isPkgMod != PKG.unknown) 388 return; 389 390 Identifier[] packages; 391 for (Dsymbol s = this.parent; s; s = s.parent) 392 packages ~= s.ident; 393 reverse(packages); 394 395 if (lookForSourceFile(getFilename(packages, ident))) 396 Module.load(Loc(), packages, this.ident); 397 else 398 isPkgMod = PKG.package_; 399 } 400 } 401 402 /*********************************************************** 403 */ 404 extern (C++) final class Module : Package 405 { 406 extern (C++) __gshared Module rootModule; 407 extern (C++) __gshared DsymbolTable modules; // symbol table of all modules 408 extern (C++) __gshared Modules amodules; // array of all modules 409 extern (C++) __gshared Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them 410 extern (C++) __gshared Dsymbols deferred2; // deferred Dsymbol's needing semantic2() run on them 411 extern (C++) __gshared Dsymbols deferred3; // deferred Dsymbol's needing semantic3() run on them 412 extern (C++) __gshared uint dprogress; // progress resolving the deferred list 413 414 static void _init() 415 { 416 modules = new DsymbolTable(); 417 } 418 419 /** 420 * Deinitializes the global state of the compiler. 421 * 422 * This can be used to restore the state set by `_init` to its original 423 * state. 424 */ 425 static void deinitialize() 426 { 427 modules = modules.init; 428 } 429 430 extern (C++) __gshared AggregateDeclaration moduleinfo; 431 432 const(char)[] arg; // original argument name 433 ModuleDeclaration* md; // if !=null, the contents of the ModuleDeclaration declaration 434 const FileName srcfile; // input source file 435 const FileName objfile; // output .obj file 436 const FileName hdrfile; // 'header' file 437 FileName docfile; // output documentation file 438 FileBuffer* srcBuffer; // set during load(), free'd in parse() 439 uint errors; // if any errors in file 440 uint numlines; // number of lines in source file 441 bool isHdrFile; // if it is a header (.di) file 442 bool isDocFile; // if it is a documentation input file, not D source 443 bool hasAlwaysInlines; // contains references to functions that must be inlined 444 bool isPackageFile; // if it is a package.d 445 Package pkg; // if isPackageFile is true, the Package that contains this package.d 446 Strings contentImportedFiles; // array of files whose content was imported 447 int needmoduleinfo; 448 int selfimports; // 0: don't know, 1: does not, 2: does 449 450 /************************************* 451 * Return true if module imports itself. 452 */ 453 bool selfImports() 454 { 455 //printf("Module::selfImports() %s\n", toChars()); 456 if (selfimports == 0) 457 { 458 for (size_t i = 0; i < amodules.dim; i++) 459 amodules[i].insearch = 0; 460 selfimports = imports(this) + 1; 461 for (size_t i = 0; i < amodules.dim; i++) 462 amodules[i].insearch = 0; 463 } 464 return selfimports == 2; 465 } 466 467 int rootimports; // 0: don't know, 1: does not, 2: does 468 469 /************************************* 470 * Return true if module imports root module. 471 */ 472 bool rootImports() 473 { 474 //printf("Module::rootImports() %s\n", toChars()); 475 if (rootimports == 0) 476 { 477 for (size_t i = 0; i < amodules.dim; i++) 478 amodules[i].insearch = 0; 479 rootimports = 1; 480 for (size_t i = 0; i < amodules.dim; ++i) 481 { 482 Module m = amodules[i]; 483 if (m.isRoot() && imports(m)) 484 { 485 rootimports = 2; 486 break; 487 } 488 } 489 for (size_t i = 0; i < amodules.dim; i++) 490 amodules[i].insearch = 0; 491 } 492 return rootimports == 2; 493 } 494 495 int insearch; 496 Identifier searchCacheIdent; 497 Dsymbol searchCacheSymbol; // cached value of search 498 int searchCacheFlags; // cached flags 499 500 /** 501 * A root module is one that will be compiled all the way to 502 * object code. This field holds the root module that caused 503 * this module to be loaded. If this module is a root module, 504 * then it will be set to `this`. This is used to determine 505 * ownership of template instantiation. 506 */ 507 Module importedFrom; 508 509 Dsymbols* decldefs; // top level declarations for this Module 510 511 Modules aimports; // all imported modules 512 513 uint debuglevel; // debug level 514 Identifiers* debugids; // debug identifiers 515 Identifiers* debugidsNot; // forward referenced debug identifiers 516 517 uint versionlevel; // version level 518 Identifiers* versionids; // version identifiers 519 Identifiers* versionidsNot; // forward referenced version identifiers 520 521 MacroTable macrotable; // document comment macros 522 Escape* escapetable; // document comment escapes 523 524 size_t nameoffset; // offset of module name from start of ModuleInfo 525 size_t namelen; // length of module name in characters 526 527 extern (D) this(const ref Loc loc, const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen) 528 { 529 super(loc, ident); 530 const(char)[] srcfilename; 531 //printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident.toChars()); 532 this.arg = filename; 533 srcfilename = FileName.defaultExt(filename, global.mars_ext); 534 if (global.run_noext && global.params.run && 535 !FileName.ext(filename) && 536 FileName.exists(srcfilename) == 0 && 537 FileName.exists(filename) == 1) 538 { 539 FileName.free(srcfilename.ptr); 540 srcfilename = FileName.removeExt(filename); // just does a mem.strdup(filename) 541 } 542 else if (!FileName.equalsExt(srcfilename, global.mars_ext) && 543 !FileName.equalsExt(srcfilename, global.hdr_ext) && 544 !FileName.equalsExt(srcfilename, "dd")) 545 { 546 547 error("source file name '%.*s' must have .%.*s extension", 548 cast(int)srcfilename.length, srcfilename.ptr, 549 cast(int)global.mars_ext.length, global.mars_ext.ptr); 550 fatal(); 551 } 552 553 srcfile = FileName(srcfilename); 554 objfile = setOutfilename(global.params.objname, global.params.objdir, filename, global.obj_ext); 555 if (doDocComment) 556 setDocfile(); 557 if (doHdrGen) 558 hdrfile = setOutfilename(global.params.hdrname, global.params.hdrdir, arg, global.hdr_ext); 559 escapetable = new Escape(); 560 } 561 562 extern (D) this(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen) 563 { 564 this(Loc.initial, filename, ident, doDocComment, doHdrGen); 565 } 566 567 static Module create(const(char)* filename, Identifier ident, int doDocComment, int doHdrGen) 568 { 569 return create(filename.toDString, ident, doDocComment, doHdrGen); 570 } 571 572 extern (D) static Module create(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen) 573 { 574 return new Module(Loc.initial, filename, ident, doDocComment, doHdrGen); 575 } 576 577 extern (C++) static Module load(Loc loc, Identifiers* packages, Identifier ident) 578 { 579 return load(loc, (*packages)[], ident); 580 } 581 582 extern (D) static Module load(Loc loc, Identifier[] packages, Identifier ident) 583 { 584 //printf("Module::load(ident = '%s')\n", ident.toChars()); 585 // Build module filename by turning: 586 // foo.bar.baz 587 // into: 588 // foo\bar\baz 589 const(char)[] filename = getFilename(packages, ident); 590 // Look for the source file 591 if (const result = lookForSourceFile(filename)) 592 filename = result; // leaks 593 594 auto m = new Module(loc, filename, ident, 0, 0); 595 596 if (!m.read(loc)) 597 return null; 598 if (global.params.verbose) 599 { 600 OutBuffer buf; 601 foreach (pid; packages) 602 { 603 buf.writestring(pid.toString()); 604 buf.writeByte('.'); 605 } 606 buf.printf("%s\t(%s)", ident.toChars(), m.srcfile.toChars()); 607 message("import %s", buf.peekChars()); 608 } 609 m = m.parse(); 610 611 // Call onImport here because if the module is going to be compiled then we 612 // need to determine it early because it affects semantic analysis. This is 613 // being done after parsing the module so the full module name can be taken 614 // from whatever was declared in the file. 615 if (!m.isRoot() && Compiler.onImport(m)) 616 { 617 m.importedFrom = m; 618 assert(m.isRoot()); 619 } 620 return m; 621 } 622 623 override const(char)* kind() const 624 { 625 return "module"; 626 } 627 628 /********************************************* 629 * Combines things into output file name for .html and .di files. 630 * Input: 631 * name Command line name given for the file, NULL if none 632 * dir Command line directory given for the file, NULL if none 633 * arg Name of the source file 634 * ext File name extension to use if 'name' is NULL 635 * global.params.preservePaths get output path from arg 636 * srcfile Input file - output file name must not match input file 637 */ 638 extern(D) FileName setOutfilename(const(char)[] name, const(char)[] dir, const(char)[] arg, const(char)[] ext) 639 { 640 const(char)[] docfilename; 641 if (name) 642 { 643 docfilename = name; 644 } 645 else 646 { 647 const(char)[] argdoc; 648 OutBuffer buf; 649 if (arg == "__stdin.d") 650 { 651 version (Posix) 652 import core.sys.posix.unistd : getpid; 653 else version (Windows) 654 import core.sys.windows.winbase : getpid = GetCurrentProcessId; 655 buf.printf("__stdin_%d.d", getpid()); 656 arg = buf[]; 657 } 658 if (global.params.preservePaths) 659 argdoc = arg; 660 else 661 argdoc = FileName.name(arg); 662 // If argdoc doesn't have an absolute path, make it relative to dir 663 if (!FileName.absolute(argdoc)) 664 { 665 //FileName::ensurePathExists(dir); 666 argdoc = FileName.combine(dir, argdoc); 667 } 668 docfilename = FileName.forceExt(argdoc, ext); 669 } 670 if (FileName.equals(docfilename, srcfile.toString())) 671 { 672 error("source file and output file have same name '%s'", srcfile.toChars()); 673 fatal(); 674 } 675 return FileName(docfilename); 676 } 677 678 extern (D) void setDocfile() 679 { 680 docfile = setOutfilename(global.params.docname, global.params.docdir, arg, global.doc_ext); 681 } 682 683 /** 684 * Loads the source buffer from the given read result into `this.srcBuffer`. 685 * 686 * Will take ownership of the buffer located inside `readResult`. 687 * 688 * Params: 689 * loc = the location 690 * readResult = the result of reading a file containing the source code 691 * 692 * Returns: `true` if successful 693 */ 694 bool loadSourceBuffer(const ref Loc loc, ref File.ReadResult readResult) 695 { 696 //printf("Module::loadSourceBuffer('%s') file '%s'\n", toChars(), srcfile.toChars()); 697 // take ownership of buffer 698 srcBuffer = new FileBuffer(readResult.extractSlice()); 699 if (readResult.success) 700 return true; 701 702 if (FileName.equals(srcfile.toString(), "object.d")) 703 { 704 .error(loc, "cannot find source code for runtime library file 'object.d'"); 705 errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions."); 706 const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found"; 707 errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr); 708 } 709 else 710 { 711 // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module 712 bool isPackageMod = (strcmp(toChars(), "package") != 0) && (strcmp(srcfile.name(), "package.d") == 0 || (strcmp(srcfile.name(), "package.di") == 0)); 713 if (isPackageMod) 714 .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars()); 715 else 716 error(loc, "is in file '%s' which cannot be read", srcfile.toChars()); 717 } 718 if (!global.gag) 719 { 720 /* Print path 721 */ 722 if (global.path) 723 { 724 foreach (i, p; *global.path) 725 fprintf(stderr, "import path[%llu] = %s\n", cast(ulong)i, p); 726 } 727 else 728 { 729 fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile.toChars()); 730 } 731 732 removeHdrFilesAndFail(global.params, Module.amodules); 733 } 734 return false; 735 } 736 737 /** 738 * Reads the file from `srcfile` and loads the source buffer. 739 * 740 * If makefile module dependency is requested, we add this module 741 * to the list of dependencies from here. 742 * 743 * Params: 744 * loc = the location 745 * 746 * Returns: `true` if successful 747 * See_Also: loadSourceBuffer 748 */ 749 bool read(const ref Loc loc) 750 { 751 if (srcBuffer) 752 return true; // already read 753 754 //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars()); 755 auto readResult = File.read(srcfile.toChars()); 756 757 if (global.params.emitMakeDeps) 758 { 759 global.params.makeDeps.push(srcfile.toChars()); 760 } 761 762 return loadSourceBuffer(loc, readResult); 763 } 764 765 /// syntactic parse 766 Module parse() 767 { 768 return parseModule!ASTCodegen(); 769 } 770 771 /// ditto 772 extern (D) Module parseModule(AST)() 773 { 774 775 776 enum Endian { little, big} 777 enum SourceEncoding { utf16, utf32} 778 779 /* 780 * Convert a buffer from UTF32 to UTF8 781 * Params: 782 * Endian = is the buffer big/little endian 783 * buf = buffer of UTF32 data 784 * Returns: 785 * input buffer reencoded as UTF8 786 */ 787 788 char[] UTF32ToUTF8(Endian endian)(const(char)[] buf) 789 { 790 static if (endian == Endian.little) 791 alias readNext = Port.readlongLE; 792 else 793 alias readNext = Port.readlongBE; 794 795 if (buf.length & 3) 796 { 797 error("odd length of UTF-32 char source %llu", cast(ulong) buf.length); 798 fatal(); 799 } 800 801 const (uint)[] eBuf = cast(const(uint)[])buf; 802 803 OutBuffer dbuf; 804 dbuf.reserve(eBuf.length); 805 806 foreach (i; 0 .. eBuf.length) 807 { 808 const u = readNext(&eBuf[i]); 809 if (u & ~0x7F) 810 { 811 if (u > 0x10FFFF) 812 { 813 error("UTF-32 value %08x greater than 0x10FFFF", u); 814 fatal(); 815 } 816 dbuf.writeUTF8(u); 817 } 818 else 819 dbuf.writeByte(u); 820 } 821 dbuf.writeByte(0); //add null terminator 822 return dbuf.extractSlice(); 823 } 824 825 /* 826 * Convert a buffer from UTF16 to UTF8 827 * Params: 828 * Endian = is the buffer big/little endian 829 * buf = buffer of UTF16 data 830 * Returns: 831 * input buffer reencoded as UTF8 832 */ 833 834 char[] UTF16ToUTF8(Endian endian)(const(char)[] buf) 835 { 836 static if (endian == Endian.little) 837 alias readNext = Port.readwordLE; 838 else 839 alias readNext = Port.readwordBE; 840 841 if (buf.length & 1) 842 { 843 error("odd length of UTF-16 char source %llu", cast(ulong) buf.length); 844 fatal(); 845 } 846 847 const (ushort)[] eBuf = cast(const(ushort)[])buf; 848 849 OutBuffer dbuf; 850 dbuf.reserve(eBuf.length); 851 852 //i will be incremented in the loop for high codepoints 853 foreach (ref i; 0 .. eBuf.length) 854 { 855 uint u = readNext(&eBuf[i]); 856 if (u & ~0x7F) 857 { 858 if (0xD800 <= u && u < 0xDC00) 859 { 860 i++; 861 if (i >= eBuf.length) 862 { 863 error("surrogate UTF-16 high value %04x at end of file", u); 864 fatal(); 865 } 866 const u2 = readNext(&eBuf[i]); 867 if (u2 < 0xDC00 || 0xE000 <= u2) 868 { 869 error("surrogate UTF-16 low value %04x out of range", u2); 870 fatal(); 871 } 872 u = (u - 0xD7C0) << 10; 873 u |= (u2 - 0xDC00); 874 } 875 else if (u >= 0xDC00 && u <= 0xDFFF) 876 { 877 error("unpaired surrogate UTF-16 value %04x", u); 878 fatal(); 879 } 880 else if (u == 0xFFFE || u == 0xFFFF) 881 { 882 error("illegal UTF-16 value %04x", u); 883 fatal(); 884 } 885 dbuf.writeUTF8(u); 886 } 887 else 888 dbuf.writeByte(u); 889 } 890 dbuf.writeByte(0); //add a terminating null byte 891 return dbuf.extractSlice(); 892 } 893 894 const(char)* srcname = srcfile.toChars(); 895 //printf("Module::parse(srcname = '%s')\n", srcname); 896 isPackageFile = (strcmp(srcfile.name(), "package.d") == 0 || 897 strcmp(srcfile.name(), "package.di") == 0); 898 const(char)[] buf = cast(const(char)[]) srcBuffer.data; 899 900 bool needsReencoding = true; 901 bool hasBOM = true; //assume there's a BOM 902 Endian endian; 903 SourceEncoding sourceEncoding; 904 905 if (buf.length >= 2) 906 { 907 /* Convert all non-UTF-8 formats to UTF-8. 908 * BOM : http://www.unicode.org/faq/utf_bom.html 909 * 00 00 FE FF UTF-32BE, big-endian 910 * FF FE 00 00 UTF-32LE, little-endian 911 * FE FF UTF-16BE, big-endian 912 * FF FE UTF-16LE, little-endian 913 * EF BB BF UTF-8 914 */ 915 if (buf[0] == 0xFF && buf[1] == 0xFE) 916 { 917 endian = Endian.little; 918 919 sourceEncoding = buf.length >= 4 && buf[2] == 0 && buf[3] == 0 920 ? SourceEncoding.utf32 921 : SourceEncoding.utf16; 922 } 923 else if (buf[0] == 0xFE && buf[1] == 0xFF) 924 { 925 endian = Endian.big; 926 sourceEncoding = SourceEncoding.utf16; 927 } 928 else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) 929 { 930 endian = Endian.big; 931 sourceEncoding = SourceEncoding.utf32; 932 } 933 else if (buf.length >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) 934 { 935 needsReencoding = false;//utf8 with BOM 936 } 937 else 938 { 939 /* There is no BOM. Make use of Arcane Jill's insight that 940 * the first char of D source must be ASCII to 941 * figure out the encoding. 942 */ 943 hasBOM = false; 944 if (buf.length >= 4 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) 945 { 946 endian = Endian.little; 947 sourceEncoding = SourceEncoding.utf32; 948 } 949 else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0) 950 { 951 endian = Endian.big; 952 sourceEncoding = SourceEncoding.utf32; 953 } 954 else if (buf.length >= 2 && buf[1] == 0) //try to check for UTF-16 955 { 956 endian = Endian.little; 957 sourceEncoding = SourceEncoding.utf16; 958 } 959 else if (buf[0] == 0) 960 { 961 endian = Endian.big; 962 sourceEncoding = SourceEncoding.utf16; 963 } 964 else { 965 // It's UTF-8 966 needsReencoding = false; 967 if (buf[0] >= 0x80) 968 { 969 error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); 970 fatal(); 971 } 972 } 973 } 974 //throw away BOM 975 if (hasBOM) 976 { 977 if (!needsReencoding) buf = buf[3..$];// utf-8 already 978 else if (sourceEncoding == SourceEncoding.utf32) buf = buf[4..$]; 979 else buf = buf[2..$]; //utf 16 980 } 981 } 982 // Assume the buffer is from memory and has not be read from disk. Assume UTF-8. 983 else if (buf.length >= 1 && (buf[0] == '\0' || buf[0] == 0x1A)) 984 needsReencoding = false; 985 //printf("%s, %d, %d, %d\n", srcfile.name.toChars(), needsReencoding, endian == Endian.little, sourceEncoding == SourceEncoding.utf16); 986 if (needsReencoding) 987 { 988 if (sourceEncoding == SourceEncoding.utf16) 989 { 990 buf = endian == Endian.little 991 ? UTF16ToUTF8!(Endian.little)(buf) 992 : UTF16ToUTF8!(Endian.big)(buf); 993 } 994 else 995 { 996 buf = endian == Endian.little 997 ? UTF32ToUTF8!(Endian.little)(buf) 998 : UTF32ToUTF8!(Endian.big)(buf); 999 } 1000 } 1001 1002 /* If it starts with the string "Ddoc", then it's a documentation 1003 * source file. 1004 */ 1005 if (buf.length>= 4 && buf[0..4] == "Ddoc") 1006 { 1007 comment = buf.ptr + 4; 1008 isDocFile = true; 1009 if (!docfile) 1010 setDocfile(); 1011 return this; 1012 } 1013 /* If it has the extension ".dd", it is also a documentation 1014 * source file. Documentation source files may begin with "Ddoc" 1015 * but do not have to if they have the .dd extension. 1016 * https://issues.dlang.org/show_bug.cgi?id=15465 1017 */ 1018 if (FileName.equalsExt(arg, "dd")) 1019 { 1020 comment = buf.ptr; // the optional Ddoc, if present, is handled above. 1021 isDocFile = true; 1022 if (!docfile) 1023 setDocfile(); 1024 return this; 1025 } 1026 /* If it has the extension ".di", it is a "header" file. 1027 */ 1028 if (FileName.equalsExt(arg, "di")) 1029 { 1030 isHdrFile = true; 1031 } 1032 { 1033 scope p = new Parser!AST(this, buf, cast(bool) docfile); 1034 p.nextToken(); 1035 members = p.parseModule(); 1036 p.reportDiagnostics(); 1037 md = p.md; 1038 numlines = p.scanloc.linnum; 1039 } 1040 srcBuffer.destroy(); 1041 srcBuffer = null; 1042 /* The symbol table into which the module is to be inserted. 1043 */ 1044 DsymbolTable dst; 1045 if (md) 1046 { 1047 /* A ModuleDeclaration, md, was provided. 1048 * The ModuleDeclaration sets the packages this module appears in, and 1049 * the name of this module. 1050 */ 1051 this.ident = md.id; 1052 Package ppack = null; 1053 dst = Package.resolve(md.packages, &this.parent, &ppack); 1054 1055 // Mark the package path as accessible from the current module 1056 // https://issues.dlang.org/show_bug.cgi?id=21661 1057 // Code taken from Import.addPackageAccess() 1058 if (md.packages.length > 0) 1059 { 1060 // module a.b.c.d; 1061 auto p = ppack; // a 1062 addAccessiblePackage(p, Visibility(Visibility.Kind.private_)); 1063 foreach (id; md.packages[1 .. $]) // [b, c] 1064 { 1065 p = cast(Package) p.symtab.lookup(id); 1066 addAccessiblePackage(p, Visibility(Visibility.Kind.private_)); 1067 } 1068 } 1069 assert(dst); 1070 Module m = ppack ? ppack.isModule() : null; 1071 if (m && (strcmp(m.srcfile.name(), "package.d") != 0 && 1072 strcmp(m.srcfile.name(), "package.di") != 0)) 1073 { 1074 .error(md.loc, "package name '%s' conflicts with usage as a module name in file %s", ppack.toPrettyChars(), m.srcfile.toChars()); 1075 } 1076 } 1077 else 1078 { 1079 /* The name of the module is set to the source file name. 1080 * There are no packages. 1081 */ 1082 dst = modules; // and so this module goes into global module symbol table 1083 /* Check to see if module name is a valid identifier 1084 */ 1085 if (!Identifier.isValidIdentifier(this.ident.toChars())) 1086 error("has non-identifier characters in filename, use module declaration instead"); 1087 } 1088 // Insert module into the symbol table 1089 Dsymbol s = this; 1090 if (isPackageFile) 1091 { 1092 /* If the source tree is as follows: 1093 * pkg/ 1094 * +- package.d 1095 * +- common.d 1096 * the 'pkg' will be incorporated to the internal package tree in two ways: 1097 * import pkg; 1098 * and: 1099 * import pkg.common; 1100 * 1101 * If both are used in one compilation, 'pkg' as a module (== pkg/package.d) 1102 * and a package name 'pkg' will conflict each other. 1103 * 1104 * To avoid the conflict: 1105 * 1. If preceding package name insertion had occurred by Package::resolve, 1106 * reuse the previous wrapping 'Package' if it exists 1107 * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here. 1108 * 1109 * Then change Package::isPkgMod to PKG.module_ and set Package::mod. 1110 * 1111 * Note that the 'wrapping Package' is the Package that contains package.d and other submodules, 1112 * the one inserted to the symbol table. 1113 */ 1114 auto ps = dst.lookup(ident); 1115 Package p = ps ? ps.isPackage() : null; 1116 if (p is null) 1117 { 1118 p = new Package(Loc.initial, ident); 1119 p.tag = this.tag; // reuse the same package tag 1120 p.symtab = new DsymbolTable(); 1121 } 1122 this.tag = p.tag; // reuse the 'older' package tag 1123 this.pkg = p; 1124 p.parent = this.parent; 1125 p.isPkgMod = PKG.module_; 1126 p.mod = this; 1127 s = p; 1128 } 1129 if (!dst.insert(s)) 1130 { 1131 /* It conflicts with a name that is already in the symbol table. 1132 * Figure out what went wrong, and issue error message. 1133 */ 1134 Dsymbol prev = dst.lookup(ident); 1135 assert(prev); 1136 if (Module mprev = prev.isModule()) 1137 { 1138 if (!FileName.equals(srcname, mprev.srcfile.toChars())) 1139 error(loc, "from file %s conflicts with another module %s from file %s", srcname, mprev.toChars(), mprev.srcfile.toChars()); 1140 else if (isRoot() && mprev.isRoot()) 1141 error(loc, "from file %s is specified twice on the command line", srcname); 1142 else 1143 error(loc, "from file %s must be imported with 'import %s;'", srcname, toPrettyChars()); 1144 // https://issues.dlang.org/show_bug.cgi?id=14446 1145 // Return previously parsed module to avoid AST duplication ICE. 1146 return mprev; 1147 } 1148 else if (Package pkg = prev.isPackage()) 1149 { 1150 // 'package.d' loaded after a previous 'Package' insertion 1151 if (isPackageFile) 1152 amodules.push(this); // Add to global array of all modules 1153 else 1154 error(md ? md.loc : loc, "from file %s conflicts with package name %s", srcname, pkg.toChars()); 1155 } 1156 else 1157 assert(global.errors); 1158 } 1159 else 1160 { 1161 // Add to global array of all modules 1162 amodules.push(this); 1163 } 1164 Compiler.onParseModule(this); 1165 return this; 1166 } 1167 1168 override void importAll(Scope* prevsc) 1169 { 1170 //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); 1171 if (_scope) 1172 return; // already done 1173 if (isDocFile) 1174 { 1175 error("is a Ddoc file, cannot import it"); 1176 return; 1177 } 1178 1179 /* Note that modules get their own scope, from scratch. 1180 * This is so regardless of where in the syntax a module 1181 * gets imported, it is unaffected by context. 1182 * Ignore prevsc. 1183 */ 1184 Scope* sc = Scope.createGlobal(this); // create root scope 1185 1186 if (md && md.msg) 1187 md.msg = semanticString(sc, md.msg, "deprecation message"); 1188 1189 // Add import of "object", even for the "object" module. 1190 // If it isn't there, some compiler rewrites, like 1191 // classinst == classinst -> .object.opEquals(classinst, classinst) 1192 // would fail inside object.d. 1193 if (members.dim == 0 || (*members)[0].ident != Id.object || 1194 (*members)[0].isImport() is null) 1195 { 1196 auto im = new Import(Loc.initial, null, Id.object, null, 0); 1197 members.shift(im); 1198 } 1199 if (!symtab) 1200 { 1201 // Add all symbols into module's symbol table 1202 symtab = new DsymbolTable(); 1203 for (size_t i = 0; i < members.dim; i++) 1204 { 1205 Dsymbol s = (*members)[i]; 1206 s.addMember(sc, sc.scopesym); 1207 } 1208 } 1209 // anything else should be run after addMember, so version/debug symbols are defined 1210 /* Set scope for the symbols so that if we forward reference 1211 * a symbol, it can possibly be resolved on the spot. 1212 * If this works out well, it can be extended to all modules 1213 * before any semantic() on any of them. 1214 */ 1215 setScope(sc); // remember module scope for semantic 1216 for (size_t i = 0; i < members.dim; i++) 1217 { 1218 Dsymbol s = (*members)[i]; 1219 s.setScope(sc); 1220 } 1221 for (size_t i = 0; i < members.dim; i++) 1222 { 1223 Dsymbol s = (*members)[i]; 1224 s.importAll(sc); 1225 } 1226 sc = sc.pop(); 1227 sc.pop(); // 2 pops because Scope.createGlobal() created 2 1228 } 1229 1230 /********************************** 1231 * Determine if we need to generate an instance of ModuleInfo 1232 * for this Module. 1233 */ 1234 int needModuleInfo() 1235 { 1236 //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov); 1237 return needmoduleinfo || global.params.cov; 1238 } 1239 1240 /******************************************* 1241 * Print deprecation warning if we're deprecated, when 1242 * this module is imported from scope sc. 1243 * 1244 * Params: 1245 * sc = the scope into which we are imported 1246 * loc = the location of the import statement 1247 */ 1248 void checkImportDeprecation(const ref Loc loc, Scope* sc) 1249 { 1250 if (md && md.isdeprecated && !sc.isDeprecated) 1251 { 1252 Expression msg = md.msg; 1253 if (StringExp se = msg ? msg.toStringExp() : null) 1254 { 1255 const slice = se.peekString(); 1256 deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr); 1257 } 1258 else 1259 deprecation(loc, "is deprecated"); 1260 } 1261 } 1262 1263 override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) 1264 { 1265 /* Since modules can be circularly referenced, 1266 * need to stop infinite recursive searches. 1267 * This is done with the cache. 1268 */ 1269 //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch); 1270 if (insearch) 1271 return null; 1272 1273 /* Qualified module searches always search their imports, 1274 * even if SearchLocalsOnly 1275 */ 1276 if (!(flags & SearchUnqualifiedModule)) 1277 flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); 1278 1279 if (searchCacheIdent == ident && searchCacheFlags == flags) 1280 { 1281 //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", 1282 // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); 1283 return searchCacheSymbol; 1284 } 1285 1286 uint errors = global.errors; 1287 1288 insearch = 1; 1289 Dsymbol s = ScopeDsymbol.search(loc, ident, flags); 1290 insearch = 0; 1291 1292 if (errors == global.errors) 1293 { 1294 // https://issues.dlang.org/show_bug.cgi?id=10752 1295 // Can cache the result only when it does not cause 1296 // access error so the side-effect should be reproduced in later search. 1297 searchCacheIdent = ident; 1298 searchCacheSymbol = s; 1299 searchCacheFlags = flags; 1300 } 1301 return s; 1302 } 1303 1304 override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) 1305 { 1306 if (insearch) // don't follow import cycles 1307 return false; 1308 insearch = true; 1309 scope (exit) 1310 insearch = false; 1311 if (flags & IgnorePrivateImports) 1312 visibility = Visibility(Visibility.Kind.public_); // only consider public imports 1313 return super.isPackageAccessible(p, visibility); 1314 } 1315 1316 override Dsymbol symtabInsert(Dsymbol s) 1317 { 1318 searchCacheIdent = null; // symbol is inserted, so invalidate cache 1319 return Package.symtabInsert(s); 1320 } 1321 1322 void deleteObjFile() 1323 { 1324 if (global.params.obj) 1325 File.remove(objfile.toChars()); 1326 if (docfile) 1327 File.remove(docfile.toChars()); 1328 } 1329 1330 /******************************************* 1331 * Can't run semantic on s now, try again later. 1332 */ 1333 extern (D) static void addDeferredSemantic(Dsymbol s) 1334 { 1335 //printf("Module::addDeferredSemantic('%s')\n", s.toChars()); 1336 deferred.push(s); 1337 } 1338 1339 extern (D) static void addDeferredSemantic2(Dsymbol s) 1340 { 1341 //printf("Module::addDeferredSemantic2('%s')\n", s.toChars()); 1342 deferred2.push(s); 1343 } 1344 1345 extern (D) static void addDeferredSemantic3(Dsymbol s) 1346 { 1347 //printf("Module::addDeferredSemantic3('%s')\n", s.toChars()); 1348 deferred3.push(s); 1349 } 1350 1351 /****************************************** 1352 * Run semantic() on deferred symbols. 1353 */ 1354 static void runDeferredSemantic() 1355 { 1356 if (dprogress == 0) 1357 return; 1358 1359 __gshared int nested; 1360 if (nested) 1361 return; 1362 //if (deferred.dim) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.dim); 1363 nested++; 1364 1365 size_t len; 1366 do 1367 { 1368 dprogress = 0; 1369 len = deferred.dim; 1370 if (!len) 1371 break; 1372 1373 Dsymbol* todo; 1374 Dsymbol* todoalloc = null; 1375 Dsymbol tmp; 1376 if (len == 1) 1377 { 1378 todo = &tmp; 1379 } 1380 else 1381 { 1382 todo = cast(Dsymbol*)Mem.check(malloc(len * Dsymbol.sizeof)); 1383 todoalloc = todo; 1384 } 1385 memcpy(todo, deferred.tdata(), len * Dsymbol.sizeof); 1386 deferred.setDim(0); 1387 1388 for (size_t i = 0; i < len; i++) 1389 { 1390 Dsymbol s = todo[i]; 1391 s.dsymbolSemantic(null); 1392 //printf("deferred: %s, parent = %s\n", s.toChars(), s.parent.toChars()); 1393 } 1394 //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); 1395 if (todoalloc) 1396 free(todoalloc); 1397 } 1398 while (deferred.dim < len || dprogress); // while making progress 1399 nested--; 1400 //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.dim); 1401 } 1402 1403 static void runDeferredSemantic2() 1404 { 1405 Module.runDeferredSemantic(); 1406 1407 Dsymbols* a = &Module.deferred2; 1408 for (size_t i = 0; i < a.dim; i++) 1409 { 1410 Dsymbol s = (*a)[i]; 1411 //printf("[%d] %s semantic2a\n", i, s.toPrettyChars()); 1412 s.semantic2(null); 1413 1414 if (global.errors) 1415 break; 1416 } 1417 a.setDim(0); 1418 } 1419 1420 static void runDeferredSemantic3() 1421 { 1422 Module.runDeferredSemantic2(); 1423 1424 Dsymbols* a = &Module.deferred3; 1425 for (size_t i = 0; i < a.dim; i++) 1426 { 1427 Dsymbol s = (*a)[i]; 1428 //printf("[%d] %s semantic3a\n", i, s.toPrettyChars()); 1429 s.semantic3(null); 1430 1431 if (global.errors) 1432 break; 1433 } 1434 a.setDim(0); 1435 } 1436 1437 extern (D) static void clearCache() 1438 { 1439 for (size_t i = 0; i < amodules.dim; i++) 1440 { 1441 Module m = amodules[i]; 1442 m.searchCacheIdent = null; 1443 } 1444 } 1445 1446 /************************************ 1447 * Recursively look at every module this module imports, 1448 * return true if it imports m. 1449 * Can be used to detect circular imports. 1450 */ 1451 int imports(Module m) 1452 { 1453 //printf("%s Module::imports(%s)\n", toChars(), m.toChars()); 1454 version (none) 1455 { 1456 for (size_t i = 0; i < aimports.dim; i++) 1457 { 1458 Module mi = cast(Module)aimports.data[i]; 1459 printf("\t[%d] %s\n", i, mi.toChars()); 1460 } 1461 } 1462 for (size_t i = 0; i < aimports.dim; i++) 1463 { 1464 Module mi = aimports[i]; 1465 if (mi == m) 1466 return true; 1467 if (!mi.insearch) 1468 { 1469 mi.insearch = 1; 1470 int r = mi.imports(m); 1471 if (r) 1472 return r; 1473 } 1474 } 1475 return false; 1476 } 1477 1478 bool isRoot() 1479 { 1480 return this.importedFrom == this; 1481 } 1482 1483 // true if the module source file is directly 1484 // listed in command line. 1485 bool isCoreModule(Identifier ident) 1486 { 1487 return this.ident == ident && parent && parent.ident == Id.core && !parent.parent; 1488 } 1489 1490 // Back end 1491 int doppelganger; // sub-module 1492 Symbol* cov; // private uint[] __coverage; 1493 uint* covb; // bit array of valid code line numbers 1494 Symbol* sictor; // module order independent constructor 1495 Symbol* sctor; // module constructor 1496 Symbol* sdtor; // module destructor 1497 Symbol* ssharedctor; // module shared constructor 1498 Symbol* sshareddtor; // module shared destructor 1499 Symbol* stest; // module unit test 1500 Symbol* sfilename; // symbol for filename 1501 1502 uint[uint] ctfe_cov; /// coverage information from ctfe execution_count[line] 1503 1504 override inout(Module) isModule() inout 1505 { 1506 return this; 1507 } 1508 1509 override void accept(Visitor v) 1510 { 1511 v.visit(this); 1512 } 1513 1514 /*********************************************** 1515 * Writes this module's fully-qualified name to buf 1516 * Params: 1517 * buf = The buffer to write to 1518 */ 1519 void fullyQualifiedName(ref OutBuffer buf) 1520 { 1521 buf.writestring(ident.toString()); 1522 1523 for (auto package_ = parent; package_ !is null; package_ = package_.parent) 1524 { 1525 buf.prependstring("."); 1526 buf.prependstring(package_.ident.toChars()); 1527 } 1528 } 1529 } 1530 1531 /*********************************************************** 1532 */ 1533 extern (C++) struct ModuleDeclaration 1534 { 1535 Loc loc; 1536 Identifier id; 1537 Identifier[] packages; // array of Identifier's representing packages 1538 bool isdeprecated; // if it is a deprecated module 1539 Expression msg; 1540 1541 extern (D) this(const ref Loc loc, Identifier[] packages, Identifier id, Expression msg, bool isdeprecated) 1542 { 1543 this.loc = loc; 1544 this.packages = packages; 1545 this.id = id; 1546 this.msg = msg; 1547 this.isdeprecated = isdeprecated; 1548 } 1549 1550 extern (C++) const(char)* toChars() const 1551 { 1552 OutBuffer buf; 1553 foreach (pid; packages) 1554 { 1555 buf.writestring(pid.toString()); 1556 buf.writeByte('.'); 1557 } 1558 buf.writestring(id.toString()); 1559 return buf.extractChars(); 1560 } 1561 1562 /// Provide a human readable representation 1563 extern (D) const(char)[] toString() const 1564 { 1565 return this.toChars().toDString; 1566 } 1567 }