diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/cgen.nim | 6 | ||||
-rw-r--r-- | compiler/depends.nim | 4 | ||||
-rw-r--r-- | compiler/docgen2.nim | 4 | ||||
-rw-r--r-- | compiler/importer.nim | 2 | ||||
-rw-r--r-- | compiler/jsgen.nim | 6 | ||||
-rw-r--r-- | compiler/main.nim | 193 | ||||
-rw-r--r-- | compiler/modules.nim | 308 | ||||
-rw-r--r-- | compiler/nim.nim | 8 | ||||
-rw-r--r-- | compiler/nimsuggest/nimsuggest.nim | 12 | ||||
-rw-r--r-- | compiler/passaux.nim | 4 | ||||
-rw-r--r-- | compiler/passes.nim | 35 | ||||
-rw-r--r-- | compiler/rodwrite.nim | 4 | ||||
-rw-r--r-- | compiler/scriptconfig.nim | 14 | ||||
-rw-r--r-- | compiler/sem.nim | 10 | ||||
-rw-r--r-- | compiler/semdata.nim | 9 | ||||
-rw-r--r-- | compiler/semstmts.nim | 4 | ||||
-rw-r--r-- | compiler/suggest.nim | 2 | ||||
-rw-r--r-- | compiler/vm.nim | 4 |
18 files changed, 261 insertions, 368 deletions
diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 86b0d60d0..6e18c8389 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -16,6 +16,8 @@ import condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, semparallel +from modulegraphs import ModuleGraph + import strutils except `%` # collides with ropes.`%` when options.hasTinyCBackend: @@ -1174,7 +1176,7 @@ proc newModule(module: PSym): BModule = if (sfDeadCodeElim in module.flags): internalError("added pending module twice: " & module.filename) -proc myOpen(module: PSym; cache: IdentCache): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = result = newModule(module) if optGenIndex in gGlobalOptions and generatedHeader == nil: let f = if headerFile.len > 0: headerFile else: gProjectFull @@ -1209,7 +1211,7 @@ proc getCFile(m: BModule): string = else: ".c" result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext) -proc myOpenCached(module: PSym, rd: PRodReader): PPassContext = +proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = assert optSymbolFiles in gGlobalOptions var m = newModule(module) readMergeInfo(getCFile(m), m) diff --git a/compiler/depends.nim b/compiler/depends.nim index f8b8a3d71..9087f89f2 100644 --- a/compiler/depends.nim +++ b/compiler/depends.nim @@ -12,6 +12,8 @@ import os, options, ast, astalgo, msgs, ropes, idents, passes, importer +from modulegraphs import ModuleGraph + proc generateDot*(project: string) type @@ -46,7 +48,7 @@ proc generateDot(project: string) = rope(changeFileExt(extractFilename(project), "")), gDotGraph], changeFileExt(project, "dot")) -proc myOpen(module: PSym; cache: IdentCache): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = var g: PGen new(g) g.module = module diff --git a/compiler/docgen2.nim b/compiler/docgen2.nim index 17b6caaba..9504ab52f 100644 --- a/compiler/docgen2.nim +++ b/compiler/docgen2.nim @@ -13,6 +13,8 @@ import os, options, ast, astalgo, msgs, ropes, idents, passes, docgen +from modulegraphs import ModuleGraph + type TGen = object of TPassContext doc: PDoc @@ -49,7 +51,7 @@ proc processNodeJson(c: PPassContext, n: PNode): PNode = var g = PGen(c) generateJson(g.doc, n) -proc myOpen(module: PSym; cache: IdentCache): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = var g: PGen new(g) g.module = module diff --git a/compiler/importer.nim b/compiler/importer.nim index 771ab35d0..ce365c4dc 100644 --- a/compiler/importer.nim +++ b/compiler/importer.nim @@ -162,7 +162,7 @@ proc importModuleAs(n: PNode, realModule: PSym): PSym = proc myImportModule(c: PContext, n: PNode): PSym = var f = checkModuleName(n) if f != InvalidFileIDX: - result = importModuleAs(n, gImportModule(c.module, f, c.cache)) + result = importModuleAs(n, gImportModule(c.graph, c.module, f, c.cache)) # we cannot perform this check reliably because of # test: modules/import_in_config) if result.info.fileIndex == c.module.info.fileIndex and diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index eaa492a27..028dd00f0 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -35,6 +35,8 @@ import times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, intsets, cgmeth, lowerings +from modulegraphs import ModuleGraph + type TTarget = enum targetJS, targetPHP @@ -2272,11 +2274,11 @@ proc myClose(b: PPassContext, n: PNode): PNode = for obj, content in items(globals.classes): genClass(obj, content, ext) -proc myOpenCached(s: PSym, rd: PRodReader): PPassContext = +proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext = internalError("symbol files are not possible with the JS code generator") result = nil -proc myOpen(s: PSym; cache: IdentCache): PPassContext = +proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = var r = newModule(s) r.target = if gCmd == cmdCompileToPHP: targetPHP else: targetJS result = r diff --git a/compiler/main.nim b/compiler/main.nim index 103eef877..2118078be 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -15,7 +15,8 @@ import wordrecg, sem, semdata, idents, passes, docgen, extccomp, cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, - docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists + docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists, + modulegraphs from magicsys import systemModule, resetSysTypes @@ -30,80 +31,44 @@ proc semanticPasses = registerPass verbosePass registerPass semPass -proc commandGenDepend(cache: IdentCache) = +proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) = semanticPasses() registerPass(gendependPass) registerPass(cleanupPass) - compileProject(cache) + compileProject(graph, cache) generateDot(gProjectFull) execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") & ' ' & changeFileExt(gProjectFull, "dot")) -proc commandCheck(cache: IdentCache) = +proc commandCheck(graph: ModuleGraph; cache: IdentCache) = msgs.gErrorMax = high(int) # do not stop after first error defineSymbol("nimcheck") semanticPasses() # use an empty backend for semantic checking only rodPass() - compileProject(cache) + compileProject(graph, cache) -proc commandDoc2(cache: IdentCache; json: bool) = +proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) = msgs.gErrorMax = high(int) # do not stop after first error semanticPasses() if json: registerPass(docgen2JsonPass) else: registerPass(docgen2Pass) #registerPass(cleanupPass()) - compileProject(cache) + compileProject(graph, cache) finishDoc2Pass(gProjectName) -proc commandCompileToC(cache: IdentCache) = +proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) = extccomp.initVars() semanticPasses() registerPass(cgenPass) rodPass() #registerPass(cleanupPass()) - compileProject(cache) + compileProject(graph, cache) cgenWriteModules() if gCmd != cmdRun: extccomp.callCCompiler(changeFileExt(gProjectFull, "")) - if isServing: - # caas will keep track only of the compilation commands - lastCaasCmd = curCaasCmd - resetCgenModules() - for i in 0 .. <gMemCacheData.len: - gMemCacheData[i].hashStatus = hashCached - gMemCacheData[i].needsRecompile = Maybe - - # XXX: clean these global vars - # ccgstmts.gBreakpoints - # ccgthreadvars.nimtv - # ccgthreadvars.nimtVDeps - # ccgthreadvars.nimtvDeclared - # cgendata - # cgmeth? - # condsyms? - # depends? - # lexer.gLinesCompiled - # msgs - error counts - # magicsys, when system.nim changes - # rodread.rodcompilerProcs - # rodread.gTypeTable - # rodread.gMods - - # !! ropes.cache - # semthreads.computed? - # - # suggest.usageSym - # - # XXX: can we run out of IDs? - # XXX: detect config reloading (implement as error/require restart) - # XXX: options are appended (they will accumulate over time) - resetCompilationLists() - ccgutils.resetCaches() - GC_fullCollect() - -proc commandCompileToJS(cache: IdentCache) = +proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) = #incl(gGlobalOptions, optSafeCode) setTarget(osJS, cpuJS) #initDefines() @@ -113,9 +78,9 @@ proc commandCompileToJS(cache: IdentCache) = if gCmd == cmdCompileToPHP: defineSymbol("nimphp") semanticPasses() registerPass(JSgenPass) - compileProject(cache) + compileProject(graph, cache) -proc interactivePasses(cache: IdentCache) = +proc interactivePasses(graph: ModuleGraph; cache: IdentCache) = #incl(gGlobalOptions, optSafeCode) #setTarget(osNimrodVM, cpuNimrodVM) initDefines() @@ -125,28 +90,28 @@ proc interactivePasses(cache: IdentCache) = registerPass(semPass) registerPass(evalPass) -proc commandInteractive(cache: IdentCache) = +proc commandInteractive(graph: ModuleGraph; cache: IdentCache) = msgs.gErrorMax = high(int) # do not stop after first error - interactivePasses(cache) - compileSystemModule(cache) + interactivePasses(graph, cache) + compileSystemModule(graph, cache) if commandArgs.len > 0: - discard compileModule(fileInfoIdx(gProjectFull), cache, {}) + discard graph.compileModule(fileInfoIdx(gProjectFull), cache, {}) else: - var m = makeStdinModule() + var m = graph.makeStdinModule() incl(m.flags, sfMainModule) - processModule(m, llStreamOpenStdIn(), nil, cache) + processModule(graph, m, llStreamOpenStdIn(), nil, cache) const evalPasses = [verbosePass, semPass, evalPass] -proc evalNim(nodes: PNode, module: PSym; cache: IdentCache) = - carryPasses(nodes, module, cache, evalPasses) +proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache) = + carryPasses(graph, nodes, module, cache, evalPasses) -proc commandEval(cache: IdentCache; exp: string) = +proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = if systemModule == nil: - interactivePasses(cache) - compileSystemModule(cache) + interactivePasses(graph, cache) + compileSystemModule(graph, cache) let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" - evalNim(echoExp.parseString(cache), makeStdinModule(), cache) + evalNim(graph, echoExp.parseString(cache), makeStdinModule(graph), cache) proc commandScan(cache: IdentCache) = var f = addFileExt(mainCommandArg(), NimExt) @@ -165,75 +130,11 @@ proc commandScan(cache: IdentCache) = else: rawMessage(errCannotOpenFile, f) -proc commandSuggest(cache: IdentCache) = - if isServing: - # XXX: hacky work-around ahead - # Currently, it's possible to issue a idetools command, before - # issuing the first compile command. This will leave the compiler - # cache in a state where "no recompilation is necessary", but the - # cgen pass was never executed at all. - commandCompileToC(cache) - let gDirtyBufferIdx = gTrackPos.fileIndex - discard compileModule(gDirtyBufferIdx, cache, {sfDirty}) - resetModule(gDirtyBufferIdx) - else: - msgs.gErrorMax = high(int) # do not stop after first error - semanticPasses() - rodPass() - # XXX: this handles the case when the dirty buffer is the main file, - # but doesn't handle the case when it's imported module - #var projFile = if gProjectMainIdx == gDirtyOriginalIdx: gDirtyBufferIdx - # else: gProjectMainIdx - compileProject(cache) #(projFile) - -proc resetMemory = - resetCompilationLists() - ccgutils.resetCaches() - resetAllModules() - resetRopeCache() - resetSysTypes() - gOwners = @[] - resetIdentCache() - - # XXX: clean these global vars - # ccgstmts.gBreakpoints - # ccgthreadvars.nimtv - # ccgthreadvars.nimtVDeps - # ccgthreadvars.nimtvDeclared - # cgendata - # cgmeth? - # condsyms? - # depends? - # lexer.gLinesCompiled - # msgs - error counts - # magicsys, when system.nim changes - # rodread.rodcompilerProcs - # rodread.gTypeTable - # rodread.gMods - - # !! ropes.cache - # - # suggest.usageSym - # - # XXX: can we run out of IDs? - # XXX: detect config reloading (implement as error/require restart) - # XXX: options are appended (they will accumulate over time) - # vis = visimpl - when compileOption("gc", "v2"): - gcDebugging = true - echo "COLLECT 1" - GC_fullCollect() - echo "COLLECT 2" - GC_fullCollect() - echo "COLLECT 3" - GC_fullCollect() - echo GC_getStatistics() - const SimulateCaasMemReset = false PrintRopeCacheStats = false -proc mainCommand*(cache: IdentCache) = +proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = when SimulateCaasMemReset: gGlobalOptions.incl(optCaasEnabled) @@ -249,28 +150,28 @@ proc mainCommand*(cache: IdentCache) = of "c", "cc", "compile", "compiletoc": # compile means compileToC currently gCmd = cmdCompileToC - commandCompileToC(cache) + commandCompileToC(graph, cache) of "cpp", "compiletocpp": gCmd = cmdCompileToCpp defineSymbol("cpp") - commandCompileToC(cache) + commandCompileToC(graph, cache) of "objc", "compiletooc": gCmd = cmdCompileToOC defineSymbol("objc") - commandCompileToC(cache) + commandCompileToC(graph, cache) of "run": gCmd = cmdRun when hasTinyCBackend: extccomp.setCC("tcc") - commandCompileToC(cache) + commandCompileToC(graph, cache) else: rawMessage(errInvalidCommandX, command) of "js", "compiletojs": gCmd = cmdCompileToJS - commandCompileToJS(cache) + commandCompileToJS(graph, cache) of "php": gCmd = cmdCompileToPHP - commandCompileToJS(cache) + commandCompileToJS(graph, cache) of "doc": wantMainModule() gCmd = cmdDoc @@ -280,7 +181,7 @@ proc mainCommand*(cache: IdentCache) = gCmd = cmdDoc loadConfigs(DocConfig, cache) defineSymbol("nimdoc") - commandDoc2(cache, false) + commandDoc2(graph, cache, false) of "rst2html": gCmd = cmdRst2html loadConfigs(DocConfig, cache) @@ -301,14 +202,14 @@ proc mainCommand*(cache: IdentCache) = loadConfigs(DocConfig, cache) wantMainModule() defineSymbol("nimdoc") - commandDoc2(cache, true) + commandDoc2(graph, cache, true) of "buildindex": gCmd = cmdDoc loadConfigs(DocConfig, cache) commandBuildIndex() of "gendepend": gCmd = cmdGenDepend - commandGenDepend(cache) + commandGenDepend(graph, cache) of "dump": gCmd = cmdDump if getConfigVar("dump.format") == "json": @@ -337,7 +238,7 @@ proc mainCommand*(cache: IdentCache) = for it in iterSearchPath(searchPaths): msgWriteln(it) of "check": gCmd = cmdCheck - commandCheck(cache) + commandCheck(graph, cache) of "parse": gCmd = cmdParse wantMainModule() @@ -346,26 +247,12 @@ proc mainCommand*(cache: IdentCache) = gCmd = cmdScan wantMainModule() commandScan(cache) - msgWriteln("Beware: Indentation tokens depend on the parser\'s state!") + msgWriteln("Beware: Indentation tokens depend on the parser's state!") of "secret": gCmd = cmdInteractive - commandInteractive(cache) + commandInteractive(graph, cache) of "e": - # XXX: temporary command for easier testing - commandEval(cache, mainCommandArg()) - of "reset": - resetMemory() - of "idetools": - gCmd = cmdIdeTools - if gEvalExpr != "": - commandEval(cache, gEvalExpr) - else: - commandSuggest(cache) - of "serve": - isServing = true - gGlobalOptions.incl(optCaasEnabled) - msgs.gErrorMax = high(int) # do not stop after first error - serve(cache, mainCommand) + commandEval(graph, cache, mainCommandArg()) of "nop", "help": # prevent the "success" message: gCmd = cmdDump @@ -393,4 +280,4 @@ proc mainCommand*(cache: IdentCache) = resetAttributes() -proc mainCommand*() = mainCommand(newIdentCache()) +proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache()) diff --git a/compiler/modules.nim b/compiler/modules.nim index be1de16d9..e901ba896 100644 --- a/compiler/modules.nim +++ b/compiler/modules.nim @@ -7,130 +7,118 @@ # distribution, for details about the copyright. # -## implements the module handling +## Implements the module handling, including the caching of modules. import ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options, - idents, os, lexer, idgen, passes, syntaxes, llstream - -type - TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled - THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged - - TModuleInMemory* = object - compiledAt*: float - hash*: SecureHash - deps*: seq[int32] ## XXX: slurped files are currently not tracked - needsRecompile*: TNeedRecompile - hashStatus*: THashStatus - -var - gCompiledModules: seq[PSym] = @[] - gMemCacheData*: seq[TModuleInMemory] = @[] - ## XXX: we should implement recycling of file IDs - ## if the user keeps renaming modules, the file IDs will keep growing - gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why. - packageSyms: TStrTable - -initStrTable(packageSyms) - -proc getModule*(fileIdx: int32): PSym = - if fileIdx >= 0 and fileIdx < gCompiledModules.len: - result = gCompiledModules[fileIdx] - -proc hashChanged(fileIdx: int32): bool = - internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len - - template updateStatus = - gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged - else: hashNotChanged - # echo "TESTING Hash: ", fileIdx.toFilename, " ", result - - case gMemCacheData[fileIdx].hashStatus - of hashHasChanged: - result = true - of hashNotChanged: - result = false - of hashCached: - let newHash = secureHashFile(fileIdx.toFullPath) - result = newHash != gMemCacheData[fileIdx].hash - gMemCacheData[fileIdx].hash = newHash - updateStatus() - of hashNotTaken: - gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath) - result = true - updateStatus() - -proc doHash(fileIdx: int32) = - if gMemCacheData[fileIdx].hashStatus == hashNotTaken: - # echo "FIRST Hash: ", fileIdx.ToFilename - gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath) - -proc addDep(x: PSym, dep: int32) = - growCache gMemCacheData, dep - gMemCacheData[x.position].deps.safeAdd(dep) - -proc resetModule*(fileIdx: int32) = - # echo "HARD RESETTING ", fileIdx.toFilename - if fileIdx <% gMemCacheData.len: - gMemCacheData[fileIdx].needsRecompile = Yes - if fileIdx <% gCompiledModules.len: - gCompiledModules[fileIdx] = nil - if fileIdx <% cgendata.gModules.len: - cgendata.gModules[fileIdx] = nil - -proc resetModule*(module: PSym) = - let conflict = getModule(module.position.int32) - if conflict == nil: return - doAssert conflict == module - resetModule(module.position.int32) - initStrTable(module.tab) - -proc resetAllModules* = - for i in 0..gCompiledModules.high: - if gCompiledModules[i] != nil: - resetModule(i.int32) - resetPackageCache() - initStrTable(packageSyms) - # for m in cgenModules(): echo "CGEN MODULE FOUND" - -proc resetAllModulesHard* = - resetPackageCache() - gCompiledModules.setLen 0 - gMemCacheData.setLen 0 - magicsys.resetSysTypes() - initStrTable(packageSyms) - # XXX - #gOwners = @[] - -proc checkDepMem(fileIdx: int32): TNeedRecompile = - template markDirty = - resetModule(fileIdx) - return Yes - - if gFuzzyGraphChecking: - if gMemCacheData[fileIdx].needsRecompile != Maybe: - return gMemCacheData[fileIdx].needsRecompile - else: - # cycle detection: We claim that a cycle does no harm. - if gMemCacheData[fileIdx].needsRecompile == Probing: - return No + idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs + +when false: + type + TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled + THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged + + TModuleInMemory* = object + hash*: SecureHash + deps*: seq[int32] ## XXX: slurped files are currently not tracked + + needsRecompile*: TNeedRecompile + hashStatus*: THashStatus + + var + gCompiledModules: seq[PSym] = @[] + gMemCacheData*: seq[TModuleInMemory] = @[] + ## XXX: we should implement recycling of file IDs + ## if the user keeps renaming modules, the file IDs will keep growing + gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why. + + proc hashChanged(fileIdx: int32): bool = + internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len + + template updateStatus = + gMemCacheData[fileIdx].hashStatus = if result: hashHasChanged + else: hashNotChanged + # echo "TESTING Hash: ", fileIdx.toFilename, " ", result + + case gMemCacheData[fileIdx].hashStatus + of hashHasChanged: + result = true + of hashNotChanged: + result = false + of hashCached: + let newHash = secureHashFile(fileIdx.toFullPath) + result = newHash != gMemCacheData[fileIdx].hash + gMemCacheData[fileIdx].hash = newHash + updateStatus() + of hashNotTaken: + gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath) + result = true + updateStatus() + + proc doHash(fileIdx: int32) = + if gMemCacheData[fileIdx].hashStatus == hashNotTaken: + # echo "FIRST Hash: ", fileIdx.ToFilename + gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath) + + proc resetModule*(fileIdx: int32) = + # echo "HARD RESETTING ", fileIdx.toFilename + if fileIdx <% gMemCacheData.len: + gMemCacheData[fileIdx].needsRecompile = Yes + if fileIdx <% gCompiledModules.len: + gCompiledModules[fileIdx] = nil + if fileIdx <% cgendata.gModules.len: + cgendata.gModules[fileIdx] = nil + + proc resetModule*(module: PSym) = + let conflict = getModule(module.position.int32) + if conflict == nil: return + doAssert conflict == module + resetModule(module.position.int32) + initStrTable(module.tab) + + proc resetAllModules* = + for i in 0..gCompiledModules.high: + if gCompiledModules[i] != nil: + resetModule(i.int32) + resetPackageCache() + # for m in cgenModules(): echo "CGEN MODULE FOUND" + + proc resetAllModulesHard* = + resetPackageCache() + gCompiledModules.setLen 0 + gMemCacheData.setLen 0 + magicsys.resetSysTypes() + # XXX + #gOwners = @[] + + proc checkDepMem(fileIdx: int32): TNeedRecompile = + template markDirty = + resetModule(fileIdx) + return Yes + + if gFuzzyGraphChecking: + if gMemCacheData[fileIdx].needsRecompile != Maybe: + return gMemCacheData[fileIdx].needsRecompile + else: + # cycle detection: We claim that a cycle does no harm. + if gMemCacheData[fileIdx].needsRecompile == Probing: + return No - if optForceFullMake in gGlobalOptions or hashChanged(fileIdx): - markDirty() + if optForceFullMake in gGlobalOptions or hashChanged(fileIdx): + markDirty() - if gMemCacheData[fileIdx].deps != nil: - gMemCacheData[fileIdx].needsRecompile = Probing - for dep in gMemCacheData[fileIdx].deps: - let d = checkDepMem(dep) - if d in {Yes, Recompiled}: - # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d - markDirty() + if gMemCacheData[fileIdx].deps != nil: + gMemCacheData[fileIdx].needsRecompile = Probing + for dep in gMemCacheData[fileIdx].deps: + let d = checkDepMem(dep) + if d in {Yes, Recompiled}: + # echo fileIdx.toFilename, " depends on ", dep.toFilename, " ", d + markDirty() - gMemCacheData[fileIdx].needsRecompile = No - return No + gMemCacheData[fileIdx].needsRecompile = No + return No -proc newModule(fileIdx: int32): PSym = +proc newModule(graph: ModuleGraph; fileIdx: int32): PSym = # We cannot call ``newSym`` here, because we have to circumvent the ID # mechanism, which we do in order to assign each module a persistent ID. new(result) @@ -143,20 +131,19 @@ proc newModule(fileIdx: int32): PSym = result.info = newLineInfo(fileIdx, 1, 1) let pack = getIdent(getPackageName(filename)) - var packSym = packageSyms.strTableGet(pack) + var packSym = graph.packageSyms.strTableGet(pack) if packSym == nil: let pck = getPackageName(filename) let pck2 = if pck.len > 0: pck else: "unknown" packSym = newSym(skPackage, getIdent(pck2), nil, result.info) initStrTable(packSym.tab) - packageSyms.strTableAdd(packSym) + graph.packageSyms.strTableAdd(packSym) result.owner = packSym result.position = fileIdx - growCache gMemCacheData, fileIdx - growCache gCompiledModules, fileIdx - gCompiledModules[result.position] = result + growCache graph.modules, fileIdx + graph.modules[result.position] = result incl(result.flags, sfUsed) initStrTable(result.tab) @@ -167,13 +154,12 @@ proc newModule(fileIdx: int32): PSym = # strTableIncl() for error corrections: discard strTableIncl(packSym.tab, result) -proc compileModule*(fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym = - result = getModule(fileIdx) +proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym = + result = graph.getModule(fileIdx) if result == nil: - growCache gMemCacheData, fileIdx - gMemCacheData[fileIdx].needsRecompile = Probing - result = newModule(fileIdx) - #var rd = handleSymbolFile(result) + #growCache gMemCacheData, fileIdx + #gMemCacheData[fileIdx].needsRecompile = Probing + result = newModule(graph, fileIdx) var rd: PRodReader result.flags = result.flags + flags if sfMainModule in result.flags: @@ -182,44 +168,51 @@ proc compileModule*(fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym = if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: rd = handleSymbolFile(result, cache) if result.id < 0: - internalError("handleSymbolFile should have set the module\'s ID") + internalError("handleSymbolFile should have set the module's ID") return else: result.id = getID() - let validFile = processModule(result, + discard processModule(graph, result, if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil, rd, cache) - if optCaasEnabled in gGlobalOptions: - gMemCacheData[fileIdx].compiledAt = gLastCmdTime - gMemCacheData[fileIdx].needsRecompile = Recompiled - if validFile: doHash fileIdx - else: - if checkDepMem(fileIdx) == Yes: - result = compileModule(fileIdx, cache, flags) - else: - result = gCompiledModules[fileIdx] - -proc importModule*(s: PSym, fileIdx: int32; cache: IdentCache): PSym {.procvar.} = + #if optCaasEnabled in gGlobalOptions: + # gMemCacheData[fileIdx].needsRecompile = Recompiled + # if validFile: doHash fileIdx + elif graph.isDirty(result): + result.flags.excl sfDirty + # reset module fields: + initStrTable(result.tab) + result.ast = nil + discard processModule(graph, result, + if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil, + nil, cache) + graph.markClientsDirty(fileIdx) + when false: + if checkDepMem(fileIdx) == Yes: + result = compileModule(fileIdx, cache, flags) + else: + result = gCompiledModules[fileIdx] + +proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32; + cache: IdentCache): PSym {.procvar.} = # this is called by the semantic checking phase - result = compileModule(fileIdx, cache, {}) - if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx) + result = compileModule(graph, fileIdx, cache, {}) + graph.addDep(s, fileIdx) #if sfSystemModule in result.flags: # localError(result.info, errAttemptToRedefine, result.name.s) # restore the notes for outer module: gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes else: ForeignPackageNotes -proc includeModule*(s: PSym, fileIdx: int32; cache: IdentCache): PNode {.procvar.} = +proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: int32; + cache: IdentCache): PNode {.procvar.} = result = syntaxes.parseFile(fileIdx, cache) - if optCaasEnabled in gGlobalOptions: - growCache gMemCacheData, fileIdx - addDep(s, fileIdx) - doHash(fileIdx) + graph.addDep(s, fileIdx) -proc compileSystemModule*(cache: IdentCache) = +proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) = if magicsys.systemModule == nil: systemFileIdx = fileInfoIdx(options.libpath/"system.nim") - discard compileModule(systemFileIdx, cache, {sfSystemModule}) + discard graph.compileModule(systemFileIdx, cache, {sfSystemModule}) proc wantMainModule* = if gProjectFull.len == 0: @@ -229,18 +222,19 @@ proc wantMainModule* = passes.gIncludeFile = includeModule passes.gImportModule = importModule -proc compileProject*(cache: IdentCache; projectFileIdx = -1'i32) = +proc compileProject*(graph: ModuleGraph; cache: IdentCache; + projectFileIdx = -1'i32) = wantMainModule() let systemFileIdx = fileInfoIdx(options.libpath / "system.nim") let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx if projectFile == systemFileIdx: - discard compileModule(projectFile, cache, {sfMainModule, sfSystemModule}) + discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule}) else: - compileSystemModule(cache) - discard compileModule(projectFile, cache, {sfMainModule}) + graph.compileSystemModule(cache) + discard graph.compileModule(projectFile, cache, {sfMainModule}) -proc makeModule*(filename: string): PSym = - result = newModule(fileInfoIdx filename) +proc makeModule*(graph: ModuleGraph; filename: string): PSym = + result = graph.newModule(fileInfoIdx filename) result.id = getID() -proc makeStdinModule*(): PSym = makeModule"stdin" +proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule"stdin" diff --git a/compiler/nim.nim b/compiler/nim.nim index aeab9421e..f8d6b607a 100644 --- a/compiler/nim.nim +++ b/compiler/nim.nim @@ -14,14 +14,14 @@ when defined(gcc) and defined(windows): {.link: "icons/nim_icon.o".} when defined(amd64) and defined(windows) and defined(vcc): - {.link: "icons/nim-amd64-windows-vcc.res" .} + {.link: "icons/nim-amd64-windows-vcc.res".} when defined(i386) and defined(windows) and defined(vcc): - {.link: "icons/nim-i386-windows-vcc.res" .} + {.link: "icons/nim-i386-windows-vcc.res".} import commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, extccomp, strutils, os, osproc, platform, main, parseopt, service, - nodejs, scriptconfig, idents + nodejs, scriptconfig, idents, modulegraphs when hasTinyCBackend: import tccgen @@ -73,7 +73,7 @@ proc handleCmdLine(cache: IdentCache) = processCmdLine(passCmd2, "") if options.command == "": rawMessage(errNoCommand, command) - mainCommand(cache) + mainCommand(newModuleGraph(), cache) if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics()) #echo(GC_getStatistics()) if msgs.gErrorCounter == 0: diff --git a/compiler/nimsuggest/nimsuggest.nim b/compiler/nimsuggest/nimsuggest.nim deleted file mode 100644 index 2be368d68..000000000 --- a/compiler/nimsuggest/nimsuggest.nim +++ /dev/null @@ -1,12 +0,0 @@ -# -# -# The Nim Compiler -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## Nimsuggest has been moved to https://github.com/nim-lang/nimsuggest - -{.error: "This project has moved to the following repo: https://github.com/nim-lang/nimsuggest".} diff --git a/compiler/passaux.nim b/compiler/passaux.nim index dc99ffd0c..eeaf12953 100644 --- a/compiler/passaux.nim +++ b/compiler/passaux.nim @@ -12,7 +12,9 @@ import strutils, ast, astalgo, passes, idents, msgs, options, idgen -proc verboseOpen(s: PSym; cache: IdentCache): PPassContext = +from modulegraphs import ModuleGraph + +proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = #MessageOut('compiling ' + s.name.s); result = nil # we don't need a context rawMessage(hintProcessing, s.name.s) diff --git a/compiler/passes.nim b/compiler/passes.nim index 9e383849a..4f1d4e3aa 100644 --- a/compiler/passes.nim +++ b/compiler/passes.nim @@ -13,7 +13,7 @@ import strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, - nimsets, syntaxes, times, rodread, idgen + nimsets, syntaxes, times, rodread, idgen, modulegraphs type TPassContext* = object of RootObj # the pass's context @@ -21,9 +21,9 @@ type PPassContext* = ref TPassContext - TPassOpen* = proc (module: PSym; cache: IdentCache): PPassContext {.nimcall.} + TPassOpen* = proc (graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext {.nimcall.} TPassOpenCached* = - proc (module: PSym, rd: PRodReader): PPassContext {.nimcall.} + proc (graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext {.nimcall.} TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.} TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.} @@ -48,8 +48,8 @@ proc makePass*(open: TPassOpen = nil, # the semantic checker needs these: var - gImportModule*: proc (m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.} - gIncludeFile*: proc (m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.} + gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.} + gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.} # implementation @@ -90,29 +90,32 @@ proc registerPass*(p: TPass) = gPasses[gPassesLen] = p inc(gPassesLen) -proc carryPass*(p: TPass, module: PSym; cache: IdentCache; +proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache; m: TPassData): TPassData = - var c = p.open(module, cache) + var c = p.open(g, module, cache) result.input = p.process(c, m.input) result.closeOutput = if p.close != nil: p.close(c, m.closeOutput) else: m.closeOutput -proc carryPasses*(nodes: PNode, module: PSym; cache: IdentCache; passes: TPasses) = +proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym; + cache: IdentCache; passes: TPasses) = var passdata: TPassData passdata.input = nodes for pass in passes: - passdata = carryPass(pass, module, cache, passdata) + passdata = carryPass(g, pass, module, cache, passdata) -proc openPasses(a: var TPassContextArray, module: PSym; cache: IdentCache) = +proc openPasses(g: ModuleGraph; a: var TPassContextArray; + module: PSym; cache: IdentCache) = for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].open): - a[i] = gPasses[i].open(module, cache) + a[i] = gPasses[i].open(g, module, cache) else: a[i] = nil -proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) = +proc openPassesCached(g: ModuleGraph; a: var TPassContextArray, module: PSym, + rd: PRodReader) = for i in countup(0, gPassesLen - 1): if not isNil(gPasses[i].openCached): - a[i] = gPasses[i].openCached(module, rd) + a[i] = gPasses[i].openCached(g, module, rd) if a[i] != nil: a[i].fromCache = true else: @@ -155,7 +158,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind, importStmt.addSon str if not processTopLevelStmt(importStmt, a): break -proc processModule*(module: PSym, stream: PLLStream, +proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, rd: PRodReader; cache: IdentCache): bool {.discardable.} = var p: TParsers @@ -163,7 +166,7 @@ proc processModule*(module: PSym, stream: PLLStream, s: PLLStream fileIdx = module.fileIdx if rd == nil: - openPasses(a, module, cache) + openPasses(graph, a, module, cache) if stream == nil: let filename = fileIdx.toFullPathConsiderDirty s = llStreamOpen(filename, fmRead) @@ -203,7 +206,7 @@ proc processModule*(module: PSym, stream: PLLStream, # id synchronization point for more consistent code generation: idSynchronizationPoint(1000) else: - openPassesCached(a, module, rd) + openPassesCached(graph, a, module, rd) var n = loadInitSection(rd) for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a) closePassesCached(a) diff --git a/compiler/rodwrite.nim b/compiler/rodwrite.nim index 4e8b27733..f2422f947 100644 --- a/compiler/rodwrite.nim +++ b/compiler/rodwrite.nim @@ -16,6 +16,8 @@ import condsyms, ropes, idents, securehash, rodread, passes, importer, idgen, rodutils +from modulegraphs import ModuleGraph + type TRodWriter = object of TPassContext module: PSym @@ -633,7 +635,7 @@ proc process(c: PPassContext, n: PNode): PNode = else: discard -proc myOpen(module: PSym; cache: IdentCache): PPassContext = +proc myOpen(g: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = if module.id < 0: internalError("rodwrite: module ID not set") var w = newRodWriter(module.fileIdx.getHash, module, cache) rawAddInterfaceSym(w, module) diff --git a/compiler/scriptconfig.nim b/compiler/scriptconfig.nim index 891ee80ad..ddd73e6f8 100644 --- a/compiler/scriptconfig.nim +++ b/compiler/scriptconfig.nim @@ -13,7 +13,7 @@ import ast, modules, idents, passes, passaux, condsyms, options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, - os, times, osproc, wordrecg, strtabs + os, times, osproc, wordrecg, strtabs, modulegraphs # we support 'cmpIgnoreStyle' natively for efficiency: from strutils import cmpIgnoreStyle, contains @@ -134,9 +134,11 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext cbconf selfExe: setResult(a, os.getAppFilename()) -proc runNimScript*(cache: IdentCache; scriptName: string; freshDefines=true) = +proc runNimScript*(cache: IdentCache; scriptName: string; + freshDefines=true) = passes.gIncludeFile = includeModule passes.gImportModule = importModule + let graph = newModuleGraph() if freshDefines: initDefines() defineSymbol("nimscript") @@ -146,15 +148,15 @@ proc runNimScript*(cache: IdentCache; scriptName: string; freshDefines=true) = appendStr(searchPaths, options.libpath) - var m = makeModule(scriptName) + var m = graph.makeModule(scriptName) incl(m.flags, sfMainModule) vm.globalCtx = setupVM(m, cache, scriptName) - compileSystemModule(cache) - discard processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) + graph.compileSystemModule(cache) + discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) # ensure we load 'system.nim' again for the real non-config stuff! - resetAllModulesHard() + #resetAllModulesHard() vm.globalCtx = nil # do not remove the defined symbols #initDefines() diff --git a/compiler/sem.nim b/compiler/sem.nim index e5ce7c6ce..02c779ef0 100644 --- a/compiler/sem.nim +++ b/compiler/sem.nim @@ -18,6 +18,8 @@ import evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity, semparallel, lowerings, pluginsupport, plugins.active +from modulegraphs import ModuleGraph + when defined(nimfix): import nimfix.prettybase @@ -398,8 +400,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) = addSon(n, prc.ast) c.lastGenericIdx = c.generics.len -proc myOpen(module: PSym; cache: IdentCache): PPassContext = - var c = newContext(module, cache) +proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = + var c = newContext(graph, module, cache) if c.p != nil: internalError(module.info, "sem.myOpen") c.semConstExpr = semConstExpr c.semExpr = semExpr @@ -428,8 +430,8 @@ proc myOpen(module: PSym; cache: IdentCache): PPassContext = gNotes = ForeignPackageNotes result = c -proc myOpenCached(module: PSym; rd: PRodReader): PPassContext = - result = myOpen(module, rd.cache) +proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext = + result = myOpen(graph, module, rd.cache) for m in items(rd.methods): methodDef(m, true) proc isImportSystemStmt(n: PNode): bool = diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 9a6011834..5b84b7cdf 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -1,7 +1,7 @@ # # # The Nim Compiler -# (c) Copyright 2012 Andreas Rumpf +# (c) Copyright 2016 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. @@ -13,7 +13,8 @@ import strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab, wordrecg, ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, - magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef + magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef, + modulegraphs type TOptionEntry* = object of lists.TListEntry # entries to put on a @@ -107,6 +108,7 @@ type op: TTypeAttachedOp; col: int): PSym {.nimcall.} selfName*: PIdent cache*: IdentCache + graph*: ModuleGraph signatures*: TStrTable proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = @@ -151,7 +153,7 @@ proc newOptionEntry*(): POptionEntry = result.dynlib = nil result.notes = gNotes -proc newContext*(module: PSym; cache: IdentCache): PContext = +proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext = new(result) result.ambiguousSymbols = initIntSet() initLinkedList(result.optionStack) @@ -166,6 +168,7 @@ proc newContext*(module: PSym; cache: IdentCache): PContext = result.generics = @[] result.unknownIdents = initIntSet() result.cache = cache + result.graph = graph initStrTable(result.signatures) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index f8ec00b23..0c6f6848e 100644 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -820,7 +820,7 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode = if containsOrIncl(c.includedFiles, f): localError(n.info, errRecursiveDependencyX, f.toFilename) else: - let code = gIncludeFile(c.module, f, c.cache) + let code = gIncludeFile(c.graph, c.module, f, c.cache) gatherStmts c, code, result excl(c.includedFiles, f) of nkStmtList: @@ -1418,7 +1418,7 @@ proc evalInclude(c: PContext, n: PNode): PNode = if containsOrIncl(c.includedFiles, f): localError(n.info, errRecursiveDependencyX, f.toFilename) else: - addSon(result, semStmt(c, gIncludeFile(c.module, f, c.cache))) + addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache))) excl(c.includedFiles, f) proc setLine(n: PNode, info: TLineInfo) = diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 558581e04..39689099a 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -233,7 +233,7 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) = # error: no known module name: typ = nil else: - let m = gImportModule(c.module, fullpath.fileInfoIdx, c.cache) + let m = gImportModule(c.graph, c.module, fullpath.fileInfoIdx, c.cache) if m == nil: typ = nil else: for it in items(n.sym.tab): diff --git a/compiler/vm.nim b/compiler/vm.nim index 8e1c9f661..1bb440c6c 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -24,6 +24,8 @@ import from semfold import leValueConv, ordinalValToString from evaltempl import evalTemplate +from modulegraphs import ModuleGraph + when hasFFI: import evalffi @@ -1516,7 +1518,7 @@ proc setupGlobalCtx(module: PSym; cache: IdentCache) = else: refresh(globalCtx, module) -proc myOpen(module: PSym; cache: IdentCache): PPassContext = +proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = #var c = newEvalContext(module, emRepl) #c.features = {allowCast, allowFFI, allowInfiniteLoops} #pushStackFrame(c, newStackFrame()) |