CaaS in-memory caching
removed some redundant filepath params and variables and switched to canonical paths in most places
This commit is contained in:
parent
091c1b3075
commit
36e25a6849
23 changed files with 299 additions and 215 deletions
|
|
@ -824,6 +824,14 @@ proc linkTo*(s: PSym, t: PType): PSym {.discardable.} =
|
||||||
s.typ = t
|
s.typ = t
|
||||||
result = s
|
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) =
|
proc appendToModule*(m: PSym, n: PNode) =
|
||||||
## The compiler will use this internally to add nodes that will be
|
## The compiler will use this internally to add nodes that will be
|
||||||
## appended to the module after the sem pass
|
## appended to the module after the sem pass
|
||||||
|
|
|
||||||
|
|
@ -1013,17 +1013,20 @@ proc rawNewModule(module: PSym, filename: string): BModule =
|
||||||
result.nimTypesName = getTempName()
|
result.nimTypesName = getTempName()
|
||||||
result.PreventStackTrace = sfSystemModule in module.flags
|
result.PreventStackTrace = sfSystemModule in module.flags
|
||||||
|
|
||||||
proc newModule(module: PSym, filename: string): BModule =
|
proc rawNewModule(module: PSym): BModule =
|
||||||
result = rawNewModule(module, filename)
|
result = rawNewModule(module, module.filename)
|
||||||
|
|
||||||
|
proc newModule(module: PSym): BModule =
|
||||||
|
result = rawNewModule(module)
|
||||||
if gModules.len <= module.position: gModules.setLen(module.position + 1)
|
if gModules.len <= module.position: gModules.setLen(module.position + 1)
|
||||||
gModules[module.position] = result
|
gModules[module.position] = result
|
||||||
|
|
||||||
if (optDeadCodeElim in gGlobalOptions):
|
if (optDeadCodeElim in gGlobalOptions):
|
||||||
if (sfDeadCodeElim in module.flags):
|
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 =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
result = newModule(module, filename)
|
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
|
||||||
generatedHeader = rawNewModule(module,
|
generatedHeader = rawNewModule(module,
|
||||||
|
|
@ -1053,9 +1056,8 @@ proc writeHeader(m: BModule) =
|
||||||
proc getCFile(m: BModule): string =
|
proc getCFile(m: BModule): string =
|
||||||
result = changeFileExt(completeCFilePath(m.cfilename), cExt)
|
result = changeFileExt(completeCFilePath(m.cfilename), cExt)
|
||||||
|
|
||||||
proc myOpenCached(module: PSym, filename: string,
|
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||||
rd: PRodReader): PPassContext =
|
var m = newModule(module)
|
||||||
var m = newModule(module, filename)
|
|
||||||
readMergeInfo(getCFile(m), m)
|
readMergeInfo(getCFile(m), m)
|
||||||
result = m
|
result = m
|
||||||
|
|
||||||
|
|
@ -1150,9 +1152,15 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||||
if generatedHeader != nil: finishModule(generatedHeader)
|
if generatedHeader != nil: finishModule(generatedHeader)
|
||||||
while gForwardedProcsCounter > 0:
|
while gForwardedProcsCounter > 0:
|
||||||
for i in countup(0, high(gModules)):
|
for i in countup(0, high(gModules)):
|
||||||
finishModule(gModules[i])
|
# 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)):
|
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)
|
writeMapping(gMapping)
|
||||||
if generatedHeader != nil: writeHeader(generatedHeader)
|
if generatedHeader != nil: writeHeader(generatedHeader)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ proc generateDot*(project: string)
|
||||||
type
|
type
|
||||||
TGen = object of TPassContext
|
TGen = object of TPassContext
|
||||||
module*: PSym
|
module*: PSym
|
||||||
filename*: string
|
|
||||||
PGen = ref TGen
|
PGen = ref TGen
|
||||||
|
|
||||||
var gDotGraph: PRope # the generated DOT file; we need a global variable
|
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]),
|
toRope(changeFileExt(extractFileName(project), "")), gDotGraph]),
|
||||||
changeFileExt(project, "dot"))
|
changeFileExt(project, "dot"))
|
||||||
|
|
||||||
proc myOpen(module: PSym, filename: string): PPassContext =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
var g: PGen
|
var g: PGen
|
||||||
new(g)
|
new(g)
|
||||||
g.module = module
|
g.module = module
|
||||||
g.filename = filename
|
|
||||||
result = g
|
result = g
|
||||||
|
|
||||||
const gendependPass* = makePass(open = myOpen, process = addDotDependency)
|
const gendependPass* = makePass(open = myOpen, process = addDotDependency)
|
||||||
|
|
|
||||||
|
|
@ -337,7 +337,7 @@ proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) =
|
||||||
writeRope(content, getOutFile(filename, outExt), useWarning)
|
writeRope(content, getOutFile(filename, outExt), useWarning)
|
||||||
|
|
||||||
proc CommandDoc*() =
|
proc CommandDoc*() =
|
||||||
var ast = parseFile(addFileExt(gProjectFull, nimExt))
|
var ast = parseFile(gProjectMainIdx)
|
||||||
if ast == nil: return
|
if ast == nil: return
|
||||||
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
var d = newDocumentor(gProjectFull, options.gConfigVars)
|
||||||
d.hasToc = true
|
d.hasToc = true
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,13 @@ type
|
||||||
TGen = object of TPassContext
|
TGen = object of TPassContext
|
||||||
doc: PDoc
|
doc: PDoc
|
||||||
module: PSym
|
module: PSym
|
||||||
filename: string
|
|
||||||
PGen = ref TGen
|
PGen = ref TGen
|
||||||
|
|
||||||
proc close(p: PPassContext, n: PNode): PNode =
|
proc close(p: PPassContext, n: PNode): PNode =
|
||||||
var g = PGen(p)
|
var g = PGen(p)
|
||||||
let useWarning = sfMainModule notin g.module.flags
|
let useWarning = sfMainModule notin g.module.flags
|
||||||
if gWholeProject or sfMainModule in 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:
|
try:
|
||||||
generateIndex(g.doc)
|
generateIndex(g.doc)
|
||||||
except EIO:
|
except EIO:
|
||||||
|
|
@ -35,12 +34,11 @@ proc processNode(c: PPassContext, n: PNode): PNode =
|
||||||
var g = PGen(c)
|
var g = PGen(c)
|
||||||
generateDoc(g.doc, n)
|
generateDoc(g.doc, n)
|
||||||
|
|
||||||
proc myOpen(module: PSym, filename: string): PPassContext =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
var g: PGen
|
var g: PGen
|
||||||
new(g)
|
new(g)
|
||||||
g.module = module
|
g.module = module
|
||||||
g.filename = filename
|
var d = newDocumentor(module.filename, options.gConfigVars)
|
||||||
var d = newDocumentor(filename, options.gConfigVars)
|
|
||||||
d.hasToc = true
|
d.hasToc = true
|
||||||
g.doc = d
|
g.doc = d
|
||||||
result = g
|
result = g
|
||||||
|
|
|
||||||
|
|
@ -1549,9 +1549,8 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
|
||||||
|
|
||||||
var globals: PGlobals
|
var globals: PGlobals
|
||||||
|
|
||||||
proc newModule(module: PSym, filename: string): BModule =
|
proc newModule(module: PSym): BModule =
|
||||||
new(result)
|
new(result)
|
||||||
result.filename = filename
|
|
||||||
result.module = module
|
result.module = module
|
||||||
if globals == nil: globals = newGlobals()
|
if globals == nil: globals = newGlobals()
|
||||||
|
|
||||||
|
|
@ -1612,11 +1611,11 @@ proc myClose(b: PPassContext, n: PNode): PNode =
|
||||||
var outfile = changeFileExt(completeCFilePath(m.filename), "js")
|
var outfile = changeFileExt(completeCFilePath(m.filename), "js")
|
||||||
discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
|
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")
|
InternalError("symbol files are not possible with the Ecmas code generator")
|
||||||
result = nil
|
result = nil
|
||||||
|
|
||||||
proc myOpen(s: PSym, filename: string): PPassContext =
|
proc myOpen(s: PSym): PPassContext =
|
||||||
result = newModule(s, filename)
|
result = newModule(s)
|
||||||
|
|
||||||
const ecmasgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
const ecmasgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,7 @@ proc newStackFrame*(): PStackFrame =
|
||||||
initIdNodeTable(result.mapping)
|
initIdNodeTable(result.mapping)
|
||||||
result.params = @[]
|
result.params = @[]
|
||||||
|
|
||||||
proc newEvalContext*(module: PSym, filename: string,
|
proc newEvalContext*(module: PSym, mode: TEvalMode): PEvalContext =
|
||||||
mode: TEvalMode): PEvalContext =
|
|
||||||
new(result)
|
new(result)
|
||||||
result.module = module
|
result.module = module
|
||||||
result.mode = mode
|
result.mode = mode
|
||||||
|
|
@ -1392,7 +1391,7 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
|
||||||
stackTrace(c, n, errCannotInterpretNodeX, renderTree(n))
|
stackTrace(c, n, errCannotInterpretNodeX, renderTree(n))
|
||||||
|
|
||||||
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
|
proc evalConstExprAux(module: PSym, e: PNode, mode: TEvalMode): PNode =
|
||||||
var p = newEvalContext(module, "", mode)
|
var p = newEvalContext(module, mode)
|
||||||
var s = newStackFrame()
|
var s = newStackFrame()
|
||||||
s.call = e
|
s.call = e
|
||||||
pushStackFrame(p, s)
|
pushStackFrame(p, s)
|
||||||
|
|
@ -1432,8 +1431,8 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
|
||||||
dec(evalTemplateCounter)
|
dec(evalTemplateCounter)
|
||||||
c.callsite = nil
|
c.callsite = nil
|
||||||
|
|
||||||
proc myOpen(module: PSym, filename: string): PPassContext =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
var c = newEvalContext(module, filename, emRepl)
|
var c = newEvalContext(module, emRepl)
|
||||||
pushStackFrame(c, newStackFrame())
|
pushStackFrame(c, newStackFrame())
|
||||||
result = c
|
result = c
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,15 @@ proc getModuleName*(n: PNode): string =
|
||||||
internalError(n.info, "getModuleName")
|
internalError(n.info, "getModuleName")
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
proc checkModuleName*(n: PNode): string =
|
proc checkModuleName*(n: PNode): int32 =
|
||||||
# This returns the full canonical path for a given module import
|
# This returns the full canonical path for a given module import
|
||||||
var modulename = n.getModuleName
|
let modulename = n.getModuleName
|
||||||
result = findModule(modulename)
|
let fullPath = findModule(modulename)
|
||||||
if result.len == 0:
|
if fullPath.len == 0:
|
||||||
LocalError(n.info, errCannotOpenFile, modulename)
|
LocalError(n.info, errCannotOpenFile, modulename)
|
||||||
|
result = InvalidFileIDX
|
||||||
|
else:
|
||||||
|
result = fullPath.fileInfoIdx
|
||||||
|
|
||||||
proc rawImportSymbol(c: PContext, s: PSym) =
|
proc rawImportSymbol(c: PContext, s: PSym) =
|
||||||
# This does not handle stubs, because otherwise loading on demand would be
|
# 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
|
result = n
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var f = checkModuleName(n.sons[i])
|
var f = checkModuleName(n.sons[i])
|
||||||
if f.len > 0:
|
if f != InvalidFileIDX:
|
||||||
var m = gImportModule(f)
|
var m = gImportModule(c.module, f)
|
||||||
if sfDeprecated in m.flags:
|
if sfDeprecated in m.flags:
|
||||||
Message(n.sons[i].info, warnDeprecated, m.name.s)
|
Message(n.sons[i].info, warnDeprecated, m.name.s)
|
||||||
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
# ``addDecl`` needs to be done before ``importAllSymbols``!
|
||||||
|
|
@ -123,8 +126,8 @@ proc evalFrom(c: PContext, n: PNode): PNode =
|
||||||
result = n
|
result = n
|
||||||
checkMinSonsLen(n, 2)
|
checkMinSonsLen(n, 2)
|
||||||
var f = checkModuleName(n.sons[0])
|
var f = checkModuleName(n.sons[0])
|
||||||
if f.len > 0:
|
if f != InvalidFileIDX:
|
||||||
var m = gImportModule(f)
|
var m = gImportModule(c.module, f)
|
||||||
n.sons[0] = newSymNode(m)
|
n.sons[0] = newSymNode(m)
|
||||||
addDecl(c, m) # add symbol to symbol table of module
|
addDecl(c, m) # add symbol to symbol table of module
|
||||||
for i in countup(1, sonsLen(n) - 1): importSymbol(c, n.sons[i], m)
|
for i in countup(1, sonsLen(n) - 1): importSymbol(c, n.sons[i], m)
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ proc pushInd*(L: var TLexer, indent: int)
|
||||||
|
|
||||||
proc popInd*(L: var TLexer)
|
proc popInd*(L: var TLexer)
|
||||||
proc isKeyword*(kind: TTokType): bool
|
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)
|
proc rawGetTok*(L: var TLexer, tok: var TToken)
|
||||||
# reads in the next token into tok and skips it
|
# reads in the next token into tok and skips it
|
||||||
proc getColumn*(L: TLexer): int
|
proc getColumn*(L: TLexer): int
|
||||||
|
|
@ -135,6 +135,9 @@ proc closeLexer*(lex: var TLexer)
|
||||||
proc PrintTok*(tok: TToken)
|
proc PrintTok*(tok: TToken)
|
||||||
proc tokToStr*(tok: TToken): string
|
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 lexMessage*(L: TLexer, msg: TMsgKind, arg = "")
|
||||||
|
|
||||||
proc isKeyword(kind: TTokType): bool =
|
proc isKeyword(kind: TTokType): bool =
|
||||||
|
|
@ -211,10 +214,10 @@ proc fillToken(L: var TToken) =
|
||||||
L.base = base10
|
L.base = base10
|
||||||
L.ident = dummyIdent
|
L.ident = dummyIdent
|
||||||
|
|
||||||
proc openLexer(lex: var TLexer, filename: string, inputstream: PLLStream) =
|
proc openLexer(lex: var TLexer, fileIdx: int32, inputstream: PLLStream) =
|
||||||
openBaseLexer(lex, inputstream)
|
openBaseLexer(lex, inputstream)
|
||||||
lex.indentStack = @[0]
|
lex.indentStack = @[0]
|
||||||
lex.fileIdx = filename.fileInfoIdx
|
lex.fileIdx = fileIdx
|
||||||
lex.indentAhead = - 1
|
lex.indentAhead = - 1
|
||||||
inc(lex.Linenumber, inputstream.lineOffset)
|
inc(lex.Linenumber, inputstream.lineOffset)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,11 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
llstream, strutils, ast, astalgo, lexer, syntaxes, renderer, options, msgs,
|
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,
|
wordrecg, sem, semdata, idents, passes, docgen, extccomp,
|
||||||
cgen, ecmasgen,
|
cgen, ecmasgen,
|
||||||
platform, nimconf, importer, passaux, depends, evals, types, idgen,
|
platform, nimconf, importer, passaux, depends, evals, types, idgen,
|
||||||
tables, docgen2, service, magicsys, parser
|
tables, docgen2, service, magicsys, parser, crc
|
||||||
|
|
||||||
const
|
const
|
||||||
has_LLVM_Backend = false
|
has_LLVM_Backend = false
|
||||||
|
|
@ -28,60 +28,113 @@ proc MainCommand*()
|
||||||
|
|
||||||
# ------------------ module handling -----------------------------------------
|
# ------------------ module handling -----------------------------------------
|
||||||
|
|
||||||
|
type
|
||||||
|
TModuleInMemory = object
|
||||||
|
compiledAt: float
|
||||||
|
crc: int
|
||||||
|
deps: seq[int32] ## XXX: slurped files are not currently tracked
|
||||||
|
needsRecompile: bool
|
||||||
|
|
||||||
var
|
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 getModule(fileIdx: int32): PSym =
|
||||||
proc registerModule(filename: string, module: PSym) =
|
if fileIdx >= 0 and fileIdx < gCompiledModules.len:
|
||||||
compMods[filename] = module
|
result = gCompiledModules[fileIdx]
|
||||||
|
else:
|
||||||
|
result = nil
|
||||||
|
|
||||||
# This expects a normalized module path
|
template compiledAt(x: PSym): expr =
|
||||||
proc getModule(filename: string): PSym =
|
gMemCacheData[x.position].compiledAt
|
||||||
result = compMods[filename]
|
|
||||||
|
|
||||||
var gModulesCount = 0
|
template crc(x: PSym): expr =
|
||||||
proc newModule(filename: string): PSym =
|
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
|
# 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)
|
||||||
result.id = - 1 # for better error checking
|
result.id = - 1 # for better error checking
|
||||||
result.kind = skModule
|
result.kind = skModule
|
||||||
|
let filename = fileIdx.toFilename
|
||||||
result.name = getIdent(splitFile(filename).name)
|
result.name = getIdent(splitFile(filename).name)
|
||||||
if not isNimrodIdentifier(result.name.s):
|
if not isNimrodIdentifier(result.name.s):
|
||||||
rawMessage(errInvalidModuleName, result.name.s)
|
rawMessage(errInvalidModuleName, result.name.s)
|
||||||
|
|
||||||
result.owner = result # a module belongs to itself
|
result.owner = result # a module belongs to itself
|
||||||
result.info = newLineInfo(filename, 1, 1)
|
result.info = newLineInfo(fileIdx, 1, 1)
|
||||||
result.position = gModulesCount
|
result.position = fileIdx
|
||||||
inc gModulesCount
|
|
||||||
|
growCache gMemCacheData, fileIdx
|
||||||
|
growCache gCompiledModules, fileIdx
|
||||||
|
gCompiledModules[result.position] = result
|
||||||
|
|
||||||
incl(result.flags, sfUsed)
|
incl(result.flags, sfUsed)
|
||||||
initStrTable(result.tab)
|
initStrTable(result.tab)
|
||||||
RegisterModule(filename, result)
|
|
||||||
StrTableAdd(result.tab, result) # a module knows itself
|
StrTableAdd(result.tab, result) # a module knows itself
|
||||||
|
|
||||||
proc CompileModule(filename: string, flags: TSymFlags): PSym
|
proc compileModule(fileIdx: int32, flags: TSymFlags): PSym =
|
||||||
proc importModule(filename: string): 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
|
# this is called by the semantic checking phase
|
||||||
result = getModule(filename)
|
result = getModule(fileIdx)
|
||||||
if result == nil:
|
if result == nil:
|
||||||
# compile the module
|
# compile the module
|
||||||
result = compileModule(filename, {})
|
result = compileModule(fileIdx, {})
|
||||||
|
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
|
||||||
elif sfSystemModule in result.flags:
|
elif sfSystemModule in result.flags:
|
||||||
LocalError(result.info, errAttemptToRedefine, result.Name.s)
|
LocalError(result.info, errAttemptToRedefine, result.Name.s)
|
||||||
|
|
||||||
proc CompileModule(filename: string, flags: TSymFlags): PSym =
|
proc includeModule(s: PSym, fileIdx: int32): PNode =
|
||||||
var rd: PRodReader = nil
|
result = syntaxes.parseFile(fileIdx)
|
||||||
var f = addFileExt(filename, nimExt)
|
if optCaasEnabled in gGlobalOptions: addDep(s, fileIdx)
|
||||||
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 `==^`(a, b: string): bool =
|
proc `==^`(a, b: string): bool =
|
||||||
try:
|
try:
|
||||||
|
|
@ -91,7 +144,8 @@ proc `==^`(a, b: string): bool =
|
||||||
|
|
||||||
proc compileSystemModule =
|
proc compileSystemModule =
|
||||||
if magicsys.SystemModule == nil:
|
if magicsys.SystemModule == nil:
|
||||||
discard CompileModule(options.libpath /"system", {sfSystemModule})
|
SystemFileIdx = fileInfoIdx(options.libpath/"system.nim")
|
||||||
|
discard CompileModule(SystemFileIdx, {sfSystemModule})
|
||||||
|
|
||||||
proc CompileProject(projectFile = gProjectFull) =
|
proc CompileProject(projectFile = gProjectFull) =
|
||||||
let systemFile = options.libpath / "system"
|
let systemFile = options.libpath / "system"
|
||||||
|
|
@ -140,6 +194,8 @@ proc CommandCompileToC =
|
||||||
compileProject()
|
compileProject()
|
||||||
if gCmd != cmdRun:
|
if gCmd != cmdRun:
|
||||||
extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
|
extccomp.CallCCompiler(changeFileExt(gProjectFull, ""))
|
||||||
|
# caas will keep track only of the compilation commands
|
||||||
|
lastCaasCmd = curCaasCmd
|
||||||
|
|
||||||
when has_LLVM_Backend:
|
when has_LLVM_Backend:
|
||||||
proc CommandCompileToLLVM =
|
proc CommandCompileToLLVM =
|
||||||
|
|
@ -171,7 +227,7 @@ proc InteractivePasses =
|
||||||
var stdinModule: PSym
|
var stdinModule: PSym
|
||||||
proc makeStdinModule: PSym =
|
proc makeStdinModule: PSym =
|
||||||
if stdinModule == nil:
|
if stdinModule == nil:
|
||||||
stdinModule = newModule("stdin")
|
stdinModule = newModule(gCmdLineInfo.fileIndex)
|
||||||
stdinModule.id = getID()
|
stdinModule.id = getID()
|
||||||
result = stdinModule
|
result = stdinModule
|
||||||
|
|
||||||
|
|
@ -184,24 +240,23 @@ proc CommandInteractive =
|
||||||
else:
|
else:
|
||||||
var m = makeStdinModule()
|
var m = makeStdinModule()
|
||||||
incl(m.flags, sfMainModule)
|
incl(m.flags, sfMainModule)
|
||||||
processModule(m, "stdin", LLStreamOpenStdIn(), nil)
|
processModule(m, LLStreamOpenStdIn(), nil)
|
||||||
|
|
||||||
const evalPasses = [verbosePass, semPass, evalPass]
|
const evalPasses = [verbosePass, semPass, evalPass]
|
||||||
|
|
||||||
proc evalNim(nodes: PNode, module: PSym, filename: string) =
|
proc evalNim(nodes: PNode, module: PSym) =
|
||||||
# we don't want to mess with gPasses here, because in nimrod serve
|
carryPasses(nodes, module, evalPasses)
|
||||||
# scenario, it may be set up properly for normal cgenPass() compilation
|
|
||||||
carryPasses(nodes, module, filename, evalPasses)
|
|
||||||
|
|
||||||
proc commandEval(exp: string) =
|
proc commandEval(exp: string) =
|
||||||
if SystemModule == nil:
|
if SystemModule == nil:
|
||||||
InteractivePasses()
|
InteractivePasses()
|
||||||
compileSystemModule()
|
compileSystemModule()
|
||||||
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
|
var echoExp = "echo \"eval\\t\", " & "repr(" & exp & ")"
|
||||||
evalNim(echoExp.parseString, makeStdinModule(), "stdin")
|
evalNim(echoExp.parseString, makeStdinModule())
|
||||||
|
|
||||||
proc CommandPretty =
|
proc CommandPretty =
|
||||||
var module = parseFile(addFileExt(mainCommandArg(), NimExt))
|
var projectFile = addFileExt(mainCommandArg(), NimExt)
|
||||||
|
var module = parseFile(projectFile.fileInfoIdx)
|
||||||
if module != nil:
|
if module != nil:
|
||||||
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
|
renderModule(module, getOutFile(mainCommandArg(), "pretty." & NimExt))
|
||||||
|
|
||||||
|
|
@ -231,16 +286,18 @@ proc CommandSuggest =
|
||||||
proc wantMainModule =
|
proc wantMainModule =
|
||||||
if gProjectFull.len == 0:
|
if gProjectFull.len == 0:
|
||||||
Fatal(gCmdLineInfo, errCommandExpectsFilename)
|
Fatal(gCmdLineInfo, errCommandExpectsFilename)
|
||||||
|
gProjectMainIdx = addFileExt(gProjectFull, nimExt).fileInfoIdx
|
||||||
|
|
||||||
proc MainCommand =
|
proc MainCommand =
|
||||||
# In "nimrod serve" scenario, each command must reset the registered passes
|
# In "nimrod serve" scenario, each command must reset the registered passes
|
||||||
clearPasses()
|
clearPasses()
|
||||||
|
gLastCmdTime = epochTime()
|
||||||
appendStr(searchPaths, options.libpath)
|
appendStr(searchPaths, options.libpath)
|
||||||
if gProjectFull.len != 0:
|
if gProjectFull.len != 0:
|
||||||
# current path is always looked first for modules
|
# current path is always looked first for modules
|
||||||
prependStr(searchPaths, gProjectPath)
|
prependStr(searchPaths, gProjectPath)
|
||||||
setID(100)
|
setID(100)
|
||||||
passes.gIncludeFile = syntaxes.parseFile
|
passes.gIncludeFile = includeModule
|
||||||
passes.gImportModule = importModule
|
passes.gImportModule = importModule
|
||||||
case command.normalize
|
case command.normalize
|
||||||
of "c", "cc", "compile", "compiletoc":
|
of "c", "cc", "compile", "compiletoc":
|
||||||
|
|
@ -323,7 +380,7 @@ proc MainCommand =
|
||||||
of "parse":
|
of "parse":
|
||||||
gCmd = cmdParse
|
gCmd = cmdParse
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
discard parseFile(addFileExt(gProjectFull, nimExt))
|
discard parseFile(gProjectMainIdx)
|
||||||
of "scan":
|
of "scan":
|
||||||
gCmd = cmdScan
|
gCmd = cmdScan
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
|
|
@ -343,9 +400,14 @@ proc MainCommand =
|
||||||
wantMainModule()
|
wantMainModule()
|
||||||
CommandSuggest()
|
CommandSuggest()
|
||||||
of "serve":
|
of "serve":
|
||||||
gCmd = cmdIdeTools
|
gGlobalOptions.incl(optCaasEnabled)
|
||||||
msgs.gErrorMax = high(int) # do not stop after first error
|
msgs.gErrorMax = high(int) # do not stop after first error
|
||||||
serve(MainCommand)
|
serve(MainCommand)
|
||||||
|
|
||||||
else: rawMessage(errInvalidCommandX, command)
|
else: rawMessage(errInvalidCommandX, command)
|
||||||
|
|
||||||
|
if msgs.gErrorCounter == 0 and gCmd notin {cmdInterpret, cmdRun}:
|
||||||
|
rawMessage(hintSuccessX, [$gLinesCompiled,
|
||||||
|
formatFloat(epochTime() - gLastCmdTime, ffDecimal, 3),
|
||||||
|
formatSize(getTotalMem())])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -416,9 +416,13 @@ type
|
||||||
ERecoverableError* = object of EInvalidValue
|
ERecoverableError* = object of EInvalidValue
|
||||||
ESuggestDone* = object of EBase
|
ESuggestDone* = object of EBase
|
||||||
|
|
||||||
|
const
|
||||||
|
InvalidFileIDX* = int32(-1)
|
||||||
|
|
||||||
var
|
var
|
||||||
filenameToIndexTbl = initTable[string, int32]()
|
filenameToIndexTbl = initTable[string, int32]()
|
||||||
fileInfos: seq[TFileInfo] = @[]
|
fileInfos*: seq[TFileInfo] = @[]
|
||||||
|
SystemFileIdx*: int32
|
||||||
|
|
||||||
proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
proc newFileInfo(fullPath, projPath: string): TFileInfo =
|
||||||
result.fullPath = fullPath
|
result.fullPath = fullPath
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ when defined(gcc) and defined(windows):
|
||||||
{.link: "icons/nimrod_icon.o".}
|
{.link: "icons/nimrod_icon.o".}
|
||||||
|
|
||||||
import
|
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
|
extccomp, strutils, os, platform, main, parseopt, service
|
||||||
|
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
|
|
@ -32,7 +32,6 @@ proc prependCurDir(f: string): string =
|
||||||
result = f
|
result = f
|
||||||
|
|
||||||
proc HandleCmdLine() =
|
proc HandleCmdLine() =
|
||||||
var start = epochTime()
|
|
||||||
if paramCount() == 0:
|
if paramCount() == 0:
|
||||||
writeCommandLineUsage()
|
writeCommandLineUsage()
|
||||||
else:
|
else:
|
||||||
|
|
@ -60,10 +59,6 @@ proc HandleCmdLine() =
|
||||||
when hasTinyCBackend:
|
when hasTinyCBackend:
|
||||||
if gCmd == cmdRun:
|
if gCmd == cmdRun:
|
||||||
tccgen.run()
|
tccgen.run()
|
||||||
if gCmd notin {cmdInterpret, cmdRun}:
|
|
||||||
rawMessage(hintSuccessX, [$gLinesCompiled,
|
|
||||||
formatFloat(epochTime() - start, ffDecimal, 3),
|
|
||||||
formatSize(getTotalMem())])
|
|
||||||
if optRun in gGlobalOptions:
|
if optRun in gGlobalOptions:
|
||||||
if gCmd == cmdCompileToEcmaScript:
|
if gCmd == cmdCompileToEcmaScript:
|
||||||
var ex = quoteIfContainsWhite(
|
var ex = quoteIfContainsWhite(
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ type # please make sure we have under 32 options
|
||||||
optGenMapping, # generate a mapping file
|
optGenMapping, # generate a mapping file
|
||||||
optRun, # run the compiled project
|
optRun, # run the compiled project
|
||||||
optSymbolFiles, # use symbol files for speeding up compilation
|
optSymbolFiles, # use symbol files for speeding up compilation
|
||||||
|
optCaasEnabled # compiler-as-a-service is running
|
||||||
optSkipConfigFile, # skip the general config file
|
optSkipConfigFile, # skip the general config file
|
||||||
optSkipProjConfigFile, # skip the project's config file
|
optSkipProjConfigFile, # skip the project's config file
|
||||||
optSkipUserConfigFile, # skip the users's config file
|
optSkipUserConfigFile, # skip the users's config file
|
||||||
|
|
@ -96,6 +97,7 @@ var
|
||||||
gNumberOfProcessors*: int # number of processors
|
gNumberOfProcessors*: int # number of processors
|
||||||
gWholeProject*: bool # for 'doc2': output any dependency
|
gWholeProject*: bool # for 'doc2': output any dependency
|
||||||
gEvalExpr*: string # expression for idetools --eval
|
gEvalExpr*: string # expression for idetools --eval
|
||||||
|
gLastCmdTime*: float # when caas is enabled, we measure each command
|
||||||
|
|
||||||
const
|
const
|
||||||
genSubDir* = "nimcache"
|
genSubDir* = "nimcache"
|
||||||
|
|
@ -115,6 +117,7 @@ var
|
||||||
gProjectName* = "" # holds a name like 'nimrod'
|
gProjectName* = "" # holds a name like 'nimrod'
|
||||||
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
|
gProjectPath* = "" # holds a path like /home/alice/projects/nimrod/compiler/
|
||||||
gProjectFull* = "" # projectPath/projectName
|
gProjectFull* = "" # projectPath/projectName
|
||||||
|
gProjectMainIdx*: int32 # the canonical path id of the main module
|
||||||
nimcacheDir* = ""
|
nimcacheDir* = ""
|
||||||
command* = "" # the main command (e.g. cc, check, scan, etc)
|
command* = "" # the main command (e.g. cc, check, scan, etc)
|
||||||
commandArgs*: seq[string] = @[] # any arguments after the main command
|
commandArgs*: seq[string] = @[] # any arguments after the main command
|
||||||
|
|
|
||||||
|
|
@ -64,11 +64,14 @@ proc parseCase(p: var TParser): PNode
|
||||||
proc getTok(p: var TParser) =
|
proc getTok(p: var TParser) =
|
||||||
rawGetTok(p.lex, p.tok)
|
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)
|
initToken(p.tok)
|
||||||
OpenLexer(p.lex, filename, inputstream)
|
OpenLexer(p.lex, fileIdx, inputstream)
|
||||||
getTok(p) # read the first token
|
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) =
|
proc CloseParser(p: var TParser) =
|
||||||
CloseLexer(p.lex)
|
CloseLexer(p.lex)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
import
|
import
|
||||||
strutils, ast, astalgo, passes, msgs, options, idgen
|
strutils, ast, astalgo, passes, msgs, options, idgen
|
||||||
|
|
||||||
proc verboseOpen(s: PSym, filename: string): PPassContext =
|
proc verboseOpen(s: PSym): 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
|
||||||
if gVerbosity > 0: rawMessage(hintProcessing, s.name.s)
|
if gVerbosity > 0: rawMessage(hintProcessing, s.name.s)
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,9 @@ type
|
||||||
|
|
||||||
PPassContext* = ref TPassContext
|
PPassContext* = ref TPassContext
|
||||||
|
|
||||||
TPassOpen* = proc (module: PSym, filename: string): PPassContext {.nimcall.}
|
TPassOpen* = proc (module: PSym): PPassContext {.nimcall.}
|
||||||
TPassOpenCached* = proc (module: PSym, filename: string,
|
TPassOpenCached* =
|
||||||
rd: PRodReader): PPassContext {.nimcall.}
|
proc (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.}
|
||||||
|
|
||||||
|
|
@ -50,13 +50,12 @@ proc makePass*(open: TPassOpen = nil,
|
||||||
# processed in a pipeline. The compiler never looks at a whole module
|
# 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
|
# 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.
|
# whole program optimizations. For now, we avoid it to save a lot of memory.
|
||||||
proc processModule*(module: PSym, filename: string, stream: PLLStream,
|
proc processModule*(module: PSym, stream: PLLStream, rd: PRodReader)
|
||||||
rd: PRodReader)
|
|
||||||
|
|
||||||
# the semantic checker needs these:
|
# the semantic checker needs these:
|
||||||
var
|
var
|
||||||
gImportModule*: proc (filename: string): PSym {.nimcall.}
|
gImportModule*: proc (m: PSym, fileIdx: int32): PSym {.nimcall.}
|
||||||
gIncludeFile*: proc (filename: string): PNode {.nimcall.}
|
gIncludeFile*: proc (m: PSym, fileIdx: int32): PNode {.nimcall.}
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
|
|
@ -96,30 +95,28 @@ proc registerPass*(p: TPass) =
|
||||||
gPasses[gPassesLen] = p
|
gPasses[gPassesLen] = p
|
||||||
inc(gPassesLen)
|
inc(gPassesLen)
|
||||||
|
|
||||||
proc carryPass*(p: TPass, module: PSym, filename: string,
|
proc carryPass*(p: TPass, module: PSym, m: TPassData): TPassData =
|
||||||
m: TPassData): TPassData =
|
var c = p.open(module)
|
||||||
var c = p.open(module, filename)
|
|
||||||
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, file: string, passes: TPasses) =
|
proc carryPasses*(nodes: PNode, module: PSym, 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, 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):
|
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, filename)
|
a[i] = gPasses[i].open(module)
|
||||||
else: a[i] = nil
|
else: a[i] = nil
|
||||||
|
|
||||||
proc openPassesCached(a: var TPassContextArray, module: PSym, filename: string,
|
proc openPassesCached(a: var TPassContextArray, module: PSym, rd: PRodReader) =
|
||||||
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, filename, rd)
|
a[i] = gPasses[i].openCached(module, rd)
|
||||||
if a[i] != nil:
|
if a[i] != nil:
|
||||||
a[i].fromCache = true
|
a[i].fromCache = true
|
||||||
else:
|
else:
|
||||||
|
|
@ -162,15 +159,16 @@ 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, filename: string, stream: PLLStream,
|
proc processModule(module: PSym, stream: PLLStream, rd: PRodReader) =
|
||||||
rd: PRodReader) =
|
|
||||||
var
|
var
|
||||||
p: TParsers
|
p: TParsers
|
||||||
a: TPassContextArray
|
a: TPassContextArray
|
||||||
s: PLLStream
|
s: PLLStream
|
||||||
|
fileIdx = module.fileIdx
|
||||||
if rd == nil:
|
if rd == nil:
|
||||||
openPasses(a, module, filename)
|
openPasses(a, module)
|
||||||
if stream == nil:
|
if stream == nil:
|
||||||
|
let filename = fileIdx.toFilename
|
||||||
s = LLStreamOpen(filename, fmRead)
|
s = LLStreamOpen(filename, fmRead)
|
||||||
if s == nil:
|
if s == nil:
|
||||||
rawMessage(errCannotOpenFile, filename)
|
rawMessage(errCannotOpenFile, filename)
|
||||||
|
|
@ -178,7 +176,7 @@ proc processModule(module: PSym, filename: string, stream: PLLStream,
|
||||||
else:
|
else:
|
||||||
s = stream
|
s = stream
|
||||||
while true:
|
while true:
|
||||||
openParsers(p, filename, s)
|
openParsers(p, fileIdx, s)
|
||||||
|
|
||||||
if sfSystemModule notin module.flags:
|
if sfSystemModule notin module.flags:
|
||||||
# XXX what about caching? no processing then? what if I change the
|
# XXX what about caching? no processing then? what if I change the
|
||||||
|
|
@ -199,7 +197,7 @@ proc processModule(module: PSym, filename: string, 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, filename, rd)
|
openPassesCached(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)
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ type
|
||||||
s: cstring # mmap'ed file contents
|
s: cstring # mmap'ed file contents
|
||||||
options: TOptions
|
options: TOptions
|
||||||
reason: TReasonForRecompile
|
reason: TReasonForRecompile
|
||||||
modDeps: TStringSeq
|
modDeps: seq[int32]
|
||||||
files: TStringSeq
|
files: TStringSeq
|
||||||
dataIdx: int # offset of start of data section
|
dataIdx: int # offset of start of data section
|
||||||
convertersIdx: int # offset of start of converters section
|
convertersIdx: int # offset of start of converters section
|
||||||
|
|
@ -145,7 +145,7 @@ type
|
||||||
|
|
||||||
var rodCompilerprocs*: TStrTable
|
var rodCompilerprocs*: TStrTable
|
||||||
|
|
||||||
proc handleSymbolFile*(module: PSym, filename: string): PRodReader
|
proc handleSymbolFile*(module: PSym): PRodReader
|
||||||
# global because this is needed by magicsys
|
# global because this is needed by magicsys
|
||||||
proc loadInitSection*(r: PRodReader): PNode
|
proc loadInitSection*(r: PRodReader): PNode
|
||||||
|
|
||||||
|
|
@ -602,7 +602,7 @@ proc processRodFile(r: PRodReader, crc: TCrc32) =
|
||||||
of "DEPS":
|
of "DEPS":
|
||||||
inc(r.pos) # skip ':'
|
inc(r.pos) # skip ':'
|
||||||
while r.s[r.pos] > '\x0A':
|
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)
|
if r.s[r.pos] == ' ': inc(r.pos)
|
||||||
of "INTERF":
|
of "INTERF":
|
||||||
r.interfIdx = r.pos + 2
|
r.interfIdx = r.pos + 2
|
||||||
|
|
@ -699,10 +699,11 @@ type
|
||||||
reason*: TReasonForRecompile
|
reason*: TReasonForRecompile
|
||||||
rd*: PRodReader
|
rd*: PRodReader
|
||||||
crc*: TCrc32
|
crc*: TCrc32
|
||||||
|
crcDone*: bool
|
||||||
|
|
||||||
TFileModuleMap = seq[TFileModuleRec]
|
TFileModuleMap = seq[TFileModuleRec]
|
||||||
|
|
||||||
var gMods: TFileModuleMap = @[]
|
var gMods*: TFileModuleMap = @[]
|
||||||
|
|
||||||
proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
|
proc decodeSymSafePos(rd: PRodReader, offset: int, info: TLineInfo): PSym =
|
||||||
# all compiled modules
|
# all compiled modules
|
||||||
|
|
@ -720,6 +721,10 @@ proc findSomeWhere(id: int) =
|
||||||
if d != invalidKey:
|
if d != invalidKey:
|
||||||
echo "found id ", id, " in ", gMods[i].filename
|
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 =
|
proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
||||||
result = PSym(IdTableGet(r.syms, id))
|
result = PSym(IdTableGet(r.syms, id))
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
|
@ -732,25 +737,15 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
|
||||||
var x = ""
|
var x = ""
|
||||||
encodeVInt(id, x)
|
encodeVInt(id, x)
|
||||||
InternalError(info, "missing from both indexes: +" & x)
|
InternalError(info, "missing from both indexes: +" & x)
|
||||||
# find the reader with the correct moduleID:
|
var rd = getReader(moduleID)
|
||||||
for i in countup(0, high(gMods)):
|
d = IITableGet(rd.index.tab, id)
|
||||||
var rd = gMods[i].rd
|
if d != invalidKey:
|
||||||
if rd != nil:
|
result = decodeSymSafePos(rd, d, info)
|
||||||
if rd.moduleID == moduleID:
|
else:
|
||||||
d = IITableGet(rd.index.tab, id)
|
var x = ""
|
||||||
if d != invalidKey:
|
encodeVInt(id, x)
|
||||||
result = decodeSymSafePos(rd, d, info)
|
when false: findSomeWhere(id)
|
||||||
break
|
InternalError(info, "rrGetSym: no reader found: +" & x)
|
||||||
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)))
|
|
||||||
else:
|
else:
|
||||||
# own symbol:
|
# own symbol:
|
||||||
result = decodeSymSafePos(r, d, info)
|
result = decodeSymSafePos(r, d, info)
|
||||||
|
|
@ -790,26 +785,31 @@ proc loadMethods(r: PRodReader) =
|
||||||
r.methods.add(rrGetSym(r, d, UnknownLineInfo()))
|
r.methods.add(rrGetSym(r, d, UnknownLineInfo()))
|
||||||
if r.s[r.pos] == ' ': inc(r.pos)
|
if r.s[r.pos] == ' ': inc(r.pos)
|
||||||
|
|
||||||
proc getModuleIdx(filename: string): int =
|
proc GetCRC*(fileIdx: int32): TCrc32 =
|
||||||
for i in countup(0, high(gMods)):
|
InternalAssert fileIdx >= 0 and fileIdx < gMods.len
|
||||||
if gMods[i].filename == filename: return i
|
|
||||||
result = len(gMods)
|
|
||||||
setlen(gMods, result + 1)
|
|
||||||
|
|
||||||
proc checkDep(filename: string): TReasonForRecompile =
|
if gMods[fileIdx].crcDone:
|
||||||
assert(not isNil(filename))
|
return gMods[fileIdx].crc
|
||||||
var idx = getModuleIdx(filename)
|
|
||||||
if gMods[idx].reason != rrEmpty:
|
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:
|
# reason has already been computed for this module:
|
||||||
return gMods[idx].reason
|
return gMods[fileIdx].reason
|
||||||
var crc: TCrc32 = crcFromFile(filename)
|
let filename = fileIdx.toFilename
|
||||||
gMods[idx].reason = rrNone # we need to set it here to avoid cycles
|
var crc = GetCRC(fileIdx)
|
||||||
gMods[idx].filename = filename
|
gMods[fileIdx].reason = rrNone # we need to set it here to avoid cycles
|
||||||
gMods[idx].crc = crc
|
|
||||||
result = rrNone
|
result = rrNone
|
||||||
var r: PRodReader = nil
|
var r: PRodReader = nil
|
||||||
var rodfile = toGeneratedFile(filename, RodExt)
|
var rodfile = toGeneratedFile(filename, RodExt)
|
||||||
r = newRodReader(rodfile, crc, idx)
|
r = newRodReader(rodfile, crc, fileIdx)
|
||||||
if r == nil:
|
if r == nil:
|
||||||
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
|
result = (if ExistsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
|
||||||
else:
|
else:
|
||||||
|
|
@ -819,7 +819,7 @@ proc checkDep(filename: string): TReasonForRecompile =
|
||||||
# NOTE: we need to process the entire module graph so that no ID will
|
# 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
|
# be used twice! However, compilation speed does not suffer much from
|
||||||
# this, since results are cached.
|
# this, since results are cached.
|
||||||
var res = checkDep(options.libpath / addFileExt("system", nimExt))
|
var res = checkDep(SystemFileIdx)
|
||||||
if res != rrNone: result = rrModDeps
|
if res != rrNone: result = rrModDeps
|
||||||
for i in countup(0, high(r.modDeps)):
|
for i in countup(0, high(r.modDeps)):
|
||||||
res = checkDep(r.modDeps[i])
|
res = checkDep(r.modDeps[i])
|
||||||
|
|
@ -832,19 +832,19 @@ proc checkDep(filename: string): TReasonForRecompile =
|
||||||
# recompilation is necessary:
|
# recompilation is necessary:
|
||||||
if r != nil: memfiles.close(r.memFile)
|
if r != nil: memfiles.close(r.memFile)
|
||||||
r = nil
|
r = nil
|
||||||
gMods[idx].rd = r
|
gMods[fileIdx].rd = r
|
||||||
gMods[idx].reason = result # now we know better
|
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:
|
if optSymbolFiles notin gGlobalOptions:
|
||||||
module.id = getID()
|
module.id = getID()
|
||||||
return nil
|
return nil
|
||||||
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
|
idgen.loadMaxIds(options.gProjectPath / options.gProjectName)
|
||||||
|
|
||||||
discard checkDep(filename)
|
discard checkDep(fileIdx)
|
||||||
var idx = getModuleIdx(filename)
|
if gMods[fileIdx].reason == rrEmpty: InternalError("handleSymbolFile")
|
||||||
if gMods[idx].reason == rrEmpty: InternalError("handleSymbolFile")
|
result = gMods[fileIdx].rd
|
||||||
result = gMods[idx].rd
|
|
||||||
if result != nil:
|
if result != nil:
|
||||||
module.id = result.moduleID
|
module.id = result.moduleID
|
||||||
IdTablePut(result.syms, module, module)
|
IdTablePut(result.syms, module, module)
|
||||||
|
|
@ -855,14 +855,6 @@ proc handleSymbolFile(module: PSym, filename: string): PRodReader =
|
||||||
else:
|
else:
|
||||||
module.id = getID()
|
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) =
|
proc rawLoadStub(s: PSym) =
|
||||||
if s.kind != skStub: InternalError("loadStub")
|
if s.kind != skStub: InternalError("loadStub")
|
||||||
var rd = gMods[s.position].rd
|
var rd = gMods[s.position].rd
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,13 @@ type
|
||||||
converters, methods: string
|
converters, methods: string
|
||||||
init: string
|
init: string
|
||||||
data: string
|
data: string
|
||||||
filename: string
|
|
||||||
sstack: TSymSeq # a stack of symbols to process
|
sstack: TSymSeq # a stack of symbols to process
|
||||||
tstack: TTypeSeq # a stack of types to process
|
tstack: TTypeSeq # a stack of types to process
|
||||||
files: TStringSeq
|
files: TStringSeq
|
||||||
|
|
||||||
PRodWriter = ref TRodWriter
|
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 addModDep(w: PRodWriter, dep: string)
|
||||||
proc addInclDep(w: PRodWriter, dep: string)
|
proc addInclDep(w: PRodWriter, dep: string)
|
||||||
proc addInterfaceSym(w: PRodWriter, s: PSym)
|
proc addInterfaceSym(w: PRodWriter, s: PSym)
|
||||||
|
|
@ -63,7 +62,10 @@ proc fileIdx(w: PRodWriter, filename: string): int =
|
||||||
setlen(w.files, result + 1)
|
setlen(w.files, result + 1)
|
||||||
w.files[result] = filename
|
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)
|
new(result)
|
||||||
result.sstack = @[]
|
result.sstack = @[]
|
||||||
result.tstack = @[]
|
result.tstack = @[]
|
||||||
|
|
@ -71,7 +73,6 @@ proc newRodWriter(modfilename: string, crc: TCrc32, module: PSym): PRodWriter =
|
||||||
InitIITable(result.imports.tab)
|
InitIITable(result.imports.tab)
|
||||||
result.index.r = ""
|
result.index.r = ""
|
||||||
result.imports.r = ""
|
result.imports.r = ""
|
||||||
result.filename = modfilename
|
|
||||||
result.crc = crc
|
result.crc = crc
|
||||||
result.module = module
|
result.module = module
|
||||||
result.defines = getDefines()
|
result.defines = getDefines()
|
||||||
|
|
@ -570,9 +571,9 @@ proc process(c: PPassContext, n: PNode): PNode =
|
||||||
else:
|
else:
|
||||||
nil
|
nil
|
||||||
|
|
||||||
proc myOpen(module: PSym, filename: string): PPassContext =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
if module.id < 0: InternalError("rodwrite: module ID not set")
|
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)
|
rawAddInterfaceSym(w, module)
|
||||||
result = w
|
result = w
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ proc semMacroExpr(c: PContext, n, nOrig: PNode, sym: PSym,
|
||||||
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
GlobalError(n.info, errRecursiveDependencyX, sym.name.s)
|
||||||
|
|
||||||
if c.evalContext == nil:
|
if c.evalContext == nil:
|
||||||
c.evalContext = newEvalContext(c.module, "", emStatic)
|
c.evalContext = newEvalContext(c.module, emStatic)
|
||||||
c.evalContext.getType = proc (n: PNode): PNode =
|
c.evalContext.getType = proc (n: PNode): PNode =
|
||||||
var e = tryExpr(c, n)
|
var e = tryExpr(c, n)
|
||||||
if e == nil:
|
if e == nil:
|
||||||
|
|
@ -201,8 +201,8 @@ proc addCodeForGenerics(c: PContext, n: PNode) =
|
||||||
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
|
proc semExprNoFlags(c: PContext, n: PNode): PNode {.procvar.} =
|
||||||
result = semExpr(c, n, {})
|
result = semExpr(c, n, {})
|
||||||
|
|
||||||
proc myOpen(module: PSym, filename: string): PPassContext =
|
proc myOpen(module: PSym): PPassContext =
|
||||||
var c = newContext(module, filename)
|
var c = newContext(module)
|
||||||
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 = semExprNoFlags
|
c.semExpr = semExprNoFlags
|
||||||
|
|
@ -222,9 +222,8 @@ proc myOpen(module: PSym, filename: string): PPassContext =
|
||||||
openScope(c.tab) # scope for the module's symbols
|
openScope(c.tab) # scope for the module's symbols
|
||||||
result = c
|
result = c
|
||||||
|
|
||||||
proc myOpenCached(module: PSym, filename: string,
|
proc myOpenCached(module: PSym, rd: PRodReader): PPassContext =
|
||||||
rd: PRodReader): PPassContext =
|
result = myOpen(module)
|
||||||
result = myOpen(module, filename)
|
|
||||||
for m in items(rd.methods): methodDef(m, true)
|
for m in items(rd.methods): methodDef(m, true)
|
||||||
|
|
||||||
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
proc SemStmtAndGenerateGenerics(c: PContext, n: PNode): PNode =
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,6 @@ type
|
||||||
filter: TSymKinds): PNode {.nimcall.}
|
filter: TSymKinds): PNode {.nimcall.}
|
||||||
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
|
semTypeNode*: proc(c: PContext, n: PNode, prev: PType): PType {.nimcall.}
|
||||||
includedFiles*: TIntSet # used to detect recursive include files
|
includedFiles*: TIntSet # used to detect recursive include files
|
||||||
filename*: string # the module's filename
|
|
||||||
userPragmas*: TStrTable
|
userPragmas*: TStrTable
|
||||||
evalContext*: PEvalContext
|
evalContext*: PEvalContext
|
||||||
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
UnknownIdents*: TIntSet # ids of all unknown identifiers to prevent
|
||||||
|
|
@ -90,12 +89,16 @@ type
|
||||||
var
|
var
|
||||||
gGenericsCache: PGenericsCache # save for modularity
|
gGenericsCache: PGenericsCache # save for modularity
|
||||||
|
|
||||||
|
proc filename*(c: PContext): string =
|
||||||
|
# the module's filename
|
||||||
|
return c.module.filename
|
||||||
|
|
||||||
proc newGenericsCache*(): PGenericsCache =
|
proc newGenericsCache*(): PGenericsCache =
|
||||||
new(result)
|
new(result)
|
||||||
initIdTable(result.InstTypes)
|
initIdTable(result.InstTypes)
|
||||||
result.generics = @[]
|
result.generics = @[]
|
||||||
|
|
||||||
proc newContext*(module: PSym, nimfile: string): PContext
|
proc newContext*(module: PSym): PContext
|
||||||
|
|
||||||
proc lastOptionEntry*(c: PContext): POptionEntry
|
proc lastOptionEntry*(c: PContext): POptionEntry
|
||||||
proc newOptionEntry*(): POptionEntry
|
proc newOptionEntry*(): POptionEntry
|
||||||
|
|
@ -152,7 +155,7 @@ proc newOptionEntry(): POptionEntry =
|
||||||
result.dynlib = nil
|
result.dynlib = nil
|
||||||
result.notes = gNotes
|
result.notes = gNotes
|
||||||
|
|
||||||
proc newContext(module: PSym, nimfile: string): PContext =
|
proc newContext(module: PSym): PContext =
|
||||||
new(result)
|
new(result)
|
||||||
InitSymTab(result.tab)
|
InitSymTab(result.tab)
|
||||||
result.AmbiguousSymbols = initIntset()
|
result.AmbiguousSymbols = initIntset()
|
||||||
|
|
@ -164,7 +167,6 @@ proc newContext(module: PSym, nimfile: string): PContext =
|
||||||
result.threadEntries = @[]
|
result.threadEntries = @[]
|
||||||
result.converters = @[]
|
result.converters = @[]
|
||||||
result.patterns = @[]
|
result.patterns = @[]
|
||||||
result.filename = nimfile
|
|
||||||
result.includedFiles = initIntSet()
|
result.includedFiles = initIntSet()
|
||||||
initStrTable(result.userPragmas)
|
initStrTable(result.userPragmas)
|
||||||
if optSymbolFiles notin gGlobalOptions:
|
if optSymbolFiles notin gGlobalOptions:
|
||||||
|
|
|
||||||
|
|
@ -892,13 +892,12 @@ proc evalInclude(c: PContext, n: PNode): PNode =
|
||||||
addSon(result, n)
|
addSon(result, n)
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
var f = checkModuleName(n.sons[i])
|
var f = checkModuleName(n.sons[i])
|
||||||
if f.len > 0:
|
if f != InvalidFileIDX:
|
||||||
var fileIndex = f.fileInfoIdx
|
if ContainsOrIncl(c.includedFiles, f):
|
||||||
if ContainsOrIncl(c.includedFiles, fileIndex):
|
LocalError(n.info, errRecursiveDependencyX, f.toFilename)
|
||||||
LocalError(n.info, errRecursiveDependencyX, f.extractFilename)
|
|
||||||
else:
|
else:
|
||||||
addSon(result, semStmt(c, gIncludeFile(f)))
|
addSon(result, semStmt(c, gIncludeFile(c.module, f)))
|
||||||
Excl(c.includedFiles, fileIndex)
|
Excl(c.includedFiles, f)
|
||||||
|
|
||||||
proc setLine(n: PNode, info: TLineInfo) =
|
proc setLine(n: PNode, info: TLineInfo) =
|
||||||
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
|
for i in 0 .. <safeLen(n): setLine(n.sons[i], info)
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,13 @@ import
|
||||||
# repeated CRC calculations may turn out to be too slow.
|
# repeated CRC calculations may turn out to be too slow.
|
||||||
|
|
||||||
var
|
var
|
||||||
arguments*: string = "" # the arguments to be passed to the program that
|
curCaasCmd* = ""
|
||||||
# should be run
|
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) =
|
proc ProcessCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
var p = parseopt.initOptParser(cmd)
|
var p = parseopt.initOptParser(cmd)
|
||||||
|
|
@ -56,14 +61,18 @@ proc ProcessCmdLine*(pass: TCmdLinePass, cmd: string) =
|
||||||
rawMessage(errArgsNeedRunOption, [])
|
rawMessage(errArgsNeedRunOption, [])
|
||||||
|
|
||||||
proc serve*(action: proc (){.nimcall.}) =
|
proc serve*(action: proc (){.nimcall.}) =
|
||||||
|
template execute(cmd) =
|
||||||
|
curCaasCmd = cmd
|
||||||
|
processCmdLine(passCmd2, cmd)
|
||||||
|
action()
|
||||||
|
|
||||||
let typ = getConfigVar("server.type")
|
let typ = getConfigVar("server.type")
|
||||||
case typ
|
case typ
|
||||||
of "stdin":
|
of "stdin":
|
||||||
while true:
|
while true:
|
||||||
var line = stdin.readLine.string
|
var line = stdin.readLine.string
|
||||||
if line == "quit": quit()
|
if line == "quit": quit()
|
||||||
processCmdLine(passCmd2, line)
|
execute line
|
||||||
action()
|
|
||||||
of "tcp", "":
|
of "tcp", "":
|
||||||
var server = Socket()
|
var server = Socket()
|
||||||
let p = getConfigVar("server.port")
|
let p = getConfigVar("server.port")
|
||||||
|
|
@ -75,8 +84,7 @@ proc serve*(action: proc (){.nimcall.}) =
|
||||||
while true:
|
while true:
|
||||||
accept(server, stdoutSocket)
|
accept(server, stdoutSocket)
|
||||||
discard stdoutSocket.recvLine(inp)
|
discard stdoutSocket.recvLine(inp)
|
||||||
processCmdLine(passCmd2, inp.string)
|
execute inp.string
|
||||||
action()
|
|
||||||
stdoutSocket.send("\c\L")
|
stdoutSocket.send("\c\L")
|
||||||
stdoutSocket.close()
|
stdoutSocket.close()
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ type
|
||||||
parser*: TParser
|
parser*: TParser
|
||||||
|
|
||||||
|
|
||||||
proc ParseFile*(filename: string): PNode{.procvar.}
|
proc parseFile*(fileIdx: int32): PNode{.procvar.}
|
||||||
proc openParsers*(p: var TParsers, filename: string, inputstream: PLLStream)
|
proc openParsers*(p: var TParsers, fileIdx: int32, inputstream: PLLStream)
|
||||||
proc closeParsers*(p: var TParsers)
|
proc closeParsers*(p: var TParsers)
|
||||||
proc parseAll*(p: var TParsers): PNode
|
proc parseAll*(p: var TParsers): PNode
|
||||||
proc parseTopLevelStmt*(p: var TParsers): PNode
|
proc parseTopLevelStmt*(p: var TParsers): PNode
|
||||||
|
|
@ -40,14 +40,15 @@ proc parseTopLevelStmt*(p: var TParsers): PNode
|
||||||
|
|
||||||
# implementation
|
# implementation
|
||||||
|
|
||||||
proc ParseFile(filename: string): PNode =
|
proc ParseFile(fileIdx: int32): PNode =
|
||||||
var
|
var
|
||||||
p: TParsers
|
p: TParsers
|
||||||
f: tfile
|
f: tfile
|
||||||
|
let filename = fileIdx.toFilename
|
||||||
if not open(f, filename):
|
if not open(f, filename):
|
||||||
rawMessage(errCannotOpenFile, filename)
|
rawMessage(errCannotOpenFile, filename)
|
||||||
return
|
return
|
||||||
OpenParsers(p, filename, LLStreamOpen(f))
|
OpenParsers(p, fileIdx, LLStreamOpen(f))
|
||||||
result = ParseAll(p)
|
result = ParseAll(p)
|
||||||
CloseParsers(p)
|
CloseParsers(p)
|
||||||
|
|
||||||
|
|
@ -160,15 +161,16 @@ proc evalPipe(p: var TParsers, n: PNode, filename: string,
|
||||||
else:
|
else:
|
||||||
result = applyFilter(p, n, filename, result)
|
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
|
var s: PLLStream
|
||||||
p.skin = skinStandard
|
p.skin = skinStandard
|
||||||
|
let filename = fileIdx.toFilename
|
||||||
var pipe = parsePipe(filename, inputStream)
|
var pipe = parsePipe(filename, inputStream)
|
||||||
if pipe != nil: s = evalPipe(p, pipe, filename, inputStream)
|
if pipe != nil: s = evalPipe(p, pipe, filename, inputStream)
|
||||||
else: s = inputStream
|
else: s = inputStream
|
||||||
case p.skin
|
case p.skin
|
||||||
of skinStandard, skinBraces, skinEndX:
|
of skinStandard, skinBraces, skinEndX:
|
||||||
parser.openParser(p.parser, filename, s)
|
parser.openParser(p.parser, fileIdx, s)
|
||||||
|
|
||||||
proc closeParsers(p: var TParsers) =
|
proc closeParsers(p: var TParsers) =
|
||||||
parser.closeParser(p.parser)
|
parser.closeParser(p.parser)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue