CaaS in-memory caching

removed some redundant filepath params and variables and
switched to canonical paths in most places
This commit is contained in:
Zahary Karadjov
2012-11-16 01:48:12 +02:00
parent 091c1b3075
commit 36e25a6849
23 changed files with 299 additions and 215 deletions

View File

@@ -824,6 +824,14 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
s.typ = t
result = s
template fileIdx*(c: PSym): int32 =
# XXX: this should be used only on module symbols
c.position.int32
template filename*(c: PSym): string =
# XXX: this should be used only on module symbols
c.position.int32.toFileName
proc appendToModule*(m: PSym, n: PNode) =
## The compiler will use this internally to add nodes that will be
## appended to the module after the sem pass

View File

@@ -991,8 +991,8 @@ proc genModule(m: BModule, cfilenoext: string): PRope =
app(result, m.s[i])
app(result, genSectionEnd(i))
app(result, m.s[cfsInitProc])
proc rawNewModule(module: PSym, filename: string): BModule =
proc rawNewModule(module: PSym, filename: string): BModule =
new(result)
InitLinkedList(result.headerFiles)
result.declaredThings = initIntSet()
@@ -1013,17 +1013,20 @@ proc rawNewModule(module: PSym, filename: string): BModule =
result.nimTypesName = getTempName()
result.PreventStackTrace = sfSystemModule in module.flags
proc newModule(module: PSym, filename: string): BModule =
result = rawNewModule(module, filename)
proc rawNewModule(module: PSym): BModule =
result = rawNewModule(module, module.filename)
proc newModule(module: PSym): BModule =
result = rawNewModule(module)
if gModules.len <= module.position: gModules.setLen(module.position + 1)
gModules[module.position] = result
if (optDeadCodeElim in gGlobalOptions):
if (sfDeadCodeElim in module.flags):
InternalError("added pending module twice: " & filename)
InternalError("added pending module twice: " & module.filename)
proc myOpen(module: PSym, filename: string): PPassContext =
result = newModule(module, filename)
proc myOpen(module: PSym): PPassContext =
result = newModule(module)
if optGenIndex in gGlobalOptions and generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull
generatedHeader = rawNewModule(module,
@@ -1053,9 +1056,8 @@ proc writeHeader(m: BModule) =
proc getCFile(m: BModule): string =
result = changeFileExt(completeCFilePath(m.cfilename), cExt)
proc myOpenCached(module: PSym, filename: string,
rd: PRodReader): PPassContext =
var m = newModule(module, filename)
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
var m = newModule(module)
readMergeInfo(getCFile(m), m)
result = m
@@ -1149,10 +1151,16 @@ proc myClose(b: PPassContext, n: PNode): PNode =
# order anyway)
if generatedHeader != nil: finishModule(generatedHeader)
while gForwardedProcsCounter > 0:
for i in countup(0, high(gModules)):
finishModule(gModules[i])
for i in countup(0, high(gModules)):
# some modules (like stdin) may exist only in memory
# they won't have a cgen BModule for them and we must
# skip them
if gModules[i] != nil:
finishModule(gModules[i])
for i in countup(0, high(gModules)):
writeModule(gModules[i], pending=true)
# see above
if gModules[i] != nil:
writeModule(gModules[i], pending=true)
writeMapping(gMapping)
if generatedHeader != nil: writeHeader(generatedHeader)

View File

@@ -17,7 +17,6 @@ proc generateDot*(project: string)
type
TGen = object of TPassContext
module*: PSym
filename*: string
PGen = ref TGen
var gDotGraph: PRope # the generated DOT file; we need a global variable
@@ -47,11 +46,10 @@ proc generateDot(project: string) =
toRope(changeFileExt(extractFileName(project), "")), gDotGraph]),
changeFileExt(project, "dot"))
proc myOpen(module: PSym, filename: string): PPassContext =
proc myOpen(module: PSym): PPassContext =
var g: PGen
new(g)
g.module = module
g.filename = filename
result = g
const gendependPass* = makePass(open = myOpen, process = addDotDependency)

View File

@@ -337,7 +337,7 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
writeRope(content, getOutFile(filename, outExt), useWarning)
proc CommandDoc*() =
var ast = parseFile(addFileExt(gProjectFull, nimExt))
var ast = parseFile(gProjectMainIdx)
if ast == nil: return
var d = newDocumentor(gProjectFull, options.gConfigVars)
d.hasToc = true

View File

@@ -17,14 +17,13 @@ type
TGen = object of TPassContext
doc: PDoc
module: PSym
filename: string
PGen = ref TGen
proc close(p: PPassContext, n: PNode): PNode =
var g = PGen(p)
let useWarning = sfMainModule notin g.module.flags
if gWholeProject or sfMainModule in g.module.flags:
writeOutput(g.doc, g.filename, HtmlExt, useWarning)
writeOutput(g.doc, g.module.filename, HtmlExt, useWarning)
try:
generateIndex(g.doc)
except EIO:
@@ -35,12 +34,11 @@ proc processNode(c: PPassContext, n: PNode): PNode =
var g = PGen(c)
generateDoc(g.doc, n)
proc myOpen(module: PSym, filename: string): PPassContext =
proc myOpen(module: PSym): PPassContext =
var g: PGen
new(g)
g.module = module
g.filename = filename
var d = newDocumentor(filename, options.gConfigVars)
var d = newDocumentor(module.filename, options.gConfigVars)
d.hasToc = true
g.doc = d
result = g

View File

@@ -1549,9 +1549,8 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
var globals: PGlobals
proc newModule(module: PSym, filename: string): BModule =
proc newModule(module: PSym): BModule =
new(result)
result.filename = filename
result.module = module
if globals == nil: globals = newGlobals()
@@ -1612,11 +1611,11 @@ proc myClose(b: PPassContext, n: PNode): PNode =
var outfile = changeFileExt(completeCFilePath(m.filename), "js")
discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
proc myOpenCached(s: PSym, filename: string, rd: PRodReader): PPassContext =
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
InternalError("symbol files are not possible with the Ecmas code generator")
result = nil
proc myOpen(s: PSym, filename: string): PPassContext =
result = newModule(s, filename)
proc myOpen(s: PSym): PPassContext =
result = newModule(s)
const ecmasgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)

View File

@@ -61,8 +61,7 @@ proc newStackFrame*(): PStackFrame =
initIdNodeTable(result.mapping)
result.params = @[]
proc newEvalContext*(module: PSym, filename: string,
mode: TEvalMode): PEvalContext =
proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
new(result)
result.module = module
result.mode = mode
@@ -1392,7 +1391,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
stackTrace(c, n, errCannotInterpretNodeX, renderTree(n))
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
var p = newEvalContext(module, "", mode)
var p = newEvalContext(module, mode)
var s = newStackFrame()
s.call = e
pushStackFrame(p, s)
@@ -1432,8 +1431,8 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
dec(evalTemplateCounter)
c.callsite = nil
proc myOpen(module: PSym, filename: string): PPassContext =
var c = newEvalContext(module, filename, emRepl)
proc myOpen(module: PSym): PPassContext =
var c = newEvalContext(module, emRepl)
pushStackFrame(c, newStackFrame())
result = c

View File

@@ -32,12 +32,15 @@ proc getModuleName*(n: PNode): string =
internalError(n.info, "getModuleName")
result = ""
proc checkModuleName*(n: PNode): string =
proc checkModuleName*(n: PNode): int32 =
# This returns the full canonical path for a given module import
var modulename = n.getModuleName
result = findModule(modulename)
if result.len == 0:
let modulename = n.getModuleName
let fullPath = findModule(modulename)
if fullPath.len == 0:
LocalError(n.info, errCannotOpenFile, modulename)
result = InvalidFileIDX
else:
result = fullPath.fileInfoIdx
proc rawImportSymbol(c: PContext, s: PSym) =
# This does not handle stubs, because otherwise loading on demand would be
@@ -111,8 +114,8 @@ proc evalImport(c: PContext, n: PNode): PNode =
result = n
for i in countup(0, sonsLen(n) - 1):
var f = checkModuleName(n.sons[i])
if f.len > 0:
var m = gImportModule(f)
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
if sfDeprecated in m.flags:
Message(n.sons[i].info, warnDeprecated, m.name.s)
# ``addDecl`` needs to be done before ``importAllSymbols``!
@@ -123,8 +126,8 @@ proc evalFrom(c: PContext, n: PNode): PNode =
result = n
checkMinSonsLen(n, 2)
var f = checkModuleName(n.sons[0])
if f.len > 0:
var m = gImportModule(f)
if f != InvalidFileIDX:
var m = gImportModule(c.module, f)
n.sons[0] = newSymNode(m)
addDecl(c, m) # add symbol to symbol table of module
for i in countup(1, sonsLen(n) - 1): importSymbol(c, n.sons[i], m)

View File

@@ -126,7 +126,7 @@ proc pushInd*(L: var TLexer, indent: int)
proc popInd*(L: var TLexer)
proc isKeyword*(kind: TTokType): bool
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream)
proc openLexer*(lex: var TLexer, fileidx: int32, inputstream: PLLStream)
proc rawGetTok*(L: var TLexer, tok: var TToken)
# reads in the next token into tok and skips it
proc getColumn*(L: TLexer): int
@@ -135,6 +135,9 @@ proc closeLexer*(lex: var TLexer)
proc PrintTok*(tok: TToken)
proc tokToStr*(tok: TToken): string
proc openLexer*(lex: var TLexer, filename: string, inputstream: PLLStream) =
OpenLexer(lex, filename.fileInfoIdx, inputStream)
proc lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
proc isKeyword(kind: TTokType): bool =
@@ -211,10 +214,10 @@ proc fillToken(L: var TToken) =
L.base = base10
L.ident = dummyIdent
proc openLexer(lex: var TLexer, filename: string, inputstream: PLLStream) =
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
openBaseLexer(lex, inputstream)
lex.indentStack = @[0]
lex.fileIdx = filename.fileInfoIdx
lex.fileIdx = fileIdx
lex.indentAhead = - 1
inc(lex.Linenumber, inputstream.lineOffset)

View File

@@ -12,11 +12,11 @@
import
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
os, lists, condsyms, rodread, rodwrite, ropes, trees,
os, lists, condsyms, rodread, rodwrite, ropes, trees, times,
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
cgen, ecmasgen,
platform, nimconf, importer, passaux, depends, evals, types, idgen,
tables, docgen2, service, magicsys, parser
tables, docgen2, service, magicsys, parser, crc
const
has_LLVM_Backend = false
@@ -28,60 +28,113 @@ proc MainCommand*()
# ------------------ module handling -----------------------------------------
type
TModuleInMemory = object
compiledAt: float
crc: int
deps: seq[int32] ## XXX: slurped files are not currently tracked
needsRecompile: bool
var
compMods = initTable[string, PSym]() # all compiled modules
gCompiledModules: seq[PSym] = @[]
gMemCacheData: seq[TModuleInMemory] = @[]
## XXX: we should implement recycling of file IDs
## if the user keeps renaming modules, the file IDs will keep growing
# This expects a normalized module path
proc registerModule(filename: string, module: PSym) =
compMods[filename] = module
proc getModule(fileIdx: int32): PSym =
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
result = gCompiledModules[fileIdx]
else:
result = nil
# This expects a normalized module path
proc getModule(filename: string): PSym =
result = compMods[filename]
template compiledAt(x: PSym): expr =
gMemCacheData[x.position].compiledAt
var gModulesCount = 0
proc newModule(filename: string): PSym =
template crc(x: PSym): expr =
gMemCacheData[x.position].crc
template addDep(x: Psym, dep: int32) =
gMemCacheData[x.position].deps.add(dep)
proc checkDepMem(fileIdx: int32): bool =
template markDirty =
gMemCacheData[fileIdx].needsRecompile = true
return true
if optForceFullMake in gGlobalOptions or
curCaasCmd != lastCaasCmd: markDirty
let crc = crcFromFile(fileIdx.toFilename)
if crc != gMemCacheData[fileIdx].crc: markDirty
for dep in gMemCacheData[fileIdx].deps:
if checkDepMem(dep): markDirty
return false
proc newModule(fileIdx: int32): PSym =
# We cannot call ``newSym`` here, because we have to circumvent the ID
# mechanism, which we do in order to assign each module a persistent ID.
new(result)
result.id = - 1 # for better error checking
result.kind = skModule
let filename = fileIdx.toFilename
result.name = getIdent(splitFile(filename).name)
if not isNimrodIdentifier(result.name.s):
rawMessage(errInvalidModuleName, result.name.s)
result.owner = result # a module belongs to itself
result.info = newLineInfo(filename, 1, 1)
result.position = gModulesCount
inc gModulesCount
result.info = newLineInfo(fileIdx, 1, 1)
result.position = fileIdx
growCache gMemCacheData, fileIdx
growCache gCompiledModules, fileIdx
gCompiledModules[result.position] = result
incl(result.flags, sfUsed)
initStrTable(result.tab)
RegisterModule(filename, result)
StrTableAdd(result.tab, result) # a module knows itself
proc CompileModule(filename: string, flags: TSymFlags): PSym
proc importModule(filename: string): PSym =
proc compileModule(fileIdx: int32, flags: TSymFlags): PSym =
result = getModule(fileIdx)
if result == nil:
result = newModule(fileIdx)
var rd = handleSymbolFile(result)
result.flags = result.flags + flags
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result)
if result.id < 0:
InternalError("handleSymbolFile should have set the module\'s ID")
return
else:
result.id = getID()
processModule(result, nil, rd)
gMemCacheData[fileIdx].compiledAt = gLastCmdTime
gMemCacheData[fileIdx].needsRecompile = false
else:
InternalAssert optCaasEnabled in gGlobalOptions
if checkDepMem(fileIdx):
gCompiledModules[fileIdx] = nil
result = CompileModule(fileIdx, flags)
else:
result = gCompiledModules[fileIdx]
proc compileModule(filename: string, flags: TSymFlags): PSym =
result = compileModule(filename.fileInfoIdx, flags)
proc importModule(s: PSym, fileIdx: int32): PSym =
# this is called by the semantic checking phase
result = getModule(filename)
result = getModule(fileIdx)
if result == nil:
# compile the module
result = compileModule(filename, {})
result = compileModule(fileIdx, {})
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
elif sfSystemModule in result.flags:
LocalError(result.info, errAttemptToRedefine, result.Name.s)
proc CompileModule(filename: string, flags: TSymFlags): PSym =
var rd: PRodReader = nil
var f = addFileExt(filename, nimExt)
result = newModule(f)
result.flags = result.flags + flags
if gCmd in {cmdCompileToC, cmdCompileToCpp, cmdCheck, cmdIdeTools}:
rd = handleSymbolFile(result, f)
if result.id < 0:
InternalError("handleSymbolFile should have set the module\'s ID")
return
else:
result.id = getID()
processModule(result, f, nil, rd)
proc includeModule(s: PSym, fileIdx: int32): PNode =
result = syntaxes.parseFile(fileIdx)
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
proc `==^`(a, b: string): bool =
try:
@@ -91,7 +144,8 @@ proc `==^`(a, b: string): bool =
proc compileSystemModule =
if magicsys.SystemModule == nil:
discard CompileModule(options.libpath /"system", {sfSystemModule})
SystemFileIdx = fileInfoIdx(options.libpath/"system.nim")
discard CompileModule(SystemFileIdx, {sfSystemModule})
proc CompileProject(projectFile = gProjectFull) =
let systemFile = options.libpath / "system"
@@ -140,6 +194,8 @@ proc CommandCompileToC =
compileProject()
if gCmd != cmdRun:
extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
# caas will keep track only of the compilation commands
lastCaasCmd = curCaasCmd
when has_LLVM_Backend:
proc CommandCompileToLLVM =
@@ -171,7 +227,7 @@ proc InteractivePasses =
var stdinModule: PSym
proc makeStdinModule: PSym =
if stdinModule == nil:
stdinModule = newModule("stdin")
stdinModule = newModule(gCmdLineInfo.fileIndex)
stdinModule.id = getID()
result = stdinModule
@@ -184,24 +240,23 @@ proc CommandInteractive =
else:
var m = makeStdinModule()
incl(m.flags, sfMainModule)
processModule(m, "stdin", LLStreamOpenStdIn(), nil)
processModule(m, LLStreamOpenStdIn(), nil)
const evalPasses = [verbosePass, semPass, evalPass]
proc evalNim(nodes: PNode, module: PSym, filename: string) =
# we don't want to mess with gPasses here, because in nimrod serve
# scenario, it may be set up properly for normal cgenPass() compilation
carryPasses(nodes, module, filename, evalPasses)
proc evalNim(nodes: PNode, module: PSym) =
carryPasses(nodes, module, evalPasses)
proc commandEval(exp: string) =
if SystemModule == nil:
InteractivePasses()
compileSystemModule()
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
evalNim(echoExp.parseString, makeStdinModule(), "stdin")
evalNim(echoExp.parseString, makeStdinModule())
proc CommandPretty =
var module = parseFile(addFileExt(mainCommandArg(), NimExt))
var projectFile = addFileExt(mainCommandArg(), NimExt)
var module = parseFile(projectFile.fileInfoIdx)
if module != nil:
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
@@ -231,16 +286,18 @@ proc CommandSuggest =
proc wantMainModule =
if gProjectFull.len == 0:
Fatal(gCmdLineInfo, errCommandExpectsFilename)
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
proc MainCommand =
# In "nimrod serve" scenario, each command must reset the registered passes
clearPasses()
gLastCmdTime = epochTime()
appendStr(searchPaths, options.libpath)
if gProjectFull.len != 0:
# current path is always looked first for modules
prependStr(searchPaths, gProjectPath)
setID(100)
passes.gIncludeFile = syntaxes.parseFile
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
case command.normalize
of "c", "cc", "compile", "compiletoc":
@@ -323,7 +380,7 @@ proc MainCommand =
of "parse":
gCmd = cmdParse
wantMainModule()
discard parseFile(addFileExt(gProjectFull, nimExt))
discard parseFile(gProjectMainIdx)
of "scan":
gCmd = cmdScan
wantMainModule()
@@ -343,9 +400,14 @@ proc MainCommand =
wantMainModule()
CommandSuggest()
of "serve":
gCmd = cmdIdeTools
gGlobalOptions.incl(optCaasEnabled)
msgs.gErrorMax = high(int) # do not stop after first error
serve(MainCommand)
else: rawMessage(errInvalidCommandX, command)
if msgs.gErrorCounter == 0 and gCmd notin {cmdInterpret, cmdRun}:
rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
formatSize(getTotalMem())])

View File

@@ -416,9 +416,13 @@ type
ERecoverableError* = object of EInvalidValue
ESuggestDone* = object of EBase
const
InvalidFileIDX* = int32(-1)
var
filenameToIndexTbl = initTable[string, int32]()
fileInfos: seq[TFileInfo] = @[]
fileInfos*: seq[TFileInfo] = @[]
SystemFileIdx*: int32
proc newFileInfo(fullPath, projPath: string): TFileInfo =
result.fullPath = fullPath

View File

@@ -14,7 +14,7 @@ when defined(gcc) and defined(windows):
{.link: "icons/nimrod_icon.o".}
import
times, commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
commands, lexer, condsyms, options, msgs, nversion, nimconf, ropes,
extccomp, strutils, os, platform, main, parseopt, service
when hasTinyCBackend:
@@ -32,7 +32,6 @@ proc prependCurDir(f: string): string =
result = f
proc HandleCmdLine() =
var start = epochTime()
if paramCount() == 0:
writeCommandLineUsage()
else:
@@ -60,10 +59,6 @@ proc HandleCmdLine() =
when hasTinyCBackend:
if gCmd == cmdRun:
tccgen.run()
if gCmd notin {cmdInterpret, cmdRun}:
rawMessage(hintSuccessX, [$gLinesCompiled,
formatFloat(epochTime() - start, ffDecimal, 3),
formatSize(getTotalMem())])
if optRun in gGlobalOptions:
if gCmd == cmdCompileToEcmaScript:
var ex = quoteIfContainsWhite(

View File

@@ -43,6 +43,7 @@ type # please make sure we have under 32 options
optGenMapping, # generate a mapping file
optRun, # run the compiled project
optSymbolFiles, # use symbol files for speeding up compilation
optCaasEnabled # compiler-as-a-service is running
optSkipConfigFile, # skip the general config file
optSkipProjConfigFile, # skip the project's config file
optSkipUserConfigFile, # skip the users's config file
@@ -96,6 +97,7 @@ var
gNumberOfProcessors*: int # number of processors
gWholeProject*: bool # for 'doc2': output any dependency
gEvalExpr*: string # expression for idetools --eval
gLastCmdTime*: float # when caas is enabled, we measure each command
const
genSubDir* = "nimcache"
@@ -115,6 +117,7 @@ var
gProjectName* = "" # holds a name like 'nimrod'
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
gProjectFull* = "" # projectPath/projectName
gProjectMainIdx*: int32 # the canonical path id of the main module
nimcacheDir* = ""
command* = "" # the main command (e.g. cc, check, scan, etc)
commandArgs*: seq[string] = @[] # any arguments after the main command

View File

@@ -64,11 +64,14 @@ proc parseCase(p: var TParser): PNode
proc getTok(p: var TParser) =
rawGetTok(p.lex, p.tok)
proc OpenParser(p: var TParser, filename: string, inputStream: PLLStream) =
proc OpenParser*(p: var TParser, fileIdx: int32, inputStream: PLLStream) =
initToken(p.tok)
OpenLexer(p.lex, filename, inputstream)
OpenLexer(p.lex, fileIdx, inputstream)
getTok(p) # read the first token
proc OpenParser*(p: var TParser, filename: string, inputStream: PLLStream) =
openParser(p, filename.fileInfoIdx, inputStream)
proc CloseParser(p: var TParser) =
CloseLexer(p.lex)

View File

@@ -12,7 +12,7 @@
import
strutils, ast, astalgo, passes, msgs, options, idgen
proc verboseOpen(s: PSym, filename: string): PPassContext =
proc verboseOpen(s: PSym): PPassContext =
#MessageOut('compiling ' + s.name.s);
result = nil # we don't need a context
if gVerbosity > 0: rawMessage(hintProcessing, s.name.s)
@@ -29,7 +29,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)
proc cleanUp(c: PPassContext, n: PNode): PNode =
result = n
result = n
# we cannot clean up if dead code elimination is activated
if optDeadCodeElim in gGlobalOptions or n == nil: return
case n.kind

View File

@@ -21,9 +21,9 @@ type
PPassContext* = ref TPassContext
TPassOpen* = proc (module: PSym, filename: string): PPassContext {.nimcall.}
TPassOpenCached* = proc (module: PSym, filename: string,
rd: PRodReader): PPassContext {.nimcall.}
TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
TPassOpenCached* =
proc (module: PSym, rd: PRodReader): PPassContext {.nimcall.}
TPassClose* = proc (p: PPassContext, n: PNode): PNode {.nimcall.}
TPassProcess* = proc (p: PPassContext, topLevelStmt: PNode): PNode {.nimcall.}
@@ -50,13 +50,12 @@ proc makePass*(open: TPassOpen = nil,
# processed in a pipeline. The compiler never looks at a whole module
# any longer. However, this is simple to change, as new passes may perform
# whole program optimizations. For now, we avoid it to save a lot of memory.
proc processModule*(module: PSym, filename: string, stream: PLLStream,
rd: PRodReader)
proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
# the semantic checker needs these:
var
gImportModule*: proc (filename: string): PSym {.nimcall.}
gIncludeFile*: proc (filename: string): PNode {.nimcall.}
gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
# implementation
@@ -96,30 +95,28 @@ proc registerPass*(p: TPass) =
gPasses[gPassesLen] = p
inc(gPassesLen)
proc carryPass*(p: TPass, module: PSym, filename: string,
m: TPassData): TPassData =
var c = p.open(module, filename)
proc carryPass*(p: TPass, module: PSym, m: TPassData): TPassData =
var c = p.open(module)
result.input = p.process(c, m.input)
result.closeOutput = if p.close != nil: p.close(c, m.closeOutput)
else: m.closeOutput
proc carryPasses*(nodes: PNode, module: PSym, file: string, passes: TPasses) =
proc carryPasses*(nodes: PNode, module: PSym, passes: TPasses) =
var passdata: TPassData
passdata.input = nodes
for pass in passes:
passdata = carryPass(pass, module, file, passdata)
passdata = carryPass(pass, module, passdata)
proc openPasses(a: var TPassContextArray, module: PSym, filename: string) =
proc openPasses(a: var TPassContextArray, module: PSym) =
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].open):
a[i] = gPasses[i].open(module, filename)
a[i] = gPasses[i].open(module)
else: a[i] = nil
proc openPassesCached(a: var TPassContextArray, module: PSym, filename: string,
rd: PRodReader) =
proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
for i in countup(0, gPassesLen - 1):
if not isNil(gPasses[i].openCached):
a[i] = gPasses[i].openCached(module, filename, rd)
a[i] = gPasses[i].openCached(module, rd)
if a[i] != nil:
a[i].fromCache = true
else:
@@ -162,23 +159,24 @@ proc processImplicits(implicits: seq[string], nodeKind: TNodeKind,
importStmt.addSon str
if not processTopLevelStmt(importStmt, a): break
proc processModule(module: PSym, filename: string, stream: PLLStream,
rd: PRodReader) =
proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
var
p: TParsers
a: TPassContextArray
s: PLLStream
fileIdx = module.fileIdx
if rd == nil:
openPasses(a, module, filename)
openPasses(a, module)
if stream == nil:
let filename = fileIdx.toFilename
s = LLStreamOpen(filename, fmRead)
if s == nil:
rawMessage(errCannotOpenFile, filename)
return
return
else:
s = stream
while true:
openParsers(p, filename, s)
openParsers(p, fileIdx, s)
if sfSystemModule notin module.flags:
# XXX what about caching? no processing then? what if I change the
@@ -199,7 +197,7 @@ proc processModule(module: PSym, filename: string, stream: PLLStream,
# id synchronization point for more consistent code generation:
IDsynchronizationPoint(1000)
else:
openPassesCached(a, module, filename, rd)
openPassesCached(a, module, rd)
var n = loadInitSection(rd)
for i in countup(0, sonsLen(n) - 1): processTopLevelStmtCached(n.sons[i], a)
closePassesCached(a)

View File

@@ -126,7 +126,7 @@ type
s: cstring # mmap'ed file contents
options: TOptions
reason: TReasonForRecompile
modDeps: TStringSeq
modDeps: seq[int32]
files: TStringSeq
dataIdx: int # offset of start of data section
convertersIdx: int # offset of start of converters section
@@ -145,7 +145,7 @@ type
var rodCompilerprocs*: TStrTable
proc handleSymbolFile*(module: PSym, filename: string): PRodReader
proc handleSymbolFile*(module: PSym): PRodReader
# global because this is needed by magicsys
proc loadInitSection*(r: PRodReader): PNode
@@ -602,7 +602,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
of "DEPS":
inc(r.pos) # skip ':'
while r.s[r.pos] > '\x0A':
r.modDeps.add r.files[decodeVInt(r.s, r.pos)]
r.modDeps.add int32(decodeVInt(r.s, r.pos))
if r.s[r.pos] == ' ': inc(r.pos)
of "INTERF":
r.interfIdx = r.pos + 2
@@ -699,10 +699,11 @@ type
reason*: TReasonForRecompile
rd*: PRodReader
crc*: TCrc32
crcDone*: bool
TFileModuleMap = seq[TFileModuleRec]
var gMods: TFileModuleMap = @[]
var gMods*: TFileModuleMap = @[]
proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
# all compiled modules
@@ -720,6 +721,10 @@ proc findSomeWhere(id: int) =
if d != invalidKey:
echo "found id ", id, " in ", gMods[i].filename
proc getReader(moduleId: int): PRodReader =
InternalAssert moduleId >= 0 and moduleId < gMods.len
result = gMods[moduleId].rd
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
result = PSym(IdTableGet(r.syms, id))
if result == nil:
@@ -732,25 +737,15 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
var x = ""
encodeVInt(id, x)
InternalError(info, "missing from both indexes: +" & x)
# find the reader with the correct moduleID:
for i in countup(0, high(gMods)):
var rd = gMods[i].rd
if rd != nil:
if rd.moduleID == moduleID:
d = IITableGet(rd.index.tab, id)
if d != invalidKey:
result = decodeSymSafePos(rd, d, info)
break
else:
var x = ""
encodeVInt(id, x)
when false: findSomeWhere(id)
InternalError(info, "rrGetSym: no reader found: +" & x)
else:
#if IiTableGet(rd.index.tab, id) <> invalidKey then
# XXX expensive check!
#InternalError(info,
#'id found in other module: +' + ropeToStr(encodeInt(id)))
var rd = getReader(moduleID)
d = IITableGet(rd.index.tab, id)
if d != invalidKey:
result = decodeSymSafePos(rd, d, info)
else:
var x = ""
encodeVInt(id, x)
when false: findSomeWhere(id)
InternalError(info, "rrGetSym: no reader found: +" & x)
else:
# own symbol:
result = decodeSymSafePos(r, d, info)
@@ -789,27 +784,32 @@ proc loadMethods(r: PRodReader) =
var d = decodeVInt(r.s, r.pos)
r.methods.add(rrGetSym(r, d, UnknownLineInfo()))
if r.s[r.pos] == ' ': inc(r.pos)
proc getModuleIdx(filename: string): int =
for i in countup(0, high(gMods)):
if gMods[i].filename == filename: return i
result = len(gMods)
setlen(gMods, result + 1)
proc checkDep(filename: string): TReasonForRecompile =
assert(not isNil(filename))
var idx = getModuleIdx(filename)
if gMods[idx].reason != rrEmpty:
proc GetCRC*(fileIdx: int32): TCrc32 =
InternalAssert fileIdx >= 0 and fileIdx < gMods.len
if gMods[fileIdx].crcDone:
return gMods[fileIdx].crc
result = crcFromFile(fileIdx.toFilename)
gMods[fileIdx].crc = result
template growCache*(cache, pos) =
if cache.len <= fileIdx: cache.setLen(pos+1)
proc checkDep(fileIdx: int32): TReasonForRecompile =
assert fileIdx != InvalidFileIDX
growCache gMods, fileIdx
if gMods[fileIdx].reason != rrEmpty:
# reason has already been computed for this module:
return gMods[idx].reason
var crc: TCrc32 = crcFromFile(filename)
gMods[idx].reason = rrNone # we need to set it here to avoid cycles
gMods[idx].filename = filename
gMods[idx].crc = crc
return gMods[fileIdx].reason
let filename = fileIdx.toFilename
var crc = GetCRC(fileIdx)
gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles
result = rrNone
var r: PRodReader = nil
var rodfile = toGeneratedFile(filename, RodExt)
r = newRodReader(rodfile, crc, idx)
r = newRodReader(rodfile, crc, fileIdx)
if r == nil:
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else:
@@ -819,7 +819,7 @@ proc checkDep(filename: string): TReasonForRecompile =
# NOTE: we need to process the entire module graph so that no ID will
# be used twice! However, compilation speed does not suffer much from
# this, since results are cached.
var res = checkDep(options.libpath / addFileExt("system", nimExt))
var res = checkDep(SystemFileIdx)
if res != rrNone: result = rrModDeps
for i in countup(0, high(r.modDeps)):
res = checkDep(r.modDeps[i])
@@ -832,19 +832,19 @@ proc checkDep(filename: string): TReasonForRecompile =
# recompilation is necessary:
if r != nil: memfiles.close(r.memFile)
r = nil
gMods[idx].rd = r
gMods[idx].reason = result # now we know better
gMods[fileIdx].rd = r
gMods[fileIdx].reason = result # now we know better
proc handleSymbolFile(module: PSym, filename: string): PRodReader =
proc handleSymbolFile(module: PSym): PRodReader =
let fileIdx = module.fileIdx
if optSymbolFiles notin gGlobalOptions:
module.id = getID()
return nil
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
discard checkDep(filename)
var idx = getModuleIdx(filename)
if gMods[idx].reason == rrEmpty: InternalError("handleSymbolFile")
result = gMods[idx].rd
discard checkDep(fileIdx)
if gMods[fileIdx].reason == rrEmpty: InternalError("handleSymbolFile")
result = gMods[fileIdx].rd
if result != nil:
module.id = result.moduleID
IdTablePut(result.syms, module, module)
@@ -854,14 +854,6 @@ proc handleSymbolFile(module: PSym, filename: string): PRodReader =
loadMethods(result)
else:
module.id = getID()
proc GetCRC*(filename: string): TCrc32 =
for i in countup(0, high(gMods)):
if gMods[i].filename == filename: return gMods[i].crc
result = crcFromFile(filename)
#var idx = getModuleIdx(filename)
#result = gMods[idx].crc
proc rawLoadStub(s: PSym) =
if s.kind != skStub: InternalError("loadStub")

View File

@@ -31,14 +31,13 @@ type
converters, methods: string
init: string
data: string
filename: string
sstack: TSymSeq # a stack of symbols to process
tstack: TTypeSeq # a stack of types to process
files: TStringSeq
PRodWriter = ref TRodWriter
proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter
proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter
proc addModDep(w: PRodWriter, dep: string)
proc addInclDep(w: PRodWriter, dep: string)
proc addInterfaceSym(w: PRodWriter, s: PSym)
@@ -63,7 +62,10 @@ proc fileIdx(w: PRodWriter, filename: string): int =
setlen(w.files, result + 1)
w.files[result] = filename
proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
template filename*(w: PRodWriter): string =
w.module.filename
proc newRodWriter(crc: TCrc32, module: PSym): PRodWriter =
new(result)
result.sstack = @[]
result.tstack = @[]
@@ -71,7 +73,6 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
InitIITable(result.imports.tab)
result.index.r = ""
result.imports.r = ""
result.filename = modfilename
result.crc = crc
result.module = module
result.defines = getDefines()
@@ -570,9 +571,9 @@ proc process(c: PPassContext, n: PNode): PNode =
else:
nil
proc myOpen(module: PSym, filename: string): PPassContext =
proc myOpen(module: PSym): PPassContext =
if module.id < 0: InternalError("rodwrite: module ID not set")
var w = newRodWriter(filename, rodread.GetCRC(module.info.toFullPath), module)
var w = newRodWriter(module.fileIdx.GetCRC, module)
rawAddInterfaceSym(w, module)
result = w

View File

@@ -158,7 +158,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
if c.evalContext == nil:
c.evalContext = newEvalContext(c.module, "", emStatic)
c.evalContext = newEvalContext(c.module, emStatic)
c.evalContext.getType = proc (n: PNode): PNode =
var e = tryExpr(c, n)
if e == nil:
@@ -201,8 +201,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
result = semExpr(c, n, {})
proc myOpen(module: PSym, filename: string): PPassContext =
var c = newContext(module, filename)
proc myOpen(module: PSym): PPassContext =
var c = newContext(module)
if c.p != nil: InternalError(module.info, "sem.myOpen")
c.semConstExpr = semConstExpr
c.semExpr = semExprNoFlags
@@ -222,9 +222,8 @@ proc myOpen(module: PSym, filename: string): PPassContext =
openScope(c.tab) # scope for the module's symbols
result = c
proc myOpenCached(module: PSym, filename: string,
rd: PRodReader): PPassContext =
result = myOpen(module, filename)
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
result = myOpen(module)
for m in items(rd.methods): methodDef(m, true)
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =

View File

@@ -81,7 +81,6 @@ type
filter: TSymKinds): PNode {.nimcall.}
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
includedFiles*: TIntSet # used to detect recursive include files
filename*: string # the module's filename
userPragmas*: TStrTable
evalContext*: PEvalContext
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
@@ -90,12 +89,16 @@ type
var
gGenericsCache: PGenericsCache # save for modularity
proc filename*(c: PContext): string =
# the module's filename
return c.module.filename
proc newGenericsCache*(): PGenericsCache =
new(result)
initIdTable(result.InstTypes)
result.generics = @[]
proc newContext*(module: PSym, nimfile: string): PContext
proc newContext*(module: PSym): PContext
proc lastOptionEntry*(c: PContext): POptionEntry
proc newOptionEntry*(): POptionEntry
@@ -152,7 +155,7 @@ proc newOptionEntry(): POptionEntry =
result.dynlib = nil
result.notes = gNotes
proc newContext(module: PSym, nimfile: string): PContext =
proc newContext(module: PSym): PContext =
new(result)
InitSymTab(result.tab)
result.AmbiguousSymbols = initIntset()
@@ -164,7 +167,6 @@ proc newContext(module: PSym, nimfile: string): PContext =
result.threadEntries = @[]
result.converters = @[]
result.patterns = @[]
result.filename = nimfile
result.includedFiles = initIntSet()
initStrTable(result.userPragmas)
if optSymbolFiles notin gGlobalOptions:

View File

@@ -892,13 +892,12 @@ proc evalInclude(c: PContext, n: PNode): PNode =
addSon(result, n)
for i in countup(0, sonsLen(n) - 1):
var f = checkModuleName(n.sons[i])
if f.len > 0:
var fileIndex = f.fileInfoIdx
if ContainsOrIncl(c.includedFiles, fileIndex):
LocalError(n.info, errRecursiveDependencyX, f.extractFilename)
if f != InvalidFileIDX:
if ContainsOrIncl(c.includedFiles, f):
LocalError(n.info, errRecursiveDependencyX, f.toFilename)
else:
addSon(result, semStmt(c, gIncludeFile(f)))
Excl(c.includedFiles, fileIndex)
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
Excl(c.includedFiles, f)
proc setLine(n: PNode, info: TLineInfo) =
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)

View File

@@ -18,9 +18,14 @@ import
# file changes but expect the client to tell us about them, otherwise the
# repeated CRC calculations may turn out to be too slow.
var
arguments*: string = "" # the arguments to be passed to the program that
# should be run
var
curCaasCmd* = ""
lastCaasCmd* = ""
# in caas mode, the list of defines and options will be given at start-up?
# it's enough to check that the previous compilation command is the same?
arguments* = ""
# the arguments to be passed to the program that
# should be run
proc ProcessCmdLine*(pass: TCmdLinePass, cmd: string) =
var p = parseopt.initOptParser(cmd)
@@ -56,14 +61,18 @@ proc ProcessCmdLine*(pass: TCmdLinePass, cmd: string) =
rawMessage(errArgsNeedRunOption, [])
proc serve*(action: proc (){.nimcall.}) =
template execute(cmd) =
curCaasCmd = cmd
processCmdLine(passCmd2, cmd)
action()
let typ = getConfigVar("server.type")
case typ
of "stdin":
while true:
var line = stdin.readLine.string
if line == "quit": quit()
processCmdLine(passCmd2, line)
action()
execute line
of "tcp", "":
var server = Socket()
let p = getConfigVar("server.port")
@@ -75,8 +84,7 @@ proc serve*(action: proc (){.nimcall.}) =
while true:
accept(server, stdoutSocket)
discard stdoutSocket.recvLine(inp)
processCmdLine(passCmd2, inp.string)
action()
execute inp.string
stdoutSocket.send("\c\L")
stdoutSocket.close()
else:

View File

@@ -30,8 +30,8 @@ type
parser*: TParser
proc ParseFile*(filename: string): PNode{.procvar.}
proc openParsers*(p: var TParsers, filename: string, inputstream: PLLStream)
proc parseFile*(fileIdx: int32): PNode{.procvar.}
proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream)
proc closeParsers*(p: var TParsers)
proc parseAll*(p: var TParsers): PNode
proc parseTopLevelStmt*(p: var TParsers): PNode
@@ -40,14 +40,15 @@ proc parseTopLevelStmt*(p: var TParsers): PNode
# implementation
proc ParseFile(filename: string): PNode =
proc ParseFile(fileIdx: int32): PNode =
var
p: TParsers
f: tfile
if not open(f, filename):
let filename = fileIdx.toFilename
if not open(f, filename):
rawMessage(errCannotOpenFile, filename)
return
OpenParsers(p, filename, LLStreamOpen(f))
OpenParsers(p, fileIdx, LLStreamOpen(f))
result = ParseAll(p)
CloseParsers(p)
@@ -160,15 +161,16 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
else:
result = applyFilter(p, n, filename, result)
proc openParsers(p: var TParsers, filename: string, inputstream: PLLStream) =
proc openParsers(p: var TParsers, fileIdx: int32, inputstream: PLLStream) =
var s: PLLStream
p.skin = skinStandard
let filename = fileIdx.toFilename
var pipe = parsePipe(filename, inputStream)
if pipe != nil: s = evalPipe(p, pipe, filename, inputStream)
else: s = inputStream
case p.skin
of skinStandard, skinBraces, skinEndX:
parser.openParser(p.parser, filename, s)
of skinStandard, skinBraces, skinEndX:
parser.openParser(p.parser, fileIdx, s)
proc closeParsers(p: var TParsers) =
parser.closeParser(p.parser)