]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/dmodule.c
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/module.c
11 #include "root/dsystem.h"
12 #include "root/rmem.h"
18 #include "identifier.h"
22 #include "expression.h"
26 AggregateDeclaration
*Module::moduleinfo
;
28 Module
*Module::rootModule
;
29 DsymbolTable
*Module::modules
;
30 Modules
Module::amodules
;
32 Dsymbols
Module::deferred
; // deferred Dsymbol's needing semantic() run on them
33 Dsymbols
Module::deferred2
; // deferred Dsymbol's needing semantic2() run on them
34 Dsymbols
Module::deferred3
; // deferred Dsymbol's needing semantic3() run on them
35 unsigned Module::dprogress
;
39 modules
= new DsymbolTable();
42 Module::Module(const char *filename
, Identifier
*ident
, int doDocComment
, int doHdrGen
)
45 const char *srcfilename
;
47 // printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars());
54 isPackageFile
= false;
60 searchCacheIdent
= NULL
;
61 searchCacheSymbol
= NULL
;
91 srcfilename
= FileName::defaultExt(filename
, global
.mars_ext
.ptr
);
93 if (global
.run_noext
&& global
.params
.run
&&
94 !FileName::ext(filename
) &&
95 FileName::exists(srcfilename
) == 0 &&
96 FileName::exists(filename
) == 1)
98 FileName::free(srcfilename
);
99 srcfilename
= FileName::removeExt(filename
); // just does a mem.strdup(filename)
101 else if (!FileName::equalsExt(srcfilename
, global
.mars_ext
.ptr
) &&
102 !FileName::equalsExt(srcfilename
, global
.hdr_ext
.ptr
) &&
103 !FileName::equalsExt(srcfilename
, "dd"))
105 error("source file name '%s' must have .%s extension", srcfilename
, global
.mars_ext
);
108 srcfile
= new File(srcfilename
);
109 objfile
= setOutfile(global
.params
.objname
.ptr
, global
.params
.objdir
.ptr
, filename
, global
.obj_ext
.ptr
);
115 hdrfile
= setOutfile(global
.params
.hdrname
.ptr
, global
.params
.hdrdir
.ptr
, arg
, global
.hdr_ext
.ptr
);
117 //objfile = new File(objfilename);
120 Module
*Module::create(const char *filename
, Identifier
*ident
, int doDocComment
, int doHdrGen
)
122 return new Module(filename
, ident
, doDocComment
, doHdrGen
);
125 void Module::setDocfile()
127 docfile
= setOutfile(global
.params
.docname
.ptr
, global
.params
.docdir
.ptr
, arg
, global
.doc_ext
.ptr
);
130 /*********************************************
131 * Combines things into output file name for .html and .di files.
133 * name Command line name given for the file, NULL if none
134 * dir Command line directory given for the file, NULL if none
135 * arg Name of the source file
136 * ext File name extension to use if 'name' is NULL
137 * global.params.preservePaths get output path from arg
138 * srcfile Input file - output file name must not match input file
141 File
*Module::setOutfile(const char *name
, const char *dir
, const char *arg
, const char *ext
)
143 const char *docfilename
;
152 if (global
.params
.preservePaths
)
155 argdoc
= FileName::name(arg
);
157 // If argdoc doesn't have an absolute path, make it relative to dir
158 if (!FileName::absolute(argdoc
))
159 { //FileName::ensurePathExists(dir);
160 argdoc
= FileName::combine(dir
, argdoc
);
162 docfilename
= FileName::forceExt(argdoc
, ext
);
165 if (FileName::equals(docfilename
, srcfile
->name
->str
))
167 error("source file and output file have same name '%s'", srcfile
->name
->str
);
171 return new File(docfilename
);
174 void Module::deleteObjFile()
176 if (global
.params
.obj
)
182 const char *Module::kind() const
187 static void checkModFileAlias(OutBuffer
*buf
, OutBuffer
*dotmods
,
188 Array
<const char *> *ms
, size_t msdim
, const char *p
)
190 /* Check and replace the contents of buf[] with
191 * an alias string from global.params.modFileAliasStrings[]
193 dotmods
->writestring(p
);
194 for (size_t j
= msdim
; j
--;)
196 const char *m
= (*ms
)[j
];
197 const char *q
= strchr(m
, '=');
199 if (dotmods
->length() == (size_t)(q
- m
) && memcmp(dotmods
->peekChars(), m
, q
- m
) == 0)
202 size_t qlen
= strlen(q
+ 1);
203 if (qlen
&& (q
[qlen
] == '/' || q
[qlen
] == '\\'))
204 --qlen
; // remove trailing separator
205 buf
->write(q
+ 1, qlen
);
206 break; // last matching entry in ms[] wins
209 dotmods
->writeByte('.');
213 * Converts a chain of identifiers to the filename of the module
216 * packages = the names of the "parent" packages
217 * ident = the name of the child package or module
220 * the filename of the child package or module
222 static const char *getFilename(Identifiers
*packages
, Identifier
*ident
)
224 const char *filename
= ident
->toChars();
226 if (packages
== NULL
|| packages
->length
== 0)
231 Array
<const char *> *ms
= &global
.params
.modFileAliasStrings
;
232 const size_t msdim
= ms
? ms
->length
: 0;
234 for (size_t i
= 0; i
< packages
->length
; i
++)
236 Identifier
*pid
= (*packages
)[i
];
237 const char *p
= pid
->toChars();
240 checkModFileAlias(&buf
, &dotmods
, ms
, msdim
, p
);
247 buf
.writestring(filename
);
249 checkModFileAlias(&buf
, &dotmods
, ms
, msdim
, filename
);
251 filename
= (char *)buf
.extractData();
256 /********************************************
257 * Look for the source file if it's different from filename.
258 * Look for .di, .d, directory, and along global.path.
259 * Does not open the file.
261 * filename as supplied by the user
264 * NULL if it's not different from filename.
267 static const char *lookForSourceFile(const char *filename
)
269 /* Search along global.path for .di file, then .d file.
271 const char *sdi
= FileName::forceExt(filename
, global
.hdr_ext
.ptr
);
272 if (FileName::exists(sdi
) == 1)
275 const char *sd
= FileName::forceExt(filename
, global
.mars_ext
.ptr
);
276 if (FileName::exists(sd
) == 1)
279 if (FileName::exists(filename
) == 2)
281 /* The filename exists and it's a directory.
282 * Therefore, the result should be: filename/package.d
283 * iff filename/package.d is a file
285 const char *ni
= FileName::combine(filename
, "package.di");
286 if (FileName::exists(ni
) == 1)
289 const char *n
= FileName::combine(filename
, "package.d");
290 if (FileName::exists(n
) == 1)
295 if (FileName::absolute(filename
))
301 for (size_t i
= 0; i
< global
.path
->length
; i
++)
303 const char *p
= (*global
.path
)[i
];
304 const char *n
= FileName::combine(p
, sdi
);
305 if (FileName::exists(n
) == 1)
311 n
= FileName::combine(p
, sd
);
312 if (FileName::exists(n
) == 1)
318 const char *b
= FileName::removeExt(filename
);
319 n
= FileName::combine(p
, b
);
321 if (FileName::exists(n
) == 2)
323 const char *n2i
= FileName::combine(n
, "package.di");
324 if (FileName::exists(n2i
) == 1)
327 const char *n2
= FileName::combine(n
, "package.d");
328 if (FileName::exists(n2
) == 1)
339 Module
*Module::load(Loc loc
, Identifiers
*packages
, Identifier
*ident
)
341 //printf("Module::load(ident = '%s')\n", ident->toChars());
343 // Build module filename by turning:
347 const char *filename
= getFilename(packages
, ident
);
348 // Look for the source file
349 const char *result
= lookForSourceFile(filename
);
353 Module
*m
= new Module(filename
, ident
, 0, 0);
359 if (global
.params
.verbose
)
364 for (size_t i
= 0; i
< packages
->length
; i
++)
366 Identifier
*pid
= (*packages
)[i
];
367 buf
.writestring(pid
->toChars());
371 buf
.printf("%s\t(%s)", ident
->toChars(), m
->srcfile
->toChars());
372 message("import %s", buf
.peekChars());
377 // Call onImport here because if the module is going to be compiled then we
378 // need to determine it early because it affects semantic analysis. This is
379 // being done after parsing the module so the full module name can be taken
380 // from whatever was declared in the file.
381 if (!m
->isRoot() && Compiler::onImport(m
))
389 bool Module::read(Loc loc
)
391 //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars());
394 if (!strcmp(srcfile
->toChars(), "object.d"))
396 ::error(loc
, "cannot find source code for runtime library file 'object.d'");
397 errorSupplemental(loc
, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
398 const char *dmdConfFile
= global
.inifilename
.length
? FileName::canonicalName(global
.inifilename
.ptr
) : NULL
;
399 errorSupplemental(loc
, "config file: %s", dmdConfFile
? dmdConfFile
: "not found");
403 // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
404 bool isPackageMod
= (strcmp(toChars(), "package") != 0) &&
405 (strcmp(srcfile
->name
->name(), "package.d") == 0 || (strcmp(srcfile
->name
->name(), "package.di") == 0));
408 ::error(loc
, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'",
409 toChars(), srcfile
->toChars());
411 error(loc
, "is in file '%s' which cannot be read", srcfile
->toChars());
420 for (size_t i
= 0; i
< global
.path
->length
; i
++)
422 const char *p
= (*global
.path
)[i
];
423 fprintf(stderr
, "import path[%llu] = %s\n", (ulonglong
)i
, p
);
427 fprintf(stderr
, "Specify path to file '%s' with -I switch\n", srcfile
->toChars());
435 Module
*Module::parse()
437 //printf("Module::parse(srcfile='%s') this=%p\n", srcfile->name->toChars(), this);
439 const char *srcname
= srcfile
->name
->toChars();
440 //printf("Module::parse(srcname = '%s')\n", srcname);
442 isPackageFile
= (strcmp(srcfile
->name
->name(), "package.d") == 0 ||
443 strcmp(srcfile
->name
->name(), "package.di") == 0);
445 utf8_t
*buf
= (utf8_t
*)srcfile
->buffer
;
446 size_t buflen
= srcfile
->len
;
450 /* Convert all non-UTF-8 formats to UTF-8.
451 * BOM : http://www.unicode.org/faq/utf_bom.html
452 * 00 00 FE FF UTF-32BE, big-endian
453 * FF FE 00 00 UTF-32LE, little-endian
454 * FE FF UTF-16BE, big-endian
455 * FF FE UTF-16LE, little-endian
460 unsigned bom
= 1; // assume there's a BOM
461 if (buf
[0] == 0xFF && buf
[1] == 0xFE)
463 if (buflen
>= 4 && buf
[2] == 0 && buf
[3] == 0)
469 unsigned *pu
= (unsigned *)(buf
);
470 unsigned *pumax
= &pu
[buflen
/ 4];
473 { error("odd length of UTF-32 char source %u", buflen
);
477 dbuf
.reserve(buflen
/ 4);
478 for (pu
+= bom
; pu
< pumax
; pu
++)
481 u
= le
? Port::readlongLE(pu
) : Port::readlongBE(pu
);
485 { error("UTF-32 value %08x greater than 0x10FFFF", u
);
493 dbuf
.writeByte(0); // add 0 as sentinel for scanner
494 buflen
= dbuf
.length() - 1; // don't include sentinel in count
495 buf
= (utf8_t
*) dbuf
.extractData();
499 // Convert it to UTF-8
504 unsigned short *pu
= (unsigned short *)(buf
);
505 unsigned short *pumax
= &pu
[buflen
/ 2];
508 { error("odd length of UTF-16 char source %u", buflen
);
512 dbuf
.reserve(buflen
/ 2);
513 for (pu
+= bom
; pu
< pumax
; pu
++)
516 u
= le
? Port::readwordLE(pu
) : Port::readwordBE(pu
);
518 { if (u
>= 0xD800 && u
<= 0xDBFF)
522 { error("surrogate UTF-16 high value %04x at EOF", u
);
525 u2
= le
? Port::readwordLE(pu
) : Port::readwordBE(pu
);
526 if (u2
< 0xDC00 || u2
> 0xDFFF)
527 { error("surrogate UTF-16 low value %04x out of range", u2
);
530 u
= (u
- 0xD7C0) << 10;
533 else if (u
>= 0xDC00 && u
<= 0xDFFF)
534 { error("unpaired surrogate UTF-16 value %04x", u
);
537 else if (u
== 0xFFFE || u
== 0xFFFF)
538 { error("illegal UTF-16 value %04x", u
);
546 dbuf
.writeByte(0); // add 0 as sentinel for scanner
547 buflen
= dbuf
.length() - 1; // don't include sentinel in count
548 buf
= (utf8_t
*) dbuf
.extractData();
551 else if (buf
[0] == 0xFE && buf
[1] == 0xFF)
556 else if (buflen
>= 4 && buf
[0] == 0 && buf
[1] == 0 && buf
[2] == 0xFE && buf
[3] == 0xFF)
561 else if (buflen
>= 3 && buf
[0] == 0xEF && buf
[1] == 0xBB && buf
[2] == 0xBF)
569 /* There is no BOM. Make use of Arcane Jill's insight that
570 * the first char of D source must be ASCII to
571 * figure out the encoding.
576 { if (buf
[1] == 0 && buf
[2] == 0 && buf
[3] == 0)
581 else if (buf
[0] == 0 && buf
[1] == 0 && buf
[2] == 0)
594 else if (buf
[0] == 0)
603 { error("source file must start with BOM or ASCII character, not \\x%02X", buf
[0]);
609 /* If it starts with the string "Ddoc", then it's a documentation
612 if (buflen
>= 4 && memcmp(buf
, "Ddoc", 4) == 0)
621 Parser
p(this, buf
, buflen
, docfile
!= NULL
);
623 members
= p
.parseModule();
625 numlines
= p
.scanloc
.linnum
;
630 if (srcfile
->ref
== 0)
631 ::free(srcfile
->buffer
);
632 srcfile
->buffer
= NULL
;
635 /* The symbol table into which the module is to be inserted.
641 /* A ModuleDeclaration, md, was provided.
642 * The ModuleDeclaration sets the packages this module appears in, and
643 * the name of this module.
645 this->ident
= md
->id
;
646 Package
*ppack
= NULL
;
647 dst
= Package::resolve(md
->packages
, &this->parent
, &ppack
);
650 Module
*m
= ppack
? ppack
->isModule() : NULL
;
651 if (m
&& (strcmp(m
->srcfile
->name
->name(), "package.d") != 0 &&
652 strcmp(m
->srcfile
->name
->name(), "package.di") != 0))
654 ::error(md
->loc
, "package name '%s' conflicts with usage as a module name in file %s",
655 ppack
->toPrettyChars(), m
->srcfile
->toChars());
660 /* The name of the module is set to the source file name.
661 * There are no packages.
663 dst
= modules
; // and so this module goes into global module symbol table
665 /* Check to see if module name is a valid identifier
667 if (!Identifier::isValidIdentifier(this->ident
->toChars()))
668 error("has non-identifier characters in filename, use module declaration instead");
671 // Insert module into the symbol table
675 /* If the source tree is as follows:
679 * the 'pkg' will be incorporated to the internal package tree in two ways:
684 * If both are used in one compilation, 'pkg' as a module (== pkg/package.d)
685 * and a package name 'pkg' will conflict each other.
687 * To avoid the conflict:
688 * 1. If preceding package name insertion had occurred by Package::resolve,
689 * reuse the previous wrapping 'Package' if it exists
690 * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
692 * Then change Package::isPkgMod to PKGmodule and set Package::mod.
694 * Note that the 'wrapping Package' is the Package that contains package.d and other submodules,
695 * the one inserted to the symbol table.
697 Dsymbol
*ps
= dst
->lookup(ident
);
698 Package
*p
= ps
? ps
->isPackage() : NULL
;
701 p
= new Package(ident
);
702 p
->tag
= this->tag
; // reuse the same package tag
703 p
->symtab
= new DsymbolTable();
705 this->tag
= p
->tag
; // reuse the 'older' package tag
707 p
->parent
= this->parent
;
708 p
->isPkgMod
= PKGmodule
;
714 /* It conflicts with a name that is already in the symbol table.
715 * Figure out what went wrong, and issue error message.
717 Dsymbol
*prev
= dst
->lookup(ident
);
719 if (Module
*mprev
= prev
->isModule())
721 if (FileName::compare(srcname
, mprev
->srcfile
->toChars()) != 0)
722 error(loc
, "from file %s conflicts with another module %s from file %s",
723 srcname
, mprev
->toChars(), mprev
->srcfile
->toChars());
724 else if (isRoot() && mprev
->isRoot())
725 error(loc
, "from file %s is specified twice on the command line",
728 error(loc
, "from file %s must be imported with 'import %s;'",
729 srcname
, toPrettyChars());
731 // Bugzilla 14446: Return previously parsed module to avoid AST duplication ICE.
734 else if (Package
*pkg
= prev
->isPackage())
736 // 'package.d' loaded after a previous 'Package' insertion
738 amodules
.push(this); // Add to global array of all modules
740 error(md
? md
->loc
: loc
, "from file %s conflicts with package name %s",
741 srcname
, pkg
->toChars());
744 assert(global
.errors
);
748 // Add to global array of all modules
751 Compiler::onParseModule(this);
755 void Module::importAll(Scope
*)
757 //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
760 return; // already done
764 error("is a Ddoc file, cannot import it");
768 /* Note that modules get their own scope, from scratch.
769 * This is so regardless of where in the syntax a module
770 * gets imported, it is unaffected by context.
773 Scope
*sc
= Scope::createGlobal(this); // create root scope
776 md
->msg
= semanticString(sc
, md
->msg
, "deprecation message");
778 // Add import of "object", even for the "object" module.
779 // If it isn't there, some compiler rewrites, like
780 // classinst == classinst -> .object.opEquals(classinst, classinst)
781 // would fail inside object.d.
782 if (members
->length
== 0 || ((*members
)[0])->ident
!= Id::object
||
783 (*members
)[0]->isImport() == NULL
)
785 Import
*im
= new Import(Loc(), NULL
, Id::object
, NULL
, 0);
791 // Add all symbols into module's symbol table
792 symtab
= new DsymbolTable();
793 for (size_t i
= 0; i
< members
->length
; i
++)
795 Dsymbol
*s
= (*members
)[i
];
796 s
->addMember(sc
, sc
->scopesym
);
799 // anything else should be run after addMember, so version/debug symbols are defined
801 /* Set scope for the symbols so that if we forward reference
802 * a symbol, it can possibly be resolved on the spot.
803 * If this works out well, it can be extended to all modules
804 * before any semantic() on any of them.
806 setScope(sc
); // remember module scope for semantic
807 for (size_t i
= 0; i
< members
->length
; i
++)
809 Dsymbol
*s
= (*members
)[i
];
813 for (size_t i
= 0; i
< members
->length
; i
++)
815 Dsymbol
*s
= (*members
)[i
];
820 sc
->pop(); // 2 pops because Scope::createGlobal() created 2
823 /**********************************
824 * Determine if we need to generate an instance of ModuleInfo
828 int Module::needModuleInfo()
830 //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov);
831 return needmoduleinfo
|| global
.params
.cov
;
834 Dsymbol
*Module::search(const Loc
&loc
, Identifier
*ident
, int flags
)
836 /* Since modules can be circularly referenced,
837 * need to stop infinite recursive searches.
838 * This is done with the cache.
841 //printf("%s Module::search('%s', flags = x%x) insearch = %d\n", toChars(), ident->toChars(), flags, insearch);
845 /* Qualified module searches always search their imports,
846 * even if SearchLocalsOnly
848 if (!(flags
& SearchUnqualifiedModule
))
849 flags
&= ~(SearchUnqualifiedModule
| SearchLocalsOnly
);
851 if (searchCacheIdent
== ident
&& searchCacheFlags
== flags
)
853 //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
854 // toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null");
855 return searchCacheSymbol
;
858 unsigned int errors
= global
.errors
;
861 Dsymbol
*s
= ScopeDsymbol::search(loc
, ident
, flags
);
864 if (errors
== global
.errors
)
866 // Bugzilla 10752: We can cache the result only when it does not cause
867 // access error so the side-effect should be reproduced in later search.
868 searchCacheIdent
= ident
;
869 searchCacheSymbol
= s
;
870 searchCacheFlags
= flags
;
875 bool Module::isPackageAccessible(Package
*p
, Prot protection
, int flags
)
877 if (insearch
) // don't follow import cycles
879 if (flags
& IgnorePrivateImports
)
880 protection
= Prot(Prot::public_
); // only consider public imports
882 bool r
= ScopeDsymbol::isPackageAccessible(p
, protection
);
887 Dsymbol
*Module::symtabInsert(Dsymbol
*s
)
889 searchCacheIdent
= NULL
; // symbol is inserted, so invalidate cache
890 return Package::symtabInsert(s
);
893 void Module::clearCache()
895 for (size_t i
= 0; i
< amodules
.length
; i
++)
897 Module
*m
= amodules
[i
];
898 m
->searchCacheIdent
= NULL
;
902 /*******************************************
903 * Can't run semantic on s now, try again later.
906 void Module::addDeferredSemantic(Dsymbol
*s
)
908 // Don't add it if it is already there
909 for (size_t i
= 0; i
< deferred
.length
; i
++)
911 Dsymbol
*sd
= deferred
[i
];
917 //printf("Module::addDeferredSemantic('%s')\n", s->toChars());
921 void Module::addDeferredSemantic2(Dsymbol
*s
)
923 //printf("Module::addDeferredSemantic2('%s')\n", s->toChars());
927 void Module::addDeferredSemantic3(Dsymbol
*s
)
929 //printf("Module::addDeferredSemantic3('%s')\n", s->toChars());
933 /******************************************
934 * Run semantic() on deferred symbols.
937 void Module::runDeferredSemantic()
945 //if (deferred.length) printf("+Module::runDeferredSemantic(), len = %d\n", deferred.length);
952 len
= deferred
.length
;
957 Dsymbol
**todoalloc
= NULL
;
965 todo
= (Dsymbol
**)mem
.xmalloc(len
* sizeof(Dsymbol
*));
968 memcpy(todo
, deferred
.tdata(), len
* sizeof(Dsymbol
*));
971 for (size_t i
= 0; i
< len
; i
++)
973 Dsymbol
*s
= todo
[i
];
975 dsymbolSemantic(s
, NULL
);
976 //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars());
978 //printf("\tdeferred.length = %d, len = %d, dprogress = %d\n", deferred.length, len, dprogress);
981 } while (deferred
.length
< len
|| dprogress
); // while making progress
983 //printf("-Module::runDeferredSemantic(), len = %d\n", deferred.length);
986 void Module::runDeferredSemantic2()
988 Module::runDeferredSemantic();
990 Dsymbols
*a
= &Module::deferred2
;
991 for (size_t i
= 0; i
< a
->length
; i
++)
993 Dsymbol
*s
= (*a
)[i
];
994 //printf("[%d] %s semantic2a\n", i, s->toPrettyChars());
1003 void Module::runDeferredSemantic3()
1005 Module::runDeferredSemantic2();
1007 Dsymbols
*a
= &Module::deferred3
;
1008 for (size_t i
= 0; i
< a
->length
; i
++)
1010 Dsymbol
*s
= (*a
)[i
];
1011 //printf("[%d] %s semantic3a\n", i, s->toPrettyChars());
1021 /************************************
1022 * Recursively look at every module this module imports,
1023 * return true if it imports m.
1024 * Can be used to detect circular imports.
1027 int Module::imports(Module
*m
)
1029 //printf("%s Module::imports(%s)\n", toChars(), m->toChars());
1030 for (size_t i
= 0; i
< aimports
.length
; i
++)
1032 Module
*mi
= aimports
[i
];
1038 int r
= mi
->imports(m
);
1046 /*************************************
1047 * Return true if module imports itself.
1050 bool Module::selfImports()
1052 //printf("Module::selfImports() %s\n", toChars());
1053 if (selfimports
== 0)
1055 for (size_t i
= 0; i
< amodules
.length
; i
++)
1056 amodules
[i
]->insearch
= 0;
1058 selfimports
= imports(this) + 1;
1060 for (size_t i
= 0; i
< amodules
.length
; i
++)
1061 amodules
[i
]->insearch
= 0;
1063 return selfimports
== 2;
1066 /*************************************
1067 * Return true if module imports root module.
1070 bool Module::rootImports()
1072 //printf("Module::rootImports() %s\n", toChars());
1073 if (rootimports
== 0)
1075 for (size_t i
= 0; i
< amodules
.length
; i
++)
1076 amodules
[i
]->insearch
= 0;
1079 for (size_t i
= 0; i
< amodules
.length
; ++i
)
1081 Module
*m
= amodules
[i
];
1082 if (m
->isRoot() && imports(m
))
1089 for (size_t i
= 0; i
< amodules
.length
; i
++)
1090 amodules
[i
]->insearch
= 0;
1092 return rootimports
== 2;
1095 bool Module::isCoreModule(Identifier
*ident
)
1097 return this->ident
== ident
&& parent
&& parent
->ident
== Id::core
&& !parent
->parent
;
1100 /* =========================== ModuleDeclaration ===================== */
1102 ModuleDeclaration::ModuleDeclaration(Loc loc
, Identifiers
*packages
, Identifier
*id
)
1105 this->packages
= packages
;
1107 this->isdeprecated
= false;
1111 const char *ModuleDeclaration::toChars()
1115 if (packages
&& packages
->length
)
1117 for (size_t i
= 0; i
< packages
->length
; i
++)
1119 Identifier
*pid
= (*packages
)[i
];
1120 buf
.writestring(pid
->toChars());
1124 buf
.writestring(id
->toChars());
1125 return buf
.extractChars();
1128 /* =========================== Package ===================== */
1130 Package::Package(Identifier
*ident
)
1131 : ScopeDsymbol(ident
)
1133 this->isPkgMod
= PKGunknown
;
1135 static unsigned packageTag
= 0;
1136 this->tag
= packageTag
++;
1140 const char *Package::kind() const
1145 Module
*Package::isPackageMod()
1147 if (isPkgMod
== PKGmodule
)
1155 * Checks for the existence of a package.d to set isPkgMod appropriately
1156 * if isPkgMod == PKGunknown
1158 void Package::resolvePKGunknown()
1162 if (isPkgMod
!= PKGunknown
)
1165 Identifiers packages
;
1166 for (Dsymbol
*s
= this->parent
; s
; s
= s
->parent
)
1167 packages
.insert(0, s
->ident
);
1169 if (lookForSourceFile(getFilename(&packages
, ident
)))
1170 Module::load(Loc(), &packages
, this->ident
);
1172 isPkgMod
= PKGpackage
;
1176 * Checks if pkg is a sub-package of this
1178 * For example, if this qualifies to 'a1.a2' and pkg - to 'a1.a2.a3',
1179 * this function returns 'true'. If it is other way around or qualified
1180 * package paths conflict function returns 'false'.
1183 * pkg = possible subpackage
1188 bool Package::isAncestorPackageOf(const Package
* const pkg
) const
1192 if (!pkg
|| !pkg
->parent
)
1194 return isAncestorPackageOf(pkg
->parent
->isPackage());
1197 /****************************************************
1199 * packages[] the pkg1.pkg2 of pkg1.pkg2.mod
1201 * the symbol table that mod should be inserted into
1203 * *pparent the rightmost package, i.e. pkg2, or NULL if no packages
1204 * *ppkg the leftmost package, i.e. pkg1, or NULL if no packages
1207 DsymbolTable
*Package::resolve(Identifiers
*packages
, Dsymbol
**pparent
, Package
**ppkg
)
1209 DsymbolTable
*dst
= Module::modules
;
1210 Dsymbol
*parent
= NULL
;
1212 //printf("Package::resolve()\n");
1218 for (size_t i
= 0; i
< packages
->length
; i
++)
1220 Identifier
*pid
= (*packages
)[i
];
1222 Dsymbol
*p
= dst
->lookup(pid
);
1225 pkg
= new Package(pid
);
1227 pkg
->parent
= parent
;
1228 pkg
->symtab
= new DsymbolTable();
1232 pkg
= p
->isPackage();
1234 // It might already be a module, not a package, but that needs
1235 // to be checked at a higher level, where a nice error message
1236 // can be generated.
1237 // dot net needs modules and packages with same name
1239 // But we still need a symbol table for it
1241 pkg
->symtab
= new DsymbolTable();
1247 if (pkg
->isModule())
1249 // Return the module so that a nice error message can be generated
1251 *ppkg
= (Package
*)p
;
1261 Dsymbol
*Package::search(const Loc
&loc
, Identifier
*ident
, int flags
)
1263 //printf("%s Package::search('%s', flags = x%x)\n", toChars(), ident->toChars(), flags);
1264 flags
&= ~SearchLocalsOnly
; // searching an import is always transitive
1265 if (!isModule() && mod
)
1267 // Prefer full package name.
1268 Dsymbol
*s
= symtab
? symtab
->lookup(ident
) : NULL
;
1271 //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
1272 return mod
->search(loc
, ident
, flags
);
1275 return ScopeDsymbol::search(loc
, ident
, flags
);