diff --git a/compiler/evals.nim b/compiler/evals.nim index fa24d2b7af..f89417dc80 100644 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -1446,7 +1446,6 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = result = n else: InternalError(n.info, "evalAux: " & $n.kind) if result == nil: - debug n InternalError(n.info, "evalAux: returned nil " & $n.kind) inc(gNestedEvals) diff --git a/compiler/main.nim b/compiler/main.nim index f61288ff10..047b3ff1d6 100644 --- a/compiler/main.nim +++ b/compiler/main.nim @@ -7,16 +7,17 @@ # distribution, for details about the copyright. # -# implements the command dispatcher and several commands as well as the -# module handling +# implements the command dispatcher and several commands import llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs, - os, lists, condsyms, rodread, rodwrite, ropes, trees, times, + os, condsyms, rodread, rodwrite, times, wordrecg, sem, semdata, idents, passes, docgen, extccomp, - cgen, jsgen, cgendata, json, nversion, + cgen, jsgen, json, nversion, platform, nimconf, importer, passaux, depends, evals, types, idgen, - tables, docgen2, service, magicsys, parser, crc, ccgutils, sigmatch + tables, docgen2, service, parser, modules, ccgutils, sigmatch, ropes, lists + +from magicsys import SystemModule, resetSysTypes const has_LLVM_Backend = false @@ -24,191 +25,6 @@ const when has_LLVM_Backend: import llvmgen -proc MainCommand*() - -# ------------------ module handling ----------------------------------------- - -type - TNeedRecompile = enum Maybe, No, Yes, Probing, Recompiled - TCrcStatus = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged - - TModuleInMemory = object - compiledAt: float - crc: TCrc32 - deps: seq[int32] ## XXX: slurped files are not currently tracked - needsRecompile: TNeedRecompile - crcStatus: TCrcStatus - -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 - -proc getModule(fileIdx: int32): PSym = - if fileIdx >= 0 and fileIdx < gCompiledModules.len: - result = gCompiledModules[fileIdx] - else: - result = nil - -template compiledAt(x: PSym): expr = - gMemCacheData[x.position].compiledAt - -template crc(x: PSym): expr = - gMemCacheData[x.position].crc - -proc crcChanged(fileIdx: int32): bool = - InternalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len - - template updateStatus = - gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged - else: crcNotChanged - # echo "TESTING CRC: ", fileIdx.toFilename, " ", result - - case gMemCacheData[fileIdx].crcStatus: - of crcHasChanged: - result = true - of crcNotChanged: - result = false - of crcCached: - let newCrc = crcFromFile(fileIdx.toFilename) - result = newCrc != gMemCacheData[fileIdx].crc - gMemCacheData[fileIdx].crc = newCrc - updateStatus() - of crcNotTaken: - gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename) - result = true - updateStatus() - -proc doCRC(fileIdx: int32) = - if gMemCacheData[fileIdx].crcStatus == crcNotTaken: - # echo "FIRST CRC: ", fileIdx.ToFilename - gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename) - -proc addDep(x: Psym, dep: int32) = - growCache gMemCacheData, dep - gMemCacheData[x.position].deps.safeAdd(dep) - -proc resetModule(fileIdx: int32) = - # echo "HARD RESETTING ", fileIdx.toFilename - gMemCacheData[fileIdx].needsRecompile = Yes - gCompiledModules[fileIdx] = nil - cgendata.gModules[fileIdx] = nil - resetSourceMap(fileIdx) - -proc resetAllModules = - for i in 0..gCompiledModules.high: - if gCompiledModules[i] != nil: - resetModule(i.int32) - - # for m in cgenModules(): echo "CGEN MODULE FOUND" - -proc checkDepMem(fileIdx: int32): TNeedRecompile = - template markDirty = - resetModule(fileIdx) - return Yes - - if gMemCacheData[fileIdx].needsRecompile != Maybe: - return gMemCacheData[fileIdx].needsRecompile - - if optForceFullMake in gGlobalOptions or - crcChanged(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 - - gMemCacheData[fileIdx].needsRecompile = No - return No - -proc newModule(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) - result.id = - 1 # for better error checking - result.kind = skModule - let filename = fileIdx.toFilename - result.name = getIdent(splitFile(filename).name) - if not isNimrodIdentifier(result.name.s): - rawMessage(errInvalidModuleName, result.name.s) - - result.owner = result # a module belongs to itself - result.info = newLineInfo(fileIdx, 1, 1) - result.position = fileIdx - - growCache gMemCacheData, fileIdx - growCache gCompiledModules, fileIdx - gCompiledModules[result.position] = result - - incl(result.flags, sfUsed) - initStrTable(result.tab) - StrTableAdd(result.tab, result) # a module knows itself - -proc compileModule(fileIdx: int32, flags: TSymFlags): PSym = - result = getModule(fileIdx) - if result == nil: - growCache gMemCacheData, fileIdx - gMemCacheData[fileIdx].needsRecompile = Probing - result = newModule(fileIdx) - #var rd = handleSymbolFile(result) - var rd: PRodReader - result.flags = result.flags + flags - if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: - rd = handleSymbolFile(result) - if result.id < 0: - InternalError("handleSymbolFile should have set the module\'s ID") - return - else: - result.id = getID() - processModule(result, nil, rd) - if optCaasEnabled in gGlobalOptions: - gMemCacheData[fileIdx].compiledAt = gLastCmdTime - gMemCacheData[fileIdx].needsRecompile = Recompiled - doCRC fileIdx - else: - if checkDepMem(fileIdx) == Yes: - result = CompileModule(fileIdx, flags) - else: - result = gCompiledModules[fileIdx] - -proc importModule(s: PSym, fileIdx: int32): PSym = - # this is called by the semantic checking phase - result = compileModule(fileIdx, {}) - if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx) - if sfSystemModule in result.flags: - LocalError(result.info, errAttemptToRedefine, result.Name.s) - -proc includeModule(s: PSym, fileIdx: int32): PNode = - result = syntaxes.parseFile(fileIdx) - if optCaasEnabled in gGlobalOptions: - growCache gMemCacheData, fileIdx - addDep(s, fileIdx) - doCrc(fileIdx) - -proc `==^`(a, b: string): bool = - try: - result = sameFile(a, b) - except EOS: - result = false - -proc compileSystemModule = - if magicsys.SystemModule == nil: - SystemFileIdx = fileInfoIdx(options.libpath/"system.nim") - discard CompileModule(SystemFileIdx, {sfSystemModule}) - -proc CompileProject(projectFile = gProjectMainIdx) = - let systemFileIdx = fileInfoIdx(options.libpath / "system.nim") - if projectFile == SystemFileIdx: - discard CompileModule(projectFile, {sfMainModule, sfSystemModule}) - else: - compileSystemModule() - discard CompileModule(projectFile, {sfMainModule}) - proc rodPass = if optSymbolFiles in gGlobalOptions: registerPass(rodwritePass) @@ -323,13 +139,6 @@ proc InteractivePasses = registerPass(semPass) registerPass(evalPass) -var stdinModule: PSym -proc makeStdinModule: PSym = - if stdinModule == nil: - stdinModule = newModule(fileInfoIdx"stdin") - stdinModule.id = getID() - result = stdinModule - proc CommandInteractive = msgs.gErrorMax = high(int) # do not stop after first error InteractivePasses() @@ -341,18 +150,6 @@ proc CommandInteractive = incl(m.flags, sfMainModule) processModule(m, LLStreamOpenStdIn(), nil) -proc execute*(program: string) = - passes.gIncludeFile = includeModule - passes.gImportModule = importModule - initDefines() - LoadConfigs(DefaultConfig) - InteractivePasses() - appendStr(searchPaths, options.libpath) - compileSystemModule() - var m = makeStdinModule() - incl(m.flags, sfMainModule) - processModule(m, LLStreamOpen(program), nil) - const evalPasses = [verbosePass, semPass, evalPass] proc evalNim(nodes: PNode, module: PSym) = @@ -477,7 +274,7 @@ const SimiluateCaasMemReset = false PrintRopeCacheStats = false -proc MainCommand = +proc MainCommand* = when SimiluateCaasMemReset: gGlobalOptions.incl(optCaasEnabled) diff --git a/compiler/modules.nim b/compiler/modules.nim new file mode 100644 index 0000000000..ef6af3d69a --- /dev/null +++ b/compiler/modules.nim @@ -0,0 +1,200 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2013 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## implements the module handling + +import + ast, astalgo, magicsys, crc, rodread, msgs, cgendata, sigmatch, options, + idents, os, lexer, idgen, passes, syntaxes + +type + TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled + TCrcStatus* = enum crcNotTaken, crcCached, crcHasChanged, crcNotChanged + + TModuleInMemory* = object + compiledAt*: float + crc*: TCrc32 + deps*: seq[int32] ## XXX: slurped files are not currently tracked + needsRecompile*: TNeedRecompile + crcStatus*: TCrcStatus + +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 + +proc getModule(fileIdx: int32): PSym = + if fileIdx >= 0 and fileIdx < gCompiledModules.len: + result = gCompiledModules[fileIdx] + +template compiledAt(x: PSym): expr = + gMemCacheData[x.position].compiledAt + +template crc(x: PSym): expr = + gMemCacheData[x.position].crc + +proc crcChanged(fileIdx: int32): bool = + InternalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len + + template updateStatus = + gMemCacheData[fileIdx].crcStatus = if result: crcHasChanged + else: crcNotChanged + # echo "TESTING CRC: ", fileIdx.toFilename, " ", result + + case gMemCacheData[fileIdx].crcStatus: + of crcHasChanged: + result = true + of crcNotChanged: + result = false + of crcCached: + let newCrc = crcFromFile(fileIdx.toFilename) + result = newCrc != gMemCacheData[fileIdx].crc + gMemCacheData[fileIdx].crc = newCrc + updateStatus() + of crcNotTaken: + gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename) + result = true + updateStatus() + +proc doCRC(fileIdx: int32) = + if gMemCacheData[fileIdx].crcStatus == crcNotTaken: + # echo "FIRST CRC: ", fileIdx.ToFilename + gMemCacheData[fileIdx].crc = crcFromFile(fileIdx.toFilename) + +proc addDep(x: Psym, dep: int32) = + growCache gMemCacheData, dep + gMemCacheData[x.position].deps.safeAdd(dep) + +proc resetModule*(fileIdx: int32) = + # echo "HARD RESETTING ", fileIdx.toFilename + gMemCacheData[fileIdx].needsRecompile = Yes + gCompiledModules[fileIdx] = nil + cgendata.gModules[fileIdx] = nil + resetSourceMap(fileIdx) + +proc resetAllModules* = + for i in 0..gCompiledModules.high: + if gCompiledModules[i] != nil: + resetModule(i.int32) + + # for m in cgenModules(): echo "CGEN MODULE FOUND" + +proc checkDepMem(fileIdx: int32): TNeedRecompile = + template markDirty = + resetModule(fileIdx) + return Yes + + if gMemCacheData[fileIdx].needsRecompile != Maybe: + return gMemCacheData[fileIdx].needsRecompile + + if optForceFullMake in gGlobalOptions or + crcChanged(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 + + gMemCacheData[fileIdx].needsRecompile = No + return No + +proc newModule(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) + result.id = - 1 # for better error checking + result.kind = skModule + let filename = fileIdx.toFilename + result.name = getIdent(splitFile(filename).name) + if not isNimrodIdentifier(result.name.s): + rawMessage(errInvalidModuleName, result.name.s) + + result.owner = result # a module belongs to itself + result.info = newLineInfo(fileIdx, 1, 1) + result.position = fileIdx + + growCache gMemCacheData, fileIdx + growCache gCompiledModules, fileIdx + gCompiledModules[result.position] = result + + incl(result.flags, sfUsed) + initStrTable(result.tab) + StrTableAdd(result.tab, result) # a module knows itself + +proc compileModule*(fileIdx: int32, flags: TSymFlags): PSym = + result = getModule(fileIdx) + if result == nil: + growCache gMemCacheData, fileIdx + gMemCacheData[fileIdx].needsRecompile = Probing + result = newModule(fileIdx) + #var rd = handleSymbolFile(result) + var rd: PRodReader + result.flags = result.flags + flags + if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}: + rd = handleSymbolFile(result) + if result.id < 0: + InternalError("handleSymbolFile should have set the module\'s ID") + return + else: + result.id = getID() + processModule(result, nil, rd) + if optCaasEnabled in gGlobalOptions: + gMemCacheData[fileIdx].compiledAt = gLastCmdTime + gMemCacheData[fileIdx].needsRecompile = Recompiled + doCRC fileIdx + else: + if checkDepMem(fileIdx) == Yes: + result = CompileModule(fileIdx, flags) + else: + result = gCompiledModules[fileIdx] + +proc importModule*(s: PSym, fileIdx: int32): PSym {.procvar.} = + # this is called by the semantic checking phase + result = compileModule(fileIdx, {}) + if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx) + if sfSystemModule in result.flags: + LocalError(result.info, errAttemptToRedefine, result.Name.s) + +proc includeModule*(s: PSym, fileIdx: int32): PNode {.procvar.} = + result = syntaxes.parseFile(fileIdx) + if optCaasEnabled in gGlobalOptions: + growCache gMemCacheData, fileIdx + addDep(s, fileIdx) + doCrc(fileIdx) + +proc `==^`(a, b: string): bool = + try: + result = sameFile(a, b) + except EOS: + result = false + +proc compileSystemModule* = + if magicsys.SystemModule == nil: + SystemFileIdx = fileInfoIdx(options.libpath/"system.nim") + discard CompileModule(SystemFileIdx, {sfSystemModule}) + +proc CompileProject*(projectFile = gProjectMainIdx) = + let systemFileIdx = fileInfoIdx(options.libpath / "system.nim") + if projectFile == SystemFileIdx: + discard CompileModule(projectFile, {sfMainModule, sfSystemModule}) + else: + compileSystemModule() + discard CompileModule(projectFile, {sfMainModule}) + +var stdinModule: PSym +proc makeStdinModule*(): PSym = + if stdinModule == nil: + stdinModule = newModule(fileInfoIdx"stdin") + stdinModule.id = getID() + result = stdinModule diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index a94d89caaa..28ea50a158 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1473,7 +1473,10 @@ proc semWhen(c: PContext, n: PNode, semCheck = true): PNode = of nkElifBranch, nkElifExpr: checkSonsLen(it, 2) var e = semConstExpr(c, it.sons[0]) - if e.kind != nkIntLit: InternalError(n.info, "semWhen") + if e.kind != nkIntLit: + # can happen for cascading errors, assume false + # InternalError(n.info, "semWhen") + discard elif e.intVal != 0 and result == nil: setResult(it.sons[1]) of nkElse, nkElseExpr: diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim index 041baf1260..a3e108a34b 100644 --- a/compiler/sigmatch.nim +++ b/compiler/sigmatch.nim @@ -12,8 +12,10 @@ import intsets, ast, astalgo, semdata, types, msgs, renderer, lookups, semtypinst, - magicsys, condsyms, idents, lexer, options, parampatterns, strutils, - docgen + magicsys, condsyms, idents, lexer, options, parampatterns, strutils + +when not defined(noDocgen): + import docgen type TCandidateState* = enum diff --git a/compiler/suggest.nim b/compiler/suggest.nim index 892afc05ea..85e256cbb3 100644 --- a/compiler/suggest.nim +++ b/compiler/suggest.nim @@ -46,7 +46,8 @@ proc SymToStr(s: PSym, isLocal: bool, section: string, li: TLineInfo): string = result.add(sep) result.add($ToColumn(li)) result.add(sep) - result.add(s.extractDocComment.escape) + when not defined(noDocgen): + result.add(s.extractDocComment.escape) proc SymToStr(s: PSym, isLocal: bool, section: string): string = result = SymToStr(s, isLocal, section, s.info)