big refactoring: magicsys compiles again

This commit is contained in:
Andreas Rumpf 2018-05-10 13:12:42 +02:00
commit 0d56dd4677
10 changed files with 269 additions and 244 deletions

View file

@ -27,7 +27,7 @@ type
emit, conc, toStr: string emit, conc, toStr: string
curly, bracket, par: int curly, bracket, par: int
pendingExprLine: bool pendingExprLine: bool
config: ConfigRef
const const
PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'} PatternChars = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF', '.', '_'}
@ -90,7 +90,7 @@ proc parseLine(p: var TTmplParser) =
dec(p.indent, 2) dec(p.indent, 2)
else: else:
p.info.col = int16(j) p.info.col = int16(j)
localError(p.info, errXNotAllowedHere, "end") localError(p.config, p.info, "'end' does not close a control flow construct")
llStreamWrite(p.outp, spaces(p.indent)) llStreamWrite(p.outp, spaces(p.indent))
llStreamWrite(p.outp, "#end") llStreamWrite(p.outp, "#end")
of "if", "when", "try", "while", "for", "block", "case", "proc", "iterator", of "if", "when", "try", "while", "for", "block", "case", "proc", "iterator",
@ -175,7 +175,7 @@ proc parseLine(p: var TTmplParser) =
llStreamWrite(p.outp, p.x[j]) llStreamWrite(p.outp, p.x[j])
inc(j) inc(j)
if curly > 0: if curly > 0:
localError(p.info, errXExpected, "}") localError(p.config, p.info, "expected closing '}'")
break break
llStreamWrite(p.outp, ')') llStreamWrite(p.outp, ')')
llStreamWrite(p.outp, p.conc) llStreamWrite(p.outp, p.conc)
@ -197,22 +197,23 @@ proc parseLine(p: var TTmplParser) =
inc(j) inc(j)
else: else:
p.info.col = int16(j) p.info.col = int16(j)
localError(p.info, errInvalidExpression, "$") localError(p.config, p.info, "invalid expression")
else: else:
llStreamWrite(p.outp, p.x[j]) llStreamWrite(p.outp, p.x[j])
inc(j) inc(j)
llStreamWrite(p.outp, "\\n\"") llStreamWrite(p.outp, "\\n\"")
proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode): PLLStream = proc filterTmpl*(stdin: PLLStream, filename: string, call: PNode; conf: ConfigRef): PLLStream =
var p: TTmplParser var p: TTmplParser
p.info = newLineInfo(filename, 0, 0) p.config = conf
p.info = newLineInfo(conf, filename, 0, 0)
p.outp = llStreamOpen("") p.outp = llStreamOpen("")
p.inp = stdin p.inp = stdin
p.subsChar = charArg(call, "subschar", 1, '$') p.subsChar = charArg(conf, call, "subschar", 1, '$')
p.nimDirective = charArg(call, "metachar", 2, '#') p.nimDirective = charArg(conf, call, "metachar", 2, '#')
p.emit = strArg(call, "emit", 3, "result.add") p.emit = strArg(conf, call, "emit", 3, "result.add")
p.conc = strArg(call, "conc", 4, " & ") p.conc = strArg(conf, call, "conc", 4, " & ")
p.toStr = strArg(call, "tostring", 5, "$") p.toStr = strArg(conf, call, "tostring", 5, "$")
p.x = newStringOfCap(120) p.x = newStringOfCap(120)
# do not process the first line which contains the directive: # do not process the first line which contains the directive:
if llStreamReadLine(p.inp, p.x): if llStreamReadLine(p.inp, p.x):

View file

@ -13,43 +13,44 @@ import
llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options, llstream, os, wordrecg, idents, strutils, ast, astalgo, msgs, options,
renderer renderer
proc invalidPragma(n: PNode) = proc invalidPragma(conf: ConfigRef; n: PNode) =
localError(n.info, errXNotAllowedHere, renderTree(n, {renderNoComments})) localError(conf, n.info,
"'$1' not allowed here" % renderTree(n, {renderNoComments}))
proc getArg(n: PNode, name: string, pos: int): PNode = proc getArg(conf: ConfigRef; n: PNode, name: string, pos: int): PNode =
result = nil result = nil
if n.kind in {nkEmpty..nkNilLit}: return if n.kind in {nkEmpty..nkNilLit}: return
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
if n.sons[i].kind == nkExprEqExpr: if n.sons[i].kind == nkExprEqExpr:
if n.sons[i].sons[0].kind != nkIdent: invalidPragma(n) if n.sons[i].sons[0].kind != nkIdent: invalidPragma(conf, n)
if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0: if cmpIgnoreStyle(n.sons[i].sons[0].ident.s, name) == 0:
return n.sons[i].sons[1] return n.sons[i].sons[1]
elif i == pos: elif i == pos:
return n.sons[i] return n.sons[i]
proc charArg*(n: PNode, name: string, pos: int, default: char): char = proc charArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: char): char =
var x = getArg(n, name, pos) var x = getArg(conf, n, name, pos)
if x == nil: result = default if x == nil: result = default
elif x.kind == nkCharLit: result = chr(int(x.intVal)) elif x.kind == nkCharLit: result = chr(int(x.intVal))
else: invalidPragma(n) else: invalidPragma(conf, n)
proc strArg*(n: PNode, name: string, pos: int, default: string): string = proc strArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: string): string =
var x = getArg(n, name, pos) var x = getArg(conf, n, name, pos)
if x == nil: result = default if x == nil: result = default
elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal elif x.kind in {nkStrLit..nkTripleStrLit}: result = x.strVal
else: invalidPragma(n) else: invalidPragma(conf, n)
proc boolArg*(n: PNode, name: string, pos: int, default: bool): bool = proc boolArg*(conf: ConfigRef; n: PNode, name: string, pos: int, default: bool): bool =
var x = getArg(n, name, pos) var x = getArg(conf, n, name, pos)
if x == nil: result = default if x == nil: result = default
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "true") == 0: result = true
elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false elif x.kind == nkIdent and cmpIgnoreStyle(x.ident.s, "false") == 0: result = false
else: invalidPragma(n) else: invalidPragma(conf, n)
proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream = proc filterStrip*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
var pattern = strArg(call, "startswith", 1, "") var pattern = strArg(conf, call, "startswith", 1, "")
var leading = boolArg(call, "leading", 2, true) var leading = boolArg(conf, call, "leading", 2, true)
var trailing = boolArg(call, "trailing", 3, true) var trailing = boolArg(conf, call, "trailing", 3, true)
result = llStreamOpen("") result = llStreamOpen("")
var line = newStringOfCap(80) var line = newStringOfCap(80)
while llStreamReadLine(stdin, line): while llStreamReadLine(stdin, line):
@ -60,10 +61,10 @@ proc filterStrip*(stdin: PLLStream, filename: string, call: PNode): PLLStream =
llStreamWriteln(result, line) llStreamWriteln(result, line)
llStreamClose(stdin) llStreamClose(stdin)
proc filterReplace*(stdin: PLLStream, filename: string, call: PNode): PLLStream = proc filterReplace*(conf: ConfigRef; stdin: PLLStream, filename: string, call: PNode): PLLStream =
var sub = strArg(call, "sub", 1, "") var sub = strArg(conf, call, "sub", 1, "")
if len(sub) == 0: invalidPragma(call) if len(sub) == 0: invalidPragma(conf, call)
var by = strArg(call, "by", 2, "") var by = strArg(conf, call, "by", 2, "")
result = llStreamOpen("") result = llStreamOpen("")
var line = newStringOfCap(80) var line = newStringOfCap(80)
while llStreamReadLine(stdin, line): while llStreamReadLine(stdin, line):

View file

@ -10,63 +10,59 @@
# Built-in types and compilerprocs are registered here. # Built-in types and compilerprocs are registered here.
import import
ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread ast, astalgo, hashes, msgs, platform, nversion, times, idents, rodread,
modulegraphs
var systemModule*: PSym proc nilOrSysInt*(g: ModuleGraph): PType = g.sysTypes[tyInt]
var proc registerSysType*(g: ModuleGraph; t: PType) =
gSysTypes: array[TTypeKind, PType] if g.sysTypes[t.kind] == nil: g.sysTypes[t.kind] = t
compilerprocs: TStrTable
exposed: TStrTable
proc nilOrSysInt*: PType = gSysTypes[tyInt] proc newSysType(g: ModuleGraph; kind: TTypeKind, size: int): PType =
result = newType(kind, g.systemModule)
proc registerSysType*(t: PType) =
if gSysTypes[t.kind] == nil: gSysTypes[t.kind] = t
proc newSysType(kind: TTypeKind, size: int): PType =
result = newType(kind, systemModule)
result.size = size result.size = size
result.align = size.int16 result.align = size.int16
proc getSysSym*(name: string): PSym = proc getSysSym*(g: ModuleGraph; info: TLineInfo; name: string): PSym =
result = strTableGet(systemModule.tab, getIdent(name)) result = strTableGet(g.systemModule.tab, getIdent(name))
if result == nil: if result == nil:
rawMessage(errSystemNeeds, name) localError(g.config, info, "system module needs: " & name)
result = newSym(skError, getIdent(name), systemModule, systemModule.info) result = newSym(skError, getIdent(name), g.systemModule, g.systemModule.info)
result.typ = newType(tyError, systemModule) result.typ = newType(tyError, g.systemModule)
if result.kind == skStub: loadStub(result) if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner if result.kind == skAlias: result = result.owner
proc createMagic*(name: string, m: TMagic): PSym = proc createMagic*(g: ModuleGraph; name: string, m: TMagic): PSym =
result = newSym(skProc, getIdent(name), nil, unknownLineInfo()) result = newSym(skProc, getIdent(name), nil, unknownLineInfo())
result.magic = m result.magic = m
let when false:
opNot* = createMagic("not", mNot) let
opContains* = createMagic("contains", mInSet) opNot* = createMagic("not", mNot)
opContains* = createMagic("contains", mInSet)
proc getSysMagic*(name: string, m: TMagic): PSym = proc getSysMagic*(g: ModuleGraph; info: TLineInfo; name: string, m: TMagic): PSym =
var ti: TIdentIter var ti: TIdentIter
let id = getIdent(name) let id = getIdent(name)
var r = initIdentIter(ti, systemModule.tab, id) var r = initIdentIter(ti, g.systemModule.tab, id)
while r != nil: while r != nil:
if r.kind == skStub: loadStub(r) if r.kind == skStub: loadStub(r)
if r.magic == m: if r.magic == m:
# prefer the tyInt variant: # prefer the tyInt variant:
if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r if r.typ.sons[0] != nil and r.typ.sons[0].kind == tyInt: return r
result = r result = r
r = nextIdentIter(ti, systemModule.tab) r = nextIdentIter(ti, g.systemModule.tab)
if result != nil: return result if result != nil: return result
rawMessage(errSystemNeeds, name) localError(g.config, info, "system module needs: " & name)
result = newSym(skError, id, systemModule, systemModule.info) result = newSym(skError, id, g.systemModule, g.systemModule.info)
result.typ = newType(tyError, systemModule) result.typ = newType(tyError, g.systemModule)
proc sysTypeFromName*(name: string): PType = proc sysTypeFromName*(g: ModuleGraph; info: TLineInfo; name: string): PType =
result = getSysSym(name).typ result = getSysSym(g, info, name).typ
proc getSysType*(kind: TTypeKind): PType = proc getSysType*(g: ModuleGraph; info: TLineInfo; kind: TTypeKind): PType =
result = gSysTypes[kind] template sysTypeFromName(s: string): untyped = sysTypeFromName(g, info, s)
result = g.sysTypes[kind]
if result == nil: if result == nil:
case kind case kind
of tyInt: result = sysTypeFromName("int") of tyInt: result = sysTypeFromName("int")
@ -88,51 +84,49 @@ proc getSysType*(kind: TTypeKind): PType =
of tyString: result = sysTypeFromName("string") of tyString: result = sysTypeFromName("string")
of tyCString: result = sysTypeFromName("cstring") of tyCString: result = sysTypeFromName("cstring")
of tyPointer: result = sysTypeFromName("pointer") of tyPointer: result = sysTypeFromName("pointer")
of tyNil: result = newSysType(tyNil, ptrSize) of tyNil: result = newSysType(g, tyNil, ptrSize)
else: internalError("request for typekind: " & $kind) else: internalError(g.config, "request for typekind: " & $kind)
gSysTypes[kind] = result g.sysTypes[kind] = result
if result.kind != kind: if result.kind != kind:
internalError("wanted: " & $kind & " got: " & $result.kind) internalError(g.config, "wanted: " & $kind & " got: " & $result.kind)
if result == nil: internalError("type not found: " & $kind) if result == nil: internalError(g.config, "type not found: " & $kind)
var proc resetSysTypes*(g: ModuleGraph) =
intTypeCache: array[-5..64, PType] g.systemModule = nil
initStrTable(g.compilerprocs)
initStrTable(g.exposed)
for i in low(g.sysTypes)..high(g.sysTypes):
g.sysTypes[i] = nil
proc resetSysTypes* = for i in low(g.intTypeCache)..high(g.intTypeCache):
systemModule = nil g.intTypeCache[i] = nil
initStrTable(compilerprocs)
initStrTable(exposed)
for i in low(gSysTypes)..high(gSysTypes):
gSysTypes[i] = nil
for i in low(intTypeCache)..high(intTypeCache): proc getIntLitType*(g: ModuleGraph; literal: PNode): PType =
intTypeCache[i] = nil
proc getIntLitType*(literal: PNode): PType =
# we cache some common integer literal types for performance: # we cache some common integer literal types for performance:
let value = literal.intVal let value = literal.intVal
if value >= low(intTypeCache) and value <= high(intTypeCache): if value >= low(g.intTypeCache) and value <= high(g.intTypeCache):
result = intTypeCache[value.int] result = g.intTypeCache[value.int]
if result == nil: if result == nil:
let ti = getSysType(tyInt) let ti = getSysType(g, literal.info, tyInt)
result = copyType(ti, ti.owner, false) result = copyType(ti, ti.owner, false)
result.n = literal result.n = literal
intTypeCache[value.int] = result g.intTypeCache[value.int] = result
else: else:
let ti = getSysType(tyInt) let ti = getSysType(g, literal.info, tyInt)
result = copyType(ti, ti.owner, false) result = copyType(ti, ti.owner, false)
result.n = literal result.n = literal
proc getFloatLitType*(literal: PNode): PType = proc getFloatLitType*(g: ModuleGraph; literal: PNode): PType =
# for now we do not cache these: # for now we do not cache these:
result = newSysType(tyFloat, size=8) result = newSysType(g, tyFloat, size=8)
result.n = literal result.n = literal
proc skipIntLit*(t: PType): PType {.inline.} = proc skipIntLit*(t: PType): PType {.inline.} =
if t.n != nil: if t.n != nil and t.kind in {tyInt, tyFloat}:
if t.kind in {tyInt, tyFloat}: result = copyType(t, t.owner, false)
return getSysType(t.kind) result.n = nil
result = t else:
result = t
proc addSonSkipIntLit*(father, son: PType) = proc addSonSkipIntLit*(father, son: PType) =
if isNil(father.sons): father.sons = @[] if isNil(father.sons): father.sons = @[]
@ -140,60 +134,59 @@ proc addSonSkipIntLit*(father, son: PType) =
add(father.sons, s) add(father.sons, s)
propagateToOwner(father, s) propagateToOwner(father, s)
proc setIntLitType*(result: PNode) = proc setIntLitType*(g: ModuleGraph; result: PNode) =
let i = result.intVal let i = result.intVal
case platform.intSize case platform.intSize
of 8: result.typ = getIntLitType(result) of 8: result.typ = getIntLitType(g, result)
of 4: of 4:
if i >= low(int32) and i <= high(int32): if i >= low(int32) and i <= high(int32):
result.typ = getIntLitType(result) result.typ = getIntLitType(g, result)
else: else:
result.typ = getSysType(tyInt64) result.typ = getSysType(g, result.info, tyInt64)
of 2: of 2:
if i >= low(int16) and i <= high(int16): if i >= low(int16) and i <= high(int16):
result.typ = getIntLitType(result) result.typ = getIntLitType(g, result)
elif i >= low(int32) and i <= high(int32): elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(tyInt32) result.typ = getSysType(g, result.info, tyInt32)
else: else:
result.typ = getSysType(tyInt64) result.typ = getSysType(g, result.info, tyInt64)
of 1: of 1:
# 8 bit CPUs are insane ... # 8 bit CPUs are insane ...
if i >= low(int8) and i <= high(int8): if i >= low(int8) and i <= high(int8):
result.typ = getIntLitType(result) result.typ = getIntLitType(g, result)
elif i >= low(int16) and i <= high(int16): elif i >= low(int16) and i <= high(int16):
result.typ = getSysType(tyInt16) result.typ = getSysType(g, result.info, tyInt16)
elif i >= low(int32) and i <= high(int32): elif i >= low(int32) and i <= high(int32):
result.typ = getSysType(tyInt32) result.typ = getSysType(g, result.info, tyInt32)
else: else:
result.typ = getSysType(tyInt64) result.typ = getSysType(g, result.info, tyInt64)
else: internalError(result.info, "invalid int size")
proc getCompilerProc*(name: string): PSym =
let ident = getIdent(name)
result = strTableGet(compilerprocs, ident)
if result == nil:
result = strTableGet(rodCompilerprocs, ident)
if result != nil:
strTableAdd(compilerprocs, result)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner
proc registerCompilerProc*(s: PSym) =
strTableAdd(compilerprocs, s)
proc registerNimScriptSymbol*(s: PSym) =
# Nimscript symbols must be al unique:
let conflict = strTableGet(exposed, s.name)
if conflict == nil:
strTableAdd(exposed, s)
else: else:
localError(s.info, "symbol conflicts with other .exportNims symbol at: " & internalError(g.config, result.info, "invalid int size")
$conflict.info)
proc getNimScriptSymbol*(name: string): PSym = proc getCompilerProc*(g: ModuleGraph; name: string): PSym =
strTableGet(exposed, getIdent(name)) let ident = getIdent(name)
result = strTableGet(g.compilerprocs, ident)
when false:
if result == nil:
result = strTableGet(g.rodCompilerprocs, ident)
if result != nil:
strTableAdd(g.compilerprocs, result)
if result.kind == skStub: loadStub(result)
if result.kind == skAlias: result = result.owner
proc resetNimScriptSymbols*() = initStrTable(exposed) proc registerCompilerProc*(g: ModuleGraph; s: PSym) =
strTableAdd(g.compilerprocs, s)
initStrTable(compilerprocs) proc registerNimScriptSymbol*(g: ModuleGraph; s: PSym) =
initStrTable(exposed) # Nimscript symbols must be al unique:
let conflict = strTableGet(g.exposed, s.name)
if conflict == nil:
strTableAdd(g.exposed, s)
else:
localError(g.config, s.info,
"symbol conflicts with other .exportNims symbol at: " & $conflict.info)
proc getNimScriptSymbol*(g: ModuleGraph; name: string): PSym =
strTableGet(g.exposed, getIdent(name))
proc resetNimScriptSymbols*(g: ModuleGraph) = initStrTable(g.exposed)

View file

@ -44,6 +44,11 @@ type
usageSym*: PSym # for nimsuggest usageSym*: PSym # for nimsuggest
owners*: seq[PSym] owners*: seq[PSym]
methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]] methods*: seq[tuple[methods: TSymSeq, dispatcher: PSym]]
systemModule*: PSym
sysTypes*: array[TTypeKind, PType]
compilerprocs*: TStrTable
exposed*: TStrTable
intTypeCache*: array[-5..64, PType]
proc hash*(x: FileIndex): Hash {.borrow.} proc hash*(x: FileIndex): Hash {.borrow.}
@ -65,6 +70,8 @@ proc newModuleGraph*(config: ConfigRef = nil): ModuleGraph =
result.config = config result.config = config
result.owners = @[] result.owners = @[]
result.methods = @[] result.methods = @[]
initStrTable(result.compilerprocs)
initStrTable(result.exposed)
proc resetAllModules*(g: ModuleGraph) = proc resetAllModules*(g: ModuleGraph) =
initStrTable(packageSyms) initStrTable(packageSyms)
@ -75,6 +82,8 @@ proc resetAllModules*(g: ModuleGraph) =
usageSym = nil usageSym = nil
owners = @[] owners = @[]
methods = @[] methods = @[]
initStrTable(compilerprocs)
initStrTable(exposed)
proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym = proc getModule*(g: ModuleGraph; fileIdx: FileIndex): PSym =
if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len: if fileIdx.int32 >= 0 and fileIdx.int32 < modules.len:

View file

@ -629,9 +629,9 @@ proc quotedFilename*(i: TLineInfo): Rope =
ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) = ropes.errorHandler = proc (err: RopesError, msg: string, useWarning: bool) =
case err case err
of rInvalidFormatStr: of rInvalidFormatStr:
internalError(newConfigRef(), "ropes: invalid format string: " & msg) internalError(newPartialConfigRef(), "ropes: invalid format string: " & msg)
of rCannotOpenFile: of rCannotOpenFile:
rawMessage(newConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg) rawMessage(newPartialConfigRef(), if useWarning: warnCannotOpenFile else: errCannotOpenFile, msg)
proc listWarnings*(conf: ConfigRef) = proc listWarnings*(conf: ConfigRef) =
msgWriteln("Warnings:") msgWriteln("Warnings:")

View file

@ -141,6 +141,12 @@ proc newConfigRef*(): ConfigRef =
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1], notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1],
symbols: newStringTable(modeStyleInsensitive)) symbols: newStringTable(modeStyleInsensitive))
proc newPartialConfigRef*(): ConfigRef =
## create a new ConfigRef that is only good enough for error reporting.
result = ConfigRef(foreignPackageNotes: {hintProcessing, warnUnknownMagic,
hintQuitCalled, hintExecuting},
notes: NotesVerbosity[1], mainPackageNotes: NotesVerbosity[1])
proc cppDefine*(c: ConfigRef; define: string) = proc cppDefine*(c: ConfigRef; define: string) =
c.cppDefines.incl define c.cppDefines.incl define

View file

@ -10,7 +10,7 @@
# This module implements the renderer of the standard Nim representation. # This module implements the renderer of the standard Nim representation.
import import
lexer, options, idents, strutils, ast, msgs lexer, options, idents, strutils, ast, msgs, configuration
type type
TRenderFlag* = enum TRenderFlag* = enum
@ -40,6 +40,7 @@ type
when defined(nimpretty): when defined(nimpretty):
pendingNewlineCount: int pendingNewlineCount: int
fid*: FileIndex fid*: FileIndex
config*: ConfigRef
# We render the source code in a two phases: The first # We render the source code in a two phases: The first
# determines how long the subtree will likely be, the second # determines how long the subtree will likely be, the second
@ -90,7 +91,7 @@ const
MaxLineLen = 80 MaxLineLen = 80
LineCommentColumn = 30 LineCommentColumn = 30
proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) = proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags; config: ConfigRef) =
g.comStack = @[] g.comStack = @[]
g.tokens = @[] g.tokens = @[]
g.indent = 0 g.indent = 0
@ -102,6 +103,7 @@ proc initSrcGen(g: var TSrcGen, renderFlags: TRenderFlags) =
g.pendingNL = -1 g.pendingNL = -1
g.pendingWhitespace = -1 g.pendingWhitespace = -1
g.inGenericParams = false g.inGenericParams = false
g.config = config
proc addTok(g: var TSrcGen, kind: TTokType, s: string) = proc addTok(g: var TSrcGen, kind: TTokType, s: string) =
var length = len(g.tokens) var length = len(g.tokens)
@ -377,7 +379,7 @@ proc atom(g: TSrcGen; n: PNode): string =
if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s if (n.typ != nil) and (n.typ.sym != nil): result = n.typ.sym.name.s
else: result = "[type node]" else: result = "[type node]"
else: else:
internalError("rnimsyn.atom " & $n.kind) internalError(g.config, "rnimsyn.atom " & $n.kind)
result = "" result = ""
proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int = proc lcomma(g: TSrcGen; n: PNode, start: int = 0, theEnd: int = - 1): int =
@ -1422,11 +1424,11 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) =
gTypeClassTy(g, n) gTypeClassTy(g, n)
else: else:
#nkNone, nkExplicitTypeListCall: #nkNone, nkExplicitTypeListCall:
internalError(n.info, "rnimsyn.gsub(" & $n.kind & ')') internalError(g.config, n.info, "rnimsyn.gsub(" & $n.kind & ')')
proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string = proc renderTree*(n: PNode, renderFlags: TRenderFlags = {}): string =
var g: TSrcGen var g: TSrcGen
initSrcGen(g, renderFlags) initSrcGen(g, renderFlags, newPartialConfigRef())
# do not indent the initial statement list so that # do not indent the initial statement list so that
# writeFile("file.nim", repr n) # writeFile("file.nim", repr n)
# produces working Nim code: # produces working Nim code:
@ -1444,7 +1446,7 @@ proc renderModule*(n: PNode, infile, outfile: string,
var var
f: File f: File
g: TSrcGen g: TSrcGen
initSrcGen(g, renderFlags) initSrcGen(g, renderFlags, newPartialConfigRef())
g.fid = fid g.fid = fid
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
gsub(g, n.sons[i]) gsub(g, n.sons[i])
@ -1460,10 +1462,10 @@ proc renderModule*(n: PNode, infile, outfile: string,
write(f, g.buf) write(f, g.buf)
close(f) close(f)
else: else:
rawMessage(errCannotOpenFile, outfile) rawMessage(g.config, errGenerated, "cannot open file: " & outfile)
proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) = proc initTokRender*(r: var TSrcGen, n: PNode, renderFlags: TRenderFlags = {}) =
initSrcGen(r, renderFlags) initSrcGen(r, renderFlags, newPartialConfigRef())
gsub(r, n) gsub(r, n)
proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) = proc getNextTok*(r: var TSrcGen, kind: var TTokType, literal: var string) =

View file

@ -90,7 +90,8 @@
import import
os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms, os, options, strutils, nversion, ast, astalgo, msgs, platform, condsyms,
ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables ropes, idents, std / sha1, idgen, types, rodutils, memfiles, tables,
configuration
type type
TReasonForRecompile* = enum ## all the reasons that can trigger recompilation TReasonForRecompile* = enum ## all the reasons that can trigger recompilation
@ -143,6 +144,7 @@ type
origFile: string origFile: string
inViewMode: bool inViewMode: bool
cache*: IdentCache cache*: IdentCache
config: ConfigRef
PRodReader* = ref TRodReader PRodReader* = ref TRodReader
@ -222,14 +224,14 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
var fl = decodeStr(r.s, r.pos) var fl = decodeStr(r.s, r.pos)
result.ident = r.cache.getIdent(fl) result.ident = r.cache.getIdent(fl)
else: else:
internalError(result.info, "decodeNode: nkIdent") internalError(r.config, result.info, "decodeNode: nkIdent")
of nkSym: of nkSym:
if r.s[r.pos] == '!': if r.s[r.pos] == '!':
inc(r.pos) inc(r.pos)
var id = decodeVInt(r.s, r.pos) var id = decodeVInt(r.s, r.pos)
result.sym = rrGetSym(r, id, result.info) result.sym = rrGetSym(r, id, result.info)
else: else:
internalError(result.info, "decodeNode: nkSym") internalError(r.config, result.info, "decodeNode: nkSym")
else: else:
var i = 0 var i = 0
while r.s[r.pos] != ')': while r.s[r.pos] != ')':
@ -241,9 +243,9 @@ proc decodeNodeLazyBody(r: PRodReader, fInfo: TLineInfo,
addSonNilAllowed(result, decodeNodeLazyBody(r, result.info, nil)) addSonNilAllowed(result, decodeNodeLazyBody(r, result.info, nil))
inc i inc i
if r.s[r.pos] == ')': inc(r.pos) if r.s[r.pos] == ')': inc(r.pos)
else: internalError(result.info, "decodeNode: ')' missing") else: internalError(r.config, result.info, "decodeNode: ')' missing")
else: else:
internalError(fInfo, "decodeNode: '(' missing " & $r.pos) internalError(r.config, fInfo, "decodeNode: '(' missing " & $r.pos)
proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode = proc decodeNode(r: PRodReader, fInfo: TLineInfo): PNode =
result = decodeNodeLazyBody(r, fInfo, nil) result = decodeNodeLazyBody(r, fInfo, nil)
@ -277,7 +279,7 @@ proc decodeLoc(r: PRodReader, loc: var TLoc, info: TLineInfo) =
else: else:
loc.r = nil loc.r = nil
if r.s[r.pos] == '>': inc(r.pos) if r.s[r.pos] == '>': inc(r.pos)
else: internalError(info, "decodeLoc " & r.s[r.pos]) else: internalError(r.config, info, "decodeLoc " & r.s[r.pos])
proc decodeType(r: PRodReader, info: TLineInfo): PType = proc decodeType(r: PRodReader, info: TLineInfo): PType =
result = nil result = nil
@ -294,7 +296,7 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
setId(result.id) setId(result.id)
if debugIds: registerID(result) if debugIds: registerID(result)
else: else:
internalError(info, "decodeType: no id") internalError(r.config, info, "decodeType: no id")
# here this also avoids endless recursion for recursive type # here this also avoids endless recursion for recursive type
idTablePut(gTypeTable, result, result) idTablePut(gTypeTable, result, result)
if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo()) if r.s[r.pos] == '(': result.n = decodeNode(r, unknownLineInfo())
@ -345,14 +347,14 @@ proc decodeType(r: PRodReader, info: TLineInfo): PType =
doAssert r.s[r.pos] == '\20' doAssert r.s[r.pos] == '\20'
inc(r.pos) inc(r.pos)
let y = rrGetSym(r, decodeVInt(r.s, r.pos), info) let y = rrGetSym(r, decodeVInt(r.s, r.pos), info)
result.methods.safeAdd((x, y)) result.methods.add((x, y))
decodeLoc(r, result.loc, info) decodeLoc(r, result.loc, info)
while r.s[r.pos] == '^': while r.s[r.pos] == '^':
inc(r.pos) inc(r.pos)
if r.s[r.pos] == '(': if r.s[r.pos] == '(':
inc(r.pos) inc(r.pos)
if r.s[r.pos] == ')': inc(r.pos) if r.s[r.pos] == ')': inc(r.pos)
else: internalError(info, "decodeType ^(" & r.s[r.pos]) else: internalError(r.config, info, "decodeType ^(" & r.s[r.pos])
rawAddSon(result, nil) rawAddSon(result, nil)
else: else:
var d = decodeVInt(r.s, r.pos) var d = decodeVInt(r.s, r.pos)
@ -364,10 +366,10 @@ proc decodeLib(r: PRodReader, info: TLineInfo): PLib =
new(result) new(result)
inc(r.pos) inc(r.pos)
result.kind = TLibKind(decodeVInt(r.s, r.pos)) result.kind = TLibKind(decodeVInt(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 1") if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 1")
inc(r.pos) inc(r.pos)
result.name = rope(decodeStr(r.s, r.pos)) result.name = rope(decodeStr(r.s, r.pos))
if r.s[r.pos] != '|': internalError("decodeLib: 2") if r.s[r.pos] != '|': internalError(r.config, "decodeLib: 2")
inc(r.pos) inc(r.pos)
result.path = decodeNode(r, info) result.path = decodeNode(r, info)
@ -385,7 +387,7 @@ proc decodeInstantiations(r: PRodReader; info: TLineInfo;
if r.s[r.pos] == '\20': if r.s[r.pos] == '\20':
inc(r.pos) inc(r.pos)
ii.compilesId = decodeVInt(r.s, r.pos) ii.compilesId = decodeVInt(r.s, r.pos)
s.safeAdd ii s.add ii
proc decodeSym(r: PRodReader, info: TLineInfo): PSym = proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
var var
@ -403,12 +405,12 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
id = decodeVInt(r.s, r.pos) id = decodeVInt(r.s, r.pos)
setId(id) setId(id)
else: else:
internalError(info, "decodeSym: no id") internalError(r.config, info, "decodeSym: no id")
if r.s[r.pos] == '&': if r.s[r.pos] == '&':
inc(r.pos) inc(r.pos)
ident = r.cache.getIdent(decodeStr(r.s, r.pos)) ident = r.cache.getIdent(decodeStr(r.s, r.pos))
else: else:
internalError(info, "decodeSym: no ident") internalError(r.config, info, "decodeSym: no ident")
#echo "decoding: {", ident.s #echo "decoding: {", ident.s
result = r.syms.getOrDefault(id) result = r.syms.getOrDefault(id)
if result == nil: if result == nil:
@ -417,7 +419,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
r.syms[result.id] = result r.syms[result.id] = result
if debugIds: registerID(result) if debugIds: registerID(result)
elif result.id != id: elif result.id != id:
internalError(info, "decodeSym: wrong id") internalError(r.config, info, "decodeSym: wrong id")
elif result.kind != skStub and not r.inViewMode: elif result.kind != skStub and not r.inViewMode:
# we already loaded the symbol # we already loaded the symbol
return return
@ -465,7 +467,7 @@ proc decodeSym(r: PRodReader, info: TLineInfo): PSym =
of skType, skGenericParam: of skType, skGenericParam:
while r.s[r.pos] == '\14': while r.s[r.pos] == '\14':
inc(r.pos) inc(r.pos)
result.typeInstCache.safeAdd rrGetType(r, decodeVInt(r.s, r.pos), result.info) result.typeInstCache.add rrGetType(r, decodeVInt(r.s, r.pos), result.info)
of routineKinds: of routineKinds:
decodeInstantiations(r, result.info, result.procInstCache) decodeInstantiations(r, result.info, result.procInstCache)
if r.s[r.pos] == '\16': if r.s[r.pos] == '\16':
@ -512,7 +514,7 @@ proc skipSection(r: PRodReader) =
else: discard else: discard
inc(r.pos) inc(r.pos)
else: else:
internalError("skipSection " & $r.line) internalError(r.config, "skipSection " & $r.line)
proc rdWord(r: PRodReader): string = proc rdWord(r: PRodReader): string =
result = "" result = ""
@ -530,7 +532,7 @@ proc newStub(r: PRodReader, name: string, id: int): PSym =
if debugIds: registerID(result) if debugIds: registerID(result)
proc processInterf(r: PRodReader, module: PSym) = proc processInterf(r: PRodReader, module: PSym) =
if r.interfIdx == 0: internalError("processInterf") if r.interfIdx == 0: internalError(r.config, "processInterf")
r.pos = r.interfIdx r.pos = r.interfIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos) var w = decodeStr(r.s, r.pos)
@ -543,7 +545,7 @@ proc processInterf(r: PRodReader, module: PSym) =
r.syms[s.id] = s r.syms[s.id] = s
proc processCompilerProcs(r: PRodReader, module: PSym) = proc processCompilerProcs(r: PRodReader, module: PSym) =
if r.compilerProcsIdx == 0: internalError("processCompilerProcs") if r.compilerProcsIdx == 0: internalError(r.config, "processCompilerProcs")
r.pos = r.compilerProcsIdx r.pos = r.compilerProcsIdx
while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'): while (r.s[r.pos] > '\x0A') and (r.s[r.pos] != ')'):
var w = decodeStr(r.s, r.pos) var w = decodeStr(r.s, r.pos)
@ -637,10 +639,10 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
while r.s[r.pos] > '\x0A': while r.s[r.pos] > '\x0A':
w = decodeStr(r.s, r.pos) w = decodeStr(r.s, r.pos)
inc(d) inc(d)
if not condsyms.isDefined(r.cache.getIdent(w)): if not isDefined(r.config, w):
r.reason = rrDefines #MessageOut('not defined, but should: ' + w); r.reason = rrDefines #MessageOut('not defined, but should: ' + w);
if r.s[r.pos] == ' ': inc(r.pos) if r.s[r.pos] == ' ': inc(r.pos)
if d != countDefinedSymbols(): r.reason = rrDefines if d != countDefinedSymbols(r.config.symbols): r.reason = rrDefines
of "FILES": of "FILES":
inc(r.pos, 2) # skip "(\10" inc(r.pos, 2) # skip "(\10"
inc(r.line) inc(r.line)
@ -648,7 +650,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
let finalPath = decodeStr(r.s, r.pos) let finalPath = decodeStr(r.s, r.pos)
#let resolvedPath = relativePath.findModule(r.origFile) #let resolvedPath = relativePath.findModule(r.origFile)
#let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath #let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx) r.files.add(fileInfoIdx(r.config, finalPath))
inc(r.pos) # skip #10 inc(r.pos) # skip #10
inc(r.line) inc(r.line)
if r.s[r.pos] == ')': inc(r.pos) if r.s[r.pos] == ')': inc(r.pos)
@ -696,7 +698,7 @@ proc processRodFile(r: PRodReader, hash: SecureHash) =
r.initIdx = r.pos + 2 # "(\10" r.initIdx = r.pos + 2 # "(\10"
skipSection(r) skipSection(r)
else: else:
internalError("invalid section: '" & section & internalError(r.config, "invalid section: '" & section &
"' at " & $r.line & " in " & r.filename) "' at " & $r.line & " in " & r.filename)
#MsgWriteln("skipping section: " & section & #MsgWriteln("skipping section: " & section &
# " at " & $r.line & " in " & r.filename) # " at " & $r.line & " in " & r.filename)
@ -712,9 +714,11 @@ proc startsWith(buf: cstring, token: string, pos = 0): bool =
result = s == token.len result = s == token.len
proc newRodReader(modfilename: string, hash: SecureHash, proc newRodReader(modfilename: string, hash: SecureHash,
readerIndex: int; cache: IdentCache): PRodReader = readerIndex: int; cache: IdentCache;
config: ConfigRef): PRodReader =
new(result) new(result)
result.cache = cache result.cache = cache
result.config = config
try: try:
result.memfile = memfiles.open(modfilename) result.memfile = memfiles.open(modfilename)
except OSError: except OSError:
@ -757,13 +761,13 @@ proc rrGetType(r: PRodReader, id: int, info: TLineInfo): PType =
# load the type: # load the type:
var oldPos = r.pos var oldPos = r.pos
var d = iiTableGet(r.index.tab, id) var d = iiTableGet(r.index.tab, id)
if d == InvalidKey: internalError(info, "rrGetType") if d == InvalidKey: internalError(r.config, info, "rrGetType")
r.pos = d + r.dataIdx r.pos = d + r.dataIdx
result = decodeType(r, info) result = decodeType(r, info)
r.pos = oldPos r.pos = oldPos
type type
TFileModuleRec{.final.} = object TFileModuleRec = object
filename*: string filename*: string
reason*: TReasonForRecompile reason*: TReasonForRecompile
rd*: PRodReader rd*: PRodReader
@ -776,7 +780,7 @@ 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
if rd.dataIdx == 0: internalError(info, "dataIdx == 0") if rd.dataIdx == 0: internalError(rd.config, info, "dataIdx == 0")
var oldPos = rd.pos var oldPos = rd.pos
rd.pos = offset + rd.dataIdx rd.pos = offset + rd.dataIdx
result = decodeSym(rd, info) result = decodeSym(rd, info)
@ -811,7 +815,7 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
if moduleID < 0: if moduleID < 0:
var x = "" var x = ""
encodeVInt(id, x) encodeVInt(id, x)
internalError(info, "missing from both indexes: +" & x) internalError(r.config, info, "missing from both indexes: +" & x)
var rd = getReader(moduleID) var rd = getReader(moduleID)
doAssert rd != nil doAssert rd != nil
d = iiTableGet(rd.index.tab, id) d = iiTableGet(rd.index.tab, id)
@ -821,14 +825,14 @@ proc rrGetSym(r: PRodReader, id: int, info: TLineInfo): PSym =
var x = "" var x = ""
encodeVInt(id, x) encodeVInt(id, x)
when false: findSomeWhere(id) when false: findSomeWhere(id)
internalError(info, "rrGetSym: no reader found: +" & x) internalError(r.config, info, "rrGetSym: no reader found: +" & x)
else: else:
# own symbol: # own symbol:
result = decodeSymSafePos(r, d, info) result = decodeSymSafePos(r, d, info)
if result != nil and result.kind == skStub: rawLoadStub(result) if result != nil and result.kind == skStub: rawLoadStub(result)
proc loadInitSection*(r: PRodReader): PNode = proc loadInitSection*(r: PRodReader): PNode =
if r.initIdx == 0 or r.dataIdx == 0: internalError("loadInitSection") if r.initIdx == 0 or r.dataIdx == 0: internalError(r.config, "loadInitSection")
var oldPos = r.pos var oldPos = r.pos
r.pos = r.initIdx r.pos = r.initIdx
result = newNode(nkStmtList) result = newNode(nkStmtList)
@ -845,7 +849,7 @@ proc loadConverters(r: PRodReader) =
# We have to ensure that no exported converter is a stub anymore, and the # We have to ensure that no exported converter is a stub anymore, and the
# import mechanism takes care of the rest. # import mechanism takes care of the rest.
if r.convertersIdx == 0 or r.dataIdx == 0: if r.convertersIdx == 0 or r.dataIdx == 0:
internalError("importConverters") internalError(r.config, "importConverters")
r.pos = r.convertersIdx r.pos = r.convertersIdx
while r.s[r.pos] > '\x0A': while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos) var d = decodeVInt(r.s, r.pos)
@ -854,7 +858,7 @@ proc loadConverters(r: PRodReader) =
proc loadMethods(r: PRodReader) = proc loadMethods(r: PRodReader) =
if r.methodsIdx == 0 or r.dataIdx == 0: if r.methodsIdx == 0 or r.dataIdx == 0:
internalError("loadMethods") internalError(r.config, "loadMethods")
r.pos = r.methodsIdx r.pos = r.methodsIdx
while r.s[r.pos] > '\x0A': while r.s[r.pos] > '\x0A':
var d = decodeVInt(r.s, r.pos) var d = decodeVInt(r.s, r.pos)
@ -872,7 +876,7 @@ proc getHash*(fileIdx: FileIndex): SecureHash =
template growCache*(cache, pos) = template growCache*(cache, pos) =
if cache.len <= pos: cache.setLen(pos+1) if cache.len <= pos: cache.setLen(pos+1)
proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile = proc checkDep(fileIdx: FileIndex; cache: IdentCache; conf: ConfigRef): TReasonForRecompile =
assert fileIdx != InvalidFileIDX assert fileIdx != InvalidFileIDX
growCache gMods, fileIdx.int32 growCache gMods, fileIdx.int32
if gMods[fileIdx.int32].reason != rrEmpty: if gMods[fileIdx.int32].reason != rrEmpty:
@ -882,8 +886,8 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
var hash = getHash(fileIdx) var hash = getHash(fileIdx)
gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles gMods[fileIdx.int32].reason = rrNone # we need to set it here to avoid cycles
result = rrNone result = rrNone
var rodfile = toGeneratedFile(filename.withPackageName, RodExt) var rodfile = toGeneratedFile(conf, filename.withPackageName, RodExt)
var r = newRodReader(rodfile, hash, fileIdx.int32, cache) var r = newRodReader(rodfile, hash, fileIdx.int32, cache, conf)
if r == nil: if r == nil:
result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist) result = (if existsFile(rodfile): rrRodInvalid else: rrRodDoesNotExist)
else: else:
@ -894,15 +898,15 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): 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(systemFileIdx, cache) var res = checkDep(systemFileIdx, cache, conf)
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], cache) res = checkDep(r.modDeps[i], cache, conf)
if res != rrNone: if res != rrNone:
result = rrModDeps result = rrModDeps
# we cannot break here, because of side-effects of `checkDep` # we cannot break here, because of side-effects of `checkDep`
if result != rrNone: if result != rrNone:
rawMessage(hintProcessing, reasonToFrmt[result] % filename) rawMessage(conf, hintProcessing, reasonToFrmt[result] % filename)
if result != rrNone or optForceFullMake in gGlobalOptions: if result != rrNone or optForceFullMake in gGlobalOptions:
# recompilation is necessary: # recompilation is necessary:
if r != nil: memfiles.close(r.memfile) if r != nil: memfiles.close(r.memfile)
@ -910,14 +914,14 @@ proc checkDep(fileIdx: FileIndex; cache: IdentCache): TReasonForRecompile =
gMods[fileIdx.int32].rd = r gMods[fileIdx.int32].rd = r
gMods[fileIdx.int32].reason = result # now we know better gMods[fileIdx.int32].reason = result # now we know better
proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader = proc handleSymbolFile*(module: PSym; cache: IdentCache; conf: ConfigRef): PRodReader =
if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}: if gSymbolFiles in {disabledSf, writeOnlySf, v2Sf}:
module.id = getID() module.id = getID()
return nil return nil
idgen.loadMaxIds(options.gProjectPath / options.gProjectName) idgen.loadMaxIds(conf, options.gProjectPath / options.gProjectName)
let fileIdx = module.fileIdx let fileIdx = module.fileIdx
discard checkDep(fileIdx, cache) discard checkDep(fileIdx, cache, conf)
if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile") #if gMods[fileIdx.int32].reason == rrEmpty: internalError("handleSymbolFile")
result = gMods[fileIdx.int32].rd result = gMods[fileIdx.int32].rd
if result != nil: if result != nil:
module.id = result.moduleID module.id = result.moduleID
@ -930,19 +934,20 @@ proc handleSymbolFile*(module: PSym; cache: IdentCache): PRodReader =
module.id = getID() module.id = getID()
proc rawLoadStub(s: PSym) = proc rawLoadStub(s: PSym) =
if s.kind != skStub: internalError("loadStub") assert s.kind == skStub
#if s.kind != skStub: internalError("loadStub")
var rd = gMods[s.position].rd var rd = gMods[s.position].rd
var theId = s.id # used for later check var theId = s.id # used for later check
var d = iiTableGet(rd.index.tab, s.id) var d = iiTableGet(rd.index.tab, s.id)
if d == InvalidKey: internalError("loadStub: invalid key") #if d == InvalidKey: internalError("loadStub: invalid key")
var rs = decodeSymSafePos(rd, d, unknownLineInfo()) var rs = decodeSymSafePos(rd, d, unknownLineInfo())
if rs != s: when false:
#echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2), if rs != s:
# "\ns: ", toHex(cast[int](s.position), int.sizeof * 2) #echo "rs: ", toHex(cast[int](rs.position), int.sizeof * 2),
internalError(rs.info, "loadStub: wrong symbol") # "\ns: ", toHex(cast[int](s.position), int.sizeof * 2)
elif rs.id != theId: internalError(rs.info, "loadStub: wrong symbol")
internalError(rs.info, "loadStub: wrong ID") elif rs.id != theId:
#MessageOut('loaded stub: ' + s.name.s); internalError(rs.info, "loadStub: wrong ID")
proc loadStub*(s: PSym) = proc loadStub*(s: PSym) =
## loads the stub symbol `s`. ## loads the stub symbol `s`.
@ -1083,9 +1088,10 @@ proc writeType(f: File; t: PType) =
f.write("]\n") f.write("]\n")
proc viewFile(rodfile: string) = proc viewFile(rodfile: string) =
var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache()) let conf = newConfigRef()
var r = newRodReader(rodfile, secureHash(""), 0, newIdentCache(), conf)
if r == nil: if r == nil:
rawMessage(errGenerated, "cannot open file (or maybe wrong version):" & rawMessage(conf, errGenerated, "cannot open file (or maybe wrong version):" &
rodfile) rodfile)
return return
r.inViewMode = true r.inViewMode = true
@ -1133,9 +1139,9 @@ proc viewFile(rodfile: string) =
outf.write("FILES(\n") outf.write("FILES(\n")
while r.s[r.pos] != ')': while r.s[r.pos] != ')':
let relativePath = decodeStr(r.s, r.pos) let relativePath = decodeStr(r.s, r.pos)
let resolvedPath = relativePath.findModule(r.origFile) let resolvedPath = findModule(conf, relativePath, r.origFile)
let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath let finalPath = if resolvedPath.len > 0: resolvedPath else: relativePath
r.files.add(finalPath.fileInfoIdx) r.files.add(fileInfoIdx(conf, finalPath))
inc(r.pos) # skip #10 inc(r.pos) # skip #10
inc(r.line) inc(r.line)
outf.writeLine finalPath outf.writeLine finalPath
@ -1227,7 +1233,7 @@ proc viewFile(rodfile: string) =
if r.s[r.pos] == ')': inc r.pos if r.s[r.pos] == ')': inc r.pos
outf.write("<not supported by viewer>)\n") outf.write("<not supported by viewer>)\n")
else: else:
internalError("invalid section: '" & section & internalError(r.config, "invalid section: '" & section &
"' at " & $r.line & " in " & r.filename) "' at " & $r.line & " in " & r.filename)
skipSection(r) skipSection(r)
if r.s[r.pos] == '\x0A': if r.s[r.pos] == '\x0A':

View file

@ -11,7 +11,7 @@
import import
strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser, strutils, llstream, ast, astalgo, idents, lexer, options, msgs, parser,
filters, filter_tmpl, renderer filters, filter_tmpl, renderer, configuration
type type
TFilterKind* = enum TFilterKind* = enum
@ -30,12 +30,14 @@ type
skin*: TParserKind skin*: TParserKind
parser*: TParser parser*: TParser
template config(p: TParsers): ConfigRef = p.parser.lex.config
proc parseAll*(p: var TParsers): PNode = proc parseAll*(p: var TParsers): PNode =
case p.skin case p.skin
of skinStandard, skinStrongSpaces: of skinStandard, skinStrongSpaces:
result = parser.parseAll(p.parser) result = parser.parseAll(p.parser)
of skinEndX: of skinEndX:
internalError("parser to implement") internalError(p.config, "parser to implement")
result = ast.emptyNode result = ast.emptyNode
proc parseTopLevelStmt*(p: var TParsers): PNode = proc parseTopLevelStmt*(p: var TParsers): PNode =
@ -43,7 +45,7 @@ proc parseTopLevelStmt*(p: var TParsers): PNode =
of skinStandard, skinStrongSpaces: of skinStandard, skinStrongSpaces:
result = parser.parseTopLevelStmt(p.parser) result = parser.parseTopLevelStmt(p.parser)
of skinEndX: of skinEndX:
internalError("parser to implement") internalError(p.config, "parser to implement")
result = ast.emptyNode result = ast.emptyNode
proc utf8Bom(s: string): int = proc utf8Bom(s: string): int =
@ -86,39 +88,39 @@ proc getFilter(ident: PIdent): TFilterKind =
return i return i
result = filtNone result = filtNone
proc getParser(ident: PIdent): TParserKind = proc getParser(conf: ConfigRef; n: PNode; ident: PIdent): TParserKind =
for i in countup(low(TParserKind), high(TParserKind)): for i in countup(low(TParserKind), high(TParserKind)):
if cmpIgnoreStyle(ident.s, parserNames[i]) == 0: if cmpIgnoreStyle(ident.s, parserNames[i]) == 0:
return i return i
rawMessage(errInvalidDirectiveX, ident.s) localError(conf, n.info, "unknown parser: " & ident.s)
proc getCallee(n: PNode): PIdent = proc getCallee(conf: ConfigRef; n: PNode): PIdent =
if n.kind in nkCallKinds and n.sons[0].kind == nkIdent: if n.kind in nkCallKinds and n.sons[0].kind == nkIdent:
result = n.sons[0].ident result = n.sons[0].ident
elif n.kind == nkIdent: elif n.kind == nkIdent:
result = n.ident result = n.ident
else: else:
rawMessage(errXNotAllowedHere, renderTree(n)) localError(conf, n.info, "invalid filter: " & renderTree(n))
proc applyFilter(p: var TParsers, n: PNode, filename: string, proc applyFilter(p: var TParsers, n: PNode, filename: string,
stdin: PLLStream): PLLStream = stdin: PLLStream): PLLStream =
var ident = getCallee(n) var ident = getCallee(p.config, n)
var f = getFilter(ident) var f = getFilter(ident)
case f case f
of filtNone: of filtNone:
p.skin = getParser(ident) p.skin = getParser(p.config, n, ident)
result = stdin result = stdin
of filtTemplate: of filtTemplate:
result = filterTmpl(stdin, filename, n) result = filterTmpl(stdin, filename, n, p.config)
of filtStrip: of filtStrip:
result = filterStrip(stdin, filename, n) result = filterStrip(p.config, stdin, filename, n)
of filtReplace: of filtReplace:
result = filterReplace(stdin, filename, n) result = filterReplace(p.config, stdin, filename, n)
if f != filtNone: if f != filtNone:
if hintCodeBegin in gNotes: if hintCodeBegin in p.config.notes:
rawMessage(hintCodeBegin, []) rawMessage(p.config, hintCodeBegin, [])
msgWriteln(result.s) msgWriteln(result.s)
rawMessage(hintCodeEnd, []) rawMessage(p.config, hintCodeEnd, [])
proc evalPipe(p: var TParsers, n: PNode, filename: string, proc evalPipe(p: var TParsers, n: PNode, filename: string,
start: PLLStream): PLLStream = start: PLLStream): PLLStream =
@ -158,7 +160,7 @@ proc parseFile*(fileIdx: FileIndex; cache: IdentCache; config: ConfigRef): PNode
f: File f: File
let filename = fileIdx.toFullPathConsiderDirty let filename = fileIdx.toFullPathConsiderDirty
if not open(f, filename): if not open(f, filename):
rawMessage(errCannotOpenFile, filename) rawMessage(config, errGenerated, "cannot open file: " & filename)
return return
openParsers(p, fileIdx, llStreamOpen(f), cache, config) openParsers(p, fileIdx, llStreamOpen(f), cache, config)
result = parseAll(p) result = parseAll(p)

View file

@ -10,7 +10,7 @@
# this module contains routines for accessing and iterating over types # this module contains routines for accessing and iterating over types
import import
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options
type type
TPreferedDesc* = enum TPreferedDesc* = enum
@ -92,8 +92,9 @@ proc getOrdValue*(n: PNode): BiggestInt =
of nkNilLit: result = 0 of nkNilLit: result = 0
of nkHiddenStdConv: result = getOrdValue(n.sons[1]) of nkHiddenStdConv: result = getOrdValue(n.sons[1])
else: else:
localError(n.info, errOrdinalTypeExpected) #localError(n.info, errOrdinalTypeExpected)
result = 0 # XXX check usages of getOrdValue
result = high(BiggestInt)
proc isIntLit*(t: PType): bool {.inline.} = proc isIntLit*(t: PType): bool {.inline.} =
result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit result = t.kind == tyInt and t.n != nil and t.n.kind == nkIntLit
@ -105,14 +106,14 @@ proc getProcHeader*(sym: PSym; prefer: TPreferedDesc = preferName): string =
result = sym.owner.name.s & '.' & sym.name.s & '(' result = sym.owner.name.s & '.' & sym.name.s & '('
var n = sym.typ.n var n = sym.typ.n
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
var p = n.sons[i] let p = n.sons[i]
if p.kind == nkSym: if p.kind == nkSym:
add(result, p.sym.name.s) add(result, p.sym.name.s)
add(result, ": ") add(result, ": ")
add(result, typeToString(p.sym.typ, prefer)) add(result, typeToString(p.sym.typ, prefer))
if i != sonsLen(n)-1: add(result, ", ") if i != sonsLen(n)-1: add(result, ", ")
else: else:
internalError("getProcHeader") result.add renderTree(p)
add(result, ')') add(result, ')')
if n.sons[0].typ != nil: if n.sons[0].typ != nil:
result.add(": " & typeToString(n.sons[0].typ, prefer)) result.add(": " & typeToString(n.sons[0].typ, prefer))
@ -195,10 +196,10 @@ proc searchTypeNodeForAux(n: PNode, p: TTypePredicate,
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker) result = searchTypeNodeForAux(lastSon(n.sons[i]), p, marker)
if result: return if result: return
else: internalError("searchTypeNodeForAux(record case branch)") else: discard
of nkSym: of nkSym:
result = searchTypeForAux(n.sym.typ, p, marker) result = searchTypeForAux(n.sym.typ, p, marker)
else: internalError(n.info, "searchTypeNodeForAux()") else: discard
proc searchTypeForAux(t: PType, predicate: TTypePredicate, proc searchTypeForAux(t: PType, predicate: TTypePredicate,
marker: var IntSet): bool = marker: var IntSet): bool =
@ -244,7 +245,7 @@ proc analyseObjectWithTypeFieldAux(t: PType,
if t == nil: return if t == nil: return
case t.kind case t.kind
of tyObject: of tyObject:
if (t.n != nil): if t.n != nil:
if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker): if searchTypeNodeForAux(t.n, isObjectWithTypeFieldPredicate, marker):
return frEmbedded return frEmbedded
for i in countup(0, sonsLen(t) - 1): for i in countup(0, sonsLen(t) - 1):
@ -453,16 +454,17 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
if t.sons[0].kind == tyNone: result = "typedesc" if t.sons[0].kind == tyNone: result = "typedesc"
else: result = "type " & typeToString(t.sons[0]) else: result = "type " & typeToString(t.sons[0])
of tyStatic: of tyStatic:
internalAssert t.len > 0
if prefer == preferGenericArg and t.n != nil: if prefer == preferGenericArg and t.n != nil:
result = t.n.renderTree result = t.n.renderTree
else: else:
result = "static[" & typeToString(t.sons[0]) & "]" result = "static[" & (if t.len > 0: typeToString(t.sons[0]) else: "") & "]"
if t.n != nil: result.add "(" & renderTree(t.n) & ")" if t.n != nil: result.add "(" & renderTree(t.n) & ")"
of tyUserTypeClass: of tyUserTypeClass:
internalAssert t.sym != nil and t.sym.owner != nil if t.sym != nil and t.sym.owner != nil:
if t.isResolvedUserTypeClass: return typeToString(t.lastSon) if t.isResolvedUserTypeClass: return typeToString(t.lastSon)
return t.sym.owner.name.s return t.sym.owner.name.s
else:
result = "<invalid tyUserTypeClass>"
of tyBuiltInTypeClass: of tyBuiltInTypeClass:
result = case t.base.kind: result = case t.base.kind:
of tyVar: "var" of tyVar: "var"
@ -496,7 +498,7 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
of tyNot: of tyNot:
result = "not " & typeToString(t.sons[0]) result = "not " & typeToString(t.sons[0])
of tyExpr: of tyExpr:
internalAssert t.len == 0 #internalAssert t.len == 0
result = "untyped" result = "untyped"
of tyFromExpr: of tyFromExpr:
result = renderTree(t.n) result = renderTree(t.n)
@ -616,9 +618,9 @@ proc firstOrd*(t: PType): BiggestInt =
result = firstOrd(lastSon(t)) result = firstOrd(lastSon(t))
of tyOrdinal: of tyOrdinal:
if t.len > 0: result = firstOrd(lastSon(t)) if t.len > 0: result = firstOrd(lastSon(t))
else: internalError("invalid kind for firstOrd(" & $t.kind & ')') else: internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')')
else: else:
internalError("invalid kind for firstOrd(" & $t.kind & ')') internalError(newPartialConfigRef(), "invalid kind for firstOrd(" & $t.kind & ')')
result = 0 result = 0
proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt = proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
@ -656,9 +658,9 @@ proc lastOrd*(t: PType; fixedUnsigned = false): BiggestInt =
of tyProxy: result = 0 of tyProxy: result = 0
of tyOrdinal: of tyOrdinal:
if t.len > 0: result = lastOrd(lastSon(t)) if t.len > 0: result = lastOrd(lastSon(t))
else: internalError("invalid kind for lastOrd(" & $t.kind & ')') else: internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')')
else: else:
internalError("invalid kind for lastOrd(" & $t.kind & ')') internalError(newPartialConfigRef(), "invalid kind for lastOrd(" & $t.kind & ')')
result = 0 result = 0
proc lengthOrd*(t: PType): BiggestInt = proc lengthOrd*(t: PType): BiggestInt =
@ -748,7 +750,7 @@ proc equalParam(a, b: PSym): TParamsEquality =
proc sameConstraints(a, b: PNode): bool = proc sameConstraints(a, b: PNode): bool =
if isNil(a) and isNil(b): return true if isNil(a) and isNil(b): return true
internalAssert a.len == b.len if a.len != b.len: return false
for i in 1 ..< a.len: for i in 1 ..< a.len:
if not exprStructuralEquivalent(a[i].sym.constraint, if not exprStructuralEquivalent(a[i].sym.constraint,
b[i].sym.constraint): b[i].sym.constraint):
@ -807,7 +809,8 @@ proc sameTuple(a, b: PType, c: var TSameTypeClosure): bool =
var y = b.n.sons[i].sym var y = b.n.sons[i].sym
result = x.name.id == y.name.id result = x.name.id == y.name.id
if not result: break if not result: break
else: internalError(a.n.info, "sameTuple") else:
return false
elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags: elif a.n != b.n and (a.n == nil or b.n == nil) and IgnoreTupleFields notin c.flags:
result = false result = false
@ -997,7 +1000,7 @@ proc sameTypeAux(x, y: PType, c: var TSameTypeClosure): bool =
cycleCheck() cycleCheck()
result = sameTypeAux(a.lastSon, b.lastSon, c) result = sameTypeAux(a.lastSon, b.lastSon, c)
of tyNone: result = false of tyNone: result = false
of tyUnused, tyOptAsRef: internalError("sameFlags") of tyUnused, tyOptAsRef: result = false
proc sameBackendType*(x, y: PType): bool = proc sameBackendType*(x, y: PType): bool =
var c = initSameTypeClosure() var c = initSameTypeClosure()
@ -1191,7 +1194,7 @@ proc typeAllowedAux(marker: var IntSet, typ: PType, kind: TSymKind,
# for now same as error node; we say it's a valid type as it should # for now same as error node; we say it's a valid type as it should
# prevent cascading errors: # prevent cascading errors:
result = nil result = nil
of tyUnused, tyOptAsRef: internalError("typeAllowedAux") of tyUnused, tyOptAsRef: result = t
proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType = proc typeAllowed*(t: PType, kind: TSymKind; flags: TTypeAllowedFlags = {}): PType =
# returns 'nil' on success and otherwise the part of the type that is # returns 'nil' on success and otherwise the part of the type that is
@ -1280,7 +1283,8 @@ proc computeRecSizeAux(n: PNode, a, currOffset: var BiggestInt): BiggestInt =
if res < 0: return res if res < 0: return res
maxSize = max(maxSize, res) maxSize = max(maxSize, res)
maxAlign = max(maxAlign, b) maxAlign = max(maxAlign, b)
else: internalError("computeRecSizeAux(record case branch)") else:
return szIllegalRecursion
currOffset = align(currOffset, maxAlign) + maxSize currOffset = align(currOffset, maxAlign) + maxSize
result = align(result, maxAlign) + maxSize result = align(result, maxAlign) + maxSize
a = maxAlign a = maxAlign
@ -1441,7 +1445,8 @@ proc getReturnType*(s: PSym): PType =
proc getSize*(typ: PType): BiggestInt = proc getSize*(typ: PType): BiggestInt =
result = computeSize(typ) result = computeSize(typ)
if result < 0: internalError("getSize: " & $typ.kind) #if result < 0: internalError("getSize: " & $typ.kind)
# XXX review all usages of 'getSize'
proc containsGenericTypeIter(t: PType, closure: RootRef): bool = proc containsGenericTypeIter(t: PType, closure: RootRef): bool =
case t.kind case t.kind
@ -1469,8 +1474,7 @@ proc baseOfDistinct*(t: PType): PType =
while it.kind in {tyPtr, tyRef}: while it.kind in {tyPtr, tyRef}:
parent = it parent = it
it = it.lastSon it = it.lastSon
if it.kind == tyDistinct: if it.kind == tyDistinct and parent != nil:
internalAssert parent != nil
parent.sons[0] = it.sons[0] parent.sons[0] = it.sons[0]
proc safeInheritanceDiff*(a, b: PType): int = proc safeInheritanceDiff*(a, b: PType): int =
@ -1502,8 +1506,9 @@ type
proc compatibleEffects*(formal, actual: PType): EffectsCompat = proc compatibleEffects*(formal, actual: PType): EffectsCompat =
# for proc type compatibility checking: # for proc type compatibility checking:
assert formal.kind == tyProc and actual.kind == tyProc assert formal.kind == tyProc and actual.kind == tyProc
internalAssert formal.n.sons[0].kind == nkEffectList if formal.n.sons[0].kind != nkEffectList or
internalAssert actual.n.sons[0].kind == nkEffectList actual.n.sons[0].kind != nkEffectList:
return efTagsUnknown
var spec = formal.n.sons[0] var spec = formal.n.sons[0]
if spec.len != 0: if spec.len != 0:
@ -1628,14 +1633,14 @@ proc skipHiddenSubConv*(n: PNode): PNode =
else: else:
result = n result = n
proc typeMismatch*(info: TLineInfo, formal, actual: PType) = proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) =
if formal.kind != tyError and actual.kind != tyError: if formal.kind != tyError and actual.kind != tyError:
let named = typeToString(formal) let named = typeToString(formal)
let desc = typeToString(formal, preferDesc) let desc = typeToString(formal, preferDesc)
let x = if named == desc: named else: named & " = " & desc let x = if named == desc: named else: named & " = " & desc
var msg = msgKindToString(errTypeMismatch) & var msg = "type mismatch: got <" &
typeToString(actual) & "> " & typeToString(actual) & "> " &
msgKindToString(errButExpectedX) % [x] "but expected " & x & "'"
if formal.kind == tyProc and actual.kind == tyProc: if formal.kind == tyProc and actual.kind == tyProc:
case compatibleEffects(formal, actual) case compatibleEffects(formal, actual)
@ -1650,4 +1655,4 @@ proc typeMismatch*(info: TLineInfo, formal, actual: PType) =
msg.add "\n.tag effect is 'any tag allowed'" msg.add "\n.tag effect is 'any tag allowed'"
of efLockLevelsDiffer: of efLockLevelsDiffer:
msg.add "\nlock levels differ" msg.add "\nlock levels differ"
localError(info, errGenerated, msg) localError(conf, info, msg)