1 /** 2 * This file is part of DCD, a development tool for the D programming language. 3 * Copyright (C) 2014 Brian Schott 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 module dsymbol.conversion.second; 20 21 import dsymbol.semantic; 22 import dsymbol.string_interning; 23 import dsymbol.symbol; 24 import dsymbol.scope_; 25 import dsymbol.builtin.names; 26 import dsymbol.builtin.symbols; 27 import dsymbol.type_lookup; 28 import dsymbol.deferred; 29 import dsymbol.import_; 30 import dsymbol.modulecache; 31 import containers.unrolledlist; 32 import stdx.allocator; 33 import stdx.allocator.mallocator; 34 import std.experimental.logger; 35 import dparse.ast; 36 import dparse.lexer; 37 38 void secondPass(SemanticSymbol* currentSymbol, Scope* moduleScope, ref ModuleCache cache) 39 { 40 with (CompletionKind) final switch (currentSymbol.acSymbol.kind) 41 { 42 case className: 43 case interfaceName: 44 resolveInheritance(currentSymbol.acSymbol, currentSymbol.typeLookups, 45 moduleScope, cache); 46 break; 47 case withSymbol: 48 case variableName: 49 case memberVariableName: 50 case functionName: 51 case aliasName: 52 // type may not be null in the case of a renamed import 53 if (currentSymbol.acSymbol.type is null) 54 { 55 resolveType(currentSymbol.acSymbol, currentSymbol.typeLookups, 56 moduleScope, cache); 57 } 58 break; 59 case importSymbol: 60 if (currentSymbol.acSymbol.type is null) 61 resolveImport(currentSymbol.acSymbol, currentSymbol.typeLookups, cache); 62 break; 63 case structName: 64 case unionName: 65 case enumName: 66 case keyword: 67 case enumMember: 68 case packageName: 69 case moduleName: 70 case dummy: 71 case templateName: 72 case mixinTemplateName: 73 break; 74 } 75 76 foreach (child; currentSymbol.children) 77 secondPass(child, moduleScope, cache); 78 79 // Alias this and mixin templates are resolved after child nodes are 80 // resolved so that the correct symbol information will be available. 81 with (CompletionKind) switch (currentSymbol.acSymbol.kind) 82 { 83 case className: 84 case interfaceName: 85 case structName: 86 case unionName: 87 resolveAliasThis(currentSymbol.acSymbol, currentSymbol.typeLookups, moduleScope, cache); 88 resolveMixinTemplates(currentSymbol.acSymbol, currentSymbol.typeLookups, 89 moduleScope, cache); 90 break; 91 default: 92 break; 93 } 94 } 95 96 void resolveImport(DSymbol* acSymbol, ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, 97 ref ModuleCache cache) 98 in 99 { 100 assert (acSymbol.kind == CompletionKind.importSymbol); 101 } 102 body 103 { 104 if (acSymbol.qualifier == SymbolQualifier.selectiveImport) 105 { 106 assert(acSymbol.symbolFile !is null); 107 DSymbol* moduleSymbol = cache.cacheModule(acSymbol.symbolFile); 108 if (moduleSymbol is null) 109 { 110 tryAgain: 111 DeferredSymbol* deferred = Mallocator.instance.make!DeferredSymbol(acSymbol); 112 deferred.typeLookups.insert(typeLookups[]); 113 // Get rid of the old references to the lookups, this new deferred 114 // symbol owns them now 115 typeLookups.clear(); 116 cache.deferredSymbols.insert(deferred); 117 } 118 else 119 { 120 immutable size_t breadcrumbCount = typeLookups.front.breadcrumbs.length; 121 assert(breadcrumbCount <= 2 && breadcrumbCount > 0, "Malformed selective import"); 122 123 istring symbolName = typeLookups.front.breadcrumbs.front; 124 DSymbol* selected = moduleSymbol.getFirstPartNamed(symbolName); 125 if (acSymbol is null) 126 goto tryAgain; 127 acSymbol.type = selected; 128 acSymbol.ownType = false; 129 130 // count of 1 means selective import 131 // count of 2 means a renamed selective import 132 if (breadcrumbCount == 2) 133 { 134 acSymbol.kind = CompletionKind.aliasName; 135 acSymbol.symbolFile = acSymbol.altFile; 136 } 137 } 138 } 139 else 140 { 141 assert(acSymbol.symbolFile !is null); 142 DSymbol* moduleSymbol = cache.cacheModule(acSymbol.symbolFile); 143 if (moduleSymbol is null) 144 { 145 DeferredSymbol* deferred = Mallocator.instance.make!DeferredSymbol(acSymbol); 146 cache.deferredSymbols.insert(deferred); 147 } 148 else 149 { 150 acSymbol.type = moduleSymbol; 151 acSymbol.ownType = false; 152 } 153 } 154 } 155 156 void resolveTypeFromType(DSymbol* symbol, TypeLookup* lookup, Scope* moduleScope, 157 ref ModuleCache cache, UnrolledList!(DSymbol*, Mallocator, false)* imports) 158 in 159 { 160 if (imports !is null) 161 foreach (i; imports.opSlice()) 162 assert(i.kind == CompletionKind.importSymbol); 163 } 164 body 165 { 166 // The left-most suffix 167 DSymbol* suffix; 168 // The right-most suffix 169 DSymbol* lastSuffix; 170 171 // Create symbols for the type suffixes such as array and 172 // associative array 173 while (!lookup.breadcrumbs.empty) 174 { 175 auto back = lookup.breadcrumbs.back; 176 immutable bool isArr = back == ARRAY_SYMBOL_NAME; 177 immutable bool isAssoc = back == ASSOC_ARRAY_SYMBOL_NAME; 178 immutable bool isFunction = back == FUNCTION_SYMBOL_NAME; 179 if (back == POINTER_SYMBOL_NAME) 180 { 181 lastSuffix.isPointer = true; 182 lookup.breadcrumbs.popBack(); 183 continue; 184 } 185 if (!isArr && !isAssoc && !isFunction) 186 break; 187 immutable qualifier = isAssoc ? SymbolQualifier.assocArray : 188 (isFunction ? SymbolQualifier.func : SymbolQualifier.array); 189 lastSuffix = cache.symbolAllocator.make!DSymbol(back, CompletionKind.dummy, lastSuffix); 190 lastSuffix.qualifier = qualifier; 191 lastSuffix.ownType = true; 192 if (isFunction) 193 { 194 lookup.breadcrumbs.popBack(); 195 lastSuffix.callTip = lookup.breadcrumbs.back(); 196 } 197 else 198 lastSuffix.addChildren(isArr ? arraySymbols[] : assocArraySymbols[], false); 199 200 if (suffix is null) 201 suffix = lastSuffix; 202 lookup.breadcrumbs.popBack(); 203 } 204 205 UnrolledList!(DSymbol*, Mallocator, false) remainingImports; 206 207 DSymbol* currentSymbol; 208 209 void getSymbolFromImports(UnrolledList!(DSymbol*, Mallocator, false)* importList, istring name) 210 { 211 foreach (im; importList.opSlice()) 212 { 213 assert(im.symbolFile !is null); 214 // Try to find a cached version of the module 215 DSymbol* moduleSymbol = cache.getModuleSymbol(im.symbolFile); 216 // If the module has not been cached yet, store it in the 217 // remaining imports list 218 if (moduleSymbol is null) 219 { 220 remainingImports.insert(im); 221 continue; 222 } 223 // Try to get the symbol from the imported module 224 currentSymbol = moduleSymbol.getFirstPartNamed(name); 225 if (currentSymbol is null) 226 continue; 227 } 228 } 229 230 // Follow all the names and try to resolve them 231 size_t i = 0; 232 foreach (part; lookup.breadcrumbs[]) 233 { 234 if (i == 0) 235 { 236 if (moduleScope is null) 237 getSymbolFromImports(imports, part); 238 else 239 { 240 auto symbols = moduleScope.getSymbolsByNameAndCursor(part, symbol.location); 241 if (symbols.length > 0) 242 currentSymbol = symbols[0]; 243 else 244 return; 245 } 246 } 247 else 248 { 249 if (currentSymbol.kind == CompletionKind.aliasName) 250 currentSymbol = currentSymbol.type; 251 if (currentSymbol is null) 252 return; 253 if (currentSymbol.kind == CompletionKind.moduleName && currentSymbol.type !is null) 254 currentSymbol = currentSymbol.type; 255 if (currentSymbol is null) 256 return; 257 if (currentSymbol.kind == CompletionKind.importSymbol) 258 currentSymbol = currentSymbol.type; 259 if (currentSymbol is null) 260 return; 261 currentSymbol = currentSymbol.getFirstPartNamed(part); 262 } 263 ++i; 264 if (currentSymbol is null) 265 return; 266 } 267 268 if (lastSuffix !is null) 269 { 270 assert(suffix !is null); 271 suffix.type = currentSymbol; 272 suffix.ownType = false; 273 symbol.type = lastSuffix; 274 symbol.ownType = true; 275 if (currentSymbol is null && !remainingImports.empty) 276 { 277 // info("Deferring type resolution for ", symbol.name); 278 auto deferred = Mallocator.instance.make!DeferredSymbol(suffix); 279 // TODO: The scope has ownership of the import information 280 deferred.imports.insert(remainingImports[]); 281 deferred.typeLookups.insert(lookup); 282 cache.deferredSymbols.insert(deferred); 283 } 284 } 285 else if (currentSymbol !is null) 286 { 287 symbol.type = currentSymbol; 288 symbol.ownType = false; 289 } 290 else if (!remainingImports.empty) 291 { 292 auto deferred = Mallocator.instance.make!DeferredSymbol(symbol); 293 // info("Deferring type resolution for ", symbol.name); 294 // TODO: The scope has ownership of the import information 295 deferred.imports.insert(remainingImports[]); 296 deferred.typeLookups.insert(lookup); 297 cache.deferredSymbols.insert(deferred); 298 } 299 } 300 301 private: 302 303 void resolveInheritance(DSymbol* symbol, ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, 304 Scope* moduleScope, ref ModuleCache cache) 305 { 306 import std.algorithm : filter; 307 308 outer: foreach (TypeLookup* lookup; typeLookups[]) 309 { 310 if (lookup.kind != TypeLookupKind.inherit) 311 continue; 312 DSymbol* baseClass; 313 assert(lookup.breadcrumbs.length > 0); 314 315 // TODO: Delayed type lookup 316 auto symbolScope = moduleScope.getScopeByCursor(symbol.location); 317 auto symbols = moduleScope.getSymbolsByNameAndCursor(lookup.breadcrumbs.front, 318 symbol.location); 319 if (symbols.length == 0) 320 continue; 321 322 baseClass = symbols[0]; 323 lookup.breadcrumbs.popFront(); 324 foreach (part; lookup.breadcrumbs[]) 325 { 326 symbols = baseClass.getPartsByName(part); 327 if (symbols.length == 0) 328 continue outer; 329 baseClass = symbols[0]; 330 } 331 332 DSymbol* imp = cache.symbolAllocator.make!DSymbol(IMPORT_SYMBOL_NAME, 333 CompletionKind.importSymbol, baseClass); 334 symbol.addChild(imp, true); 335 symbolScope.addSymbol(imp, false); 336 if (baseClass.kind == CompletionKind.className) 337 { 338 auto s = cache.symbolAllocator.make!DSymbol(SUPER_SYMBOL_NAME, 339 CompletionKind.variableName, baseClass); 340 symbolScope.addSymbol(s, true); 341 } 342 } 343 } 344 345 void resolveAliasThis(DSymbol* symbol, 346 ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, Scope* moduleScope, ref ModuleCache cache) 347 { 348 import std.algorithm : filter; 349 350 foreach (aliasThis; typeLookups[].filter!(a => a.kind == TypeLookupKind.aliasThis)) 351 { 352 assert(aliasThis.breadcrumbs.length > 0); 353 auto parts = symbol.getPartsByName(aliasThis.breadcrumbs.front); 354 if (parts.length == 0 || parts[0].type is null) 355 continue; 356 DSymbol* s = cache.symbolAllocator.make!DSymbol(IMPORT_SYMBOL_NAME, 357 CompletionKind.importSymbol, parts[0].type); 358 symbol.addChild(s, true); 359 auto symbolScope = moduleScope.getScopeByCursor(s.location); 360 if (symbolScope !is null) 361 symbolScope.addSymbol(s, false); 362 } 363 } 364 365 void resolveMixinTemplates(DSymbol* symbol, 366 ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, Scope* moduleScope, ref ModuleCache cache) 367 { 368 import std.algorithm : filter; 369 370 foreach (mix; typeLookups[].filter!(a => a.kind == TypeLookupKind.mixinTemplate)) 371 { 372 assert(mix.breadcrumbs.length > 0); 373 auto symbols = moduleScope.getSymbolsByNameAndCursor(mix.breadcrumbs.front, 374 symbol.location); 375 if (symbols.length == 0) 376 continue; 377 auto currentSymbol = symbols[0]; 378 mix.breadcrumbs.popFront(); 379 foreach (m; mix.breadcrumbs[]) 380 { 381 auto s = currentSymbol.getPartsByName(m); 382 if (s.length == 0) 383 { 384 currentSymbol = null; 385 break; 386 } 387 else 388 currentSymbol = s[0]; 389 } 390 if (currentSymbol !is null) 391 { 392 auto i = cache.symbolAllocator.make!DSymbol(IMPORT_SYMBOL_NAME, 393 CompletionKind.importSymbol, currentSymbol); 394 i.ownType = false; 395 symbol.addChild(i, true); 396 } 397 } 398 } 399 400 void resolveType(DSymbol* symbol, ref UnrolledList!(TypeLookup*, Mallocator, false) typeLookups, 401 Scope* moduleScope, ref ModuleCache cache) 402 { 403 if (typeLookups.length == 0) 404 return; 405 assert(typeLookups.length == 1); 406 auto lookup = typeLookups.front; 407 if (lookup.kind == TypeLookupKind.varOrFunType) 408 resolveTypeFromType(symbol, lookup, moduleScope, cache, null); 409 else if (lookup.kind == TypeLookupKind.initializer) 410 resolveTypeFromInitializer(symbol, lookup, moduleScope, cache); 411 else 412 assert(false, "How did this happen?"); 413 } 414 415 416 void resolveTypeFromInitializer(DSymbol* symbol, TypeLookup* lookup, 417 Scope* moduleScope, ref ModuleCache cache) 418 { 419 if (lookup.breadcrumbs.length == 0) 420 return; 421 DSymbol* currentSymbol = null; 422 size_t i = 0; 423 424 auto crumbs = lookup.breadcrumbs[]; 425 foreach (crumb; crumbs) 426 { 427 if (i == 0) 428 { 429 currentSymbol = moduleScope.getFirstSymbolByNameAndCursor( 430 symbolNameToTypeName(crumb), symbol.location); 431 432 // solves auto arrays 433 if (crumb == ARRAY_SYMBOL_NAME) 434 { 435 auto nestedArr = crumbs.save(); 436 auto a = nestedArr.front(); 437 438 DSymbol* suffix; 439 DSymbol* lastSuffix; 440 441 // process the flags set in ArrayInitializer visit 442 while (true) 443 { 444 lastSuffix = cache.symbolAllocator.make!(DSymbol)(a, CompletionKind.dummy, lastSuffix); 445 lastSuffix.qualifier = SymbolQualifier.array; 446 447 if (suffix is null) 448 suffix = lastSuffix; 449 450 nestedArr.popFront(); 451 if (nestedArr.empty()) 452 break; 453 a = nestedArr.front(); 454 if (a != ARRAY_SYMBOL_NAME) 455 break; 456 } 457 458 // last crumb should be the element type 459 DSymbol* elemType; 460 if (!nestedArr.empty) 461 { 462 suffix.addChildren(arraySymbols[], false); 463 elemType = moduleScope.getFirstSymbolByNameAndCursor( 464 symbolNameToTypeName(a), symbol.location); 465 } 466 467 // put the elem type to the back of the *arr* chain 468 if (suffix !is null && elemType) 469 { 470 suffix.type = elemType; 471 suffix.ownType = false; 472 symbol.type = lastSuffix; 473 symbol.ownType = true; 474 } 475 } 476 if (currentSymbol is null) 477 return; 478 } 479 else if (crumb == ARRAY_SYMBOL_NAME) 480 { 481 typeSwap(currentSymbol); 482 if (currentSymbol is null) 483 return; 484 485 // Index expressions can be an array index or an AA index 486 if (currentSymbol.qualifier == SymbolQualifier.array 487 || currentSymbol.qualifier == SymbolQualifier.assocArray 488 || currentSymbol.kind == CompletionKind.aliasName) 489 { 490 if (currentSymbol.type !is null) 491 currentSymbol = currentSymbol.type; 492 else 493 return; 494 } 495 else 496 { 497 auto opIndex = currentSymbol.getFirstPartNamed(internString("opIndex")); 498 if (opIndex !is null) 499 currentSymbol = opIndex.type; 500 else 501 return; 502 } 503 } 504 else if (crumb == "foreach") 505 { 506 typeSwap(currentSymbol); 507 if (currentSymbol is null) 508 return; 509 if (currentSymbol.qualifier == SymbolQualifier.array 510 || currentSymbol.qualifier == SymbolQualifier.assocArray) 511 { 512 currentSymbol = currentSymbol.type; 513 break; 514 } 515 auto front = currentSymbol.getFirstPartNamed(internString("front")); 516 if (front !is null) 517 { 518 currentSymbol = front.type; 519 break; 520 } 521 auto opApply = currentSymbol.getFirstPartNamed(internString("opApply")); 522 if (opApply !is null) 523 { 524 currentSymbol = opApply.type; 525 break; 526 } 527 } 528 else 529 { 530 typeSwap(currentSymbol); 531 if (currentSymbol is null ) 532 return; 533 currentSymbol = currentSymbol.getFirstPartNamed(crumb); 534 } 535 ++i; 536 if (currentSymbol is null) 537 return; 538 } 539 typeSwap(currentSymbol); 540 symbol.type = currentSymbol; 541 symbol.ownType = false; 542 } 543 544 void typeSwap(ref DSymbol* currentSymbol) 545 { 546 while (currentSymbol !is null && currentSymbol.type !is currentSymbol 547 && (currentSymbol.kind == CompletionKind.variableName 548 || currentSymbol.kind == CompletionKind.importSymbol 549 || currentSymbol.kind == CompletionKind.withSymbol 550 || currentSymbol.kind == CompletionKind.aliasName)) 551 currentSymbol = currentSymbol.type; 552 }