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