incremental compilation: implemented basic replay logic

This commit is contained in:
Andreas Rumpf 2018-06-02 09:41:27 +02:00
commit 826c1e2d78
25 changed files with 295 additions and 271 deletions

View file

@ -1058,22 +1058,6 @@ proc newTree*(kind: TNodeKind; children: varargs[PNode]): PNode =
result.info = children[0].info result.info = children[0].info
result.sons = @children result.sons = @children
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind)
result.intVal = intVal
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
result = newIntNode(kind, intVal)
result.typ = typ
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
result = newNode(kind)
result.floatVal = floatVal
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind)
result.strVal = strVal
template previouslyInferred*(t: PType): PType = template previouslyInferred*(t: PType): PType =
if t.sons.len > 1: t.lastSon else: nil if t.sons.len > 1: t.lastSon else: nil
@ -1221,6 +1205,26 @@ proc newNodeIT*(kind: TNodeKind, info: TLineInfo, typ: PType): PNode =
result.info = info result.info = info
result.typ = typ result.typ = typ
proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind)
result.intVal = intVal
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
result = newIntNode(kind, intVal)
result.typ = typ
proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
result = newNode(kind)
result.floatVal = floatVal
proc newStrNode*(kind: TNodeKind, strVal: string): PNode =
result = newNode(kind)
result.strVal = strVal
proc newStrNode*(strVal: string; info: TLineInfo): PNode =
result = newNodeI(nkStrLit, info)
result.strVal = strVal
proc addSon*(father, son: PNode) = proc addSon*(father, son: PNode) =
assert son != nil assert son != nil
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]

View file

@ -1316,7 +1316,7 @@ template injectG() {.dirty.} =
graph.backend = newModuleList(graph) graph.backend = newModuleList(graph)
let g = BModuleList(graph.backend) let g = BModuleList(graph.backend)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
injectG() injectG()
result = newModule(g, module, graph.config) result = newModule(g, module, graph.config)
if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil: if optGenIndex in graph.config.globalOptions and g.generatedHeader == nil:
@ -1360,6 +1360,7 @@ proc getCFile(m: BModule): string =
else: ".c" else: ".c"
result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext) result = changeFileExt(completeCFilePath(m.config, withPackageName(m.config, m.cfilename)), ext)
when false:
proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext = proc myOpenCached(graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext =
injectG() injectG()
var m = newModule(g, module, graph.config) var m = newModule(g, module, graph.config)
@ -1506,4 +1507,4 @@ proc cgenWriteModules*(backend: RootRef, config: ConfigRef) =
writeMapping(config, g.mapping) writeMapping(config, g.mapping)
if g.generatedHeader != nil: writeHeader(g.generatedHeader) if g.generatedHeader != nil: writeHeader(g.generatedHeader)
const cgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) const cgenPass* = makePass(myOpen, myProcess, myClose)

View file

@ -51,7 +51,7 @@ proc generateDot*(graph: ModuleGraph; project: string) =
rope(changeFileExt(extractFilename(project), "")), b.dotGraph], rope(changeFileExt(extractFilename(project), "")), b.dotGraph],
changeFileExt(project, "dot")) changeFileExt(project, "dot"))
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module

View file

@ -51,7 +51,7 @@ proc processNodeJson(c: PPassContext, n: PNode): PNode =
var g = PGen(c) var g = PGen(c)
generateJson(g.doc, n) generateJson(g.doc, n)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module

View file

@ -133,7 +133,7 @@ proc importModuleAs(c: PContext; n: PNode, realModule: PSym): PSym =
result = createModuleAlias(realModule, n.sons[1].ident, realModule.info, result = createModuleAlias(realModule, n.sons[1].ident, realModule.info,
c.config.options) c.config.options)
proc myImportModule(c: PContext, n: PNode): PSym = proc myImportModule(c: PContext, n: PNode; importStmtResult: PNode): PSym =
var f = checkModuleName(c.config, n) var f = checkModuleName(c.config, n)
if f != InvalidFileIDX: if f != InvalidFileIDX:
let L = c.graph.importStack.len let L = c.graph.importStack.len
@ -147,7 +147,7 @@ proc myImportModule(c: PContext, n: PNode): PSym =
err.add toFullPath(c.config, c.graph.importStack[i]) & " imports " & err.add toFullPath(c.config, c.graph.importStack[i]) & " imports " &
toFullPath(c.config, c.graph.importStack[i+1]) toFullPath(c.config, c.graph.importStack[i+1])
c.recursiveDep = err c.recursiveDep = err
result = importModuleAs(c, n, gImportModule(c.graph, c.module, f, c.cache)) result = importModuleAs(c, n, c.graph.importModuleCallback(c.graph, c.module, f))
#echo "set back to ", L #echo "set back to ", L
c.graph.importStack.setLen(L) c.graph.importStack.setLen(L)
# we cannot perform this check reliably because of # we cannot perform this check reliably because of
@ -162,9 +162,10 @@ proc myImportModule(c: PContext, n: PNode): PSym =
else: else:
message(c.config, n.info, warnDeprecated, result.name.s) message(c.config, n.info, warnDeprecated, result.name.s)
suggestSym(c.config, n.info, result, c.graph.usageSym, false) suggestSym(c.config, n.info, result, c.graph.usageSym, false)
importStmtResult.add newStrNode(toFullPath(c.config, f), n.info)
proc impMod(c: PContext; it: PNode) = proc impMod(c: PContext; it: PNode; importStmtResult: PNode) =
let m = myImportModule(c, it) let m = myImportModule(c, it, importStmtResult)
if m != nil: if m != nil:
var emptySet: IntSet var emptySet: IntSet
# ``addDecl`` needs to be done before ``importAllSymbols``! # ``addDecl`` needs to be done before ``importAllSymbols``!
@ -173,7 +174,8 @@ proc impMod(c: PContext; it: PNode) =
#importForwarded(c, m.ast, emptySet) #importForwarded(c, m.ast, emptySet)
proc evalImport(c: PContext, n: PNode): PNode = proc evalImport(c: PContext, n: PNode): PNode =
result = n #result = n
result = newNodeI(nkImportStmt, n.info)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket: if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket:
@ -185,14 +187,14 @@ proc evalImport(c: PContext, n: PNode): PNode =
a.add sep # dummy entry, replaced in the loop a.add sep # dummy entry, replaced in the loop
for x in it[2]: for x in it[2]:
a.sons[2] = x a.sons[2] = x
impMod(c, a) impMod(c, a, result)
else: else:
impMod(c, it) impMod(c, it, result)
proc evalFrom(c: PContext, n: PNode): PNode = proc evalFrom(c: PContext, n: PNode): PNode =
result = n result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0]) var m = myImportModule(c, n.sons[0], result)
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) n.sons[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module addDecl(c, m, n.info) # add symbol to symbol table of module
@ -201,9 +203,9 @@ proc evalFrom(c: PContext, n: PNode): PNode =
importSymbol(c, n.sons[i], m) importSymbol(c, n.sons[i], m)
proc evalImportExcept*(c: PContext, n: PNode): PNode = proc evalImportExcept*(c: PContext, n: PNode): PNode =
result = n result = newNodeI(nkImportStmt, n.info)
checkMinSonsLen(n, 2, c.config) checkMinSonsLen(n, 2, c.config)
var m = myImportModule(c, n.sons[0]) var m = myImportModule(c, n.sons[0], result)
if m != nil: if m != nil:
n.sons[0] = newSymNode(m) n.sons[0] = newSymNode(m)
addDecl(c, m, n.info) # add symbol to symbol table of module addDecl(c, m, n.info) # add symbol to symbol table of module

View file

@ -2277,12 +2277,8 @@ proc myClose(graph: ModuleGraph; b: PPassContext, n: PNode): PNode =
for obj, content in items(globals.classes): for obj, content in items(globals.classes):
genClass(m.config, obj, content, ext) genClass(m.config, obj, content, ext)
proc myOpenCached(graph: ModuleGraph; s: PSym, rd: PRodReader): PPassContext = proc myOpen(graph: ModuleGraph; s: PSym): PPassContext =
internalError(graph.config, "symbol files are not possible with the JS code generator")
result = nil
proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
result = newModule(graph, s) result = newModule(graph, s)
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) const JSgenPass* = makePass(myOpen, myProcess, myClose)

View file

@ -40,37 +40,37 @@ proc writeDepsFile(g: ModuleGraph; project: string) =
f.writeLine(toFullPath(g.config, k)) f.writeLine(toFullPath(g.config, k))
f.close() f.close()
proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) = proc commandGenDepend(graph: ModuleGraph) =
semanticPasses(graph) semanticPasses(graph)
registerPass(graph, gendependPass) registerPass(graph, gendependPass)
compileProject(graph, cache) compileProject(graph)
let project = graph.config.projectFull let project = graph.config.projectFull
writeDepsFile(graph, project) writeDepsFile(graph, project)
generateDot(graph, project) generateDot(graph, project)
execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") & execExternalProgram(graph.config, "dot -Tpng -o" & changeFileExt(project, "png") &
' ' & changeFileExt(project, "dot")) ' ' & changeFileExt(project, "dot"))
proc commandCheck(graph: ModuleGraph; cache: IdentCache) = proc commandCheck(graph: ModuleGraph) =
graph.config.errorMax = high(int) # do not stop after first error graph.config.errorMax = high(int) # do not stop after first error
defineSymbol(graph.config.symbols, "nimcheck") defineSymbol(graph.config.symbols, "nimcheck")
semanticPasses(graph) # use an empty backend for semantic checking only semanticPasses(graph) # use an empty backend for semantic checking only
compileProject(graph, cache) compileProject(graph)
proc commandDoc2(graph: ModuleGraph; cache: IdentCache; json: bool) = proc commandDoc2(graph: ModuleGraph; json: bool) =
graph.config.errorMax = high(int) # do not stop after first error graph.config.errorMax = high(int) # do not stop after first error
semanticPasses(graph) semanticPasses(graph)
if json: registerPass(graph, docgen2JsonPass) if json: registerPass(graph, docgen2JsonPass)
else: registerPass(graph, docgen2Pass) else: registerPass(graph, docgen2Pass)
compileProject(graph, cache) compileProject(graph)
finishDoc2Pass(graph.config.projectName) finishDoc2Pass(graph.config.projectName)
proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) = proc commandCompileToC(graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
extccomp.initVars(conf) extccomp.initVars(conf)
semanticPasses(graph) semanticPasses(graph)
registerPass(graph, cgenPass) registerPass(graph, cgenPass)
compileProject(graph, cache) compileProject(graph)
cgenWriteModules(graph.backend, conf) cgenWriteModules(graph.backend, conf)
if conf.cmd != cmdRun: if conf.cmd != cmdRun:
let proj = changeFileExt(conf.projectFull, "") let proj = changeFileExt(conf.projectFull, "")
@ -79,11 +79,11 @@ proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
if optGenScript in graph.config.globalOptions: if optGenScript in graph.config.globalOptions:
writeDepsFile(graph, toGeneratedFile(conf, proj, "")) writeDepsFile(graph, toGeneratedFile(conf, proj, ""))
proc commandJsonScript(graph: ModuleGraph; cache: IdentCache) = proc commandJsonScript(graph: ModuleGraph) =
let proj = changeFileExt(graph.config.projectFull, "") let proj = changeFileExt(graph.config.projectFull, "")
extccomp.runJsonBuildInstructions(graph.config, proj) extccomp.runJsonBuildInstructions(graph.config, proj)
proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) = proc commandCompileToJS(graph: ModuleGraph) =
#incl(gGlobalOptions, optSafeCode) #incl(gGlobalOptions, optSafeCode)
setTarget(graph.config.target, osJS, cpuJS) setTarget(graph.config.target, osJS, cpuJS)
#initDefines() #initDefines()
@ -91,9 +91,9 @@ proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
defineSymbol(graph.config.symbols, "js") defineSymbol(graph.config.symbols, "js")
semanticPasses(graph) semanticPasses(graph)
registerPass(graph, JSgenPass) registerPass(graph, JSgenPass)
compileProject(graph, cache) compileProject(graph)
proc interactivePasses(graph: ModuleGraph; cache: IdentCache) = proc interactivePasses(graph: ModuleGraph) =
initDefines(graph.config.symbols) initDefines(graph.config.symbols)
defineSymbol(graph.config.symbols, "nimscript") defineSymbol(graph.config.symbols, "nimscript")
when hasFFI: defineSymbol(graph.config.symbols, "nimffi") when hasFFI: defineSymbol(graph.config.symbols, "nimffi")
@ -101,29 +101,29 @@ proc interactivePasses(graph: ModuleGraph; cache: IdentCache) =
registerPass(graph, semPass) registerPass(graph, semPass)
registerPass(graph, evalPass) registerPass(graph, evalPass)
proc commandInteractive(graph: ModuleGraph; cache: IdentCache) = proc commandInteractive(graph: ModuleGraph) =
graph.config.errorMax = high(int) # do not stop after first error graph.config.errorMax = high(int) # do not stop after first error
interactivePasses(graph, cache) interactivePasses(graph)
compileSystemModule(graph, cache) compileSystemModule(graph)
if graph.config.commandArgs.len > 0: if graph.config.commandArgs.len > 0:
discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), cache, {}) discard graph.compileModule(fileInfoIdx(graph.config, graph.config.projectFull), {})
else: else:
var m = graph.makeStdinModule() var m = graph.makeStdinModule()
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
processModule(graph, m, llStreamOpenStdIn(), nil, cache) processModule(graph, m, llStreamOpenStdIn())
const evalPasses = [verbosePass, semPass, evalPass] const evalPasses = [verbosePass, semPass, evalPass]
proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache) = proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym) =
carryPasses(graph, nodes, module, cache, evalPasses) carryPasses(graph, nodes, module, evalPasses)
proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) = proc commandEval(graph: ModuleGraph; exp: string) =
if graph.systemModule == nil: if graph.systemModule == nil:
interactivePasses(graph, cache) interactivePasses(graph)
compileSystemModule(graph, cache) compileSystemModule(graph)
let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
evalNim(graph, echoExp.parseString(cache, graph.config), evalNim(graph, echoExp.parseString(graph.cache, graph.config),
makeStdinModule(graph), cache) makeStdinModule(graph))
proc commandScan(cache: IdentCache, config: ConfigRef) = proc commandScan(cache: IdentCache, config: ConfigRef) =
var f = addFileExt(mainCommandArg(config), NimExt) var f = addFileExt(mainCommandArg(config), NimExt)
@ -145,8 +145,9 @@ proc commandScan(cache: IdentCache, config: ConfigRef) =
const const
PrintRopeCacheStats = false PrintRopeCacheStats = false
proc mainCommand*(graph: ModuleGraph; cache: IdentCache) = proc mainCommand*(graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
let cache = graph.cache
setupModuleCache(graph) setupModuleCache(graph)
# In "nim serve" scenario, each command must reset the registered passes # In "nim serve" scenario, each command must reset the registered passes
@ -158,25 +159,25 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
of "c", "cc", "compile", "compiletoc": of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently # compile means compileToC currently
conf.cmd = cmdCompileToC conf.cmd = cmdCompileToC
commandCompileToC(graph, cache) commandCompileToC(graph)
of "cpp", "compiletocpp": of "cpp", "compiletocpp":
conf.cmd = cmdCompileToCpp conf.cmd = cmdCompileToCpp
defineSymbol(graph.config.symbols, "cpp") defineSymbol(graph.config.symbols, "cpp")
commandCompileToC(graph, cache) commandCompileToC(graph)
of "objc", "compiletooc": of "objc", "compiletooc":
conf.cmd = cmdCompileToOC conf.cmd = cmdCompileToOC
defineSymbol(graph.config.symbols, "objc") defineSymbol(graph.config.symbols, "objc")
commandCompileToC(graph, cache) commandCompileToC(graph)
of "run": of "run":
conf.cmd = cmdRun conf.cmd = cmdRun
when hasTinyCBackend: when hasTinyCBackend:
extccomp.setCC("tcc") extccomp.setCC("tcc")
commandCompileToC(graph, cache) commandCompileToC(graph)
else: else:
rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc") rawMessage(conf, errGenerated, "'run' command not available; rebuild with -d:tinyc")
of "js", "compiletojs": of "js", "compiletojs":
conf.cmd = cmdCompileToJS conf.cmd = cmdCompileToJS
commandCompileToJS(graph, cache) commandCompileToJS(graph)
of "doc0": of "doc0":
wantMainModule(conf) wantMainModule(conf)
conf.cmd = cmdDoc conf.cmd = cmdDoc
@ -186,7 +187,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
conf.cmd = cmdDoc conf.cmd = cmdDoc
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
defineSymbol(conf.symbols, "nimdoc") defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, cache, false) commandDoc2(graph, false)
of "rst2html": of "rst2html":
conf.cmd = cmdRst2html conf.cmd = cmdRst2html
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
@ -207,7 +208,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
loadConfigs(DocConfig, cache, conf) loadConfigs(DocConfig, cache, conf)
wantMainModule(conf) wantMainModule(conf)
defineSymbol(conf.symbols, "nimdoc") defineSymbol(conf.symbols, "nimdoc")
commandDoc2(graph, cache, true) commandDoc2(graph, true)
of "ctags": of "ctags":
wantMainModule(conf) wantMainModule(conf)
conf.cmd = cmdDoc conf.cmd = cmdDoc
@ -220,7 +221,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
commandBuildIndex(cache, conf) commandBuildIndex(cache, conf)
of "gendepend": of "gendepend":
conf.cmd = cmdGenDepend conf.cmd = cmdGenDepend
commandGenDepend(graph, cache) commandGenDepend(graph)
of "dump": of "dump":
conf.cmd = cmdDump conf.cmd = cmdDump
if getConfigVar(conf, "dump.format") == "json": if getConfigVar(conf, "dump.format") == "json":
@ -249,7 +250,7 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
for it in conf.searchPaths: msgWriteln(conf, it) for it in conf.searchPaths: msgWriteln(conf, it)
of "check": of "check":
conf.cmd = cmdCheck conf.cmd = cmdCheck
commandCheck(graph, cache) commandCheck(graph)
of "parse": of "parse":
conf.cmd = cmdParse conf.cmd = cmdParse
wantMainModule(conf) wantMainModule(conf)
@ -261,15 +262,15 @@ proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!") msgWriteln(conf, "Beware: Indentation tokens depend on the parser's state!")
of "secret": of "secret":
conf.cmd = cmdInteractive conf.cmd = cmdInteractive
commandInteractive(graph, cache) commandInteractive(graph)
of "e": of "e":
commandEval(graph, cache, mainCommandArg(conf)) commandEval(graph, mainCommandArg(conf))
of "nop", "help": of "nop", "help":
# prevent the "success" message: # prevent the "success" message:
conf.cmd = cmdDump conf.cmd = cmdDump
of "jsonscript": of "jsonscript":
conf.cmd = cmdJsonScript conf.cmd = cmdJsonScript
commandJsonScript(graph, cache) commandJsonScript(graph)
else: else:
rawMessage(conf, errGenerated, "invalid command: " & conf.command) rawMessage(conf, errGenerated, "invalid command: " & conf.command)

View file

@ -56,6 +56,9 @@ type
opContains*, opNot*: PSym opContains*, opNot*: PSym
emptyNode*: PNode emptyNode*: PNode
incr*: IncrementalCtx incr*: IncrementalCtx
importModuleCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PSym {.nimcall.}
includeFileCallback*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex): PNode {.nimcall.}
recordStmt*: proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.}
proc hash*(x: FileIndex): Hash {.borrow.} proc hash*(x: FileIndex): Hash {.borrow.}
@ -85,6 +88,8 @@ proc newModuleGraph*(cache: IdentCache; config: ConfigRef): ModuleGraph =
result.opContains = createMagic(result, "contains", mInSet) result.opContains = createMagic(result, "contains", mInSet)
result.emptyNode = newNode(nkEmpty) result.emptyNode = newNode(nkEmpty)
init(result.incr) init(result.incr)
result.recordStmt = proc (graph: ModuleGraph; m: PSym; n: PNode) {.nimcall.} =
discard
proc resetAllModules*(g: ModuleGraph) = proc resetAllModules*(g: ModuleGraph) =
initStrTable(packageSyms) initStrTable(packageSyms)

View file

@ -58,52 +58,30 @@ proc newModule(graph: ModuleGraph; fileIdx: FileIndex): PSym =
# strTableIncl() for error corrections: # strTableIncl() for error corrections:
discard strTableIncl(packSym.tab, result) discard strTableIncl(packSym.tab, result)
proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; cache: IdentCache, flags: TSymFlags): PSym = proc compileModule*(graph: ModuleGraph; fileIdx: FileIndex; flags: TSymFlags): PSym =
result = graph.getModule(fileIdx) result = graph.getModule(fileIdx)
if result == nil: if result == nil:
#growCache gMemCacheData, fileIdx
#gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(graph, fileIdx) result = newModule(graph, fileIdx)
var rd: PRodReader
result.flags = result.flags + flags result.flags = result.flags + flags
if sfMainModule in result.flags: if sfMainModule in result.flags:
graph.config.mainPackageId = result.owner.id graph.config.mainPackageId = result.owner.id
when false:
if conf.cmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result, cache)
if result.id < 0:
internalError("handleSymbolFile should have set the module's ID")
return
else:
discard
result.id = getModuleId(graph, fileIdx, toFullPath(graph.config, fileIdx)) result.id = getModuleId(graph, fileIdx, toFullPath(graph.config, fileIdx))
discard processModule(graph, result, discard processModule(graph, result,
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil, if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
rd, cache)
#if optCaasEnabled in gGlobalOptions:
# gMemCacheData[fileIdx].needsRecompile = Recompiled
# if validFile: doHash fileIdx
elif graph.isDirty(result): elif graph.isDirty(result):
result.flags.excl sfDirty result.flags.excl sfDirty
# reset module fields: # reset module fields:
initStrTable(result.tab) initStrTable(result.tab)
result.ast = nil result.ast = nil
discard processModule(graph, result, discard processModule(graph, result,
if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil, if sfMainModule in flags and graph.config.projectIsStdin: stdin.llStreamOpen else: nil)
nil, cache)
graph.markClientsDirty(fileIdx) 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: FileIndex; proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PSym {.procvar.} =
cache: IdentCache): PSym {.procvar.} =
# this is called by the semantic checking phase # this is called by the semantic checking phase
assert graph.config != nil assert graph.config != nil
result = compileModule(graph, fileIdx, cache, {}) result = compileModule(graph, fileIdx, {})
graph.addDep(s, fileIdx) graph.addDep(s, fileIdx)
#if sfSystemModule in result.flags: #if sfSystemModule in result.flags:
# localError(result.info, errAttemptToRedefine, result.name.s) # localError(result.info, errAttemptToRedefine, result.name.s)
@ -112,37 +90,37 @@ proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex;
if s.owner.id == graph.config.mainPackageId: graph.config.mainPackageNotes if s.owner.id == graph.config.mainPackageId: graph.config.mainPackageNotes
else: graph.config.foreignPackageNotes else: graph.config.foreignPackageNotes
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode {.procvar.} =
cache: IdentCache): PNode {.procvar.} = result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
result = syntaxes.parseFile(fileIdx, cache, graph.config)
graph.addDep(s, fileIdx) graph.addDep(s, fileIdx)
graph.addIncludeDep(s.position.FileIndex, fileIdx) graph.addIncludeDep(s.position.FileIndex, fileIdx)
proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) = proc compileSystemModule*(graph: ModuleGraph) =
if graph.systemModule == nil: if graph.systemModule == nil:
graph.config.m.systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim") graph.config.m.systemFileIdx = fileInfoIdx(graph.config, graph.config.libpath / "system.nim")
discard graph.compileModule(graph.config.m.systemFileIdx, cache, {sfSystemModule}) discard graph.compileModule(graph.config.m.systemFileIdx, {sfSystemModule})
proc wantMainModule*(conf: ConfigRef) = proc wantMainModule*(conf: ConfigRef) =
if conf.projectFull.len == 0: if conf.projectFull.len == 0:
fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename") fatal(conf, newLineInfo(conf, "command line", 1, 1), errGenerated, "command expects a filename")
conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt)) conf.projectMainIdx = fileInfoIdx(conf, addFileExt(conf.projectFull, NimExt))
passes.gIncludeFile = includeModule proc connectCallbacks*(graph: ModuleGraph) =
passes.gImportModule = importModule graph.includeFileCallback = includeModule
graph.importModuleCallback = importModule
proc compileProject*(graph: ModuleGraph; cache: IdentCache; proc compileProject*(graph: ModuleGraph; projectFileIdx = InvalidFileIDX) =
projectFileIdx = InvalidFileIDX) = connectCallbacks(graph)
let conf = graph.config let conf = graph.config
wantMainModule(conf) wantMainModule(conf)
let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim") let systemFileIdx = fileInfoIdx(conf, conf.libpath / "system.nim")
let projectFile = if projectFileIdx == InvalidFileIDX: conf.projectMainIdx else: projectFileIdx let projectFile = if projectFileIdx == InvalidFileIDX: conf.projectMainIdx else: projectFileIdx
graph.importStack.add projectFile graph.importStack.add projectFile
if projectFile == systemFileIdx: if projectFile == systemFileIdx:
discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule}) discard graph.compileModule(projectFile, {sfMainModule, sfSystemModule})
else: else:
graph.compileSystemModule(cache) graph.compileSystemModule()
discard graph.compileModule(projectFile, cache, {sfMainModule}) discard graph.compileModule(projectFile, {sfMainModule})
proc makeModule*(graph: ModuleGraph; filename: string): PSym = proc makeModule*(graph: ModuleGraph; filename: string): PSym =
result = graph.newModule(fileInfoIdx(graph.config, filename)) result = graph.newModule(fileInfoIdx(graph.config, filename))

View file

@ -94,7 +94,7 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
processCmdLine(passCmd2, "", conf) processCmdLine(passCmd2, "", conf)
if conf.command == "": if conf.command == "":
rawMessage(conf, errGenerated, "command missing") rawMessage(conf, errGenerated, "command missing")
mainCommand(newModuleGraph(cache, conf), cache) mainCommand(newModuleGraph(cache, conf))
if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics()) if optHints in conf.options and hintGCStats in conf.notes: echo(GC_getStatistics())
#echo(GC_getStatistics()) #echo(GC_getStatistics())
if conf.errorCounter == 0: if conf.errorCounter == 0:

View file

@ -95,6 +95,7 @@ proc createInterpreter*(scriptName: string;
var conf = newConfigRef() var conf = newConfigRef()
var cache = newIdentCache() var cache = newIdentCache()
var graph = newModuleGraph(cache, conf) var graph = newModuleGraph(cache, conf)
connectCallbacks(graph)
initDefines(conf.symbols) initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript") defineSymbol(conf.symbols, "nimscript")
defineSymbol(conf.symbols, "nimconfig") defineSymbol(conf.symbols, "nimconfig")

View file

@ -238,6 +238,19 @@ type
structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string; structuredErrorHook*: proc (config: ConfigRef; info: TLineInfo; msg: string;
severity: Severity) {.closure.} severity: Severity) {.closure.}
template depConfigFields*(fn) {.dirty.} =
fn(target)
fn(options)
fn(globalOptions)
fn(selectedGC)
template serializeConfigFields(fn) {.dirty.} =
fn(cppDefines)
fn(externalToLink)
fn(linkOptions)
fn(compileOptions)
fn(toCompile)
const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel} const oldExperimentalFeatures* = {implicitDeref, dotOperators, callOperator, parallel}
const const

View file

@ -18,7 +18,7 @@ type
VerboseRef = ref object of TPassContext VerboseRef = ref object of TPassContext
config: ConfigRef config: ConfigRef
proc verboseOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext = proc verboseOpen(graph: ModuleGraph; s: PSym): PPassContext =
#MessageOut('compiling ' + s.name.s); #MessageOut('compiling ' + s.name.s);
result = VerboseRef(config: graph.config) result = VerboseRef(config: graph.config)
rawMessage(graph.config, hintProcessing, s.name.s) rawMessage(graph.config, hintProcessing, s.name.s)

View file

@ -18,19 +18,15 @@ import
type type
PRodReader* = ref object
TPassContext* = object of RootObj # the pass's context TPassContext* = object of RootObj # the pass's context
PPassContext* = ref TPassContext PPassContext* = ref TPassContext
TPassOpen* = proc (graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext {.nimcall.} TPassOpen* = proc (graph: ModuleGraph; module: PSym): PPassContext {.nimcall.}
TPassOpenCached* =
proc (graph: ModuleGraph; module: PSym, rd: PRodReader): PPassContext {.nimcall.}
TPassClose* = proc (graph: ModuleGraph; p: PPassContext, n: PNode): PNode {.nimcall.} TPassClose* = proc (graph: ModuleGraph; p: PPassContext, n: PNode): PNode {.nimcall.}
TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.} TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
TPass* = tuple[open: TPassOpen, openCached: TPassOpenCached, TPass* = tuple[open: TPassOpen, process: TPassProcess, close: TPassClose,
process: TPassProcess, close: TPassClose,
isFrontend: bool] isFrontend: bool]
TPassData* = tuple[input: PNode, closeOutput: PNode] TPassData* = tuple[input: PNode, closeOutput: PNode]
@ -41,23 +37,14 @@ type
# This mechanism used to be used for the instantiation of generics. # This mechanism used to be used for the instantiation of generics.
proc makePass*(open: TPassOpen = nil, proc makePass*(open: TPassOpen = nil,
openCached: TPassOpenCached = nil,
process: TPassProcess = nil, process: TPassProcess = nil,
close: TPassClose = nil, close: TPassClose = nil,
isFrontend = false): TPass = isFrontend = false): TPass =
result.open = open result.open = open
result.openCached = openCached
result.close = close result.close = close
result.process = process result.process = process
result.isFrontend = isFrontend result.isFrontend = isFrontend
# the semantic checker needs these:
var
gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PSym {.nimcall.}
gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: FileIndex; cache: IdentCache): PNode {.nimcall.}
# implementation
proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} = proc skipCodegen*(config: ConfigRef; n: PNode): bool {.inline.} =
# can be used by codegen passes to determine whether they should do # can be used by codegen passes to determine whether they should do
# something with `n`. Currently, this ignores `n` and uses the global # something with `n`. Currently, this ignores `n` and uses the global
@ -81,35 +68,27 @@ proc registerPass*(g: ModuleGraph; p: TPass) =
gPasses[gPassesLen] = p gPasses[gPassesLen] = p
inc(gPassesLen) inc(gPassesLen)
proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache; proc carryPass*(g: ModuleGraph; p: TPass, module: PSym;
m: TPassData): TPassData = m: TPassData): TPassData =
var c = p.open(g, module, cache) var c = p.open(g, module)
result.input = p.process(c, m.input) result.input = p.process(c, m.input)
result.closeOutput = if p.close != nil: p.close(g, c, m.closeOutput) result.closeOutput = if p.close != nil: p.close(g, c, m.closeOutput)
else: m.closeOutput else: m.closeOutput
proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym; proc carryPasses*(g: ModuleGraph; nodes: PNode, module: PSym;
cache: IdentCache; passes: TPasses) = passes: TPasses) =
var passdata: TPassData var passdata: TPassData
passdata.input = nodes passdata.input = nodes
for pass in passes: for pass in passes:
passdata = carryPass(g, pass, module, cache, passdata) passdata = carryPass(g, pass, module, passdata)
proc openPasses(g: ModuleGraph; a: var TPassContextArray; proc openPasses(g: ModuleGraph; a: var TPassContextArray;
module: PSym; cache: IdentCache) = module: PSym) =
for i in countup(0, gPassesLen - 1): for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].open): if not isNil(gPasses[i].open):
a[i] = gPasses[i].open(g, module, cache) a[i] = gPasses[i].open(g, module)
else: a[i] = nil else: a[i] = nil
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(g, module, rd)
else:
a[i] = nil
proc closePasses(graph: ModuleGraph; a: var TPassContextArray) = proc closePasses(graph: ModuleGraph; a: var TPassContextArray) =
var m: PNode = nil var m: PNode = nil
for i in countup(0, gPassesLen - 1): for i in countup(0, gPassesLen - 1):
@ -125,19 +104,6 @@ proc processTopLevelStmt(n: PNode, a: var TPassContextArray): bool =
if isNil(m): return false if isNil(m): return false
result = true result = true
proc processTopLevelStmtCached(n: PNode, a: var TPassContextArray) =
# this implements the code transformation pipeline
var m = n
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached): m = gPasses[i].process(a[i], m)
proc closePassesCached(graph: ModuleGraph; a: var TPassContextArray) =
var m: PNode = nil
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached) and not isNil(gPasses[i].close):
m = gPasses[i].close(graph, a[i], m)
a[i] = nil # free the memory here
proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex = proc resolveMod(conf: ConfigRef; module, relativeTo: string): FileIndex =
let fullPath = findModule(conf, module, relativeTo) let fullPath = findModule(conf, module, relativeTo)
if fullPath.len == 0: if fullPath.len == 0:
@ -159,8 +125,7 @@ proc processImplicits(conf: ConfigRef; implicits: seq[string], nodeKind: TNodeKi
importStmt.addSon str importStmt.addSon str
if not processTopLevelStmt(importStmt, a): break if not processTopLevelStmt(importStmt, a): break
proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream, proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream): bool {.discardable.} =
rd: PRodReader; cache: IdentCache): bool {.discardable.} =
if graph.stopCompile(): return true if graph.stopCompile(): return true
var var
p: TParsers p: TParsers
@ -171,24 +136,17 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
# new module caching mechanism: # new module caching mechanism:
for i in 0..<gPassesLen: for i in 0..<gPassesLen:
if not isNil(gPasses[i].open) and not gPasses[i].isFrontend: if not isNil(gPasses[i].open) and not gPasses[i].isFrontend:
a[i] = gPasses[i].open(graph, module, cache) a[i] = gPasses[i].open(graph, module)
else: else:
a[i] = nil a[i] = nil
var stmtIndex = 0 if not graph.stopCompile():
var doContinue = true let n = loadNode(graph, module)
while doContinue:
let n = loadNode(graph, module, stmtIndex)
if n == nil or graph.stopCompile(): break
#if n.kind == nkImportStmt:
# echo "yes and it's ", n
inc stmtIndex
var m = n var m = n
for i in 0..<gPassesLen: for i in 0..<gPassesLen:
if not isNil(gPasses[i].process) and not gPasses[i].isFrontend: if not isNil(gPasses[i].process) and not gPasses[i].isFrontend:
m = gPasses[i].process(a[i], m) m = gPasses[i].process(a[i], m)
if isNil(m): if isNil(m):
doContinue = false
break break
var m: PNode = nil var m: PNode = nil
@ -197,7 +155,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
m = gPasses[i].close(graph, a[i], m) m = gPasses[i].close(graph, a[i], m)
a[i] = nil a[i] = nil
else: else:
openPasses(graph, a, module, cache) openPasses(graph, a, module)
if stream == nil: if stream == nil:
let filename = toFullPathConsiderDirty(graph.config, fileIdx) let filename = toFullPathConsiderDirty(graph.config, fileIdx)
s = llStreamOpen(filename, fmRead) s = llStreamOpen(filename, fmRead)
@ -207,7 +165,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
else: else:
s = stream s = stream
while true: while true:
openParsers(p, fileIdx, s, cache, graph.config) openParsers(p, fileIdx, s, graph.cache, graph.config)
if sfSystemModule notin module.flags: if sfSystemModule notin module.flags:
# XXX what about caching? no processing then? what if I change the # XXX what about caching? no processing then? what if I change the
@ -230,7 +188,7 @@ proc processModule*(graph: ModuleGraph; module: PSym, stream: PLLStream,
if n.kind == nkEmpty: break if n.kind == nkEmpty: break
sl.add n sl.add n
if sfReorder in module.flags: if sfReorder in module.flags:
sl = reorder(graph, sl, module, cache) sl = reorder(graph, sl, module)
discard processTopLevelStmt(sl, a) discard processTopLevelStmt(sl, a)
break break
elif not processTopLevelStmt(n, a): break elif not processTopLevelStmt(n, a): break

View file

@ -84,6 +84,13 @@ proc getPragmaVal*(procAst: PNode; name: TSpecialWord): PNode =
proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) proc pragma*(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords)
# implementation # implementation
proc recordPragma(c: PContext; n: PNode; key, val: string; val2 = "") =
var recorded = newNodeI(nkCommentStmt, n.info)
recorded.add newStrNode(key, n.info)
recorded.add newStrNode(val, n.info)
if val2.len > 0: recorded.add newStrNode(val2, n.info)
c.graph.recordStmt(c.graph, c.module, recorded)
const const
errStringLiteralExpected = "string literal expected" errStringLiteralExpected = "string literal expected"
errIntLiteralExpected = "integer literal expected" errIntLiteralExpected = "integer literal expected"
@ -227,7 +234,7 @@ proc pragmaNoForward(c: PContext, n: PNode; flag=sfNoForward) =
proc processCallConv(c: PContext, n: PNode) = proc processCallConv(c: PContext, n: PNode) =
if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent: if n.kind in nkPragmaCallKinds and n.len == 2 and n.sons[1].kind == nkIdent:
var sw = whichKeyword(n.sons[1].ident) let sw = whichKeyword(n.sons[1].ident)
case sw case sw
of FirstCallConv..LastCallConv: of FirstCallConv..LastCallConv:
c.optionStack[^1].defaultCC = wordToCallConv(sw) c.optionStack[^1].defaultCC = wordToCallConv(sw)
@ -412,6 +419,10 @@ proc relativeFile(c: PContext; n: PNode; ext=""): string =
if result.len == 0: result = s if result.len == 0: result = s
proc processCompile(c: PContext, n: PNode) = proc processCompile(c: PContext, n: PNode) =
proc docompile(c: PContext; it: PNode; src, dest: string) =
var cf = Cfile(cname: src, obj: dest, flags: {CfileFlag.External})
extccomp.addExternalFileToCompile(c.config, cf)
recordPragma(c, it, "compile", src, dest)
proc getStrLit(c: PContext, n: PNode; i: int): string = proc getStrLit(c: PContext, n: PNode; i: int): string =
n.sons[i] = c.semConstExpr(c, n[i]) n.sons[i] = c.semConstExpr(c, n[i])
@ -428,11 +439,8 @@ proc processCompile(c: PContext, n: PNode) =
let dest = getStrLit(c, it, 1) let dest = getStrLit(c, it, 1)
var found = parentDir(toFullPath(c.config, n.info)) / s var found = parentDir(toFullPath(c.config, n.info)) / s
for f in os.walkFiles(found): for f in os.walkFiles(found):
let nameOnly = extractFilename(f) let obj = completeCFilePath(c.config, dest % extractFilename(f))
var cf = Cfile(cname: f, docompile(c, it, f, obj)
obj: completeCFilePath(c.config, dest % nameOnly),
flags: {CfileFlag.External})
extccomp.addExternalFileToCompile(c.config, cf)
else: else:
let s = expectStrLit(c, n) let s = expectStrLit(c, n)
var found = parentDir(toFullPath(c.config, n.info)) / s var found = parentDir(toFullPath(c.config, n.info)) / s
@ -441,15 +449,19 @@ proc processCompile(c: PContext, n: PNode) =
else: else:
found = findFile(c.config, s) found = findFile(c.config, s)
if found.len == 0: found = s if found.len == 0: found = s
extccomp.addExternalFileToCompile(c.config, found) let obj = toObjFile(c.config, completeCFilePath(c.config, changeFileExt(found, ""), false))
docompile(c, it, found, obj)
proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) = proc processCommonLink(c: PContext, n: PNode, feature: TLinkFeature) =
let found = relativeFile(c, n, CC[c.config.cCompiler].objExt) let found = relativeFile(c, n, CC[c.config.cCompiler].objExt)
case feature case feature
of linkNormal: extccomp.addExternalFileToLink(c.config, found) of linkNormal:
extccomp.addExternalFileToLink(c.config, found)
recordPragma(c, n, "link", found)
of linkSys: of linkSys:
extccomp.addExternalFileToLink(c.config, let dest = c.config.libpath / completeCFilePath(c.config, found, false)
c.config.libpath / completeCFilePath(c.config, found, false)) extccomp.addExternalFileToLink(c.config, dest)
recordPragma(c, n, "link", dest)
else: internalError(c.config, n.info, "processCommonLink") else: internalError(c.config, n.info, "processCommonLink")
proc pragmaBreakpoint(c: PContext, n: PNode) = proc pragmaBreakpoint(c: PContext, n: PNode) =
@ -724,7 +736,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty i.inc(userPragma.ast.len - 1) # inc by -1 is ok, user pragmas was empty
dec c.instCounter dec c.instCounter
else: else:
var k = whichKeyword(ident) let k = whichKeyword(ident)
if k in validPragmas: if k in validPragmas:
case k case k
of wExportc: of wExportc:
@ -891,8 +903,14 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it) noVal(c, it)
if sym.typ == nil: invalidPragma(c, it) if sym.typ == nil: invalidPragma(c, it)
else: incl(sym.typ.flags, tfPacked) else: incl(sym.typ.flags, tfPacked)
of wHint: message(c.config, it.info, hintUser, expectStrLit(c, it)) of wHint:
of wWarning: message(c.config, it.info, warnUser, expectStrLit(c, it)) let s = expectStrLit(c, it)
recordPragma(c, it, "hint", s)
message(c.config, it.info, hintUser, s)
of wWarning:
let s = expectStrLit(c, it)
recordPragma(c, it, "warning", s)
message(c.config, it.info, warnUser, s)
of wError: of wError:
if sym != nil and sym.isRoutine: if sym != nil and sym.isRoutine:
# This is subtle but correct: the error *statement* is only # This is subtle but correct: the error *statement* is only
@ -902,7 +920,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
noVal(c, it) noVal(c, it)
incl(sym.flags, sfError) incl(sym.flags, sfError)
else: else:
localError(c.config, it.info, errUser, expectStrLit(c, it)) let s = expectStrLit(c, it)
recordPragma(c, it, "error", s)
localError(c.config, it.info, errUser, s)
of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it)) of wFatal: fatal(c.config, it.info, errUser, expectStrLit(c, it))
of wDefine: processDefine(c, it) of wDefine: processDefine(c, it)
of wUndef: processUndef(c, it) of wUndef: processUndef(c, it)
@ -1066,8 +1086,7 @@ proc implicitPragmas*(c: PContext, sym: PSym, n: PNode,
if sym.loc.r == nil: sym.loc.r = rope(sym.name.s) if sym.loc.r == nil: sym.loc.r = rope(sym.name.s)
proc hasPragma*(n: PNode, pragma: TSpecialWord): bool = proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
if n == nil or n.sons == nil: if n == nil: return false
return false
for p in n: for p in n:
var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p var key = if p.kind in nkPragmaCallKinds and p.len > 1: p[0] else: p
@ -1079,7 +1098,7 @@ proc hasPragma*(n: PNode, pragma: TSpecialWord): bool =
proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) = proc pragmaRec(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
if n == nil: return if n == nil: return
var i = 0 var i = 0
while i < n.len(): while i < n.len:
if singlePragma(c, sym, n, i, validPragmas): break if singlePragma(c, sym, n, i, validPragmas): break
inc i inc i

View file

@ -136,15 +136,13 @@ proc hasIncludes(n:PNode): bool =
if a.kind == nkIncludeStmt: if a.kind == nkIncludeStmt:
return true return true
proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex; proc includeModule*(graph: ModuleGraph; s: PSym, fileIdx: FileIndex): PNode {.procvar.} =
cache: IdentCache): PNode {.procvar.} = result = syntaxes.parseFile(fileIdx, graph.cache, graph.config)
result = syntaxes.parseFile(fileIdx, cache, graph.config)
graph.addDep(s, fileIdx) graph.addDep(s, fileIdx)
graph.addIncludeDep(FileIndex s.position, fileIdx) graph.addIncludeDep(FileIndex s.position, fileIdx)
proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode, proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
modulePath: string, includedFiles: var IntSet, modulePath: string, includedFiles: var IntSet): PNode =
cache: IdentCache): PNode =
# Parses includes and injects them in the current tree # Parses includes and injects them in the current tree
if not n.hasIncludes: if not n.hasIncludes:
return n return n
@ -158,9 +156,9 @@ proc expandIncludes(graph: ModuleGraph, module: PSym, n: PNode,
localError(graph.config, a.info, "recursive dependency: '$1'" % localError(graph.config, a.info, "recursive dependency: '$1'" %
toFilename(graph.config, f)) toFilename(graph.config, f))
else: else:
let nn = includeModule(graph, module, f, cache) let nn = includeModule(graph, module, f)
let nnn = expandIncludes(graph, module, nn, modulePath, let nnn = expandIncludes(graph, module, nn, modulePath,
includedFiles, cache) includedFiles)
excl(includedFiles, f.int) excl(includedFiles, f.int)
for b in nnn: for b in nnn:
result.add b result.add b
@ -427,19 +425,19 @@ proc hasForbiddenPragma(n: PNode): bool =
a[0].ident.s == "push": a[0].ident.s == "push":
return true return true
proc reorder*(graph: ModuleGraph, n: PNode, module: PSym, cache: IdentCache): PNode = proc reorder*(graph: ModuleGraph, n: PNode, module: PSym): PNode =
if n.hasForbiddenPragma: if n.hasForbiddenPragma:
return n return n
var includedFiles = initIntSet() var includedFiles = initIntSet()
let mpath = toFullPath(graph.config, module.fileIdx) let mpath = toFullPath(graph.config, module.fileIdx)
let n = expandIncludes(graph, module, n, mpath, let n = expandIncludes(graph, module, n, mpath,
includedFiles, cache).splitSections includedFiles).splitSections
result = newNodeI(nkStmtList, n.info) result = newNodeI(nkStmtList, n.info)
var deps = newSeq[(IntSet, IntSet)](n.len) var deps = newSeq[(IntSet, IntSet)](n.len)
for i in 0..<n.len: for i in 0..<n.len:
deps[i][0] = initIntSet() deps[i][0] = initIntSet()
deps[i][1] = initIntSet() deps[i][1] = initIntSet()
computeDeps(cache, n[i], deps[i][0], deps[i][1], true) computeDeps(graph.cache, n[i], deps[i][0], deps[i][1], true)
var g = buildGraph(n, deps) var g = buildGraph(n, deps)
let comps = getStrongComponents(g) let comps = getStrongComponents(g)

View file

@ -14,7 +14,7 @@ import ast, idgen, lineinfos, msgs, incremental, modulegraphs
when not nimIncremental: when not nimIncremental:
template setupModuleCache*(g: ModuleGraph) = discard template setupModuleCache*(g: ModuleGraph) = discard
template storeNode*(g: ModuleGraph; module: PSym; n: PNode) = discard template storeNode*(g: ModuleGraph; module: PSym; n: PNode) = discard
template loadNode*(g: ModuleGraph; module: PSym; index: var int): PNode = PNode(nil) template loadNode*(g: ModuleGraph; module: PSym): PNode = newNode(nkStmtList)
template getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: string): int = getID() template getModuleId*(g: ModuleGraph; fileIdx: FileIndex; fullpath: string): int = getID()

View file

@ -10,7 +10,7 @@
## This module implements the new compilation cache. ## This module implements the new compilation cache.
import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types, import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
renderer, rodutils, idents, astalgo, btrees, magicsys renderer, rodutils, idents, astalgo, btrees, magicsys, cgmeth, extccomp
## Todo: ## Todo:
## - Implement the 'import' replay logic so that the codegen runs over ## - Implement the 'import' replay logic so that the codegen runs over
@ -18,7 +18,7 @@ import strutils, os, intsets, tables, ropes, db_sqlite, msgs, options, types,
## - Make conditional symbols and the configuration part of a module's ## - Make conditional symbols and the configuration part of a module's
## dependencies. ## dependencies.
## - Test multi methods. ## - Test multi methods.
## - Implement the limited VM support based on sets. ## - Implement the limited VM support based on replays.
## - Depencency computation should use *signature* hashes in order to ## - Depencency computation should use *signature* hashes in order to
## avoid recompiling dependent modules. ## avoid recompiling dependent modules.
@ -381,6 +381,9 @@ proc storeNode*(g: ModuleGraph; module: PSym; n: PNode) =
break break
inc i inc i
proc recordStmt*(g: ModuleGraph; module: PSym; n: PNode) =
storeNode(g, module, n)
proc storeRemaining*(g: ModuleGraph; module: PSym) = proc storeRemaining*(g: ModuleGraph; module: PSym) =
if g.config.symbolFiles == disabledSf: return if g.config.symbolFiles == disabledSf: return
var stillForwarded: seq[PSym] = @[] var stillForwarded: seq[PSym] = @[]
@ -399,7 +402,6 @@ type
pos: int pos: int
using using
r: var Reader
b: var BlobReader b: var BlobReader
g: ModuleGraph g: ModuleGraph
@ -760,21 +762,68 @@ proc loadModuleSymTab(g; module: PSym) =
if sfSystemModule in module.flags: if sfSystemModule in module.flags:
g.systemModule = module g.systemModule = module
proc loadNode*(g: ModuleGraph; module: PSym; index: int): PNode = proc replay(g: ModuleGraph; module: PSym; n: PNode) =
if index == 0: case n.kind
of nkStaticStmt:
#evalStaticStmt()
discard "XXX to implement"
of nkVarSection, nkLetSection:
#setupCompileTimeVar()
discard "XXX to implement"
of nkMethodDef:
methodDef(g, n[namePos].sym, fromCache=true)
of nkCommentStmt:
# pragmas are complex and can be user-overriden via templates. So
# instead of using the original ``nkPragma`` nodes, we rely on the
# fact that pragmas.nim was patched to produce specialized recorded
# statements for us in the form of ``nkCommentStmt`` with (key, value)
# pairs. Ordinary nkCommentStmt nodes never have children so this is
# not ambiguous.
# Fortunately only a tiny subset of the available pragmas need to
# be replayed here. This is always a subset of ``pragmas.stmtPragmas``.
if n.len >= 2:
internalAssert g.config, n[0].kind == nkStrLit and n[1].kind == nkStrLit
case n[0].strVal
of "hint": message(g.config, n.info, hintUser, n[1].strVal)
of "warning": message(g.config, n.info, warnUser, n[1].strVal)
of "error": localError(g.config, n.info, errUser, n[1].strVal)
of "compile":
internalAssert g.config, n.len == 3 and n[2].kind == nkStrLit
var cf = Cfile(cname: n[1].strVal, obj: n[2].strVal,
flags: {CfileFlag.External})
extccomp.addExternalFileToCompile(g.config, cf)
of "link":
extccomp.addExternalFileToLink(g.config, n[1].strVal)
else:
internalAssert g.config, false
of nkImportStmt:
for x in n:
if x.kind == nkStrLit:
# XXX check that importModuleCallback implements the right logic
let imported = g.importModuleCallback(g, module, fileInfoIdx(g.config, n[0].strVal))
internalAssert g.config, imported.id < 0
of nkStmtList, nkStmtListExpr:
for x in n: replay(g, module, x)
else: discard "nothing to do for this node"
proc loadNode*(g: ModuleGraph; module: PSym): PNode =
loadModuleSymTab(g, module) loadModuleSymTab(g, module)
#index = parseInt db.getValue( result = newNodeI(nkStmtList, module.info)
# sql"select min(id) from toplevelstmts where module = ?", abs module.id) for row in db.rows(sql"select data from toplevelstmts where module = ? order by position asc",
abs module.id):
var b = BlobReader(pos: 0) var b = BlobReader(pos: 0)
b.s = db.getValue(sql"select data from toplevelstmts where position = ? and module = ?", shallowCopy b.s, row[0]
index, abs module.id) # ensure we can read without index checks:
if b.s.len == 0: b.s.add '\0'
result.add decodeNode(g, b, module.info)
db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId) db.exec(sql"insert into controlblock(idgen) values (?)", gFrontEndId)
return nil # end marker replay(g, module, result)
result = decodeNode(g, b, module.info)
proc setupModuleCache*(g: ModuleGraph) = proc setupModuleCache*(g: ModuleGraph) =
if g.config.symbolFiles == disabledSf: return if g.config.symbolFiles == disabledSf: return
g.recordStmt = recordStmt
let dbfile = getNimcacheDir(g.config) / "rodfiles.db" let dbfile = getNimcacheDir(g.config) / "rodfiles.db"
if not fileExists(dbfile): if not fileExists(dbfile):
db = open(connection=dbfile, user="nim", password="", db = open(connection=dbfile, user="nim", password="",

View file

@ -154,6 +154,7 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
rawMessage(conf, hintConf, scriptName) rawMessage(conf, hintConf, scriptName)
let graph = newModuleGraph(cache, conf) let graph = newModuleGraph(cache, conf)
connectCallbacks(graph)
if freshDefines: initDefines(conf.symbols) if freshDefines: initDefines(conf.symbols)
defineSymbol(conf.symbols, "nimscript") defineSymbol(conf.symbols, "nimscript")
@ -167,8 +168,8 @@ proc runNimScript*(cache: IdentCache; scriptName: string;
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
graph.vm = setupVM(m, cache, scriptName, graph) graph.vm = setupVM(m, cache, scriptName, graph)
graph.compileSystemModule(cache) graph.compileSystemModule()
discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) discard graph.processModule(m, llStreamOpen(scriptName, fmRead))
# ensure we load 'system.nim' again for the real non-config stuff! # ensure we load 'system.nim' again for the real non-config stuff!
resetSystemArtifacts(graph) resetSystemArtifacts(graph)

View file

@ -314,7 +314,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
c.config.errorMax = high(int) c.config.errorMax = high(int)
try: try:
result = evalConstExpr(c.module, c.cache, c.graph, e) result = evalConstExpr(c.module, c.graph, e)
if result == nil or result.kind == nkEmpty: if result == nil or result.kind == nkEmpty:
result = nil result = nil
else: else:
@ -338,7 +338,7 @@ proc semConstExpr(c: PContext, n: PNode): PNode =
result = getConstExpr(c.module, e, c.graph) result = getConstExpr(c.module, e, c.graph)
if result == nil: if result == nil:
#if e.kind == nkEmpty: globalError(n.info, errConstExprExpected) #if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
result = evalConstExpr(c.module, c.cache, c.graph, e) result = evalConstExpr(c.module, c.graph, e)
if result == nil or result.kind == nkEmpty: if result == nil or result.kind == nkEmpty:
if e.info != n.info: if e.info != n.info:
pushInfoContext(c.config, n.info) pushInfoContext(c.config, n.info)
@ -446,7 +446,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
#if c.evalContext == nil: #if c.evalContext == nil:
# c.evalContext = c.createEvalContext(emStatic) # c.evalContext = c.createEvalContext(emStatic)
result = evalMacroCall(c.module, c.cache, c.graph, n, nOrig, sym) result = evalMacroCall(c.module, c.graph, n, nOrig, sym)
if efNoSemCheck notin flags: if efNoSemCheck notin flags:
result = semAfterMacroCall(c, n, result, sym, flags) result = semAfterMacroCall(c, n, result, sym, flags)
result = wrapInComesFrom(nOrig.info, sym, result) result = wrapInComesFrom(nOrig.info, sym, result)
@ -482,7 +482,7 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
addSon(n, prc.ast) addSon(n, prc.ast)
c.lastGenericIdx = c.generics.len c.lastGenericIdx = c.generics.len
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
var c = newContext(graph, module) var c = newContext(graph, module)
if c.p != nil: internalError(graph.config, module.info, "sem.myOpen") if c.p != nil: internalError(graph.config, module.info, "sem.myOpen")
c.semConstExpr = semConstExpr c.semConstExpr = semConstExpr
@ -512,9 +512,6 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
graph.config.notes = graph.config.foreignPackageNotes graph.config.notes = graph.config.foreignPackageNotes
result = c result = c
proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
result = myOpen(graph, module, graph.cache)
proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool = proc isImportSystemStmt(g: ModuleGraph; n: PNode): bool =
if g.systemModule == nil: return false if g.systemModule == nil: return false
case n.kind case n.kind
@ -625,5 +622,5 @@ proc myClose(graph: ModuleGraph; context: PPassContext, n: PNode): PNode =
storeRemaining(c.graph, c.module) storeRemaining(c.graph, c.module)
if c.runnableExamples != nil: testExamples(c) if c.runnableExamples != nil: testExamples(c)
const semPass* = makePass(myOpen, myOpenCached, myProcess, myClose, const semPass* = makePass(myOpen, myProcess, myClose,
isFrontend = true) isFrontend = true)

View file

@ -617,12 +617,12 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
call.add(a) call.add(a)
#echo "NOW evaluating at compile time: ", call.renderTree #echo "NOW evaluating at compile time: ", call.renderTree
if sfCompileTime in callee.flags: if sfCompileTime in callee.flags:
result = evalStaticExpr(c.module, c.cache, c.graph, call, c.p.owner) result = evalStaticExpr(c.module, c.graph, call, c.p.owner)
if result.isNil: if result.isNil:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call)) localError(c.config, n.info, errCannotInterpretNodeX % renderTree(call))
else: result = fixupTypeAfterEval(c, result, n) else: result = fixupTypeAfterEval(c, result, n)
else: else:
result = evalConstExpr(c.module, c.cache, c.graph, call) result = evalConstExpr(c.module, c.graph, call)
if result.isNil: result = n if result.isNil: result = n
else: result = fixupTypeAfterEval(c, result, n) else: result = fixupTypeAfterEval(c, result, n)
#if result != n: #if result != n:
@ -631,7 +631,7 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
proc semStaticExpr(c: PContext, n: PNode): PNode = proc semStaticExpr(c: PContext, n: PNode): PNode =
let a = semExpr(c, n.sons[0]) let a = semExpr(c, n.sons[0])
if a.findUnresolvedStatic != nil: return a if a.findUnresolvedStatic != nil: return a
result = evalStaticExpr(c.module, c.cache, c.graph, a, c.p.owner) result = evalStaticExpr(c.module, c.graph, a, c.p.owner)
if result.isNil: if result.isNil:
localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n)) localError(c.config, n.info, errCannotInterpretNodeX % renderTree(n))
result = c.graph.emptyNode result = c.graph.emptyNode

View file

@ -572,7 +572,8 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
if v.flags * {sfGlobal, sfThread} == {sfGlobal}: if v.flags * {sfGlobal, sfThread} == {sfGlobal}:
message(c.config, v.info, hintGlobalVar) message(c.config, v.info, hintGlobalVar)
if hasCompileTime: if hasCompileTime:
vm.setupCompileTimeVar(c.module, c.cache, c.graph, result) vm.setupCompileTimeVar(c.module, c.graph, result)
c.graph.recordStmt(c.graph, c.module, result)
proc semConst(c: PContext, n: PNode): PNode = proc semConst(c: PContext, n: PNode): PNode =
result = copyNode(n) result = copyNode(n)
@ -1059,7 +1060,7 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
if containsOrIncl(c.includedFiles, f.int): if containsOrIncl(c.includedFiles, f.int):
localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f)) localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
else: else:
let code = gIncludeFile(c.graph, c.module, f, c.cache) let code = c.graph.includeFileCallback(c.graph, c.module, f)
gatherStmts c, code, result gatherStmts c, code, result
excl(c.includedFiles, f.int) excl(c.includedFiles, f.int)
of nkStmtList: of nkStmtList:
@ -1741,7 +1742,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
if containsOrIncl(c.includedFiles, f.int): if containsOrIncl(c.includedFiles, f.int):
localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f)) localError(c.config, n.info, errRecursiveDependencyX % toFilename(c.config, f))
else: else:
addSon(result, semStmt(c, gIncludeFile(c.graph, c.module, f, c.cache))) addSon(result, semStmt(c, c.graph.includeFileCallback(c.graph, c.module, f)))
excl(c.includedFiles, f.int) excl(c.includedFiles, f.int)
proc setLine(n: PNode, info: TLineInfo) = proc setLine(n: PNode, info: TLineInfo) =
@ -1770,7 +1771,7 @@ proc semStaticStmt(c: PContext, n: PNode): PNode =
let a = semStmt(c, n.sons[0]) let a = semStmt(c, n.sons[0])
dec c.inStaticContext dec c.inStaticContext
n.sons[0] = a n.sons[0] = a
evalStaticStmt(c.module, c.cache, c.graph, a, c.p.owner) evalStaticStmt(c.module, c.graph, a, c.p.owner)
result = newNodeI(nkDiscardStmt, n.info, 1) result = newNodeI(nkDiscardStmt, n.info, 1)
result.sons[0] = c.graph.emptyNode result.sons[0] = c.graph.emptyNode

View file

@ -323,7 +323,7 @@ proc suggestFieldAccess(c: PContext, n, field: PNode, outputs: var Suggestions)
# error: no known module name: # error: no known module name:
typ = nil typ = nil
else: else:
let m = gImportModule(c.graph, c.module, fileInfoIdx(c.config, fullpath), c.cache) let m = c.graph.importModuleCallback(c.graph, c.module, fileInfoIdx(c.config, fullpath))
if m == nil: typ = nil if m == nil: typ = nil
else: else:
for it in items(n.sym.tab): for it in items(n.sym.tab):

View file

@ -1657,20 +1657,20 @@ proc getGlobalValue*(c: PCtx; s: PSym): PNode =
include vmops include vmops
proc setupGlobalCtx(module: PSym; cache: IdentCache; graph: ModuleGraph) = proc setupGlobalCtx(module: PSym; graph: ModuleGraph) =
if graph.vm.isNil: if graph.vm.isNil:
graph.vm = newCtx(module, cache, graph) graph.vm = newCtx(module, graph.cache, graph)
registerAdditionalOps(PCtx graph.vm) registerAdditionalOps(PCtx graph.vm)
else: else:
refresh(PCtx graph.vm, module) refresh(PCtx graph.vm, module)
proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym): PPassContext =
#var c = newEvalContext(module, emRepl) #var c = newEvalContext(module, emRepl)
#c.features = {allowCast, allowFFI, allowInfiniteLoops} #c.features = {allowCast, allowFFI, allowInfiniteLoops}
#pushStackFrame(c, newStackFrame()) #pushStackFrame(c, newStackFrame())
# XXX produce a new 'globals' environment here: # XXX produce a new 'globals' environment here:
setupGlobalCtx(module, cache, graph) setupGlobalCtx(module, graph)
result = PCtx graph.vm result = PCtx graph.vm
when hasFFI: when hasFFI:
PCtx(graph.vm).features = {allowFFI, allowCast} PCtx(graph.vm).features = {allowFFI, allowCast}
@ -1688,13 +1688,13 @@ proc myProcess(c: PPassContext, n: PNode): PNode =
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode = proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
myProcess(c, n) myProcess(c, n)
const evalPass* = makePass(myOpen, nil, myProcess, myClose) const evalPass* = makePass(myOpen, myProcess, myClose)
proc evalConstExprAux(module: PSym; cache: IdentCache; proc evalConstExprAux(module: PSym;
g: ModuleGraph; prc: PSym, n: PNode, g: ModuleGraph; prc: PSym, n: PNode,
mode: TEvalMode): PNode = mode: TEvalMode): PNode =
let n = transformExpr(g, module, n) let n = transformExpr(g, module, n)
setupGlobalCtx(module, cache, g) setupGlobalCtx(module, g)
var c = PCtx g.vm var c = PCtx g.vm
let oldMode = c.mode let oldMode = c.mode
defer: c.mode = oldMode defer: c.mode = oldMode
@ -1709,17 +1709,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache;
result = rawExecute(c, start, tos).regToNode result = rawExecute(c, start, tos).regToNode
if result.info.col < 0: result.info = n.info if result.info.col < 0: result.info = n.info
proc evalConstExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode): PNode = proc evalConstExpr*(module: PSym; g: ModuleGraph; e: PNode): PNode =
result = evalConstExprAux(module, cache, g, nil, e, emConst) result = evalConstExprAux(module, g, nil, e, emConst)
proc evalStaticExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym): PNode = proc evalStaticExpr*(module: PSym; g: ModuleGraph; e: PNode, prc: PSym): PNode =
result = evalConstExprAux(module, cache, g, prc, e, emStaticExpr) result = evalConstExprAux(module, g, prc, e, emStaticExpr)
proc evalStaticStmt*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym) = proc evalStaticStmt*(module: PSym; g: ModuleGraph; e: PNode, prc: PSym) =
discard evalConstExprAux(module, cache, g, prc, e, emStaticStmt) discard evalConstExprAux(module, g, prc, e, emStaticStmt)
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, g: ModuleGraph; n: PNode) = proc setupCompileTimeVar*(module: PSym; g: ModuleGraph; n: PNode) =
discard evalConstExprAux(module, cache, g, nil, n, emStaticStmt) discard evalConstExprAux(module, g, nil, n, emStaticStmt)
proc setupMacroParam(x: PNode, typ: PType): TFullReg = proc setupMacroParam(x: PNode, typ: PType): TFullReg =
case typ.kind case typ.kind
@ -1746,7 +1746,7 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
# to prevent endless recursion in macro instantiation # to prevent endless recursion in macro instantiation
const evalMacroLimit = 1000 const evalMacroLimit = 1000
proc evalMacroCall*(module: PSym; cache: IdentCache; g: ModuleGraph; proc evalMacroCall*(module: PSym; g: ModuleGraph;
n, nOrig: PNode, sym: PSym): PNode = n, nOrig: PNode, sym: PSym): PNode =
# XXX globalError() is ugly here, but I don't know a better solution for now # XXX globalError() is ugly here, but I don't know a better solution for now
inc(g.config.evalMacroCounter) inc(g.config.evalMacroCounter)
@ -1759,7 +1759,7 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; g: ModuleGraph;
globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [ globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [
n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)]) n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)])
setupGlobalCtx(module, cache, g) setupGlobalCtx(module, g)
var c = PCtx g.vm var c = PCtx g.vm
c.comesFromHeuristic.line = 0'u16 c.comesFromHeuristic.line = 0'u16

View file

@ -159,7 +159,7 @@ proc symFromInfo(graph: ModuleGraph; trackPos: TLineInfo): PSym =
result = findNode(m.ast, trackPos) result = findNode(m.ast, trackPos)
proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
graph: ModuleGraph; cache: IdentCache) = graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
myLog("cmd: " & $cmd & ", file: " & file & ", dirtyFile: " & dirtyfile & myLog("cmd: " & $cmd & ", file: " & file & ", dirtyFile: " & dirtyfile &
"[" & $line & ":" & $col & "]") "[" & $line & ":" & $col & "]")
@ -184,7 +184,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
if conf.suggestVersion == 1: if conf.suggestVersion == 1:
graph.usageSym = nil graph.usageSym = nil
if not isKnownFile: if not isKnownFile:
graph.compileProject(cache) graph.compileProject()
if conf.suggestVersion == 0 and conf.ideCmd in {ideUse, ideDus} and if conf.suggestVersion == 0 and conf.ideCmd in {ideUse, ideDus} and
dirtyfile.len == 0: dirtyfile.len == 0:
discard "no need to recompile anything" discard "no need to recompile anything"
@ -193,7 +193,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
graph.markDirty dirtyIdx graph.markDirty dirtyIdx
graph.markClientsDirty dirtyIdx graph.markClientsDirty dirtyIdx
if conf.ideCmd != ideMod: if conf.ideCmd != ideMod:
graph.compileProject(cache, modIdx) graph.compileProject(modIdx)
if conf.ideCmd in {ideUse, ideDus}: if conf.ideCmd in {ideUse, ideDus}:
let u = if conf.suggestVersion != 1: graph.symFromInfo(conf.m.trackPos) else: graph.usageSym let u = if conf.suggestVersion != 1: graph.symFromInfo(conf.m.trackPos) else: graph.usageSym
if u != nil: if u != nil:
@ -202,7 +202,7 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
localError(conf, conf.m.trackPos, "found no symbol at this position " & (conf $ conf.m.trackPos)) localError(conf, conf.m.trackPos, "found no symbol at this position " & (conf $ conf.m.trackPos))
proc executeEpc(cmd: IdeCmd, args: SexpNode; proc executeEpc(cmd: IdeCmd, args: SexpNode;
graph: ModuleGraph; cache: IdentCache) = graph: ModuleGraph) =
let let
file = args[0].getStr file = args[0].getStr
line = args[1].getNum line = args[1].getNum
@ -210,7 +210,7 @@ proc executeEpc(cmd: IdeCmd, args: SexpNode;
var dirtyfile = "" var dirtyfile = ""
if len(args) > 3: if len(args) > 3:
dirtyfile = args[3].getStr(nil) dirtyfile = args[3].getStr(nil)
execute(cmd, file, dirtyfile, int(line), int(column), graph, cache) execute(cmd, file, dirtyfile, int(line), int(column), graph)
proc returnEpc(socket: Socket, uid: BiggestInt, s: SexpNode|string, proc returnEpc(socket: Socket, uid: BiggestInt, s: SexpNode|string,
return_symbol = "return") = return_symbol = "return") =
@ -379,7 +379,7 @@ proc replEpc(x: ThreadParams) {.thread.} =
"unexpected call: " & epcAPI "unexpected call: " & epcAPI
quit errMessage quit errMessage
proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache; cachedMsgs: CachedMsgs) = proc execCmd(cmd: string; graph: ModuleGraph; cachedMsgs: CachedMsgs) =
let conf = graph.config let conf = graph.config
template sentinel() = template sentinel() =
@ -435,19 +435,19 @@ proc execCmd(cmd: string; graph: ModuleGraph; cache: IdentCache; cachedMsgs: Cac
else: else:
if conf.ideCmd == ideChk: if conf.ideCmd == ideChk:
for cm in cachedMsgs: errorHook(conf, cm.info, cm.msg, cm.sev) for cm in cachedMsgs: errorHook(conf, cm.info, cm.msg, cm.sev)
execute(conf.ideCmd, orig, dirtyfile, line, col, graph, cache) execute(conf.ideCmd, orig, dirtyfile, line, col, graph)
sentinel() sentinel()
proc recompileFullProject(graph: ModuleGraph; cache: IdentCache) = proc recompileFullProject(graph: ModuleGraph) =
#echo "recompiling full project" #echo "recompiling full project"
resetSystemArtifacts(graph) resetSystemArtifacts(graph)
graph.vm = nil graph.vm = nil
graph.resetAllModules() graph.resetAllModules()
GC_fullcollect() GC_fullcollect()
compileProject(graph, cache) compileProject(graph)
#echo GC_getStatistics() #echo GC_getStatistics()
proc mainThread(graph: ModuleGraph; cache: IdentCache) = proc mainThread(graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
if gLogging: if gLogging:
for it in conf.searchPaths: for it in conf.searchPaths:
@ -469,7 +469,7 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) =
if hasData: if hasData:
conf.writelnHook = wrHook conf.writelnHook = wrHook
conf.suggestionResultHook = sugResultHook conf.suggestionResultHook = sugResultHook
execCmd(req, graph, cache, cachedMsgs) execCmd(req, graph, cachedMsgs)
idle = 0 idle = 0
else: else:
os.sleep 250 os.sleep 250
@ -482,12 +482,12 @@ proc mainThread(graph: ModuleGraph; cache: IdentCache) =
conf.structuredErrorHook = proc (conf: ConfigRef; info: TLineInfo; msg: string; sev: Severity) = conf.structuredErrorHook = proc (conf: ConfigRef; info: TLineInfo; msg: string; sev: Severity) =
cachedMsgs.add(CachedMsg(info: info, msg: msg, sev: sev)) cachedMsgs.add(CachedMsg(info: info, msg: msg, sev: sev))
conf.suggestionResultHook = proc (s: Suggest) = discard conf.suggestionResultHook = proc (s: Suggest) = discard
recompileFullProject(graph, cache) recompileFullProject(graph)
var var
inputThread: Thread[ThreadParams] inputThread: Thread[ThreadParams]
proc mainCommand(graph: ModuleGraph; cache: IdentCache) = proc mainCommand(graph: ModuleGraph) =
let conf = graph.config let conf = graph.config
clearPasses(graph) clearPasses(graph)
registerPass graph, verbosePass registerPass graph, verbosePass
@ -509,7 +509,7 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) =
# compile the project before showing any input so that we already # compile the project before showing any input so that we already
# can answer questions right away: # can answer questions right away:
compileProject(graph, cache) compileProject(graph)
open(requests) open(requests)
open(results) open(results)
@ -522,7 +522,7 @@ proc mainCommand(graph: ModuleGraph; cache: IdentCache) =
(gPort, "sug \"" & conf.projectFull & "\":" & gAddress)) (gPort, "sug \"" & conf.projectFull & "\":" & gAddress))
of mcmdcon: createThread(inputThread, replCmdline, of mcmdcon: createThread(inputThread, replCmdline,
(gPort, "con \"" & conf.projectFull & "\":" & gAddress)) (gPort, "con \"" & conf.projectFull & "\":" & gAddress))
mainThread(graph, cache) mainThread(graph)
joinThread(inputThread) joinThread(inputThread)
close(requests) close(requests)
close(results) close(results)
@ -632,6 +632,6 @@ proc handleCmdLine(cache: IdentCache; conf: ConfigRef) =
let graph = newModuleGraph(cache, conf) let graph = newModuleGraph(cache, conf)
graph.suggestMode = true graph.suggestMode = true
mainCommand(graph, cache) mainCommand(graph)
handleCmdline(newIdentCache(), newConfigRef()) handleCmdline(newIdentCache(), newConfigRef())