more modules compile again

This commit is contained in:
Andreas Rumpf
2018-05-12 11:58:44 +02:00
parent fedc136985
commit 05724645f8
12 changed files with 260 additions and 236 deletions

View File

@@ -34,10 +34,10 @@ proc isPartOfAux(n: PNode, b: PType, marker: var IntSet): TAnalysisResult =
of nkOfBranch, nkElse:
result = isPartOfAux(lastSon(n.sons[i]), b, marker)
if result == arYes: return
else: internalError("isPartOfAux(record case branch)")
else: discard "isPartOfAux(record case branch)"
of nkSym:
result = isPartOfAux(n.sym.typ, b, marker)
else: internalError(n.info, "isPartOfAux()")
else: discard
proc isPartOfAux(a, b: PType, marker: var IntSet): TAnalysisResult =
result = arNo

View File

@@ -14,11 +14,12 @@ import
rodread
type
TemplCtx {.pure, final.} = object
TemplCtx = object
owner, genSymOwner: PSym
instLines: bool # use the instantiation lines numbers
mapping: TIdTable # every gensym'ed symbol needs to be mapped to some
# new symbol
config: ConfigRef
proc copyNode(ctx: TemplCtx, a, b: PNode): PNode =
result = copyNode(a)
@@ -42,7 +43,7 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
s.kind == skType and s.typ != nil and s.typ.kind == tyGenericParam:
handleParam actual.sons[s.owner.typ.len + s.position - 1]
else:
internalAssert sfGenSym in s.flags or s.kind == skType
internalAssert c.config, sfGenSym in s.flags or s.kind == skType
var x = PSym(idTableGet(c.mapping, s))
if x == nil:
x = copySym(s, false)
@@ -59,7 +60,12 @@ proc evalTemplateAux(templ, actual: PNode, c: var TemplCtx, result: PNode) =
evalTemplateAux(templ.sons[i], actual, c, res)
result.add res
proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
const
errWrongNumberOfArguments = "wrong number of arguments"
errMissingGenericParamsForTemplate = "'$1' has unspecified generic parameters"
errTemplateInstantiationTooNested = "template instantiation too nested"
proc evalTemplateArgs(n: PNode, s: PSym; conf: ConfigRef; fromHlo: bool): PNode =
# if the template has zero arguments, it can be called without ``()``
# `n` is then a nkSym or something similar
var totalParams = case n.kind
@@ -82,10 +88,10 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
if givenRegularParams < 0: givenRegularParams = 0
if totalParams > expectedRegularParams + genericParams:
globalError(n.info, errWrongNumberOfArguments)
globalError(conf, n.info, errWrongNumberOfArguments)
if totalParams < genericParams:
globalError(n.info, errMissingGenericParamsForTemplate,
globalError(conf, n.info, errMissingGenericParamsForTemplate %
n.renderTree)
result = newNodeI(nkArgList, n.info)
@@ -97,7 +103,7 @@ proc evalTemplateArgs(n: PNode, s: PSym; fromHlo: bool): PNode =
for i in givenRegularParams+1 .. expectedRegularParams:
let default = s.typ.n.sons[i].sym.ast
if default.isNil or default.kind == nkEmpty:
localError(n.info, errWrongNumberOfArguments)
localError(conf, n.info, errWrongNumberOfArguments)
addSon(result, ast.emptyNode)
else:
addSon(result, default.copyTree)
@@ -132,17 +138,19 @@ proc wrapInComesFrom*(info: TLineInfo; sym: PSym; res: PNode): PNode =
result.add res
result.typ = res.typ
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym;
conf: ConfigRef; fromHlo=false): PNode =
inc(evalTemplateCounter)
if evalTemplateCounter > evalTemplateLimit:
globalError(n.info, errTemplateInstantiationTooNested)
globalError(conf, n.info, errTemplateInstantiationTooNested)
result = n
# replace each param by the corresponding node:
var args = evalTemplateArgs(n, tmpl, fromHlo)
var args = evalTemplateArgs(n, tmpl, conf, fromHlo)
var ctx: TemplCtx
ctx.owner = tmpl
ctx.genSymOwner = genSymOwner
ctx.config = conf
initIdTable(ctx.mapping)
let body = tmpl.getBody
@@ -151,7 +159,7 @@ proc evalTemplate*(n: PNode, tmpl, genSymOwner: PSym; fromHlo=false): PNode =
evalTemplateAux(body, args, ctx, result)
if result.len == 1: result = result.sons[0]
else:
localError(result.info, errIllFormedAstX,
localError(conf, result.info, "illformed AST: " &
renderTree(result, {renderNoComments}))
else:
result = copyNode(body)

View File

@@ -330,8 +330,8 @@ proc canon*(n: PNode; o: Operators): PNode =
result.sons[2] = y[1]
else: discard
#proc `+@`*(a: PNode; b: BiggestInt): PNode =
# canon(if b != 0: opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a)
proc buildAdd*(a: PNode; b: BiggestInt; o: Operators): PNode =
canon(if b != 0: o.opAdd.buildCall(a, nkIntLit.newIntNode(b)) else: a, o)
proc usefulFact(n: PNode; o: Operators): PNode =
case n.getMagic

View File

@@ -12,7 +12,7 @@
proc hlo(c: PContext, n: PNode): PNode
proc evalPattern(c: PContext, n, orig: PNode): PNode =
internalAssert n.kind == nkCall and n.sons[0].kind == nkSym
internalAssert c.config, n.kind == nkCall and n.sons[0].kind == nkSym
# we need to ensure that the resulting AST is semchecked. However, it's
# aweful to semcheck before macro invocation, so we don't and treat
# templates and macros as immediate in this context.

View File

@@ -150,7 +150,7 @@ proc matches(c: PPatternContext, p, n: PNode): bool =
of "*": result = matchNested(c, p, n, rpn=false)
of "**": result = matchNested(c, p, n, rpn=true)
of "~": result = not matches(c, p.sons[1], n)
else: internalError(p.info, "invalid pattern")
else: doAssert(false, "invalid pattern")
# template {add(a, `&` * b)}(a: string{noalias}, b: varargs[string]) =
# add(a, b)
elif p.kind == nkCurlyExpr:
@@ -289,7 +289,7 @@ proc applyRule*(c: PContext, s: PSym, n: PNode): PNode =
# constraint not fulfilled:
if not ok: return nil
markUsed(n.info, s, c.graph.usageSym)
markUsed(c.config, n.info, s, c.graph.usageSym)
if ctx.subMatch:
assert m.len == 3
m.sons[1] = result

View File

@@ -17,21 +17,21 @@ proc iterToProcImpl(c: PContext, n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
let iter = n[1]
if iter.kind != nkSym or iter.sym.kind != skIterator:
localError(iter.info, "first argument needs to be an iterator")
localError(c.config, iter.info, "first argument needs to be an iterator")
return
if n[2].typ.isNil:
localError(n[2].info, "second argument needs to be a type")
localError(c.config, n[2].info, "second argument needs to be a type")
return
if n[3].kind != nkIdent:
localError(n[3].info, "third argument needs to be an identifier")
localError(c.config, n[3].info, "third argument needs to be an identifier")
return
let t = n[2].typ.skipTypes({tyTypeDesc, tyGenericInst})
if t.kind notin {tyRef, tyPtr} or t.lastSon.kind != tyObject:
localError(n[2].info,
localError(c.config, n[2].info,
"type must be a non-generic ref|ptr to object with state field")
return
let body = liftIterToProc(iter.sym, iter.sym.getBody, t)
let body = liftIterToProc(c.graph, iter.sym, iter.sym.getBody, t)
let prc = newSym(skProc, n[3].ident, iter.sym.owner, iter.sym.info)
prc.typ = copyType(iter.sym.typ, prc, false)

View File

@@ -71,7 +71,7 @@ template semIdeForTemplateOrGeneric(c: PContext; n: PNode;
proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
if arg.typ.isNil:
localError(arg.info, errExprXHasNoType,
localError(c.config, arg.info, "expression has no type: " &
renderTree(arg, {renderNoComments}))
# error correction:
result = copyTree(arg)
@@ -79,7 +79,7 @@ proc fitNode(c: PContext, formal: PType, arg: PNode; info: TLineInfo): PNode =
else:
result = indexTypesMatch(c, formal, arg.typ, arg)
if result == nil:
typeMismatch(info, formal, arg.typ)
typeMismatch(c.config, info, formal, arg.typ)
# error correction:
result = copyTree(arg)
result.typ = formal
@@ -180,7 +180,7 @@ proc commonType*(x: PType, y: PNode): PType =
commonType(x, y.typ)
proc newSymS(kind: TSymKind, n: PNode, c: PContext): PSym =
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
when defined(nimsuggest):
suggestDecl(c, n, result)
@@ -192,7 +192,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# and sfGenSym in n.sym.flags:
result = n.sym
if result.kind != kind:
localError(n.info, "cannot use symbol of kind '" &
localError(c.config, n.info, "cannot use symbol of kind '" &
$result.kind & "' as a '" & $kind & "'")
if sfGenSym in result.flags and result.kind notin {skTemplate, skMacro, skParam}:
# declarative context, so produce a fresh gensym:
@@ -204,7 +204,7 @@ proc newSymG*(kind: TSymKind, n: PNode, c: PContext): PSym =
# template; we must fix it here: see #909
result.owner = getCurrOwner(c)
else:
result = newSym(kind, considerQuotedIdent(n), getCurrOwner(c), n.info)
result = newSym(kind, considerQuotedIdent(c.config, n), getCurrOwner(c), n.info)
#if kind in {skForVar, skLet, skVar} and result.owner.kind == skModule:
# incl(result.flags, sfGlobal)
when defined(nimsuggest):
@@ -216,20 +216,20 @@ proc semIdentVis(c: PContext, kind: TSymKind, n: PNode,
proc semIdentWithPragma(c: PContext, kind: TSymKind, n: PNode,
allowed: TSymFlags): PSym
proc typeAllowedCheck(info: TLineInfo; typ: PType; kind: TSymKind;
proc typeAllowedCheck(conf: ConfigRef; info: TLineInfo; typ: PType; kind: TSymKind;
flags: TTypeAllowedFlags = {}) =
let t = typeAllowed(typ, kind, flags)
if t != nil:
if t == typ:
localError(info, "invalid type: '" & typeToString(typ) &
localError(conf, info, "invalid type: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
else:
localError(info, "invalid type: '" & typeToString(t) &
localError(conf, info, "invalid type: '" & typeToString(t) &
"' in this context: '" & typeToString(typ) &
"' for " & substr($kind, 2).toLowerAscii)
proc paramsTypeCheck(c: PContext, typ: PType) {.inline.} =
typeAllowedCheck(typ.n.info, typ, skProc)
typeAllowedCheck(c.config, typ.n.info, typ, skProc)
proc expectMacroOrTemplateCall(c: PContext, n: PNode): PSym
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode
@@ -282,10 +282,10 @@ proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
result = evaluated
let expectedType = eOrig.typ.skipTypes({tyStatic})
if hasCycle(result):
globalError(eOrig.info, "the resulting AST is cyclic and cannot be processed further")
globalError(c.config, eOrig.info, "the resulting AST is cyclic and cannot be processed further")
result = errorNode(c, eOrig)
else:
semmacrosanity.annotateType(result, expectedType)
semmacrosanity.annotateType(result, expectedType, c.config)
else:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
@@ -302,18 +302,18 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil: return
result = getConstExpr(c.module, e)
result = getConstExpr(c.module, e, c.graph)
if result != nil: return
let oldErrorCount = msgs.gErrorCounter
let oldErrorMax = msgs.gErrorMax
let oldErrorCount = c.config.errorCounter
let oldErrorMax = c.config.errorMax
let oldErrorOutputs = errorOutputs
errorOutputs = {}
msgs.gErrorMax = high(int)
c.config.errorMax = high(int)
try:
result = evalConstExpr(c.module, c.cache, c.graph.config, e)
result = evalConstExpr(c.module, c.cache, c.graph, e)
if result == nil or result.kind == nkEmpty:
result = nil
else:
@@ -322,26 +322,29 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
except ERecoverableError:
result = nil
msgs.gErrorCounter = oldErrorCount
msgs.gErrorMax = oldErrorMax
c.config.errorCounter = oldErrorCount
c.config.errorMax = oldErrorMax
errorOutputs = oldErrorOutputs
const
errConstExprExpected = "constant expression expected"
proc semConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)
if e == nil:
localError(n.info, errConstExprExpected)
localError(c.config, n.info, errConstExprExpected)
return n
result = getConstExpr(c.module, e)
result = getConstExpr(c.module, e, c.graph)
if result == nil:
#if e.kind == nkEmpty: globalError(n.info, errConstExprExpected)
result = evalConstExpr(c.module, c.cache, c.graph.config, e)
result = evalConstExpr(c.module, c.cache, c.graph, e)
if result == nil or result.kind == nkEmpty:
if e.info != n.info:
pushInfoContext(n.info)
localError(e.info, errConstExprExpected)
localError(c.config, e.info, errConstExprExpected)
popInfoContext()
else:
localError(e.info, errConstExprExpected)
localError(c.config, e.info, errConstExprExpected)
# error correction:
result = e
else:
@@ -356,7 +359,7 @@ proc semExprFlagDispatched(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
result = semExprWithType(c, n, flags)
if efPreferStatic in flags:
var evaluated = getConstExpr(c.module, result)
var evaluated = getConstExpr(c.module, result, c.graph)
if evaluated != nil: return evaluated
evaluated = evalAtCompileTime(c, result)
if evaluated != nil: return evaluated

View File

@@ -10,7 +10,7 @@
## Implements type sanity checking for ASTs resulting from macros. Lots of
## room for improvement here.
import ast, astalgo, msgs, types
import ast, astalgo, msgs, types, options
proc ithField(n: PNode, field: var int): PSym =
result = nil
@@ -20,7 +20,7 @@ proc ithField(n: PNode, field: var int): PSym =
result = ithField(n.sons[i], field)
if result != nil: return
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
if n.sons[0].kind != nkSym: return
result = ithField(n.sons[0], field)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
@@ -28,13 +28,13 @@ proc ithField(n: PNode, field: var int): PSym =
of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field)
if result != nil: return
else: internalError(n.info, "ithField(record case branch)")
else: discard
of nkSym:
if field == 0: result = n.sym
else: dec(field)
else: discard
proc annotateType*(n: PNode, t: PType) =
proc annotateType*(n: PNode, t: PType; conf: ConfigRef) =
let x = t.skipTypes(abstractInst+{tyRange})
# Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst
@@ -46,50 +46,50 @@ proc annotateType*(n: PNode, t: PType) =
var j = i-1
let field = x.n.ithField(j)
if field.isNil:
globalError n.info, "invalid field at index " & $i
globalError conf, n.info, "invalid field at index " & $i
else:
internalAssert(n.sons[i].kind == nkExprColonExpr)
annotateType(n.sons[i].sons[1], field.typ)
internalAssert(conf, n.sons[i].kind == nkExprColonExpr)
annotateType(n.sons[i].sons[1], field.typ, conf)
of nkPar, nkTupleConstr:
if x.kind == tyTuple:
n.typ = t
for i in 0 ..< n.len:
if i >= x.len: globalError n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], x.sons[i])
if i >= x.len: globalError conf, n.info, "invalid field at index " & $i
else: annotateType(n.sons[i], x.sons[i], conf)
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
else:
globalError(n.info, "() must have a tuple type")
globalError(conf, n.info, "() must have a tuple type")
of nkBracket:
if x.kind in {tyArray, tySequence, tyOpenArray}:
n.typ = t
for m in n: annotateType(m, x.elemType)
for m in n: annotateType(m, x.elemType, conf)
else:
globalError(n.info, "[] must have some form of array type")
globalError(conf, n.info, "[] must have some form of array type")
of nkCurly:
if x.kind in {tySet}:
n.typ = t
for m in n: annotateType(m, x.elemType)
for m in n: annotateType(m, x.elemType, conf)
else:
globalError(n.info, "{} must have the set type")
globalError(conf, n.info, "{} must have the set type")
of nkFloatLit..nkFloat128Lit:
if x.kind in {tyFloat..tyFloat128}:
n.typ = t
else:
globalError(n.info, "float literal must have some float type")
globalError(conf, n.info, "float literal must have some float type")
of nkCharLit..nkUInt64Lit:
if x.kind in {tyInt..tyUInt64, tyBool, tyChar, tyEnum}:
n.typ = t
else:
globalError(n.info, "integer literal must have some int type")
globalError(conf, n.info, "integer literal must have some int type")
of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCString}:
n.typ = t
else:
globalError(n.info, "string literal must be of some string type")
globalError(conf, n.info, "string literal must be of some string type")
of nkNilLit:
if x.kind in NilableTypes:
n.typ = t
else:
globalError(n.info, "nil literal must be of some pointer type")
globalError(conf, n.info, "nil literal must be of some pointer type")
else: discard

View File

@@ -23,7 +23,8 @@
import
ast, astalgo, idents, lowerings, magicsys, guards, sempass2, msgs,
renderer, types
renderer, types, modulegraphs, options
from trees import getMagic
from strutils import `%`
@@ -73,12 +74,15 @@ type
# the 'parallel' section
currentSpawnId: int
inLoop: int
graph: ModuleGraph
proc initAnalysisCtx(): AnalysisCtx =
proc initAnalysisCtx(g: ModuleGraph): AnalysisCtx =
result.locals = @[]
result.slices = @[]
result.args = @[]
result.guards = @[]
result.guards.s = @[]
result.guards.o = initOperators(g)
result.graph = g
proc lookupSlot(c: AnalysisCtx; s: PSym): int =
for i in 0..<c.locals.len:
@@ -117,7 +121,7 @@ proc checkLocal(c: AnalysisCtx; n: PNode) =
if isLocal(n):
let s = c.lookupSlot(n.sym)
if s >= 0 and c.locals[s].stride != nil:
localError(n.info, "invalid usage of counter after increment")
localError(c.graph.config, n.info, "invalid usage of counter after increment")
else:
for i in 0 ..< n.safeLen: checkLocal(c, n.sons[i])
@@ -126,14 +130,14 @@ template `?`(x): untyped = x.renderTree
proc checkLe(c: AnalysisCtx; a, b: PNode) =
case proveLe(c.guards, a, b)
of impUnknown:
localError(a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
localError(c.graph.config, a.info, "cannot prove: " & ?a & " <= " & ?b & " (bounds check)")
of impYes: discard
of impNo:
localError(a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
localError(c.graph.config, a.info, "can prove: " & ?a & " > " & ?b & " (bounds check)")
proc checkBounds(c: AnalysisCtx; arr, idx: PNode) =
checkLe(c, arr.lowBound, idx)
checkLe(c, idx, arr.highBound)
checkLe(c, idx, arr.highBound(c.guards.o))
proc addLowerBoundAsFacts(c: var AnalysisCtx) =
for v in c.locals:
@@ -142,34 +146,34 @@ proc addLowerBoundAsFacts(c: var AnalysisCtx) =
proc addSlice(c: var AnalysisCtx; n: PNode; x, le, ri: PNode) =
checkLocal(c, n)
let le = le.canon
let ri = ri.canon
let le = le.canon(c.guards.o)
let ri = ri.canon(c.guards.o)
# perform static bounds checking here; and not later!
let oldState = c.guards.len
let oldState = c.guards.s.len
addLowerBoundAsFacts(c)
c.checkBounds(x, le)
c.checkBounds(x, ri)
c.guards.setLen(oldState)
c.guards.s.setLen(oldState)
c.slices.add((x, le, ri, c.currentSpawnId, c.inLoop > 0))
proc overlap(m: TModel; x,y,c,d: PNode) =
proc overlap(m: TModel; conf: ConfigRef; x,y,c,d: PNode) =
# X..Y and C..D overlap iff (X <= D and C <= Y)
case proveLe(m, c, y)
of impUnknown:
case proveLe(m, x, d)
of impNo: discard
of impUnknown, impYes:
localError(x.info,
localError(conf, x.info,
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
[?c, ?y, ?x, ?y, ?c, ?d])
of impYes:
case proveLe(m, x, d)
of impUnknown:
localError(x.info,
localError(conf, x.info,
"cannot prove: $# > $#; required for ($#)..($#) disjoint from ($#)..($#)" %
[?x, ?d, ?x, ?y, ?c, ?d])
of impYes:
localError(x.info, "($#)..($#) not disjoint from ($#)..($#)" %
localError(conf, x.info, "($#)..($#) not disjoint from ($#)..($#)" %
[?c, ?y, ?x, ?y, ?c, ?d])
of impNo: discard
of impNo: discard
@@ -187,7 +191,7 @@ proc subStride(c: AnalysisCtx; n: PNode): PNode =
if isLocal(n):
let s = c.lookupSlot(n.sym)
if s >= 0 and c.locals[s].stride != nil:
result = n +@ c.locals[s].stride.intVal
result = buildAdd(n, c.locals[s].stride.intVal, c.guards.o)
else:
result = n
elif n.safeLen > 0:
@@ -203,7 +207,7 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
addLowerBoundAsFacts(c)
# Every slice used in a loop needs to be disjoint with itself:
for x,a,b,id,inLoop in items(c.slices):
if inLoop: overlap(c.guards, a,b, c.subStride(a), c.subStride(b))
if inLoop: overlap(c.guards, c.graph.config, a,b, c.subStride(a), c.subStride(b))
# Another tricky example is:
# while true:
# spawn f(a[i])
@@ -231,21 +235,21 @@ proc checkSlicesAreDisjoint(c: var AnalysisCtx) =
# XXX strictly speaking, 'or' is not correct here and it needs to
# be 'and'. However this prevents too many obviously correct programs
# like f(a[0..x]); for i in x+1 .. a.high: f(a[i])
overlap(c.guards, x.a, x.b, y.a, y.b)
overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
elif (let k = simpleSlice(x.a, x.b); let m = simpleSlice(y.a, y.b);
k >= 0 and m >= 0):
# ah I cannot resist the temptation and add another sweet heuristic:
# if both slices have the form (i+k)..(i+k) and (i+m)..(i+m) we
# check they are disjoint and k < stride and m < stride:
overlap(c.guards, x.a, x.b, y.a, y.b)
overlap(c.guards, c.graph.config, x.a, x.b, y.a, y.b)
let stride = min(c.stride(x.a), c.stride(y.a))
if k < stride and m < stride:
discard
else:
localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
[?x.a, ?x.b, ?y.a, ?y.b])
else:
localError(x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
localError(c.graph.config, x.x.info, "cannot prove ($#)..($#) disjoint from ($#)..($#)" %
[?x.a, ?x.b, ?y.a, ?y.b])
proc analyse(c: var AnalysisCtx; n: PNode)
@@ -292,31 +296,31 @@ proc analyseCall(c: var AnalysisCtx; n: PNode; op: PSym) =
proc analyseCase(c: var AnalysisCtx; n: PNode) =
analyse(c, n.sons[0])
let oldFacts = c.guards.len
let oldFacts = c.guards.s.len
for i in 1..<n.len:
let branch = n.sons[i]
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
addCaseBranchFacts(c.guards, n, i)
for i in 0 ..< branch.len:
analyse(c, branch.sons[i])
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
proc analyseIf(c: var AnalysisCtx; n: PNode) =
analyse(c, n.sons[0].sons[0])
let oldFacts = c.guards.len
addFact(c.guards, canon(n.sons[0].sons[0]))
let oldFacts = c.guards.s.len
addFact(c.guards, canon(n.sons[0].sons[0], c.guards.o))
analyse(c, n.sons[0].sons[1])
for i in 1..<n.len:
let branch = n.sons[i]
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
for j in 0..i-1:
addFactNeg(c.guards, canon(n.sons[j].sons[0]))
addFactNeg(c.guards, canon(n.sons[j].sons[0], c.guards.o))
if branch.len > 1:
addFact(c.guards, canon(branch.sons[0]))
addFact(c.guards, canon(branch.sons[0], c.guards.o))
for i in 0 ..< branch.len:
analyse(c, branch.sons[i])
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
proc analyse(c: var AnalysisCtx; n: PNode) =
case n.kind
@@ -349,7 +353,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
c.addSlice(n, n[0], n[1], n[1])
analyseSons(c, n)
of nkReturnStmt, nkRaiseStmt, nkTryStmt:
localError(n.info, "invalid control flow for 'parallel'")
localError(c.graph.config, n.info, "invalid control flow for 'parallel'")
# 'break' that leaves the 'parallel' section is not valid either
# or maybe we should generate a 'try' XXX
of nkVarSection, nkLetSection:
@@ -365,7 +369,7 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
if it[j].isLocal:
let slot = c.getSlot(it[j].sym)
if slot.lower.isNil: slot.lower = value
else: internalError(it.info, "slot already has a lower bound")
else: internalError(c.graph.config, it.info, "slot already has a lower bound")
if not isSpawned: analyse(c, value)
of nkCaseStmt: analyseCase(c, n)
of nkWhen, nkIfStmt, nkIfExpr: analyseIf(c, n)
@@ -378,14 +382,14 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
else:
# loop may never execute:
let oldState = c.locals.len
let oldFacts = c.guards.len
addFact(c.guards, canon(n.sons[0]))
let oldFacts = c.guards.s.len
addFact(c.guards, canon(n.sons[0], c.guards.o))
analyse(c, n.sons[1])
setLen(c.locals, oldState)
setLen(c.guards, oldFacts)
setLen(c.guards.s, oldFacts)
# we know after the loop the negation holds:
if not hasSubnodeWith(n.sons[1], nkBreakStmt):
addFactNeg(c.guards, canon(n.sons[0]))
addFactNeg(c.guards, canon(n.sons[0], c.guards.o))
dec c.inLoop
of nkTypeSection, nkProcDef, nkConverterDef, nkMethodDef, nkIteratorDef,
nkMacroDef, nkTemplateDef, nkConstSection, nkPragma, nkFuncDef:
@@ -393,13 +397,13 @@ proc analyse(c: var AnalysisCtx; n: PNode) =
else:
analyseSons(c, n)
proc transformSlices(n: PNode): PNode =
proc transformSlices(g: ModuleGraph; n: PNode): PNode =
if n.kind in nkCallKinds and n[0].kind == nkSym:
let op = n[0].sym
if op.name.s == "[]" and op.fromSystem:
result = copyNode(n)
let opSlice = newSymNode(createMagic("slice", mSlice))
opSlice.typ = getSysType(tyInt)
let opSlice = newSymNode(createMagic(g, "slice", mSlice))
opSlice.typ = getSysType(g, n.info, tyInt)
result.add opSlice
result.add n[1]
let slice = n[2].skipStmtList
@@ -409,49 +413,49 @@ proc transformSlices(n: PNode): PNode =
if n.safeLen > 0:
result = shallowCopy(n)
for i in 0 ..< n.len:
result.sons[i] = transformSlices(n.sons[i])
result.sons[i] = transformSlices(g, n.sons[i])
else:
result = n
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode
proc transformSpawnSons(owner: PSym; n, barrier: PNode): PNode =
proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode
proc transformSpawnSons(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
result = shallowCopy(n)
for i in 0 ..< n.len:
result.sons[i] = transformSpawn(owner, n.sons[i], barrier)
result.sons[i] = transformSpawn(g, owner, n.sons[i], barrier)
proc transformSpawn(owner: PSym; n, barrier: PNode): PNode =
proc transformSpawn(g: ModuleGraph; owner: PSym; n, barrier: PNode): PNode =
case n.kind
of nkVarSection, nkLetSection:
result = nil
for it in n:
let b = it.lastSon
if getMagic(b) == mSpawn:
if it.len != 3: localError(it.info, "invalid context for 'spawn'")
let m = transformSlices(b)
if it.len != 3: localError(g.config, it.info, "invalid context for 'spawn'")
let m = transformSlices(g, b)
if result.isNil:
result = newNodeI(nkStmtList, n.info)
result.add n
let t = b[1][0].typ.sons[0]
if spawnResult(t, true) == srByVar:
result.add wrapProcForSpawn(owner, m, b.typ, barrier, it[0])
result.add wrapProcForSpawn(g, owner, m, b.typ, barrier, it[0])
it.sons[it.len-1] = emptyNode
else:
it.sons[it.len-1] = wrapProcForSpawn(owner, m, b.typ, barrier, nil)
it.sons[it.len-1] = wrapProcForSpawn(g, owner, m, b.typ, barrier, nil)
if result.isNil: result = n
of nkAsgn, nkFastAsgn:
let b = n[1]
if getMagic(b) == mSpawn and (let t = b[1][0].typ.sons[0];
spawnResult(t, true) == srByVar):
let m = transformSlices(b)
return wrapProcForSpawn(owner, m, b.typ, barrier, n[0])
result = transformSpawnSons(owner, n, barrier)
let m = transformSlices(g, b)
return wrapProcForSpawn(g, owner, m, b.typ, barrier, n[0])
result = transformSpawnSons(g, owner, n, barrier)
of nkCallKinds:
if getMagic(n) == mSpawn:
result = transformSlices(n)
return wrapProcForSpawn(owner, result, n.typ, barrier, nil)
result = transformSpawnSons(owner, n, barrier)
result = transformSlices(g, n)
return wrapProcForSpawn(g, owner, result, n.typ, barrier, nil)
result = transformSpawnSons(g, owner, n, barrier)
elif n.safeLen > 0:
result = transformSpawnSons(owner, n, barrier)
result = transformSpawnSons(g, owner, n, barrier)
else:
result = n
@@ -461,7 +465,7 @@ proc checkArgs(a: var AnalysisCtx; n: PNode) =
proc generateAliasChecks(a: AnalysisCtx; result: PNode) =
discard "too implement"
proc liftParallel*(owner: PSym; n: PNode): PNode =
proc liftParallel*(g: ModuleGraph; owner: PSym; n: PNode): PNode =
# this needs to be called after the 'for' loop elimination
# first pass:
@@ -470,17 +474,17 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
# - detect used arguments
#echo "PAR ", renderTree(n)
var a = initAnalysisCtx()
var a = initAnalysisCtx(g)
let body = n.lastSon
analyse(a, body)
if a.spawns == 0:
localError(n.info, "'parallel' section without 'spawn'")
localError(g.config, n.info, "'parallel' section without 'spawn'")
checkSlicesAreDisjoint(a)
checkArgs(a, body)
var varSection = newNodeI(nkVarSection, n.info)
var temp = newSym(skTemp, getIdent"barrier", owner, n.info)
temp.typ = magicsys.getCompilerProc("Barrier").typ
temp.typ = magicsys.getCompilerProc(g, "Barrier").typ
incl(temp.flags, sfFromGeneric)
let tempNode = newSymNode(temp)
varSection.addVar tempNode
@@ -489,6 +493,6 @@ proc liftParallel*(owner: PSym; n: PNode): PNode =
result = newNodeI(nkStmtList, n.info)
generateAliasChecks(a, result)
result.add varSection
result.add callCodegenProc("openBarrier", barrier)
result.add transformSpawn(owner, body, barrier)
result.add callCodegenProc("closeBarrier", barrier)
result.add callCodegenProc(g, "openBarrier", barrier)
result.add transformSpawn(g, owner, body, barrier)
result.add callCodegenProc(g, "closeBarrier", barrier)

View File

@@ -19,7 +19,7 @@ import ast except getstr
import
strutils, astalgo, msgs, vmdef, vmgen, nimsets, types, passes,
parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
vmmarshal, gorgeimpl
vmmarshal, gorgeimpl, configuration
from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate
@@ -81,16 +81,16 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int; recursionLimit=100) =
msgWriteln(s)
proc stackTrace(c: PCtx, tos: PStackFrame, pc: int,
msg: TMsgKind, arg = "", n: PNode = nil) =
msg: string, n: PNode = nil) =
msgWriteln("stack trace: (most recent call last)")
stackTraceAux(c, tos, pc)
# XXX test if we want 'globalError' for every mode
let lineInfo = if n == nil: c.debug[pc] else: n.info
if c.mode == emRepl: globalError(lineInfo, msg, arg)
else: localError(lineInfo, msg, arg)
if c.mode == emRepl: globalError(c.config, lineInfo, msg)
else: localError(c.config, lineInfo, msg)
proc bailOut(c: PCtx; tos: PStackFrame) =
stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
stackTrace(c, tos, c.exceptionInstr, "unhandled exception: " &
c.currentExceptionA.sons[3].skipColon.strVal)
when not defined(nimComputedGoto):
@@ -308,7 +308,7 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
return pc
return -1
proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
if desttyp.kind == tyString:
if dest.kind != rkNode:
myreset(dest)
@@ -323,7 +323,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
else:
for i in 0..<n.len:
if n.sons[i].kind != nkSym: internalError("opConv for enum")
if n.sons[i].kind != nkSym: internalError(c.config, "opConv for enum")
let f = n.sons[i].sym
if f.position == x:
dest.node.strVal = if f.ast.isNil: f.name.s else: f.ast.strVal
@@ -353,7 +353,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
of tyChar:
dest.node.strVal = $chr(src.intVal)
else:
internalError("cannot convert to string " & desttyp.typeToString)
internalError(c.config, "cannot convert to string " & desttyp.typeToString)
else:
case skipTypes(desttyp, abstractRange).kind
of tyInt..tyInt64:
@@ -404,7 +404,7 @@ template handleJmpBack() {.dirty.} =
else:
msgWriteln("stack trace: (most recent call last)")
stackTraceAux(c, tos, pc)
globalError(c.debug[pc], errTooManyIterations)
globalError(c.config, c.debug[pc], errTooManyIterations)
dec(c.loopIterations)
proc recSetFlagIsRef(arg: PNode) =
@@ -434,6 +434,17 @@ proc setLenSeq(c: PCtx; node: PNode; newLen: int; info: TLineInfo) =
for i in oldLen ..< newLen:
node.sons[i] = newNodeI(typeKind, info)
const
errIndexOutOfBounds = "index ouf of bounds"
errNilAccess = "attempt to access a nil address"
errOverOrUnderflow = "over- or underflow"
errConstantDivisionByZero = "division by zero"
errIllegalConvFromXtoY = "illegal conversion from '$1' to '$2'"
errTooManyIterations = "interpretation requires too many iterations; " &
"if you are sure this is not a bug in your code edit " &
"compiler/vmdef.MaxLoopIterations and rebuild the compiler"
errFieldXNotFound = "node lacks field: "
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var pc = start
var tos = tos
@@ -447,7 +458,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
#if c.traceActive:
when traceCode:
echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra, " rb ", instr.regB, " rc ", instr.regC
# message(c.debug[pc], warnUser, "Trace")
# message(c.config, c.debug[pc], warnUser, "Trace")
case instr.opcode
of opcEof: return regs[ra]
@@ -580,7 +591,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].kind == rkNode:
regs[ra].nodeAddr = addr(regs[rb].node)
else:
stackTrace(c, tos, pc, errGenerated, "limited VM support for 'addr'")
stackTrace(c, tos, pc, "limited VM support for 'addr'")
of opcLdDeref:
# a = b[]
let ra = instr.regA
@@ -623,7 +634,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
stackTrace(c, tos, pc, errOverOrUnderflow)
of opcAddImmInt:
decodeBImm(rkInt)
#message(c.debug[pc], warnUser, "came here")
#message(c.config, c.debug[pc], warnUser, "came here")
#debug regs[rb].node
let
bVal = regs[rb].intVal
@@ -892,7 +903,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node = if a.sym.ast.isNil: newNode(nkNilLit)
else: copyTree(a.sym.ast)
else:
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
stackTrace(c, tos, pc, "node is not a symbol")
of opcEcho:
let rb = instr.regB
if rb == 1:
@@ -931,9 +942,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let rc = instr.regC
if not (leValueConv(regs[rb].regToNode, regs[ra].regToNode) and
leValueConv(regs[ra].regToNode, regs[rc].regToNode)):
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
$regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
stackTrace(c, tos, pc,
errIllegalConvFromXtoY % [
$regs[ra].regToNode, "[" & $regs[rb].regToNode & ".." & $regs[rc].regToNode & "]"])
of opcIndCall, opcIndCallAsgn:
# dest = call regStart, n; where regStart = fn, arg1, ...
let rb = instr.regB
@@ -949,20 +960,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
currentLineInfo: c.debug[pc]))
elif sfImportc in prc.flags:
if allowFFI notin c.features:
globalError(c.debug[pc], errGenerated, "VM not allowed to do FFI")
globalError(c.config, c.debug[pc], "VM not allowed to do FFI")
# we pass 'tos.slots' instead of 'regs' so that the compiler can keep
# 'regs' in a register:
when hasFFI:
let prcValue = c.globals.sons[prc.position-1]
if prcValue.kind == nkEmpty:
globalError(c.debug[pc], errGenerated, "canot run " & prc.name.s)
globalError(c.config, c.debug[pc], "canot run " & prc.name.s)
let newValue = callForeignFunction(prcValue, prc.typ, tos.slots,
rb+1, rc-1, c.debug[pc])
if newValue.kind != nkEmpty:
assert instr.opcode == opcIndCallAsgn
putIntoReg(regs[ra], newValue)
else:
globalError(c.debug[pc], errGenerated, "VM not built with FFI support")
globalError(c.config, c.debug[pc], "VM not built with FFI support")
elif prc.kind != skTemplate:
let newPc = compile(c, prc)
# tricky: a recursion is also a jump back, so we use the same
@@ -972,7 +983,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
newSeq(newFrame.slots, prc.offset+ord(isClosure))
if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro:
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info))
putIntoReg(newFrame.slots[0], getNullValue(prc.typ.sons[0], prc.info, c.config))
for i in 1 .. rc-1:
newFrame.slots[i] = regs[rb+i]
if isClosure:
@@ -994,7 +1005,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let node = regs[rb+i].regToNode
node.info = c.debug[pc]
macroCall.add(node)
var a = evalTemplate(macroCall, prc, genSymOwner)
var a = evalTemplate(macroCall, prc, genSymOwner, c.config)
if a.kind == nkStmtList and a.len == 1: a = a[0]
a.recSetFlagIsRef
ensureKind(rkNode)
@@ -1079,7 +1090,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcNew:
ensureKind(rkNode)
let typ = c.types[instr.regBx - wordExcess]
regs[ra].node = getNullValue(typ, c.debug[pc])
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
regs[ra].node.flags.incl nfIsRef
of opcNewSeq:
let typ = c.types[instr.regBx - wordExcess]
@@ -1091,7 +1102,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.typ = typ
newSeq(regs[ra].node.sons, count)
for i in 0 ..< count:
regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc])
regs[ra].node.sons[i] = getNullValue(typ.sons[0], c.debug[pc], c.config)
of opcNewStr:
decodeB(rkNode)
regs[ra].node = newNodeI(nkStrLit, c.debug[pc])
@@ -1103,7 +1114,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcLdNull:
ensureKind(rkNode)
let typ = c.types[instr.regBx - wordExcess]
regs[ra].node = getNullValue(typ, c.debug[pc])
regs[ra].node = getNullValue(typ, c.debug[pc], c.config)
# opcLdNull really is the gist of the VM's problems: should it load
# a fresh null to regs[ra].node or to regs[ra].node[]? This really
# depends on whether regs[ra] represents the variable itself or wether
@@ -1150,7 +1161,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.strVal = renderTree(regs[rb].regToNode, {renderNoComments, renderDocComments})
of opcQuit:
if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
message(c.debug[pc], hintQuitCalled)
message(c.config, c.debug[pc], hintQuitCalled)
msgQuit(int8(getOrdValue(regs[ra].regToNode)))
else:
return TFullReg(kind: rkNone)
@@ -1176,14 +1187,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[ra].node.isNil: stackTrace(c, tos, pc, errNilAccess)
else: c.setLenSeq(regs[ra].node, newLen, c.debug[pc])
of opcReset:
internalError(c.debug[pc], "too implement")
internalError(c.config, c.debug[pc], "too implement")
of opcNarrowS:
decodeB(rkInt)
let min = -(1.BiggestInt shl (rb-1))
let max = (1.BiggestInt shl (rb-1))-1
if regs[ra].intVal < min or regs[ra].intVal > max:
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errUnhandledExceptionX) % "value out of range")
stackTrace(c, tos, pc, "unhandled exception: value out of range")
of opcNarrowU:
decodeB(rkInt)
regs[ra].intVal = regs[ra].intVal and ((1'i64 shl rb)-1)
@@ -1217,7 +1227,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if u.kind notin {nkEmpty..nkNilLit}:
u.add(regs[rc].node)
else:
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
regs[ra].node = u
of opcNAddMultiple:
decodeBC(rkNode)
@@ -1227,7 +1237,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# XXX can be optimized:
for i in 0..<x.len: u.add(x.sons[i])
else:
stackTrace(c, tos, pc, errGenerated, "cannot add to node kind: " & $u.kind)
stackTrace(c, tos, pc, "cannot add to node kind: " & $u.kind)
regs[ra].node = u
of opcNKind:
decodeB(rkInt)
@@ -1239,34 +1249,34 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if a.kind == nkSym:
regs[ra].intVal = ord(a.sym.kind)
else:
stackTrace(c, tos, pc, errGenerated, "node is not a symbol")
stackTrace(c, tos, pc, "node is not a symbol")
c.comesFromHeuristic = regs[rb].node.info
of opcNIntVal:
decodeB(rkInt)
let a = regs[rb].node
case a.kind
of nkCharLit..nkUInt64Lit: regs[ra].intVal = a.intVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
else: stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
of opcNFloatVal:
decodeB(rkFloat)
let a = regs[rb].node
case a.kind
of nkFloatLit..nkFloat64Lit: regs[ra].floatVal = a.floatVal
else: stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
else: stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
of opcNSymbol:
decodeB(rkNode)
let a = regs[rb].node
if a.kind == nkSym:
regs[ra].node = copyNode(a)
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
of opcNIdent:
decodeB(rkNode)
let a = regs[rb].node
if a.kind == nkIdent:
regs[ra].node = copyNode(a)
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
stackTrace(c, tos, pc, errFieldXNotFound & "ident")
of opcNGetType:
let rb = instr.regB
let rc = instr.regC
@@ -1277,28 +1287,28 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
stackTrace(c, tos, pc, "node has no type")
of 1:
# typeKind opcode:
ensureKind(rkInt)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].intVal = ord(regs[rb].node.typ.kind)
#else:
# stackTrace(c, tos, pc, errGenerated, "node has no type")
# stackTrace(c, tos, pc, "node has no type")
of 2:
# getTypeInst opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeInstToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
stackTrace(c, tos, pc, "node has no type")
else:
# getTypeImpl opcode:
ensureKind(rkNode)
if regs[rb].kind == rkNode and regs[rb].node.typ != nil:
regs[ra].node = opMapTypeImplToAst(regs[rb].node.typ, c.debug[pc])
else:
stackTrace(c, tos, pc, errGenerated, "node has no type")
stackTrace(c, tos, pc, "node has no type")
of opcNStrVal:
decodeB(rkNode)
createStr regs[ra]
@@ -1313,12 +1323,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of nkSym:
regs[ra].node.strVal = a.sym.name.s
else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
of opcSlurp:
decodeB(rkNode)
createStr regs[ra]
regs[ra].node.strVal = opSlurp(regs[rb].node.strVal, c.debug[pc],
c.module)
c.module, c.config)
of opcGorge:
decodeBC(rkNode)
inc pc
@@ -1327,29 +1337,30 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
createStr regs[ra]
regs[ra].node.strVal = opGorge(regs[rb].node.strVal,
regs[rc].node.strVal, regs[rd].node.strVal,
c.debug[pc])[0]
c.debug[pc], c.config)[0]
of opcNError:
decodeB(rkNode)
let a = regs[ra].node
let b = regs[rb].node
stackTrace(c, tos, pc, errUser, a.strVal, if b.kind == nkNilLit: nil else: b)
stackTrace(c, tos, pc, a.strVal, if b.kind == nkNilLit: nil else: b)
of opcNWarning:
message(c.debug[pc], warnUser, regs[ra].node.strVal)
message(c.config, c.debug[pc], warnUser, regs[ra].node.strVal)
of opcNHint:
message(c.debug[pc], hintUser, regs[ra].node.strVal)
message(c.config, c.debug[pc], hintUser, regs[ra].node.strVal)
of opcParseExprToAst:
decodeB(rkNode)
# c.debug[pc].line.int - countLines(regs[rb].strVal) ?
var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
c.debug[pc].toFullPath, c.debug[pc].line.int,
proc (info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= msgs.errMax:
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= errMax:
error = formatMsg(info, msg, arg))
if not error.isNil:
c.errorFlag = error
elif sonsLen(ast) != 1:
c.errorFlag = formatMsg(c.debug[pc], errExprExpected, "multiple statements")
c.errorFlag = formatMsg(c.debug[pc], errGenerated,
"expected expression, but got multiple statements")
else:
regs[ra].node = ast.sons[0]
of opcParseStmtToAst:
@@ -1357,8 +1368,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
var error: string
let ast = parseString(regs[rb].node.strVal, c.cache, c.config,
c.debug[pc].toFullPath, c.debug[pc].line.int,
proc (info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= msgs.errMax:
proc (conf: ConfigRef; info: TLineInfo; msg: TMsgKind; arg: string) =
if error.isNil and msg <= errMax:
error = formatMsg(info, msg, arg))
if not error.isNil:
c.errorFlag = error
@@ -1371,7 +1382,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcCallSite:
ensureKind(rkNode)
if c.callsite != nil: regs[ra].node = c.callsite
else: stackTrace(c, tos, pc, errFieldXNotFound, "callsite")
else: stackTrace(c, tos, pc, errFieldXNotFound & "callsite")
of opcNGetFile:
decodeB(rkNode)
let n = regs[rb].node
@@ -1433,13 +1444,13 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcStrToIdent:
decodeB(rkNode)
if regs[rb].node.kind notin {nkStrLit..nkTripleStrLit}:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
else:
regs[ra].node = newNodeI(nkIdent, c.debug[pc])
regs[ra].node.ident = getIdent(regs[rb].node.strVal)
of opcSetType:
if regs[ra].kind != rkNode:
internalError(c.debug[pc], "cannot set type")
internalError(c.config, c.debug[pc], "cannot set type")
regs[ra].node.typ = c.types[instr.regBx - wordExcess]
of opcConv:
let rb = instr.regB
@@ -1448,9 +1459,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
inc pc
let srctyp = c.types[c.code[pc].regBx - wordExcess]
if opConv(regs[ra], regs[rb], desttyp, srctyp):
stackTrace(c, tos, pc, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
if opConv(c, regs[ra], regs[rb], desttyp, srctyp):
stackTrace(c, tos, pc,
errIllegalConvFromXtoY % [
typeToString(srctyp), typeToString(desttyp)])
of opcCast:
let rb = instr.regB
@@ -1463,7 +1474,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let dest = fficast(regs[rb], desttyp)
asgnRef(regs[ra], dest)
else:
globalError(c.debug[pc], "cannot evaluate cast")
globalError(c.config, c.debug[pc], "cannot evaluate cast")
of opcNSetIntVal:
decodeB(rkNode)
var dest = regs[ra].node
@@ -1471,7 +1482,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[rb].kind in {rkInt}:
dest.intVal = regs[rb].intVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "intVal")
stackTrace(c, tos, pc, errFieldXNotFound & "intVal")
of opcNSetFloatVal:
decodeB(rkNode)
var dest = regs[ra].node
@@ -1479,26 +1490,26 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[rb].kind in {rkFloat}:
dest.floatVal = regs[rb].floatVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "floatVal")
stackTrace(c, tos, pc, errFieldXNotFound & "floatVal")
of opcNSetSymbol:
decodeB(rkNode)
var dest = regs[ra].node
if dest.kind == nkSym and regs[rb].node.kind == nkSym:
dest.sym = regs[rb].node.sym
else:
stackTrace(c, tos, pc, errFieldXNotFound, "symbol")
stackTrace(c, tos, pc, errFieldXNotFound & "symbol")
of opcNSetIdent:
decodeB(rkNode)
var dest = regs[ra].node
if dest.kind == nkIdent and regs[rb].node.kind == nkIdent:
dest.ident = regs[rb].node.ident
else:
stackTrace(c, tos, pc, errFieldXNotFound, "ident")
stackTrace(c, tos, pc, errFieldXNotFound & "ident")
of opcNSetType:
decodeB(rkNode)
let b = regs[rb].node
internalAssert b.kind == nkSym and b.sym.kind == skType
internalAssert regs[ra].node != nil
internalAssert c.config, b.kind == nkSym and b.sym.kind == skType
internalAssert c.config, regs[ra].node != nil
regs[ra].node.typ = b.sym.typ
of opcNSetStrVal:
decodeB(rkNode)
@@ -1509,12 +1520,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
elif dest.kind == nkCommentStmt and regs[rb].kind in {rkNode}:
dest.comment = regs[rb].node.strVal
else:
stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
stackTrace(c, tos, pc, errFieldXNotFound & "strVal")
of opcNNewNimNode:
decodeBC(rkNode)
var k = regs[rb].intVal
if k < 0 or k > ord(high(TNodeKind)):
internalError(c.debug[pc],
internalError(c.config, c.debug[pc],
"request to create a NimNode of invalid kind")
let cc = regs[rc].node
@@ -1548,7 +1559,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let name = if regs[rc].node.strVal.len == 0: ":tmp"
else: regs[rc].node.strVal
if k < 0 or k > ord(high(TSymKind)):
internalError(c.debug[pc], "request to create symbol of invalid kind")
internalError(c.config, c.debug[pc], "request to create symbol of invalid kind")
var sym = newSym(k.TSymKind, name.getIdent, c.module.owner, c.debug[pc])
incl(sym.flags, sfGenSym)
regs[ra].node = newSymNode(sym)
@@ -1557,7 +1568,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
# type trait operation
decodeB(rkNode)
var typ = regs[rb].node.typ
internalAssert typ != nil
internalAssert c.config, typ != nil
while typ.kind == tyTypeDesc and typ.len > 0: typ = typ.sons[0]
createStr regs[ra]
regs[ra].node.strVal = typ.typeToString(preferExported)
@@ -1566,14 +1577,14 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
let rb = instr.regB
inc pc
let typ = c.types[c.code[pc].regBx - wordExcess]
putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ))
putIntoReg(regs[ra], loadAny(regs[rb].node.strVal, typ, c.config))
of opcMarshalStore:
decodeB(rkNode)
inc pc
let typ = c.types[c.code[pc].regBx - wordExcess]
createStrKeepNode(regs[ra])
if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode, c.config)
of opcToNarrowInt:
decodeBC(rkInt)
let mask = (1'i64 shl rc) - 1 # 0xFF
@@ -1595,7 +1606,7 @@ proc execute(c: PCtx, start: int): PNode =
proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
if sym.kind in routineKinds:
if sym.typ.len-1 != args.len:
localError(sym.info,
localError(c.config, sym.info,
"NimScript: expected $# arguments, but got $#" % [
$(sym.typ.len-1), $args.len])
else:
@@ -1607,18 +1618,18 @@ proc execProc*(c: PCtx; sym: PSym; args: openArray[PNode]): PNode =
# setup parameters:
if not isEmptyType(sym.typ.sons[0]) or sym.kind == skMacro:
putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info))
putIntoReg(tos.slots[0], getNullValue(sym.typ.sons[0], sym.info, c.config))
# XXX We could perform some type checking here.
for i in 1..<sym.typ.len:
putIntoReg(tos.slots[i], args[i-1])
result = rawExecute(c, start, tos).regToNode
else:
localError(sym.info,
localError(c.config, sym.info,
"NimScript: attempt to call non-routine: " & sym.name.s)
proc evalStmt*(c: PCtx, n: PNode) =
let n = transformExpr(c.module, n)
let n = transformExpr(c.graph, c.module, n)
let start = genStmt(c, n)
# execute new instructions; this redundant opcEof check saves us lots
# of allocations in 'execute':
@@ -1626,13 +1637,13 @@ proc evalStmt*(c: PCtx, n: PNode) =
discard execute(c, start)
proc evalExpr*(c: PCtx, n: PNode): PNode =
let n = transformExpr(c.module, n)
let n = transformExpr(c.graph, c.module, n)
let start = genExpr(c, n)
assert c.code[start].opcode != opcEof
result = execute(c, start)
proc getGlobalValue*(c: PCtx; s: PSym): PNode =
internalAssert s.kind in {skLet, skVar} and sfGlobal in s.flags
internalAssert c.config, s.kind in {skLet, skVar} and sfGlobal in s.flags
result = c.globals.sons[s.position-1]
include vmops
@@ -1643,9 +1654,9 @@ include vmops
var
globalCtx*: PCtx
proc setupGlobalCtx(module: PSym; cache: IdentCache; config: ConfigRef) =
proc setupGlobalCtx(module: PSym; cache: IdentCache; graph: ModuleGraph) =
if globalCtx.isNil:
globalCtx = newCtx(module, cache, config)
globalCtx = newCtx(module, cache, graph)
registerAdditionalOps(globalCtx)
else:
refresh(globalCtx, module)
@@ -1656,21 +1667,20 @@ proc myOpen(graph: ModuleGraph; module: PSym; cache: IdentCache): PPassContext =
#pushStackFrame(c, newStackFrame())
# XXX produce a new 'globals' environment here:
setupGlobalCtx(module, cache, graph.config)
setupGlobalCtx(module, cache, graph)
result = globalCtx
when hasFFI:
globalCtx.features = {allowFFI, allowCast}
var oldErrorCount: int
proc myProcess(c: PPassContext, n: PNode): PNode =
let c = PCtx(c)
# don't eval errornous code:
if oldErrorCount == msgs.gErrorCounter:
if c.oldErrorCount == c.config.errorCounter:
evalStmt(PCtx(c), n)
result = emptyNode
else:
result = n
oldErrorCount = msgs.gErrorCounter
c.oldErrorCount = c.config.errorCounter
proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
myProcess(c, n)
@@ -1678,10 +1688,10 @@ proc myClose(graph: ModuleGraph; c: PPassContext, n: PNode): PNode =
const evalPass* = makePass(myOpen, nil, myProcess, myClose)
proc evalConstExprAux(module: PSym; cache: IdentCache;
config: ConfigRef; prc: PSym, n: PNode,
g: ModuleGraph; prc: PSym, n: PNode,
mode: TEvalMode): PNode =
let n = transformExpr(module, n)
setupGlobalCtx(module, cache, config)
let n = transformExpr(g, module, n)
setupGlobalCtx(module, cache, g)
var c = globalCtx
let oldMode = c.mode
defer: c.mode = oldMode
@@ -1696,17 +1706,17 @@ proc evalConstExprAux(module: PSym; cache: IdentCache;
result = rawExecute(c, start, tos).regToNode
if result.info.col < 0: result.info = n.info
proc evalConstExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode): PNode =
result = evalConstExprAux(module, cache, config, nil, e, emConst)
proc evalConstExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode): PNode =
result = evalConstExprAux(module, cache, g, nil, e, emConst)
proc evalStaticExpr*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym): PNode =
result = evalConstExprAux(module, cache, config, prc, e, emStaticExpr)
proc evalStaticExpr*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym): PNode =
result = evalConstExprAux(module, cache, g, prc, e, emStaticExpr)
proc evalStaticStmt*(module: PSym; cache: IdentCache, config: ConfigRef; e: PNode, prc: PSym) =
discard evalConstExprAux(module, cache, config, prc, e, emStaticStmt)
proc evalStaticStmt*(module: PSym; cache: IdentCache, g: ModuleGraph; e: PNode, prc: PSym) =
discard evalConstExprAux(module, cache, g, prc, e, emStaticStmt)
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, config: ConfigRef; n: PNode) =
discard evalConstExprAux(module, cache, config, nil, n, emStaticStmt)
proc setupCompileTimeVar*(module: PSym; cache: IdentCache, g: ModuleGraph; n: PNode) =
discard evalConstExprAux(module, cache, g, nil, n, emStaticStmt)
proc setupMacroParam(x: PNode, typ: PType): TFullReg =
case typ.kind
@@ -1734,20 +1744,20 @@ iterator genericParamsInMacroCall*(macroSym: PSym, call: PNode): (PSym, PNode) =
const evalMacroLimit = 1000
var evalMacroCounter: int
proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
proc evalMacroCall*(module: PSym; cache: IdentCache; g: ModuleGraph;
n, nOrig: PNode, sym: PSym): PNode =
# XXX globalError() is ugly here, but I don't know a better solution for now
inc(evalMacroCounter)
if evalMacroCounter > evalMacroLimit:
globalError(n.info, errMacroInstantiationTooNested)
globalError(g.config, n.info, "macro instantiation too nested")
# immediate macros can bypass any type and arity checking so we check the
# arity here too:
if sym.typ.len > n.safeLen and sym.typ.len > 1:
globalError(n.info, "in call '$#' got $#, but expected $# argument(s)" % [
globalError(g.config, n.info, "in call '$#' got $#, but expected $# argument(s)" % [
n.renderTree, $(n.safeLen-1), $(sym.typ.len-1)])
setupGlobalCtx(module, cache, config)
setupGlobalCtx(module, cache, g)
var c = globalCtx
c.comesFromHeuristic.line = 0'u16
@@ -1781,16 +1791,16 @@ proc evalMacroCall*(module: PSym; cache: IdentCache; config: ConfigRef;
else:
dec(evalMacroCounter)
c.callsite = nil
localError(n.info, "expected " & $gp.len &
localError(c.config, n.info, "expected " & $gp.len &
" generic parameter(s)")
elif gp[i].sym.typ.kind in {tyStatic, tyTypeDesc}:
dec(evalMacroCounter)
c.callsite = nil
globalError(n.info, "static[T] or typedesc nor supported for .immediate macros")
globalError(c.config, n.info, "static[T] or typedesc nor supported for .immediate macros")
# temporary storage:
#for i in L ..< maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos).regToNode
if result.info.line < 0: result.info = n.info
if cyclicTree(result): globalError(n.info, errCyclicTree)
if cyclicTree(result): globalError(c.config, n.info, "macro produced a cyclic tree")
dec(evalMacroCounter)
c.callsite = nil

View File

@@ -208,6 +208,7 @@ type
cache*: IdentCache
config*: ConfigRef
graph*: ModuleGraph
oldErrorCount*: int
TPosition* = distinct int

View File

@@ -15,8 +15,6 @@ from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir
from options import gProjectPath
template mathop(op) {.dirty.} =
registerCallback(c, "stdlib.math." & astToStr(op), `op Wrapper`)
@@ -77,15 +75,15 @@ proc staticWalkDirImpl(path: string, relative: bool): PNode =
result.add newTree(nkTupleConstr, newIntNode(nkIntLit, k.ord),
newStrNode(nkStrLit, f))
proc gorgeExWrapper(a: VmArgs) {.nimcall.} =
let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
a.currentLineInfo)
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
proc getProjectPathWrapper(a: VmArgs) {.nimcall.} =
setResult a, gProjectPath
proc registerAdditionalOps*(c: PCtx) =
proc gorgeExWrapper(a: VmArgs) =
let (s, e) = opGorge(getString(a, 0), getString(a, 1), getString(a, 2),
a.currentLineInfo, c.config)
setResult a, newTree(nkTupleConstr, newStrNode(nkStrLit, s), newIntNode(nkIntLit, e))
proc getProjectPathWrapper(a: VmArgs) =
setResult a, c.config.projectPath
wrap1f_math(sqrt)
wrap1f_math(ln)
wrap1f_math(log10)