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 }