1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity low)
4 module dil.semantic.Pass1;
5
6 import dil.ast.Visitor,
7 dil.ast.Node,
8 dil.ast.Declarations,
9 dil.ast.Expressions,
10 dil.ast.Statements,
11 dil.ast.Types,
12 dil.ast.Parameters;
13 import dil.semantic.Symbol,
14 dil.semantic.Symbols,
15 dil.semantic.Types,
16 dil.semantic.Scope,
17 dil.semantic.Module,
18 dil.semantic.Analysis;
19 import dil.lexer.IdTable;
20 import dil.i18n.Messages;
21 import dil.Compilation,
22 dil.Diagnostics,
23 dil.Enums;
24 import util.Path;
25 import common;
26
27 /// The first pass is the declaration pass.
28 ///
29 /// The basic task of this class is to traverse the parse tree,
30 /// find all kinds of declarations and add them
31 /// to the symbol tables of their respective scopes.
32 class SemanticPass1 : Visitor
33 {
34 Scope scop; /// The current scope.
35 Module modul; /// The module to be semantically checked.
36 CompilationContext context; /// The compilation context.
37 Module delegate(cstring) importModule; /// Called when importing a module.
38
39 // Attributes:
40 LinkageType linkageType; /// Current linkage type.
41 Protection protection; /// Current protection attribute.
42 StorageClass storageClass; /// Current storage classes.
43 uint alignSize; /// Current align size.
44
45 /// Constructs a SemanticPass1 object.
46 /// Params:
47 /// modul = The module to be processed.
48 /// context = The compilation context.
49 this(Module modul, CompilationContext context)
50 {
51 this.modul = modul;
52 this.context = new CompilationContext(context);
53 this.alignSize = context.structAlign;
54 }
55
56 /// Starts processing the module.
57 void run()
58 {
59 assert(modul.root !is null);
60 // Create module scope.
61 scop = new Scope(null, modul);
62 modul.semanticPass = 1;
63 visit(modul.root);
64 }
65
66 /// Enters a new scope.
67 void enterScope(ScopeSymbol s)
68 {
69 scop = scop.enter(s);
70 }
71
72 /// Exits the current scope.
73 void exitScope()
74 {
75 scop = scop.exit();
76 }
77
78 /// Returns true if this is the module scope.
79 bool isModuleScope()
80 {
81 return scop.symbol.isModule();
82 }
83
84 /// Inserts a symbol into the current scope.
85 void insert(Symbol symbol)
86 {
87 insert(symbol, symbol.name);
88 }
89
90 /// Inserts a symbol into the current scope.
91 void insert(Symbol symbol, Identifier* name)
92 {
93 auto symX = scop.symbol.lookup(name);
94 if (symX)
95 reportSymbolConflict(symbol, symX, name);
96 else
97 scop.symbol.insert(symbol, name);
98 // Set the current scope symbol as the parent.
99 symbol.parent = scop.symbol;
100 }
101
102 /// Inserts a symbol into scopeSym.
103 void insert(Symbol symbol, ScopeSymbol scopeSym)
104 {
105 auto symX = scopeSym.lookup(symbol.name);
106 if (symX)
107 reportSymbolConflict(symbol, symX, symbol.name);
108 else
109 scopeSym.insert(symbol, symbol.name);
110 // Set the current scope symbol as the parent.
111 symbol.parent = scopeSym;
112 }
113
114 /// Inserts a symbol, overloading on the name, into the current scope.
115 void insertOverload(Symbol sym)
116 {
117 auto name = sym.name;
118 auto sym2 = scop.symbol.lookup(name);
119 if (sym2)
120 {
121 if (sym2.isOverloadSet)
122 (cast(OverloadSet)cast(void*)sym2).add(sym);
123 else
124 reportSymbolConflict(sym, sym2, name);
125 }
126 else
127 // Create a new overload set.
128 scop.symbol.insert(new OverloadSet(name, sym.loc), name);
129 // Set the current scope symbol as the parent.
130 sym.parent = scop.symbol;
131 }
132
133 /// Reports an error: new symbol s1 conflicts with existing symbol s2.
134 void reportSymbolConflict(Symbol s1, Symbol s2, Identifier* name)
135 {
136 auto loc = s2.loc.t.getErrorLocation(modul.filePath());
137 auto locString = modul.cc.diag.format("{}({},{})",
138 loc.filePath, loc.lineNum, loc.colNum);
139 error(s1.loc.t, MID.DeclConflictsWithDecl, name.str, locString);
140 }
141
142 /// Creates an error report.
143 void error(Token* token, MID mid, ...)
144 {
145 auto location = token.getErrorLocation(modul.filePath());
146 auto msg = modul.cc.diag.formatMsg(mid, _arguments, _argptr);
147 modul.cc.diag ~= new SemanticError(location, msg);
148 }
149
150 /// Collects info about nodes which have to be evaluated later.
151 static class Deferred
152 {
153 Node node;
154 ScopeSymbol symbol;
155 // Saved attributes.
156 LinkageType linkageType;
157 Protection protection;
158 StorageClass storageClass;
159 uint alignSize;
160 }
161
162 /// List of mixin, static if, static assert and pragma(msg,...) declarations.
163 ///
164 /// Their analysis must be deferred because they entail
165 /// evaluation of expressions.
166 Deferred[] deferred;
167
168 /// Adds a deferred node to the list.
169 void addDeferred(Node node)
170 {
171 auto d = new Deferred;
172 d.node = node;
173 d.symbol = scop.symbol;
174 d.linkageType = linkageType;
175 d.protection = protection;
176 d.storageClass = storageClass;
177 d.alignSize = alignSize;
178 deferred ~= d;
179 }
180
181 private alias D = Declaration; /// A handy alias. Saves typing.
182
183 override
184 {
185 alias visit = super.visit;
186
187 D visit(CompoundDecl d)
188 {
189 foreach (decl; d.decls)
190 visitD(decl);
191 return d;
192 }
193
194 D visit(IllegalDecl)
195 { assert(0, "semantic pass on invalid AST"); return null; }
196
197 // D visit(EmptyDecl ed)
198 // { return ed; }
199
200 // D visit(ModuleDecl)
201 // { return null; }
202
203 D visit(ImportDecl d)
204 {
205 if (importModule is null)
206 return d;
207 foreach (moduleFQNPath; d.getModuleFQNs(dirSep))
208 {
209 auto importedModule = importModule(moduleFQNPath);
210 if (importedModule is null)
211 error(d.begin, MID.CouldntLoadModule, moduleFQNPath ~ ".d");
212 modul.modules ~= importedModule;
213 }
214 return d;
215 }
216
217 D visit(AliasDecl ad)
218 {
219 return ad;
220 }
221
222 D visit(TypedefDecl td)
223 {
224 return td;
225 }
226
227 D visit(EnumDecl d)
228 {
229 if (d.symbol)
230 return d;
231
232 // Create the symbol.
233 d.symbol = new EnumSymbol(d.nameId, SLoc(d.name ? d.name : d.begin, d));
234
235 bool isAnonymous = d.symbol.isAnonymous;
236 if (isAnonymous)
237 d.symbol.name = context.tables.idents.genAnonEnumID();
238
239 insert(d.symbol);
240
241 auto parentScopeSymbol = scop.symbol;
242 auto enumSymbol = d.symbol;
243 enterScope(d.symbol);
244 // Declare members.
245 foreach (member; d.members)
246 {
247 visitD(member);
248
249 if (isAnonymous) // Also insert into parent scope if enum is anonymous.
250 insert(member.symbol, parentScopeSymbol);
251
252 member.symbol.type = enumSymbol.type; // Assign TypeEnum.
253 }
254 exitScope();
255 return d;
256 }
257
258 D visit(EnumMemberDecl d)
259 {
260 d.symbol = new EnumMemberSymbol(
261 d.name.ident, protection, storageClass, linkageType, SLoc(d.name, d));
262 insert(d.symbol);
263 return d;
264 }
265
266 D visit(ClassDecl d)
267 {
268 if (d.symbol)
269 return d;
270 // Create the symbol.
271 d.symbol = new ClassSymbol(d.nameId, SLoc(d.name, d));
272 // Insert into current scope.
273 insert(d.symbol);
274 enterScope(d.symbol);
275 // Continue semantic analysis.
276 d.decls && visitD(d.decls);
277 exitScope();
278 return d;
279 }
280
281 D visit(InterfaceDecl d)
282 {
283 if (d.symbol)
284 return d;
285 // Create the symbol.
286 d.symbol = new InterfaceSymbol(d.nameId, SLoc(d.name, d));
287 // Insert into current scope.
288 insert(d.symbol);
289 enterScope(d.symbol);
290 // Continue semantic analysis.
291 d.decls && visitD(d.decls);
292 exitScope();
293 return d;
294 }
295
296 D visit(StructDecl d)
297 {
298 if (d.symbol)
299 return d;
300 // Create the symbol.
301 d.symbol = new StructSymbol(d.nameId, SLoc(d.name ? d.name : d.begin, d));
302
303 if (d.symbol.isAnonymous)
304 d.symbol.name = context.tables.idents.genAnonStructID();
305 // Insert into current scope.
306 insert(d.symbol);
307
308 enterScope(d.symbol);
309 // Continue semantic analysis.
310 d.decls && visitD(d.decls);
311 exitScope();
312
313 if (d.symbol.isAnonymous)
314 // Insert members into parent scope as well.
315 foreach (member; d.symbol.members)
316 insert(member);
317 return d;
318 }
319
320 D visit(UnionDecl d)
321 {
322 if (d.symbol)
323 return d;
324 // Create the symbol.
325 d.symbol = new UnionSymbol(d.nameId, SLoc(d.name ? d.name : d.begin, d));
326
327 if (d.symbol.isAnonymous)
328 d.symbol.name = context.tables.idents.genAnonUnionID();
329
330 // Insert into current scope.
331 insert(d.symbol);
332
333 enterScope(d.symbol);
334 // Continue semantic analysis.
335 d.decls && visitD(d.decls);
336 exitScope();
337
338 if (d.symbol.isAnonymous)
339 // Insert members into parent scope as well.
340 foreach (member; d.symbol.members)
341 insert(member);
342 return d;
343 }
344
345 D visit(ConstructorDecl d)
346 {
347 auto func = new FunctionSymbol(Ident.Ctor, SLoc(d.begin, d));
348 insertOverload(func);
349 return d;
350 }
351
352 D visit(StaticCtorDecl d)
353 {
354 auto func = new FunctionSymbol(Ident.Ctor, SLoc(d.begin, d));
355 insertOverload(func);
356 return d;
357 }
358
359 D visit(DestructorDecl d)
360 {
361 auto func = new FunctionSymbol(Ident.Dtor, SLoc(d.begin, d));
362 insertOverload(func);
363 return d;
364 }
365
366 D visit(StaticDtorDecl d)
367 {
368 auto func = new FunctionSymbol(Ident.Dtor, SLoc(d.begin, d));
369 insertOverload(func);
370 return d;
371 }
372
373 D visit(FunctionDecl d)
374 {
375 auto func = new FunctionSymbol(d.name.ident, SLoc(d.name, d));
376 insertOverload(func);
377 return d;
378 }
379
380 D visit(VariablesDecl vd)
381 {
382 // Error if we are in an interface.
383 if (scop.symbol.isInterface &&
384 !(vd.isStatic || vd.isConst || vd.isManifest))
385 return error(vd.begin, MID.InterfaceCantHaveVariables), vd;
386
387 // Insert variable symbols in this declaration into the symbol table.
388 vd.variables = new VariableSymbol[vd.names.length];
389 foreach (i, name; vd.names)
390 {
391 auto variable = new VariableSymbol(name.ident, protection, storageClass,
392 linkageType, SLoc(name, vd));
393 variable.value = vd.inits[i];
394 vd.variables[i] = variable;
395 insert(variable);
396 }
397 return vd;
398 }
399
400 D visit(InvariantDecl d)
401 {
402 auto func = new FunctionSymbol(Ident.InvariantFn, SLoc(d.begin, d));
403 insert(func);
404 return d;
405 }
406
407 D visit(UnittestDecl d)
408 {
409 auto func = new FunctionSymbol(Ident.UnittestFn, SLoc(d.begin, d));
410 insertOverload(func);
411 return d;
412 }
413
414 D visit(DebugDecl d)
415 {
416 if (d.isSpecification)
417 { // debug = Id | Int
418 if (!isModuleScope())
419 error(d.begin, MID.DebugSpecModuleLevel, d.spec.text);
420 else if (d.spec.kind == TOK.Identifier)
421 context.addDebugId(d.spec.ident.str);
422 else
423 context.debugLevel = d.spec.uint_;
424 }
425 else
426 { // debug ( Condition )
427 if (debugBranchChoice(d.cond, context))
428 d.compiledDecls = d.decls;
429 else
430 d.compiledDecls = d.elseDecls;
431 d.compiledDecls && visitD(d.compiledDecls);
432 }
433 return d;
434 }
435
436 D visit(VersionDecl d)
437 {
438 if (d.isSpecification)
439 { // version = Id | Int
440 if (!isModuleScope())
441 error(d.begin, MID.VersionSpecModuleLevel, d.spec.text);
442 else if (d.spec.kind == TOK.Identifier)
443 context.addVersionId(d.spec.ident.str);
444 else
445 context.versionLevel = d.spec.uint_;
446 }
447 else
448 { // version ( Condition )
449 if (versionBranchChoice(d.cond, context))
450 d.compiledDecls = d.decls;
451 else
452 d.compiledDecls = d.elseDecls;
453 d.compiledDecls && visitD(d.compiledDecls);
454 }
455 return d;
456 }
457
458 D visit(TemplateDecl d)
459 {
460 if (d.symbol)
461 return d;
462 // Create the symbol.
463 d.symbol = new TemplateSymbol(d.nameId, SLoc(d.name, d));
464 // Insert into current scope.
465 insertOverload(d.symbol);
466 return d;
467 }
468
469 D visit(NewDecl d)
470 {
471 auto func = new FunctionSymbol(Ident.NewFn, SLoc(d.begin, d));
472 insert(func);
473 return d;
474 }
475
476 D visit(DeleteDecl d)
477 {
478 auto func = new FunctionSymbol(Ident.DeleteFn, SLoc(d.begin, d));
479 insert(func);
480 return d;
481 }
482
483 // Attributes:
484
485 D visit(ProtectionDecl d)
486 {
487 auto saved = protection; // Save.
488 protection = d.prot; // Set.
489 visitD(d.decls);
490 protection = saved; // Restore.
491 return d;
492 }
493
494 D visit(StorageClassDecl d)
495 {
496 auto saved = storageClass; // Save.
497 storageClass = d.stc; // Set.
498 visitD(d.decls);
499 storageClass = saved; // Restore.
500 return d;
501 }
502
503 D visit(LinkageDecl d)
504 {
505 auto saved = linkageType; // Save.
506 linkageType = d.linkageType; // Set.
507 visitD(d.decls);
508 linkageType = saved; // Restore.
509 return d;
510 }
511
512 D visit(AlignDecl d)
513 {
514 auto saved = alignSize; // Save.
515 alignSize = d.size; // Set.
516 visitD(d.decls);
517 alignSize = saved; // Restore.
518 return d;
519 }
520
521 // Deferred declarations:
522
523 D visit(StaticAssertDecl d)
524 {
525 addDeferred(d);
526 return d;
527 }
528
529 D visit(StaticIfDecl d)
530 {
531 addDeferred(d);
532 return d;
533 }
534
535 D visit(MixinDecl d)
536 {
537 addDeferred(d);
538 return d;
539 }
540
541 D visit(PragmaDecl d)
542 {
543 if (d.name.ident is Ident.msg)
544 addDeferred(d);
545 else
546 {
547 pragmaSemantic(scop, d.begin, d.name.ident, d.args);
548 visitD(d.decls);
549 }
550 return d;
551 }
552 } // override
553 }