new dependency tracking for nimsuggest

This commit is contained in:
Araq 2016-11-05 01:19:23 +01:00
commit bec9c4be27
21 changed files with 283 additions and 392 deletions

View file

@ -16,6 +16,8 @@ import
condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, condsyms, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases,
lowerings, semparallel lowerings, semparallel
from modulegraphs import ModuleGraph
import strutils except `%` # collides with ropes.`%` import strutils except `%` # collides with ropes.`%`
when options.hasTinyCBackend: when options.hasTinyCBackend:
@ -1174,7 +1176,7 @@ proc newModule(module: PSym): BModule =
if (sfDeadCodeElim in module.flags): if (sfDeadCodeElim in module.flags):
internalError("added pending module twice: " & module.filename) 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) result = newModule(module)
if optGenIndex in gGlobalOptions and generatedHeader == nil: if optGenIndex in gGlobalOptions and generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull let f = if headerFile.len > 0: headerFile else: gProjectFull
@ -1209,7 +1211,7 @@ proc getCFile(m: BModule): string =
else: ".c" else: ".c"
result = changeFileExt(completeCFilePath(m.cfilename.withPackageName), ext) 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 assert optSymbolFiles in gGlobalOptions
var m = newModule(module) var m = newModule(module)
readMergeInfo(getCFile(m), m) readMergeInfo(getCFile(m), m)

View file

@ -12,6 +12,8 @@
import import
os, options, ast, astalgo, msgs, ropes, idents, passes, importer os, options, ast, astalgo, msgs, ropes, idents, passes, importer
from modulegraphs import ModuleGraph
proc generateDot*(project: string) proc generateDot*(project: string)
type type
@ -46,7 +48,7 @@ proc generateDot(project: string) =
rope(changeFileExt(extractFilename(project), "")), gDotGraph], rope(changeFileExt(extractFilename(project), "")), gDotGraph],
changeFileExt(project, "dot")) changeFileExt(project, "dot"))
proc myOpen(module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module

View file

@ -13,6 +13,8 @@
import import
os, options, ast, astalgo, msgs, ropes, idents, passes, docgen os, options, ast, astalgo, msgs, ropes, idents, passes, docgen
from modulegraphs import ModuleGraph
type type
TGen = object of TPassContext TGen = object of TPassContext
doc: PDoc doc: PDoc
@ -49,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(module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
var g: PGen var g: PGen
new(g) new(g)
g.module = module g.module = module

View file

@ -162,7 +162,7 @@ proc importModuleAs(n: PNode, realModule: PSym): PSym =
proc myImportModule(c: PContext, n: PNode): PSym = proc myImportModule(c: PContext, n: PNode): PSym =
var f = checkModuleName(n) var f = checkModuleName(n)
if f != InvalidFileIDX: 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 # we cannot perform this check reliably because of
# test: modules/import_in_config) # test: modules/import_in_config)
if result.info.fileIndex == c.module.info.fileIndex and if result.info.fileIndex == c.module.info.fileIndex and

View file

@ -35,6 +35,8 @@ import
times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
intsets, cgmeth, lowerings intsets, cgmeth, lowerings
from modulegraphs import ModuleGraph
type type
TTarget = enum TTarget = enum
targetJS, targetPHP targetJS, targetPHP
@ -2272,11 +2274,11 @@ proc myClose(b: PPassContext, n: PNode): PNode =
for obj, content in items(globals.classes): for obj, content in items(globals.classes):
genClass(obj, content, ext) 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") internalError("symbol files are not possible with the JS code generator")
result = nil result = nil
proc myOpen(s: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
var r = newModule(s) var r = newModule(s)
r.target = if gCmd == cmdCompileToPHP: targetPHP else: targetJS r.target = if gCmd == cmdCompileToPHP: targetPHP else: targetJS
result = r result = r

View file

@ -15,7 +15,8 @@ import
wordrecg, sem, semdata, idents, passes, docgen, extccomp, wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, jsgen, json, nversion, cgen, jsgen, json, nversion,
platform, nimconf, importer, passaux, depends, vm, vmdef, types, idgen, 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 from magicsys import systemModule, resetSysTypes
@ -30,80 +31,44 @@ proc semanticPasses =
registerPass verbosePass registerPass verbosePass
registerPass semPass registerPass semPass
proc commandGenDepend(cache: IdentCache) = proc commandGenDepend(graph: ModuleGraph; cache: IdentCache) =
semanticPasses() semanticPasses()
registerPass(gendependPass) registerPass(gendependPass)
registerPass(cleanupPass) registerPass(cleanupPass)
compileProject(cache) compileProject(graph, cache)
generateDot(gProjectFull) generateDot(gProjectFull)
execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") & execExternalProgram("dot -Tpng -o" & changeFileExt(gProjectFull, "png") &
' ' & changeFileExt(gProjectFull, "dot")) ' ' & changeFileExt(gProjectFull, "dot"))
proc commandCheck(cache: IdentCache) = proc commandCheck(graph: ModuleGraph; cache: IdentCache) =
msgs.gErrorMax = high(int) # do not stop after first error msgs.gErrorMax = high(int) # do not stop after first error
defineSymbol("nimcheck") defineSymbol("nimcheck")
semanticPasses() # use an empty backend for semantic checking only semanticPasses() # use an empty backend for semantic checking only
rodPass() 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 msgs.gErrorMax = high(int) # do not stop after first error
semanticPasses() semanticPasses()
if json: registerPass(docgen2JsonPass) if json: registerPass(docgen2JsonPass)
else: registerPass(docgen2Pass) else: registerPass(docgen2Pass)
#registerPass(cleanupPass()) #registerPass(cleanupPass())
compileProject(cache) compileProject(graph, cache)
finishDoc2Pass(gProjectName) finishDoc2Pass(gProjectName)
proc commandCompileToC(cache: IdentCache) = proc commandCompileToC(graph: ModuleGraph; cache: IdentCache) =
extccomp.initVars() extccomp.initVars()
semanticPasses() semanticPasses()
registerPass(cgenPass) registerPass(cgenPass)
rodPass() rodPass()
#registerPass(cleanupPass()) #registerPass(cleanupPass())
compileProject(cache) compileProject(graph, cache)
cgenWriteModules() cgenWriteModules()
if gCmd != cmdRun: if gCmd != cmdRun:
extccomp.callCCompiler(changeFileExt(gProjectFull, "")) extccomp.callCCompiler(changeFileExt(gProjectFull, ""))
if isServing: proc commandCompileToJS(graph: ModuleGraph; cache: IdentCache) =
# 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) =
#incl(gGlobalOptions, optSafeCode) #incl(gGlobalOptions, optSafeCode)
setTarget(osJS, cpuJS) setTarget(osJS, cpuJS)
#initDefines() #initDefines()
@ -113,9 +78,9 @@ proc commandCompileToJS(cache: IdentCache) =
if gCmd == cmdCompileToPHP: defineSymbol("nimphp") if gCmd == cmdCompileToPHP: defineSymbol("nimphp")
semanticPasses() semanticPasses()
registerPass(JSgenPass) registerPass(JSgenPass)
compileProject(cache) compileProject(graph, cache)
proc interactivePasses(cache: IdentCache) = proc interactivePasses(graph: ModuleGraph; cache: IdentCache) =
#incl(gGlobalOptions, optSafeCode) #incl(gGlobalOptions, optSafeCode)
#setTarget(osNimrodVM, cpuNimrodVM) #setTarget(osNimrodVM, cpuNimrodVM)
initDefines() initDefines()
@ -125,28 +90,28 @@ proc interactivePasses(cache: IdentCache) =
registerPass(semPass) registerPass(semPass)
registerPass(evalPass) registerPass(evalPass)
proc commandInteractive(cache: IdentCache) = proc commandInteractive(graph: ModuleGraph; cache: IdentCache) =
msgs.gErrorMax = high(int) # do not stop after first error msgs.gErrorMax = high(int) # do not stop after first error
interactivePasses(cache) interactivePasses(graph, cache)
compileSystemModule(cache) compileSystemModule(graph, cache)
if commandArgs.len > 0: if commandArgs.len > 0:
discard compileModule(fileInfoIdx(gProjectFull), cache, {}) discard graph.compileModule(fileInfoIdx(gProjectFull), cache, {})
else: else:
var m = makeStdinModule() var m = graph.makeStdinModule()
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
processModule(m, llStreamOpenStdIn(), nil, cache) processModule(graph, m, llStreamOpenStdIn(), nil, cache)
const evalPasses = [verbosePass, semPass, evalPass] const evalPasses = [verbosePass, semPass, evalPass]
proc evalNim(nodes: PNode, module: PSym; cache: IdentCache) = proc evalNim(graph: ModuleGraph; nodes: PNode, module: PSym; cache: IdentCache) =
carryPasses(nodes, module, cache, evalPasses) carryPasses(graph, nodes, module, cache, evalPasses)
proc commandEval(cache: IdentCache; exp: string) = proc commandEval(graph: ModuleGraph; cache: IdentCache; exp: string) =
if systemModule == nil: if systemModule == nil:
interactivePasses(cache) interactivePasses(graph, cache)
compileSystemModule(cache) compileSystemModule(graph, cache)
let echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")" 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) = proc commandScan(cache: IdentCache) =
var f = addFileExt(mainCommandArg(), NimExt) var f = addFileExt(mainCommandArg(), NimExt)
@ -165,75 +130,11 @@ proc commandScan(cache: IdentCache) =
else: else:
rawMessage(errCannotOpenFile, f) 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 const
SimulateCaasMemReset = false SimulateCaasMemReset = false
PrintRopeCacheStats = false PrintRopeCacheStats = false
proc mainCommand*(cache: IdentCache) = proc mainCommand*(graph: ModuleGraph; cache: IdentCache) =
when SimulateCaasMemReset: when SimulateCaasMemReset:
gGlobalOptions.incl(optCaasEnabled) gGlobalOptions.incl(optCaasEnabled)
@ -249,28 +150,28 @@ proc mainCommand*(cache: IdentCache) =
of "c", "cc", "compile", "compiletoc": of "c", "cc", "compile", "compiletoc":
# compile means compileToC currently # compile means compileToC currently
gCmd = cmdCompileToC gCmd = cmdCompileToC
commandCompileToC(cache) commandCompileToC(graph, cache)
of "cpp", "compiletocpp": of "cpp", "compiletocpp":
gCmd = cmdCompileToCpp gCmd = cmdCompileToCpp
defineSymbol("cpp") defineSymbol("cpp")
commandCompileToC(cache) commandCompileToC(graph, cache)
of "objc", "compiletooc": of "objc", "compiletooc":
gCmd = cmdCompileToOC gCmd = cmdCompileToOC
defineSymbol("objc") defineSymbol("objc")
commandCompileToC(cache) commandCompileToC(graph, cache)
of "run": of "run":
gCmd = cmdRun gCmd = cmdRun
when hasTinyCBackend: when hasTinyCBackend:
extccomp.setCC("tcc") extccomp.setCC("tcc")
commandCompileToC(cache) commandCompileToC(graph, cache)
else: else:
rawMessage(errInvalidCommandX, command) rawMessage(errInvalidCommandX, command)
of "js", "compiletojs": of "js", "compiletojs":
gCmd = cmdCompileToJS gCmd = cmdCompileToJS
commandCompileToJS(cache) commandCompileToJS(graph, cache)
of "php": of "php":
gCmd = cmdCompileToPHP gCmd = cmdCompileToPHP
commandCompileToJS(cache) commandCompileToJS(graph, cache)
of "doc": of "doc":
wantMainModule() wantMainModule()
gCmd = cmdDoc gCmd = cmdDoc
@ -280,7 +181,7 @@ proc mainCommand*(cache: IdentCache) =
gCmd = cmdDoc gCmd = cmdDoc
loadConfigs(DocConfig, cache) loadConfigs(DocConfig, cache)
defineSymbol("nimdoc") defineSymbol("nimdoc")
commandDoc2(cache, false) commandDoc2(graph, cache, false)
of "rst2html": of "rst2html":
gCmd = cmdRst2html gCmd = cmdRst2html
loadConfigs(DocConfig, cache) loadConfigs(DocConfig, cache)
@ -301,14 +202,14 @@ proc mainCommand*(cache: IdentCache) =
loadConfigs(DocConfig, cache) loadConfigs(DocConfig, cache)
wantMainModule() wantMainModule()
defineSymbol("nimdoc") defineSymbol("nimdoc")
commandDoc2(cache, true) commandDoc2(graph, cache, true)
of "buildindex": of "buildindex":
gCmd = cmdDoc gCmd = cmdDoc
loadConfigs(DocConfig, cache) loadConfigs(DocConfig, cache)
commandBuildIndex() commandBuildIndex()
of "gendepend": of "gendepend":
gCmd = cmdGenDepend gCmd = cmdGenDepend
commandGenDepend(cache) commandGenDepend(graph, cache)
of "dump": of "dump":
gCmd = cmdDump gCmd = cmdDump
if getConfigVar("dump.format") == "json": if getConfigVar("dump.format") == "json":
@ -337,7 +238,7 @@ proc mainCommand*(cache: IdentCache) =
for it in iterSearchPath(searchPaths): msgWriteln(it) for it in iterSearchPath(searchPaths): msgWriteln(it)
of "check": of "check":
gCmd = cmdCheck gCmd = cmdCheck
commandCheck(cache) commandCheck(graph, cache)
of "parse": of "parse":
gCmd = cmdParse gCmd = cmdParse
wantMainModule() wantMainModule()
@ -346,26 +247,12 @@ proc mainCommand*(cache: IdentCache) =
gCmd = cmdScan gCmd = cmdScan
wantMainModule() wantMainModule()
commandScan(cache) commandScan(cache)
msgWriteln("Beware: Indentation tokens depend on the parser\'s state!") msgWriteln("Beware: Indentation tokens depend on the parser's state!")
of "secret": of "secret":
gCmd = cmdInteractive gCmd = cmdInteractive
commandInteractive(cache) commandInteractive(graph, cache)
of "e": of "e":
# XXX: temporary command for easier testing commandEval(graph, cache, mainCommandArg())
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)
of "nop", "help": of "nop", "help":
# prevent the "success" message: # prevent the "success" message:
gCmd = cmdDump gCmd = cmdDump
@ -393,4 +280,4 @@ proc mainCommand*(cache: IdentCache) =
resetAttributes() resetAttributes()
proc mainCommand*() = mainCommand(newIdentCache()) proc mainCommand*() = mainCommand(newModuleGraph(), newIdentCache())

View file

@ -7,38 +7,32 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## implements the module handling ## Implements the module handling, including the caching of modules.
import import
ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options, ast, astalgo, magicsys, securehash, rodread, msgs, cgendata, sigmatch, options,
idents, os, lexer, idgen, passes, syntaxes, llstream idents, os, lexer, idgen, passes, syntaxes, llstream, modulegraphs
type when false:
type
TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled TNeedRecompile* = enum Maybe, No, Yes, Probing, Recompiled
THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged THashStatus* = enum hashNotTaken, hashCached, hashHasChanged, hashNotChanged
TModuleInMemory* = object TModuleInMemory* = object
compiledAt*: float
hash*: SecureHash hash*: SecureHash
deps*: seq[int32] ## XXX: slurped files are currently not tracked deps*: seq[int32] ## XXX: slurped files are currently not tracked
needsRecompile*: TNeedRecompile needsRecompile*: TNeedRecompile
hashStatus*: THashStatus hashStatus*: THashStatus
var var
gCompiledModules: seq[PSym] = @[] gCompiledModules: seq[PSym] = @[]
gMemCacheData*: seq[TModuleInMemory] = @[] gMemCacheData*: seq[TModuleInMemory] = @[]
## XXX: we should implement recycling of file IDs ## XXX: we should implement recycling of file IDs
## if the user keeps renaming modules, the file IDs will keep growing ## if the user keeps renaming modules, the file IDs will keep growing
gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why. gFuzzyGraphChecking*: bool # nimsuggest uses this. XXX figure out why.
packageSyms: TStrTable
initStrTable(packageSyms) proc hashChanged(fileIdx: int32): bool =
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 internalAssert fileIdx >= 0 and fileIdx < gMemCacheData.len
template updateStatus = template updateStatus =
@ -61,16 +55,12 @@ proc hashChanged(fileIdx: int32): bool =
result = true result = true
updateStatus() updateStatus()
proc doHash(fileIdx: int32) = proc doHash(fileIdx: int32) =
if gMemCacheData[fileIdx].hashStatus == hashNotTaken: if gMemCacheData[fileIdx].hashStatus == hashNotTaken:
# echo "FIRST Hash: ", fileIdx.ToFilename # echo "FIRST Hash: ", fileIdx.ToFilename
gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath) gMemCacheData[fileIdx].hash = secureHashFile(fileIdx.toFullPath)
proc addDep(x: PSym, dep: int32) = proc resetModule*(fileIdx: int32) =
growCache gMemCacheData, dep
gMemCacheData[x.position].deps.safeAdd(dep)
proc resetModule*(fileIdx: int32) =
# echo "HARD RESETTING ", fileIdx.toFilename # echo "HARD RESETTING ", fileIdx.toFilename
if fileIdx <% gMemCacheData.len: if fileIdx <% gMemCacheData.len:
gMemCacheData[fileIdx].needsRecompile = Yes gMemCacheData[fileIdx].needsRecompile = Yes
@ -79,31 +69,29 @@ proc resetModule*(fileIdx: int32) =
if fileIdx <% cgendata.gModules.len: if fileIdx <% cgendata.gModules.len:
cgendata.gModules[fileIdx] = nil cgendata.gModules[fileIdx] = nil
proc resetModule*(module: PSym) = proc resetModule*(module: PSym) =
let conflict = getModule(module.position.int32) let conflict = getModule(module.position.int32)
if conflict == nil: return if conflict == nil: return
doAssert conflict == module doAssert conflict == module
resetModule(module.position.int32) resetModule(module.position.int32)
initStrTable(module.tab) initStrTable(module.tab)
proc resetAllModules* = proc resetAllModules* =
for i in 0..gCompiledModules.high: for i in 0..gCompiledModules.high:
if gCompiledModules[i] != nil: if gCompiledModules[i] != nil:
resetModule(i.int32) resetModule(i.int32)
resetPackageCache() resetPackageCache()
initStrTable(packageSyms)
# for m in cgenModules(): echo "CGEN MODULE FOUND" # for m in cgenModules(): echo "CGEN MODULE FOUND"
proc resetAllModulesHard* = proc resetAllModulesHard* =
resetPackageCache() resetPackageCache()
gCompiledModules.setLen 0 gCompiledModules.setLen 0
gMemCacheData.setLen 0 gMemCacheData.setLen 0
magicsys.resetSysTypes() magicsys.resetSysTypes()
initStrTable(packageSyms)
# XXX # XXX
#gOwners = @[] #gOwners = @[]
proc checkDepMem(fileIdx: int32): TNeedRecompile = proc checkDepMem(fileIdx: int32): TNeedRecompile =
template markDirty = template markDirty =
resetModule(fileIdx) resetModule(fileIdx)
return Yes return Yes
@ -130,7 +118,7 @@ proc checkDepMem(fileIdx: int32): TNeedRecompile =
gMemCacheData[fileIdx].needsRecompile = No gMemCacheData[fileIdx].needsRecompile = No
return 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 # 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. # mechanism, which we do in order to assign each module a persistent ID.
new(result) new(result)
@ -143,20 +131,19 @@ proc newModule(fileIdx: int32): PSym =
result.info = newLineInfo(fileIdx, 1, 1) result.info = newLineInfo(fileIdx, 1, 1)
let pack = getIdent(getPackageName(filename)) let pack = getIdent(getPackageName(filename))
var packSym = packageSyms.strTableGet(pack) var packSym = graph.packageSyms.strTableGet(pack)
if packSym == nil: if packSym == nil:
let pck = getPackageName(filename) let pck = getPackageName(filename)
let pck2 = if pck.len > 0: pck else: "unknown" let pck2 = if pck.len > 0: pck else: "unknown"
packSym = newSym(skPackage, getIdent(pck2), nil, result.info) packSym = newSym(skPackage, getIdent(pck2), nil, result.info)
initStrTable(packSym.tab) initStrTable(packSym.tab)
packageSyms.strTableAdd(packSym) graph.packageSyms.strTableAdd(packSym)
result.owner = packSym result.owner = packSym
result.position = fileIdx result.position = fileIdx
growCache gMemCacheData, fileIdx growCache graph.modules, fileIdx
growCache gCompiledModules, fileIdx graph.modules[result.position] = result
gCompiledModules[result.position] = result
incl(result.flags, sfUsed) incl(result.flags, sfUsed)
initStrTable(result.tab) initStrTable(result.tab)
@ -167,13 +154,12 @@ proc newModule(fileIdx: int32): PSym =
# strTableIncl() for error corrections: # strTableIncl() for error corrections:
discard strTableIncl(packSym.tab, result) discard strTableIncl(packSym.tab, result)
proc compileModule*(fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym = proc compileModule*(graph: ModuleGraph; fileIdx: int32; cache: IdentCache, flags: TSymFlags): PSym =
result = getModule(fileIdx) result = graph.getModule(fileIdx)
if result == nil: if result == nil:
growCache gMemCacheData, fileIdx #growCache gMemCacheData, fileIdx
gMemCacheData[fileIdx].needsRecompile = Probing #gMemCacheData[fileIdx].needsRecompile = Probing
result = newModule(fileIdx) result = newModule(graph, fileIdx)
#var rd = handleSymbolFile(result)
var rd: PRodReader var rd: PRodReader
result.flags = result.flags + flags result.flags = result.flags + flags
if sfMainModule in result.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}: if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result, cache) rd = handleSymbolFile(result, cache)
if result.id < 0: if result.id < 0:
internalError("handleSymbolFile should have set the module\'s ID") internalError("handleSymbolFile should have set the module's ID")
return return
else: else:
result.id = getID() result.id = getID()
let validFile = processModule(result, discard processModule(graph, result,
if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil, if sfMainModule in flags and gProjectIsStdin: stdin.llStreamOpen else: nil,
rd, cache) rd, cache)
if optCaasEnabled in gGlobalOptions: #if optCaasEnabled in gGlobalOptions:
gMemCacheData[fileIdx].compiledAt = gLastCmdTime # gMemCacheData[fileIdx].needsRecompile = Recompiled
gMemCacheData[fileIdx].needsRecompile = Recompiled # if validFile: doHash fileIdx
if validFile: doHash fileIdx elif graph.isDirty(result):
else: 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: if checkDepMem(fileIdx) == Yes:
result = compileModule(fileIdx, cache, flags) result = compileModule(fileIdx, cache, flags)
else: else:
result = gCompiledModules[fileIdx] result = gCompiledModules[fileIdx]
proc importModule*(s: PSym, fileIdx: int32; cache: IdentCache): PSym {.procvar.} = proc importModule*(graph: ModuleGraph; s: PSym, fileIdx: int32;
cache: IdentCache): PSym {.procvar.} =
# this is called by the semantic checking phase # this is called by the semantic checking phase
result = compileModule(fileIdx, cache, {}) result = compileModule(graph, fileIdx, cache, {})
if optCaasEnabled in gGlobalOptions: 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)
# restore the notes for outer module: # restore the notes for outer module:
gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes gNotes = if s.owner.id == gMainPackageId: gMainPackageNotes
else: ForeignPackageNotes 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) result = syntaxes.parseFile(fileIdx, cache)
if optCaasEnabled in gGlobalOptions: graph.addDep(s, fileIdx)
growCache gMemCacheData, fileIdx
addDep(s, fileIdx)
doHash(fileIdx)
proc compileSystemModule*(cache: IdentCache) = proc compileSystemModule*(graph: ModuleGraph; cache: IdentCache) =
if magicsys.systemModule == nil: if magicsys.systemModule == nil:
systemFileIdx = fileInfoIdx(options.libpath/"system.nim") systemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard compileModule(systemFileIdx, cache, {sfSystemModule}) discard graph.compileModule(systemFileIdx, cache, {sfSystemModule})
proc wantMainModule* = proc wantMainModule* =
if gProjectFull.len == 0: if gProjectFull.len == 0:
@ -229,18 +222,19 @@ proc wantMainModule* =
passes.gIncludeFile = includeModule passes.gIncludeFile = includeModule
passes.gImportModule = importModule passes.gImportModule = importModule
proc compileProject*(cache: IdentCache; projectFileIdx = -1'i32) = proc compileProject*(graph: ModuleGraph; cache: IdentCache;
projectFileIdx = -1'i32) =
wantMainModule() wantMainModule()
let systemFileIdx = fileInfoIdx(options.libpath / "system.nim") let systemFileIdx = fileInfoIdx(options.libpath / "system.nim")
let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx let projectFile = if projectFileIdx < 0: gProjectMainIdx else: projectFileIdx
if projectFile == systemFileIdx: if projectFile == systemFileIdx:
discard compileModule(projectFile, cache, {sfMainModule, sfSystemModule}) discard graph.compileModule(projectFile, cache, {sfMainModule, sfSystemModule})
else: else:
compileSystemModule(cache) graph.compileSystemModule(cache)
discard compileModule(projectFile, cache, {sfMainModule}) discard graph.compileModule(projectFile, cache, {sfMainModule})
proc makeModule*(filename: string): PSym = proc makeModule*(graph: ModuleGraph; filename: string): PSym =
result = newModule(fileInfoIdx filename) result = graph.newModule(fileInfoIdx filename)
result.id = getID() result.id = getID()
proc makeStdinModule*(): PSym = makeModule"stdin" proc makeStdinModule*(graph: ModuleGraph): PSym = graph.makeModule"stdin"

View file

@ -14,14 +14,14 @@ when defined(gcc) and defined(windows):
{.link: "icons/nim_icon.o".} {.link: "icons/nim_icon.o".}
when defined(amd64) and defined(windows) and defined(vcc): 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): when defined(i386) and defined(windows) and defined(vcc):
{.link: "icons/nim-i386-windows-vcc.res" .} {.link: "icons/nim-i386-windows-vcc.res".}
import import
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, osproc, platform, main, parseopt, service, extccomp, strutils, os, osproc, platform, main, parseopt, service,
nodejs, scriptconfig, idents nodejs, scriptconfig, idents, modulegraphs
when hasTinyCBackend: when hasTinyCBackend:
import tccgen import tccgen
@ -73,7 +73,7 @@ proc handleCmdLine(cache: IdentCache) =
processCmdLine(passCmd2, "") processCmdLine(passCmd2, "")
if options.command == "": if options.command == "":
rawMessage(errNoCommand, command) rawMessage(errNoCommand, command)
mainCommand(cache) mainCommand(newModuleGraph(), cache)
if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics()) if optHints in gOptions and hintGCStats in gNotes: echo(GC_getStatistics())
#echo(GC_getStatistics()) #echo(GC_getStatistics())
if msgs.gErrorCounter == 0: if msgs.gErrorCounter == 0:

View file

@ -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".}

View file

@ -12,7 +12,9 @@
import import
strutils, ast, astalgo, passes, idents, msgs, options, idgen 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); #MessageOut('compiling ' + s.name.s);
result = nil # we don't need a context result = nil # we don't need a context
rawMessage(hintProcessing, s.name.s) rawMessage(hintProcessing, s.name.s)

View file

@ -13,7 +13,7 @@
import import
strutils, lists, options, ast, astalgo, llstream, msgs, platform, os, strutils, lists, options, ast, astalgo, llstream, msgs, platform, os,
condsyms, idents, renderer, types, extccomp, math, magicsys, nversion, condsyms, idents, renderer, types, extccomp, math, magicsys, nversion,
nimsets, syntaxes, times, rodread, idgen nimsets, syntaxes, times, rodread, idgen, modulegraphs
type type
TPassContext* = object of RootObj # the pass's context TPassContext* = object of RootObj # the pass's context
@ -21,9 +21,9 @@ type
PPassContext* = ref TPassContext PPassContext* = ref TPassContext
TPassOpen* = proc (module: PSym; cache: IdentCache): PPassContext {.nimcall.} TPassOpen* = proc (graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext {.nimcall.}
TPassOpenCached* = 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.} TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.}
TPassProcess* = proc (p: PPassContext, topLevelStmt: 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: # the semantic checker needs these:
var var
gImportModule*: proc (m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.} gImportModule*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PSym {.nimcall.}
gIncludeFile*: proc (m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.} gIncludeFile*: proc (graph: ModuleGraph; m: PSym, fileIdx: int32; cache: IdentCache): PNode {.nimcall.}
# implementation # implementation
@ -90,29 +90,32 @@ proc registerPass*(p: TPass) =
gPasses[gPassesLen] = p gPasses[gPassesLen] = p
inc(gPassesLen) inc(gPassesLen)
proc carryPass*(p: TPass, module: PSym; cache: IdentCache; proc carryPass*(g: ModuleGraph; p: TPass, module: PSym; cache: IdentCache;
m: TPassData): TPassData = m: TPassData): TPassData =
var c = p.open(module, cache) var c = p.open(g, module, cache)
result.input = p.process(c, m.input) result.input = p.process(c, m.input)
result.closeOutput = if p.close != nil: p.close(c, m.closeOutput) result.closeOutput = if p.close != nil: p.close(c, m.closeOutput)
else: 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 var passdata: TPassData
passdata.input = nodes passdata.input = nodes
for pass in passes: 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): for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].open): 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 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): for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached): 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: if a[i] != nil:
a[i].fromCache = true a[i].fromCache = true
else: else:
@ -155,7 +158,7 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
importStmt.addSon str importStmt.addSon str
if not processTopLevelStmt(importStmt, a): break 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.} = rd: PRodReader; cache: IdentCache): bool {.discardable.} =
var var
p: TParsers p: TParsers
@ -163,7 +166,7 @@ proc processModule*(module: PSym, stream: PLLStream,
s: PLLStream s: PLLStream
fileIdx = module.fileIdx fileIdx = module.fileIdx
if rd == nil: if rd == nil:
openPasses(a, module, cache) openPasses(graph, a, module, cache)
if stream == nil: if stream == nil:
let filename = fileIdx.toFullPathConsiderDirty let filename = fileIdx.toFullPathConsiderDirty
s = llStreamOpen(filename, fmRead) s = llStreamOpen(filename, fmRead)
@ -203,7 +206,7 @@ proc processModule*(module: PSym, stream: PLLStream,
# id synchronization point for more consistent code generation: # id synchronization point for more consistent code generation:
idSynchronizationPoint(1000) idSynchronizationPoint(1000)
else: else:
openPassesCached(a, module, rd) openPassesCached(graph, a, module, rd)
var n = loadInitSection(rd) var n = loadInitSection(rd)
for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a) for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a)
closePassesCached(a) closePassesCached(a)

View file

@ -16,6 +16,8 @@ import
condsyms, ropes, idents, securehash, rodread, passes, importer, idgen, condsyms, ropes, idents, securehash, rodread, passes, importer, idgen,
rodutils rodutils
from modulegraphs import ModuleGraph
type type
TRodWriter = object of TPassContext TRodWriter = object of TPassContext
module: PSym module: PSym
@ -633,7 +635,7 @@ proc process(c: PPassContext, n: PNode): PNode =
else: else:
discard 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") if module.id < 0: internalError("rodwrite: module ID not set")
var w = newRodWriter(module.fileIdx.getHash, module, cache) var w = newRodWriter(module.fileIdx.getHash, module, cache)
rawAddInterfaceSym(w, module) rawAddInterfaceSym(w, module)

View file

@ -13,7 +13,7 @@
import import
ast, modules, idents, passes, passaux, condsyms, ast, modules, idents, passes, passaux, condsyms,
options, nimconf, lists, sem, semdata, llstream, vm, vmdef, commands, msgs, 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: # we support 'cmpIgnoreStyle' natively for efficiency:
from strutils import cmpIgnoreStyle, contains from strutils import cmpIgnoreStyle, contains
@ -134,9 +134,11 @@ proc setupVM*(module: PSym; cache: IdentCache; scriptName: string): PEvalContext
cbconf selfExe: cbconf selfExe:
setResult(a, os.getAppFilename()) setResult(a, os.getAppFilename())
proc runNimScript*(cache: IdentCache; scriptName: string; freshDefines=true) = proc runNimScript*(cache: IdentCache; scriptName: string;
freshDefines=true) =
passes.gIncludeFile = includeModule passes.gIncludeFile = includeModule
passes.gImportModule = importModule passes.gImportModule = importModule
let graph = newModuleGraph()
if freshDefines: initDefines() if freshDefines: initDefines()
defineSymbol("nimscript") defineSymbol("nimscript")
@ -146,15 +148,15 @@ proc runNimScript*(cache: IdentCache; scriptName: string; freshDefines=true) =
appendStr(searchPaths, options.libpath) appendStr(searchPaths, options.libpath)
var m = makeModule(scriptName) var m = graph.makeModule(scriptName)
incl(m.flags, sfMainModule) incl(m.flags, sfMainModule)
vm.globalCtx = setupVM(m, cache, scriptName) vm.globalCtx = setupVM(m, cache, scriptName)
compileSystemModule(cache) graph.compileSystemModule(cache)
discard processModule(m, llStreamOpen(scriptName, fmRead), nil, cache) discard graph.processModule(m, llStreamOpen(scriptName, fmRead), nil, cache)
# ensure we load 'system.nim' again for the real non-config stuff! # ensure we load 'system.nim' again for the real non-config stuff!
resetAllModulesHard() #resetAllModulesHard()
vm.globalCtx = nil vm.globalCtx = nil
# do not remove the defined symbols # do not remove the defined symbols
#initDefines() #initDefines()

View file

@ -18,6 +18,8 @@ import
evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity, evaltempl, patterns, parampatterns, sempass2, nimfix.pretty, semmacrosanity,
semparallel, lowerings, pluginsupport, plugins.active semparallel, lowerings, pluginsupport, plugins.active
from modulegraphs import ModuleGraph
when defined(nimfix): when defined(nimfix):
import nimfix.prettybase import nimfix.prettybase
@ -398,8 +400,8 @@ 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(module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
var c = newContext(module, cache) var c = newContext(graph, module, cache)
if c.p != nil: internalError(module.info, "sem.myOpen") if c.p != nil: internalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr c.semConstExpr = semConstExpr
c.semExpr = semExpr c.semExpr = semExpr
@ -428,8 +430,8 @@ proc myOpen(module: PSym; cache: IdentCache): PPassContext =
gNotes = ForeignPackageNotes gNotes = ForeignPackageNotes
result = c result = c
proc myOpenCached(module: PSym; rd: PRodReader): PPassContext = proc myOpenCached(graph: ModuleGraph; module: PSym; rd: PRodReader): PPassContext =
result = myOpen(module, rd.cache) result = myOpen(graph, module, rd.cache)
for m in items(rd.methods): methodDef(m, true) for m in items(rd.methods): methodDef(m, true)
proc isImportSystemStmt(n: PNode): bool = proc isImportSystemStmt(n: PNode): bool =

View file

@ -1,7 +1,7 @@
# #
# #
# The Nim Compiler # The Nim Compiler
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2016 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -13,7 +13,8 @@ import
strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab, strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
wordrecg, wordrecg,
ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math, 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 type
TOptionEntry* = object of lists.TListEntry # entries to put on a TOptionEntry* = object of lists.TListEntry # entries to put on a
@ -107,6 +108,7 @@ type
op: TTypeAttachedOp; col: int): PSym {.nimcall.} op: TTypeAttachedOp; col: int): PSym {.nimcall.}
selfName*: PIdent selfName*: PIdent
cache*: IdentCache cache*: IdentCache
graph*: ModuleGraph
signatures*: TStrTable signatures*: TStrTable
proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair = proc makeInstPair*(s: PSym, inst: PInstantiation): TInstantiationPair =
@ -151,7 +153,7 @@ proc newOptionEntry*(): POptionEntry =
result.dynlib = nil result.dynlib = nil
result.notes = gNotes result.notes = gNotes
proc newContext*(module: PSym; cache: IdentCache): PContext = proc newContext*(graph: ModuleGraph; module: PSym; cache: IdentCache): PContext =
new(result) new(result)
result.ambiguousSymbols = initIntSet() result.ambiguousSymbols = initIntSet()
initLinkedList(result.optionStack) initLinkedList(result.optionStack)
@ -166,6 +168,7 @@ proc newContext*(module: PSym; cache: IdentCache): PContext =
result.generics = @[] result.generics = @[]
result.unknownIdents = initIntSet() result.unknownIdents = initIntSet()
result.cache = cache result.cache = cache
result.graph = graph
initStrTable(result.signatures) initStrTable(result.signatures)

View file

@ -820,7 +820,7 @@ proc semAllTypeSections(c: PContext; n: PNode): PNode =
if containsOrIncl(c.includedFiles, f): if containsOrIncl(c.includedFiles, f):
localError(n.info, errRecursiveDependencyX, f.toFilename) localError(n.info, errRecursiveDependencyX, f.toFilename)
else: else:
let code = gIncludeFile(c.module, f, c.cache) let code = gIncludeFile(c.graph, c.module, f, c.cache)
gatherStmts c, code, result gatherStmts c, code, result
excl(c.includedFiles, f) excl(c.includedFiles, f)
of nkStmtList: of nkStmtList:
@ -1418,7 +1418,7 @@ proc evalInclude(c: PContext, n: PNode): PNode =
if containsOrIncl(c.includedFiles, f): if containsOrIncl(c.includedFiles, f):
localError(n.info, errRecursiveDependencyX, f.toFilename) localError(n.info, errRecursiveDependencyX, f.toFilename)
else: 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) excl(c.includedFiles, f)
proc setLine(n: PNode, info: TLineInfo) = proc setLine(n: PNode, info: TLineInfo) =

View file

@ -233,7 +233,7 @@ proc suggestFieldAccess(c: PContext, n: PNode, outputs: var int) =
# error: no known module name: # error: no known module name:
typ = nil typ = nil
else: 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 if m == nil: typ = nil
else: else:
for it in items(n.sym.tab): for it in items(n.sym.tab):

View file

@ -24,6 +24,8 @@ import
from semfold import leValueConv, ordinalValToString from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate from evaltempl import evalTemplate
from modulegraphs import ModuleGraph
when hasFFI: when hasFFI:
import evalffi import evalffi
@ -1516,7 +1518,7 @@ proc setupGlobalCtx(module: PSym; cache: IdentCache) =
else: else:
refresh(globalCtx, module) refresh(globalCtx, module)
proc myOpen(module: PSym; cache: IdentCache): PPassContext = proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): 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())

View file

@ -5,7 +5,7 @@
Command: Command:
//compile, c compile project with default code generator (C) //compile, c compile project with default code generator (C)
//doc generate the documentation for inputfile //doc generate the documentation for inputfile
//doc2 generate the documentation for the whole project //doc2 generate the documentation for inputfile
Arguments: Arguments:
arguments are passed to the program being run (if --run option is selected) arguments are passed to the program being run (if --run option is selected)

View file

@ -17,7 +17,7 @@ import compiler/options, compiler/commands, compiler/modules, compiler/sem,
compiler/passes, compiler/passaux, compiler/msgs, compiler/nimconf, compiler/passes, compiler/passaux, compiler/msgs, compiler/nimconf,
compiler/extccomp, compiler/condsyms, compiler/lists, compiler/extccomp, compiler/condsyms, compiler/lists,
compiler/sigmatch, compiler/ast, compiler/scriptconfig, compiler/sigmatch, compiler/ast, compiler/scriptconfig,
compiler/idents compiler/idents, compiler/modulegraphs
when defined(windows): when defined(windows):
import winlean import winlean
@ -128,19 +128,19 @@ proc findNode(n: PNode): PSym =
let res = n.sons[i].findNode let res = n.sons[i].findNode
if res != nil: return res if res != nil: return res
proc symFromInfo(gTrackPos: TLineInfo): PSym = proc symFromInfo(graph: ModuleGraph; gTrackPos: TLineInfo): PSym =
let m = getModule(gTrackPos.fileIndex) let m = graph.getModule(gTrackPos.fileIndex)
#echo m.isNil, " I knew it ", gTrackPos.fileIndex #echo m.isNil, " I knew it ", gTrackPos.fileIndex
if m != nil and m.ast != nil: if m != nil and m.ast != nil:
result = m.ast.findNode result = m.ast.findNode
proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int; proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
cache: IdentCache) = graph: ModuleGraph; cache: IdentCache) =
if gLogging: if gLogging:
logStr("cmd: " & $cmd & ", file: " & file & ", dirtyFile: " & dirtyfile & "[" & $line & ":" & $col & "]") logStr("cmd: " & $cmd & ", file: " & file & ", dirtyFile: " & dirtyfile & "[" & $line & ":" & $col & "]")
gIdeCmd = cmd gIdeCmd = cmd
if cmd == ideUse and suggestVersion != 2: if cmd == ideUse and suggestVersion != 2:
modules.resetAllModules() graph.resetAllModules()
var isKnownFile = true var isKnownFile = true
let dirtyIdx = file.fileInfoIdx(isKnownFile) let dirtyIdx = file.fileInfoIdx(isKnownFile)
@ -152,23 +152,26 @@ proc execute(cmd: IdeCmd, file, dirtyfile: string, line, col: int;
if suggestVersion < 2: if suggestVersion < 2:
usageSym = nil usageSym = nil
if not isKnownFile: if not isKnownFile:
compileProject(cache) graph.compileProject(cache)
if suggestVersion == 2 and gIdeCmd in {ideUse, ideDus} and if suggestVersion == 2 and gIdeCmd in {ideUse, ideDus} and
dirtyfile.len == 0: dirtyfile.len == 0:
discard "no need to recompile anything" discard "no need to recompile anything"
else: else:
resetModule dirtyIdx #resetModule dirtyIdx
if dirtyIdx != gProjectMainIdx: #if dirtyIdx != gProjectMainIdx:
resetModule gProjectMainIdx # resetModule gProjectMainIdx
compileProject(cache, dirtyIdx) graph.markDirty dirtyIdx
graph.markClientsDirty dirtyIdx
graph.compileProject(cache, dirtyIdx)
if gIdeCmd in {ideUse, ideDus}: if gIdeCmd in {ideUse, ideDus}:
let u = if suggestVersion >= 2: symFromInfo(gTrackPos) else: usageSym let u = if suggestVersion >= 2: graph.symFromInfo(gTrackPos) else: usageSym
if u != nil: if u != nil:
listUsages(u) listUsages(u)
else: else:
localError(gTrackPos, "found no symbol at this position " & $gTrackPos) localError(gTrackPos, "found no symbol at this position " & $gTrackPos)
proc executeEpc(cmd: IdeCmd, args: SexpNode; cache: IdentCache) = proc executeEpc(cmd: IdeCmd, args: SexpNode;
graph: ModuleGraph; cache: IdentCache) =
let let
file = args[0].getStr file = args[0].getStr
line = args[1].getNum line = args[1].getNum
@ -176,7 +179,7 @@ proc executeEpc(cmd: IdeCmd, args: SexpNode; cache: IdentCache) =
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), cache) execute(cmd, file, dirtyfile, int(line), int(column), graph, cache)
proc returnEpc(socket: var Socket, uid: BiggestInt, s: SexpNode|string, proc returnEpc(socket: var Socket, uid: BiggestInt, s: SexpNode|string,
return_symbol = "return") = return_symbol = "return") =
@ -192,7 +195,7 @@ template sendEpc(results: typed, tdef, hook: untyped) =
else: s else: s
) )
executeEpc(gIdeCmd, args, cache) executeEpc(gIdeCmd, args, graph, cache)
let res = sexp(results) let res = sexp(results)
if gLogging: if gLogging:
logStr($res) logStr($res)
@ -215,7 +218,7 @@ proc connectToNextFreePort(server: Socket, host: string): Port =
let (_, port) = server.getLocalAddr let (_, port) = server.getLocalAddr
result = port result = port
proc parseCmdLine(cmd: string; cache: IdentCache) = proc parseCmdLine(cmd: string; graph: ModuleGraph; cache: IdentCache) =
template toggle(sw) = template toggle(sw) =
if sw in gGlobalOptions: if sw in gGlobalOptions:
excl(gGlobalOptions, sw) excl(gGlobalOptions, sw)
@ -256,25 +259,25 @@ proc parseCmdLine(cmd: string; cache: IdentCache) =
i += skipWhile(cmd, seps, i) i += skipWhile(cmd, seps, i)
i += parseInt(cmd, col, i) i += parseInt(cmd, col, i)
execute(gIdeCmd, orig, dirtyfile, line, col-1, cache) execute(gIdeCmd, orig, dirtyfile, line, col-1, graph, cache)
proc serveStdin(cache: IdentCache) = proc serveStdin(graph: ModuleGraph; cache: IdentCache) =
if gEmitEof: if gEmitEof:
echo DummyEof echo DummyEof
while true: while true:
let line = readLine(stdin) let line = readLine(stdin)
parseCmdLine line, cache parseCmdLine line, graph, cache
echo DummyEof echo DummyEof
flushFile(stdout) flushFile(stdout)
else: else:
echo Help echo Help
var line = "" var line = ""
while readLineFromStdin("> ", line): while readLineFromStdin("> ", line):
parseCmdLine line, cache parseCmdLine line, graph, cache
echo "" echo ""
flushFile(stdout) flushFile(stdout)
proc serveTcp(cache: IdentCache) = proc serveTcp(graph: ModuleGraph; cache: IdentCache) =
var server = newSocket() var server = newSocket()
server.bindAddr(gPort, gAddress) server.bindAddr(gPort, gAddress)
var inp = "".TaintedString var inp = "".TaintedString
@ -288,12 +291,12 @@ proc serveTcp(cache: IdentCache) =
accept(server, stdoutSocket) accept(server, stdoutSocket)
stdoutSocket.readLine(inp) stdoutSocket.readLine(inp)
parseCmdLine inp.string, cache parseCmdLine inp.string, graph, cache
stdoutSocket.send("\c\L") stdoutSocket.send("\c\L")
stdoutSocket.close() stdoutSocket.close()
proc serveEpc(server: Socket; cache: IdentCache) = proc serveEpc(server: Socket; graph: ModuleGraph; cache: IdentCache) =
var client = newSocket() var client = newSocket()
# Wait for connection # Wait for connection
accept(server, client) accept(server, client)
@ -346,11 +349,7 @@ proc serveEpc(server: Socket; cache: IdentCache) =
"unexpected call: " & epcAPI "unexpected call: " & epcAPI
raise newException(EUnexpectedCommand, errMessage) raise newException(EUnexpectedCommand, errMessage)
template beCompatible() = proc mainCommand(graph: ModuleGraph; cache: IdentCache) =
when compiles(modules.gFuzzyGraphChecking):
modules.gFuzzyGraphChecking = true
proc mainCommand(cache: IdentCache) =
clearPasses() clearPasses()
registerPass verbosePass registerPass verbosePass
registerPass semPass registerPass semPass
@ -368,26 +367,23 @@ proc mainCommand(cache: IdentCache) =
case gMode case gMode
of mstdin: of mstdin:
beCompatible() compileProject(graph, cache)
compileProject(cache)
#modules.gFuzzyGraphChecking = false #modules.gFuzzyGraphChecking = false
serveStdin(cache) serveStdin(graph, cache)
of mtcp: of mtcp:
# until somebody accepted the connection, produce no output (logging is too # until somebody accepted the connection, produce no output (logging is too
# slow for big projects): # slow for big projects):
msgs.writelnHook = proc (msg: string) = discard msgs.writelnHook = proc (msg: string) = discard
beCompatible() compileProject(graph, cache)
compileProject(cache)
#modules.gFuzzyGraphChecking = false #modules.gFuzzyGraphChecking = false
serveTcp(cache) serveTcp(graph, cache)
of mepc: of mepc:
beCompatible()
var server = newSocket() var server = newSocket()
let port = connectToNextFreePort(server, "localhost") let port = connectToNextFreePort(server, "localhost")
server.listen() server.listen()
echo port echo port
compileProject(cache) compileProject(graph, cache)
serveEpc(server, cache) serveEpc(server, graph, cache)
proc processCmdLine*(pass: TCmdLinePass, cmd: string) = proc processCmdLine*(pass: TCmdLinePass, cmd: string) =
var p = parseopt.initOptParser(cmd) var p = parseopt.initOptParser(cmd)
@ -464,7 +460,9 @@ proc handleCmdLine(cache: IdentCache) =
extccomp.initVars() extccomp.initVars()
processCmdLine(passCmd2, "") processCmdLine(passCmd2, "")
mainCommand(cache) let graph = newModuleGraph()
graph.suggestMode = true
mainCommand(graph, cache)
when false: when false:
proc quitCalled() {.noconv.} = proc quitCalled() {.noconv.} =

View file

@ -27,7 +27,7 @@ proc parseTest(filename: string): Test =
for x in lines(filename): for x in lines(filename):
let marker = x.find(cursorMarker)+1 let marker = x.find(cursorMarker)+1
if marker > 0: if marker > 0:
markers.add filename & ";" & dest & ":" & $i & ":" & $marker markers.add "\"" & filename & "\";\"" & dest & "\":" & $i & ":" & $marker
tmp.writeLine x.replace(cursorMarker, "") tmp.writeLine x.replace(cursorMarker, "")
else: else:
tmp.writeLine x tmp.writeLine x