refactorings for the eval engine; bugfix: clean templates as accessors

This commit is contained in:
Araq
2013-07-19 22:22:20 +02:00
parent 0c18e05336
commit bfbdb1f028
10 changed files with 235 additions and 239 deletions

View File

@@ -211,7 +211,7 @@ type
nkClosure, # (prc, env)-pair (internally used for code gen)
nkGotoState, # used for the state machine (for iterators)
nkState, # give a label to a code section (for iterators)
nkBreakState # special break statement for easier code generation
nkBreakState, # special break statement for easier code generation
TNodeKinds* = set[TNodeKind]
type
@@ -534,7 +534,6 @@ type
when defined(useNodeIds):
id*: int
typ*: PType
comment*: string
info*: TLineInfo
flags*: TNodeFlags
case Kind*: TNodeKind
@@ -548,8 +547,9 @@ type
sym*: PSym
of nkIdent:
ident*: PIdent
else:
else:
sons*: TNodeSeq
comment*: string
TSymSeq* = seq[PSym]
TStrTable* = object # a table[PIdent] of PSym
@@ -667,7 +667,7 @@ type
# for modules, an unique index corresponding
# to the module's fileIdx
# for variables a slot index for the evaluator
# for routines a superop-ID
offset*: int # offset of record field
loc*: TLoc
annex*: PLib # additional fields (seldom used, so we use a
@@ -778,10 +778,10 @@ const
genericParamsPos* = 2
paramsPos* = 3
pragmasPos* = 4
exceptionPos* = 5 # will be used for exception tracking
optimizedCodePos* = 5 # will be used for exception tracking
bodyPos* = 6 # position of body; use rodread.getBody() instead!
resultPos* = 7
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 5!
dispatcherPos* = 8 # caution: if method has no 'result' it can be position 7!
nkCallKinds* = {nkCall, nkInfix, nkPrefix, nkPostfix,
nkCommand, nkCallStrLit, nkHiddenCallConv}

View File

@@ -59,6 +59,7 @@ proc InitDefines*() =
DefineSymbol("nimmixin")
DefineSymbol("nimeffects")
DefineSymbol("nimbabel")
DefineSymbol("nimsuperops")
# add platform specific symbols:
case targetCPU

View File

@@ -110,13 +110,18 @@ proc stackTraceAux(x: PStackFrame) =
add(s, x.prc.name.s)
MsgWriteln(s)
proc stackTrace(c: PEvalContext, n: PNode, msg: TMsgKind, arg = "") =
proc stackTrace(c: PEvalContext, info: TLineInfo, msg: TMsgKind, arg = "") =
MsgWriteln("stack trace: (most recent call last)")
stackTraceAux(c.tos)
LocalError(n.info, msg, arg)
LocalError(info, msg, arg)
proc isSpecial(n: PNode): bool {.inline.} =
result = n.kind == nkExceptBranch
template isSpecial(n: PNode): bool = n.kind == nkExceptBranch
template bailout() {.dirty.} =
if isSpecial(result): return
template evalX(n, flags) {.dirty.} =
result = evalAux(c, n, flags)
bailout()
proc myreset(n: PNode) =
when defined(system.reset):
@@ -128,19 +133,17 @@ proc evalIf(c: PEvalContext, n: PNode): PNode =
var i = 0
var length = sonsLen(n)
while (i < length) and (sonsLen(n.sons[i]) >= 2):
result = evalAux(c, n.sons[i].sons[0], {})
if isSpecial(result): return
if (result.kind == nkIntLit) and (result.intVal != 0):
evalX(n.sons[i].sons[0], {})
if result.kind == nkIntLit and result.intVal != 0:
return evalAux(c, n.sons[i].sons[1], {})
inc(i)
if (i < length) and (sonsLen(n.sons[i]) < 2):
if (i < length) and (sonsLen(n.sons[i]) < 2):
result = evalAux(c, n.sons[i].sons[0], {})
else:
else:
result = emptyNode
proc evalCase(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
if isSpecial(result): return
evalX(n.sons[0], {})
var res = result
result = emptyNode
for i in countup(1, sonsLen(n) - 1):
@@ -160,9 +163,8 @@ var
proc evalWhile(c: PEvalContext, n: PNode): PNode =
while true:
result = evalAux(c, n.sons[0], {})
if isSpecial(result): return
if getOrdValue(result) == 0: break
evalX(n.sons[0], {})
if getOrdValue(result) == 0: break
result = evalAux(c, n.sons[1], {})
case result.kind
of nkBreakStmt:
@@ -177,7 +179,7 @@ proc evalWhile(c: PEvalContext, n: PNode): PNode =
if allowInfiniteLoops in c.features:
gWhileCounter = 0
else:
stackTrace(c, n, errTooManyIterations)
stackTrace(c, n.info, errTooManyIterations)
break
proc evalBlock(c: PEvalContext, n: PNode): PNode =
@@ -222,7 +224,9 @@ proc evalTry(c: PEvalContext, n: PNode): PNode =
else:
for j in countup(0, blen - 2):
assert(n.sons[i].sons[j].kind == nkType)
if exc.typ.id == n.sons[i].sons[j].typ.id:
let a = exc.typ.skipTypes(abstractPtrs)
let b = n.sons[i].sons[j].typ.skipTypes(abstractPtrs)
if a == b:
result = evalAux(c, n.sons[i].sons[blen - 1], {})
exc = result
break
@@ -239,7 +243,7 @@ proc getNullValueAux(obj: PNode, result: PNode) =
getNullValueAux(obj.sons[0], result)
for i in countup(1, sonsLen(obj) - 1):
getNullValueAux(lastSon(obj.sons[i]), result)
of nkSym:
of nkSym:
var s = obj.sym
var p = newNodeIT(nkExprColonExpr, result.info, s.typ)
addSon(p, newSymNode(s, result.info))
@@ -290,14 +294,17 @@ proc evalVarValue(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n, {})
if result.kind in {nkType..nkNilLit}: result = result.copyNode
proc allocSlot(c: PStackFrame; sym: PSym): int =
result = sym.position + ord(sym.kind == skParam)
if result == 0 and sym.kind != skResult:
result = c.slots.len
if result == 0: result = 1
sym.position = result
setLen(c.slots, max(result+1, c.slots.len))
proc setSlot(c: PStackFrame, sym: PSym, val: PNode) =
assert sym.owner == c.prc
var idx = sym.position
if idx == 0:
idx = c.slots.len
if idx == 0: idx = 1
sym.position = idx
setLen(c.slots, max(idx+1, c.slots.len))
let idx = allocSlot(c, sym)
c.slots[idx] = val
proc setVar(c: PEvalContext, v: PSym, n: PNode) =
@@ -313,7 +320,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
result = evalVarValue(c, a.lastSon)
if result.kind in {nkType..nkNilLit}:
result = result.copyNode
if isSpecial(result): return
bailout()
if result.kind != nkPar:
return raiseCannotEval(c, n.info)
for i in 0 .. a.len-3:
@@ -322,7 +329,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
else:
if a.sons[2].kind != nkEmpty:
result = evalVarValue(c, a.sons[2])
if isSpecial(result): return
bailout()
else:
result = getNullValue(a.sons[0].typ, a.sons[0].info)
if a.sons[0].kind == nkSym:
@@ -331,8 +338,7 @@ proc evalVar(c: PEvalContext, n: PNode): PNode =
else:
# assign to a.sons[0]:
var x = result
result = evalAux(c, a.sons[0], {})
if isSpecial(result): return
evalX(a.sons[0], {})
myreset(x)
x.kind = result.kind
x.typ = result.typ
@@ -392,6 +398,9 @@ proc evalGlobalVar(c: PEvalContext, s: PSym, flags: TEvalFlags): PNode =
else:
result = raiseCannotEval(nil, s.info)
proc optBody(c: PEvalContext, s: PSym): PNode =
result = s.getBody
proc evalCall(c: PEvalContext, n: PNode): PNode =
var d = newStackFrame()
d.call = n
@@ -400,8 +409,7 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
setlen(d.slots, sonsLen(n) + ord(isClosure))
if isClosure:
#debug prc
result = evalAux(c, prc.sons[1], {efLValue})
if isSpecial(result): return
evalX(prc.sons[1], {efLValue})
d.slots[sonsLen(n)] = result
result = evalAux(c, prc.sons[0], {})
else:
@@ -418,8 +426,7 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
InternalError(n.info, "evalCall")
return
for i in countup(1, sonsLen(n) - 1):
result = evalAux(c, n.sons[i], {})
if isSpecial(result): return
evalX(n.sons[i], {})
d.slots[i] = result
if n.typ != nil: d.slots[0] = getNullValue(n.typ, n.info)
@@ -432,33 +439,30 @@ proc evalCall(c: PEvalContext, n: PNode): PNode =
return callForeignFunction(newCall)
pushStackFrame(c, d)
result = evalAux(c, prc.sym.getBody, {})
if result.kind == nkExceptBranch: return
evalX(optBody(c, prc.sym), {})
if n.typ != nil: result = d.slots[0]
popStackFrame(c)
proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = evalAux(c, n.sons[0], flags)
if isSpecial(result): return
evalX(n.sons[0], flags)
var x = result
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
var idx = getOrdValue(result)
result = emptyNode
case x.kind
of nkPar:
of nkPar:
if (idx >= 0) and (idx < sonsLen(x)):
result = x.sons[int(idx)]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
of nkBracket, nkMetaNode:
if (idx >= 0) and (idx < sonsLen(x)):
result = x.sons[int(idx)]
if not aliasNeeded(result, flags): result = copyTree(result)
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
of nkStrLit..nkTripleStrLit:
if efLValue in flags: return raiseCannotEval(c, n.info)
result = newNodeIT(nkCharLit, x.info, getSysType(tyChar))
@@ -467,14 +471,13 @@ proc evalArrayAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
elif idx == len(x.strVal):
nil
else:
stackTrace(c, n, errIndexOutOfBounds)
else: stackTrace(c, n, errNilAccess)
stackTrace(c, n.info, errIndexOutOfBounds)
else: stackTrace(c, n.info, errNilAccess)
proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
# a real field access; proc calls have already been transformed
# XXX: field checks!
result = evalAux(c, n.sons[0], flags)
if isSpecial(result): return
evalX(n.sons[0], flags)
var x = result
if x.kind != nkPar: return raiseCannotEval(c, n.info)
# this is performance critical:
@@ -482,48 +485,26 @@ proc evalFieldAccess(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
when false:
var field = n.sons[1].sym
for i in countup(0, sonsLen(x) - 1):
var it = x.sons[i]
if it.kind != nkExprColonExpr:
# lookup per index:
result = x.sons[field.position]
if result.kind == nkExprColonExpr: result = result.sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
#InternalError(it.info, "evalFieldAccess")
if it.sons[0].sym.name.id == field.name.id:
result = x.sons[i].sons[1]
if not aliasNeeded(result, flags): result = copyTree(result)
return
stackTrace(c, n, errFieldXNotFound, field.name.s)
result = emptyNode
proc evalAsgn(c: PEvalContext, n: PNode): PNode =
proc evalAsgn(c: PEvalContext, n: PNode): PNode =
var a = n.sons[0]
if a.kind == nkBracketExpr and a.sons[0].typ.kind in {tyString, tyCString}:
result = evalAux(c, a.sons[0], {efLValue})
if isSpecial(result): return
evalX(a.sons[0], {efLValue})
var x = result
result = evalAux(c, a.sons[1], {})
if isSpecial(result): return
evalX(a.sons[1], {})
var idx = getOrdValue(result)
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkCharLit: return raiseCannotEval(c, n.info)
evalX(n.sons[1], {})
if result.kind notin {nkIntLit, nkCharLit}: return c.raiseCannotEval(n.info)
if (idx >= 0) and (idx < len(x.strVal)):
if idx >= 0 and idx < len(x.strVal):
x.strVal[int(idx)] = chr(int(result.intVal))
else:
stackTrace(c, n, errIndexOutOfBounds)
else:
stackTrace(c, n.info, errIndexOutOfBounds)
else:
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
var x = result
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
myreset(x)
x.kind = result.kind
x.typ = result.typ
@@ -541,13 +522,11 @@ proc evalAsgn(c: PEvalContext, n: PNode): PNode =
assert result.kind == nkEmpty
proc evalSwap(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
var x = result
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
evalX(n.sons[1], {efLValue})
if x.kind != result.kind:
stackTrace(c, n, errCannotInterpretNodeX, $n.kind)
stackTrace(c, n.info, errCannotInterpretNodeX, $n.kind)
else:
case x.kind
of nkCharLit..nkInt64Lit: swap(x.intVal, result.intVal)
@@ -587,11 +566,9 @@ proc evalSym(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = raiseCannotEval(c, n.info)
proc evalIncDec(c: PEvalContext, n: PNode, sign: biggestInt): PNode =
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
evalX(n.sons[1], {efLValue})
var a = result
result = evalAux(c, n.sons[2], {})
if isSpecial(result): return
evalX(n.sons[2], {})
var b = result
case a.kind
of nkCharLit..nkInt64Lit: a.intval = a.intVal + sign * getOrdValue(b)
@@ -607,64 +584,62 @@ proc getStrValue(n: PNode): string =
proc evalEcho(c: PEvalContext, n: PNode): PNode =
for i in countup(1, sonsLen(n) - 1):
result = evalAux(c, n.sons[i], {})
if isSpecial(result): return
evalX(n.sons[i], {})
Write(stdout, getStrValue(result))
writeln(stdout, "")
result = emptyNode
proc evalExit(c: PEvalContext, n: PNode): PNode =
if c.mode in {emRepl, emStatic}:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
Message(n.info, hintQuitCalled)
quit(int(getOrdValue(result)))
else:
result = raiseCannotEval(c, n.info)
proc evalOr(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIntLit: InternalError(n.info, "evalOr")
elif result.intVal == 0: result = evalAux(c, n.sons[2], {})
evalX(n.sons[1], {})
if result.intVal == 0: result = evalAux(c, n.sons[2], {})
proc evalAnd(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIntLit: InternalError(n.info, "evalAnd")
elif result.intVal != 0: result = evalAux(c, n.sons[2], {})
evalX(n.sons[1], {})
if result.intVal != 0: result = evalAux(c, n.sons[2], {})
proc evalNew(c: PEvalContext, n: PNode): PNode =
#if c.mode == emOptimize: return raiseCannotEval(c, n.info)
# we ignore the finalizer for now and most likely forever :-)
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
evalX(n.sons[1], {efLValue})
var a = result
var t = skipTypes(n.sons[1].typ, abstractVar)
if a.kind == nkEmpty: InternalError(n.info, "first parameter is empty")
myreset(a)
a.kind = nkRefTy
a.info = n.info
let u = getNullValue(t.sons[0], n.info)
a.kind = u.kind
a.typ = t
a.sons = nil
addSon(a, getNullValue(t.sons[0], n.info))
shallowCopy(a.sons, u.sons)
result = emptyNode
when false:
a.kind = nkRefTy
a.info = n.info
a.typ = t
a.sons = nil
addSon(a, getNullValue(t.sons[0], n.info))
result = emptyNode
proc evalDeref(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
case result.kind
of nkNilLit: stackTrace(c, n, errNilAccess)
of nkNilLit: stackTrace(c, n.info, errNilAccess)
of nkRefTy:
# XXX efLValue?
result = result.sons[0]
else:
result = raiseCannotEval(c, n.info)
if skipTypes(n.sons[0].typ, abstractInst).kind != tyRef:
result = raiseCannotEval(c, n.info)
proc evalAddr(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = evalAux(c, n.sons[0], {efLValue})
if isSpecial(result): return
evalX(n.sons[0], {efLValue})
var a = result
var t = newType(tyPtr, c.module)
addSonSkipIntLit(t, a.typ)
@@ -703,24 +678,22 @@ proc evalUpConv(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
var dest = skipTypes(n.typ, abstractPtrs)
var src = skipTypes(result.typ, abstractPtrs)
if inheritanceDiff(src, dest) > 0:
stackTrace(c, n, errInvalidConversionFromTypeX, typeToString(src))
stackTrace(c, n.info, errInvalidConversionFromTypeX, typeToString(src))
proc evalRangeChck(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
if isSpecial(result): return
evalX(n.sons[0], {})
var x = result
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
evalX(n.sons[1], {})
var a = result
result = evalAux(c, n.sons[2], {})
if isSpecial(result): return
evalX(n.sons[2], {})
var b = result
if leValueConv(a, x) and leValueConv(x, b):
result = x # a <= x and x <= b
result.typ = n.typ
else:
stackTrace(c, n, errGenerated, msgKindToString(errIllegalConvFromXtoY) % [
typeToString(n.sons[0].typ), typeToString(n.typ)])
stackTrace(c, n.info, errGenerated,
msgKindToString(errIllegalConvFromXtoY) % [
typeToString(n.sons[0].typ), typeToString(n.typ)])
proc evalConvStrToCStr(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[0], {})
@@ -744,7 +717,7 @@ proc evalRaise(c: PEvalContext, n: PNode): PNode =
elif c.lastException != nil:
result = c.lastException
else:
stackTrace(c, n, errExceptionAlreadyHandled)
stackTrace(c, n.info, errExceptionAlreadyHandled)
result = newNodeIT(nkExceptBranch, n.info, nil)
addSon(result, ast.emptyNode)
else:
@@ -1089,7 +1062,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
case a.kind
of nkEmpty..nkNilLit: nil
else: result.intVal = sonsLen(a)
of mNChild:
of mNChild:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
var a = result
@@ -1100,7 +1073,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = a.sons[int(k)]
if result == nil: result = newNode(nkEmpty)
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
result = emptyNode
of mNSetChild:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1115,7 +1088,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if (k >= 0) and (k < sonsLen(a)) and not (a.kind in {nkEmpty..nkNilLit}):
a.sons[int(k)] = result
else:
stackTrace(c, n, errIndexOutOfBounds)
stackTrace(c, n.info, errIndexOutOfBounds)
result = emptyNode
of mNAdd:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1158,7 +1131,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = newNodeIT(nkIntLit, n.info, n.typ)
case a.kind
of nkCharLit..nkInt64Lit: result.intVal = a.intVal
else: stackTrace(c, n, errFieldXNotFound, "intVal")
else: stackTrace(c, n.info, errFieldXNotFound, "intVal")
of mNFloatVal:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@@ -1166,15 +1139,15 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = newNodeIT(nkFloatLit, n.info, n.typ)
case a.kind
of nkFloatLit..nkFloat64Lit: result.floatVal = a.floatVal
else: stackTrace(c, n, errFieldXNotFound, "floatVal")
else: stackTrace(c, n.info, errFieldXNotFound, "floatVal")
of mNSymbol:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
if result.kind != nkSym: stackTrace(c, n, errFieldXNotFound, "symbol")
if result.kind != nkSym: stackTrace(c, n.info, errFieldXNotFound, "symbol")
of mNIdent:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if result.kind != nkIdent: stackTrace(c, n, errFieldXNotFound, "ident")
if result.kind != nkIdent: stackTrace(c, n.info, errFieldXNotFound, "ident")
of mNGetType:
var ast = evalAux(c, n.sons[1], {})
InternalAssert c.getType != nil
@@ -1186,7 +1159,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = newNodeIT(nkStrLit, n.info, n.typ)
case a.kind
of nkStrLit..nkTripleStrLit: result.strVal = a.strVal
else: stackTrace(c, n, errFieldXNotFound, "strVal")
else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
of mNSetIntVal:
result = evalAux(c, n.sons[1], {efLValue})
if isSpecial(result): return
@@ -1197,7 +1170,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result.kind in {nkCharLit..nkInt64Lit}:
a.intVal = result.intVal
else:
stackTrace(c, n, errFieldXNotFound, "intVal")
stackTrace(c, n.info, errFieldXNotFound, "intVal")
result = emptyNode
of mNSetFloatVal:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1209,7 +1182,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result.kind in {nkFloatLit..nkFloat64Lit}:
a.floatVal = result.floatVal
else:
stackTrace(c, n, errFieldXNotFound, "floatVal")
stackTrace(c, n.info, errFieldXNotFound, "floatVal")
result = emptyNode
of mNSetSymbol:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1220,7 +1193,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if a.kind == nkSym and result.kind == nkSym:
a.sym = result.sym
else:
stackTrace(c, n, errFieldXNotFound, "symbol")
stackTrace(c, n.info, errFieldXNotFound, "symbol")
result = emptyNode
of mNSetIdent:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1231,7 +1204,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if a.kind == nkIdent and result.kind == nkIdent:
a.ident = result.ident
else:
stackTrace(c, n, errFieldXNotFound, "ident")
stackTrace(c, n.info, errFieldXNotFound, "ident")
result = emptyNode
of mNSetType:
result = evalAux(c, n.sons[1], {efLValue})
@@ -1252,7 +1225,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if a.kind in {nkStrLit..nkTripleStrLit} and
result.kind in {nkStrLit..nkTripleStrLit}:
a.strVal = result.strVal
else: stackTrace(c, n, errFieldXNotFound, "strVal")
else: stackTrace(c, n.info, errFieldXNotFound, "strVal")
result = emptyNode
of mNNewNimNode:
result = evalAux(c, n.sons[1], {})
@@ -1280,7 +1253,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
if not (result.kind in {nkStrLit..nkTripleStrLit}):
stackTrace(c, n, errFieldXNotFound, "strVal")
stackTrace(c, n.info, errFieldXNotFound, "strVal")
return
var a = result
result = newNodeIT(nkIdent, n.info, n.typ)
@@ -1333,7 +1306,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
of mNError:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
stackTrace(c, n, errUser, getStrValue(result))
stackTrace(c, n.info, errUser, getStrValue(result))
result = emptyNode
of mConStrStr:
result = evalConStrStr(c, n)
@@ -1353,7 +1326,7 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
result.strVal = newString(0)
of mNCallSite:
if c.callsite != nil: result = c.callsite
else: stackTrace(c, n, errFieldXNotFound, "callsite")
else: stackTrace(c, n.info, errFieldXNotFound, "callsite")
else:
result = evalAux(c, n.sons[1], {})
if isSpecial(result): return
@@ -1371,10 +1344,10 @@ proc evalMagicOrCall(c: PEvalContext, n: PNode): PNode =
if isEmpty(a) or isEmpty(b) or isEmpty(cc): result = emptyNode
else: result = evalOp(m, n, a, b, cc)
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = emptyNode
dec(gNestedEvals)
if gNestedEvals <= 0: stackTrace(c, n, errTooManyIterations)
if gNestedEvals <= 0: stackTrace(c, n.info, errTooManyIterations)
case n.kind
of nkSym: result = evalSym(c, n, flags)
of nkType..nkNilLit:
@@ -1473,6 +1446,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode =
result = n
else: InternalError(n.info, "evalAux: " & $n.kind)
if result == nil:
debug n
InternalError(n.info, "evalAux: returned nil " & $n.kind)
inc(gNestedEvals)
@@ -1489,9 +1463,9 @@ proc eval*(c: PEvalContext, n: PNode): PNode =
result = tryEval(c, n)
if result.kind == nkExceptBranch:
if sonsLen(result) >= 1:
stackTrace(c, n, errUnhandledExceptionX, typeToString(result.typ))
stackTrace(c, n.info, errUnhandledExceptionX, typeToString(result.typ))
else:
stackTrace(c, result, errCannotInterpretNodeX, renderTree(n))
stackTrace(c, result.info, errCannotInterpretNodeX, renderTree(n))
proc evalConstExprAux(module, prc: PSym, e: PNode, mode: TEvalMode): PNode =
var p = newEvalContext(module, mode)
@@ -1531,7 +1505,7 @@ proc evalMacroCall(c: PEvalContext, n, nOrig: PNode, sym: PSym): PNode =
# setup parameters:
for i in 1 .. < L: s.slots[i] = setupMacroParam(n.sons[i])
pushStackFrame(c, s)
discard eval(c, sym.getBody)
discard eval(c, optBody(c, sym))
result = s.slots[0]
popStackFrame(c)
if cyclicTree(result): GlobalError(n.info, errCyclicTree)

View File

@@ -12,11 +12,11 @@
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer
const
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
someEq = {mEqI, mEqI64, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
mEqUntracedRef, mEqStr, mEqSet, mEqCString}
# set excluded here as the semantics are vastly different:
someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
someLe = {mLeI, mLeI64, mLeF64, mLeU, mLeU64, mLeEnum,
mLeCh, mLeB, mLePtr, mLeStr}
someLt = {mLtI, mLtI64, mLtF64, mLtU, mLtU64, mLtEnum,
mLtCh, mLtB, mLtPtr, mLtStr}
@@ -491,20 +491,13 @@ proc factImplies(fact, prop: PNode): TImplication =
else: discard
case prop.sons[0].sym.magic
of mNot:
result = ~fact.factImplies(prop.sons[1])
of mIsNil:
result = impliesIsNil(fact, prop)
of someEq:
result = impliesEq(fact, prop)
of someLe:
result = impliesLe(fact, prop.sons[1], prop.sons[2])
of someLt:
result = impliesLt(fact, prop.sons[1], prop.sons[2])
of mInSet:
result = impliesIn(fact, prop.sons[2], prop.sons[1])
else:
internalError(prop.info, "invalid proposition")
of mNot: result = ~fact.factImplies(prop.sons[1])
of mIsNil: result = impliesIsNil(fact, prop)
of someEq: result = impliesEq(fact, prop)
of someLe: result = impliesLe(fact, prop.sons[1], prop.sons[2])
of someLt: result = impliesLt(fact, prop.sons[1], prop.sons[2])
of mInSet: result = impliesIn(fact, prop.sons[2], prop.sons[1])
else: internalError(prop.info, "invalid proposition")
proc doesImply*(facts: TModel, prop: PNode): TImplication =
assert prop.kind in nkCallKinds

View File

@@ -118,8 +118,7 @@ proc mapType(typ: PType): TJSTypeKind =
of tyPointer:
# treat a tyPointer like a typed pointer to an array of bytes
result = etyInt
of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter,
tyProxy:
of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy:
result = mapType(t.sons[0])
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
of tyBool: result = etyBool
@@ -826,17 +825,18 @@ proc genSwap(p: PProc, n: PNode) =
gen(p, n.sons[1], a)
gen(p, n.sons[2], b)
inc(p.unique)
let tmp = ropef("Tmp$1", [toRope(p.unique)])
case mapType(skipTypes(n.sons[1].typ, abstractVar))
of etyBaseIndex:
var tmp = ropef("Tmp$1", [toRope(p.unique)])
if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
inc(p.unique)
let tmp2 = ropef("Tmp$1", [toRope(p.unique)])
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
internalError(n.info, "genSwap")
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n", [tmp, a.address, b.address])
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1", [tmp2, a.res, b.res])
else:
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res])
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
"local $1 = $2; $2 = $3; $3 = $1;$n", [
tmp, a.address, b.address])
tmp = tmp2
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1" |
"local $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res])
proc getFieldPosition(f: PNode): int =
case f.kind
@@ -1664,25 +1664,27 @@ proc myProcess(b: PPassContext, n: PNode): PNode =
app(p.g.code, p.locals)
app(p.g.code, p.body)
proc wholeCode*(m: BModule): PRope =
for prc in globals.forwarded:
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options)
app(p.g.code, genProc(p, prc))
var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1:
let prc = disp.sons[i].sym
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options)
app(p.g.code, genProc(p, prc))
result = con(globals.typeInfo, globals.code)
proc myClose(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n
result = myProcess(b, n)
var m = BModule(b)
if sfMainModule in m.module.flags:
for prc in globals.forwarded:
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options)
app(p.g.code, genProc(p, prc))
var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1:
let prc = disp.sons[i].sym
if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options)
app(p.g.code, genProc(p, prc))
# write the file:
var code = con(globals.typeInfo, globals.code)
let code = wholeCode(m)
var outfile = changeFileExt(completeCFilePath(m.module.filename), "js")
discard writeRopeIfNotEqual(con(genHeader(), code), outfile)

View File

@@ -341,6 +341,18 @@ proc CommandInteractive =
incl(m.flags, sfMainModule)
processModule(m, LLStreamOpenStdIn(), nil)
proc execute*(program: string) =
passes.gIncludeFile = includeModule
passes.gImportModule = importModule
initDefines()
LoadConfigs(DefaultConfig)
InteractivePasses()
appendStr(searchPaths, options.libpath)
compileSystemModule()
var m = makeStdinModule()
incl(m.flags, sfMainModule)
processModule(m, LLStreamOpen(program), nil)
const evalPasses = [verbosePass, semPass, evalPass]
proc evalNim(nodes: PNode, module: PSym) =

View File

@@ -24,7 +24,7 @@ const
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGenSym, wInject, wRaises, wTags}
wGenSym, wInject, wRaises, wTags, wOperator}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
templatePragmas* = {wImmediate, wDeprecated, wError, wGenSym, wInject, wDirty}
@@ -34,7 +34,7 @@ const
iteratorPragmas* = {FirstCallConv..LastCallConv, wNosideEffect, wSideEffect,
wImportc, wExportc, wNodecl, wMagic, wDeprecated, wBorrow, wExtern,
wImportcpp, wImportobjc, wError, wDiscardable, wGenSym, wInject, wRaises,
wTags}
wTags, wOperator}
exprPragmas* = {wLine}
stmtPragmas* = {wChecks, wObjChecks, wFieldChecks, wRangechecks,
wBoundchecks, wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
@@ -717,6 +717,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
if sym == nil: invalidPragma(it)
of wLine: PragmaLine(c, it)
of wRaises, wTags: pragmaRaisesOrTags(c, it)
of wOperator:
if sym == nil: invalidPragma(it)
else: sym.position = expectIntLit(c, it)
else: invalidPragma(it)
else: invalidPragma(it)
else: processNote(c, it)

View File

@@ -620,7 +620,7 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
{skProc, skMethod, skConverter, skMacro, skTemplate})
if result != nil:
if result.sons[0].kind != nkSym:
InternalError("semDirectCallAnalyseEffects")
InternalError("semOverloadedCallAnalyseEffects")
return
let callee = result.sons[0].sym
case callee.kind
@@ -632,10 +632,6 @@ proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
if {sfImportc, sfSideEffect} * callee.flags != {}:
incl(c.p.owner.flags, sfSideEffect)
proc semDirectCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
flags: TExprFlags): PNode =
result = semOverloadedCallAnalyseEffects(c, n, nOrig, flags)
proc semObjConstr(c: PContext, n: PNode, flags: TExprFlags): PNode
proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = nil
@@ -707,12 +703,28 @@ proc semIndirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
LocalError(n.info, errExprXCannotBeCalled,
renderTree(n, {renderNoComments}))
return errorNode(c, n)
#result = afterCallActions(c, result, nOrig, flags)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if result.sons[0].kind == nkSym and result.sons[0].sym.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
result = evalAtCompileTime(c, result)
proc afterCallActions(c: PContext; n, orig: PNode, flags: TExprFlags): PNode =
result = n
let callee = result.sons[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, result, orig, callee)
of skTemplate: result = semTemplateExpr(c, result, callee)
else:
semFinishOperands(c, result)
activate(c, result)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
result = evalAtCompileTime(c, result)
proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this seems to be a hotspot in the compiler!
let nOrig = n.copyTree
@@ -723,18 +735,7 @@ proc semDirectOp(c: PContext, n: PNode, flags: TExprFlags): PNode =
if result == nil:
NotFoundError(c, n)
return errorNode(c, n)
let callee = result.sons[0].sym
case callee.kind
of skMacro: result = semMacroExpr(c, result, nOrig, callee)
of skTemplate: result = semTemplateExpr(c, result, callee)
else:
semFinishOperands(c, n)
activate(c, n)
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
if callee.magic != mNone:
result = magicsAfterOverloadResolution(c, result, flags)
result = evalAtCompileTime(c, result)
result = afterCallActions(c, result, nOrig, flags)
proc buildStringify(c: PContext, arg: PNode): PNode =
if arg.typ != nil and
@@ -928,30 +929,33 @@ proc builtinFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = n
markUsed(n, f)
proc dotTransformation(c: PContext, n: PNode): PNode =
if isSymChoice(n.sons[1]):
result = newNodeI(nkDotCall, n.info)
addSon(result, n.sons[1])
addSon(result, copyTree(n[0]))
else:
var i = considerAcc(n.sons[1])
var f = searchInScopes(c, i)
# if f != nil and f.kind == skStub: loadStub(f)
# ``loadStub`` is not correct here as we don't care for ``f`` really
if f != nil:
# BUGFIX: do not check for (f.kind in {skProc, skMethod, skIterator}) here
# This special node kind is to merge with the call handler in `semExpr`.
result = newNodeI(nkDotCall, n.info)
addSon(result, newIdentNode(i, n[1].info))
addSon(result, copyTree(n[0]))
else:
if not ContainsOrIncl(c.UnknownIdents, i.id):
LocalError(n.Info, errUndeclaredFieldX, i.s)
result = errorNode(c, n)
proc semFieldAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
# this is difficult, because the '.' is used in many different contexts
# in Nimrod. We first allow types in the semantic checking.
result = builtinFieldAccess(c, n, flags)
if result == nil:
if isSymChoice(n.sons[1]):
result = newNodeI(nkDotCall, n.info)
addSon(result, n.sons[1])
addSon(result, copyTree(n[0]))
else:
var i = considerAcc(n.sons[1])
var f = searchInScopes(c, i)
# if f != nil and f.kind == skStub: loadStub(f)
# ``loadStub`` is not correct here as we don't care for ``f`` really
if f != nil:
# BUGFIX: do not check for (f.kind in {skProc, skMethod, skIterator}) here
# This special node kind is to merge with the call handler in `semExpr`.
result = newNodeI(nkDotCall, n.info)
addSon(result, newIdentNode(i, n[1].info))
addSon(result, copyTree(n[0]))
else:
if not ContainsOrIncl(c.UnknownIdents, i.id):
LocalError(n.Info, errUndeclaredFieldX, i.s)
result = errorNode(c, n)
result = dotTransformation(c, n)
proc buildOverloadedSubscripts(n: PNode, ident: PIdent): PNode =
result = newNodeI(nkCall, n.info)
@@ -1030,14 +1034,12 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode =
let aOrig = nOrig[0]
result = newNode(nkCall, n.info, sons = @[setterId, a[0], semExpr(c, n[1])])
let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]])
result = semDirectCallAnalyseEffects(c, result, orig, {})
result = semOverloadedCallAnalyseEffects(c, result, orig, {})
if result != nil:
fixAbstractType(c, result)
analyseIfAddressTakenInCall(c, result)
else:
if not ContainsOrIncl(c.UnknownIdents, id.id):
LocalError(n.Info, errUndeclaredFieldX, id.s)
result = errorNode(c, n)
result = afterCallActions(c, result, nOrig, {})
#fixAbstractType(c, result)
#analyseIfAddressTakenInCall(c, result)
proc takeImplicitAddr(c: PContext, n: PNode): PNode =
case n.kind
@@ -1072,7 +1074,14 @@ proc semAsgn(c: PContext, n: PNode): PNode =
let nOrig = n.copyTree
a = builtinFieldAccess(c, a, {efLValue})
if a == nil:
return propertyWriteAccess(c, n, nOrig, n[0])
a = propertyWriteAccess(c, n, nOrig, n[0])
if a != nil: return a
# we try without the '='; proc that return 'var' or macros are still
# possible:
a = dotTransformation(c, n[0])
if a.kind == nkDotCall:
a.kind = nkCall
a = semExprWithType(c, a, {efLValue})
of nkBracketExpr:
# a[i] = x
# --> `[]=`(a, i, x)

View File

@@ -101,7 +101,7 @@ proc normalize*(s: string): string {.noSideEffect, procvar,
if j != s.len: setLen(result, j)
proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
rtl, extern: "nsuCmpIgnoreCase", procvar.} =
rtl, extern: "nsuCmpIgnoreCase", procvar, operator: 4.} =
## Compares two strings in a case insensitive manner. Returns:
##
## | 0 iff a == b
@@ -119,7 +119,7 @@ proc cmpIgnoreCase*(a, b: string): int {.noSideEffect,
# thus we compile without checks here
proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
rtl, extern: "nsuCmpIgnoreStyle", procvar.} =
rtl, extern: "nsuCmpIgnoreStyle", procvar, operator: 3.} =
## Compares two strings normalized (i.e. case and
## underscores do not matter). Returns:
##
@@ -141,7 +141,7 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
{.pop.}
proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
rtl, extern: "nsuStrip".} =
rtl, extern: "nsuStrip", operator: 5.} =
## Strips whitespace from `s` and returns the resulting string.
## If `leading` is true, leading whitespace is stripped.
## If `trailing` is true, trailing whitespace is stripped.
@@ -665,7 +665,7 @@ proc findAux(s, sub: string, start: int, a: TSkipTable): int =
return -1
proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
rtl, extern: "nsuFindStr".} =
rtl, extern: "nsuFindStr", operator: 6.} =
## Searches for `sub` in `s` starting at position `start`. Searching is
## case-sensitive. If `sub` is not in `s`, -1 is returned.
var a {.noinit.}: TSkipTable
@@ -723,7 +723,7 @@ proc contains*(s: string, chars: set[char]): bool {.noSideEffect.} =
return find(s, chars) >= 0
proc replace*(s, sub: string, by = ""): string {.noSideEffect,
rtl, extern: "nsuReplaceStr".} =
rtl, extern: "nsuReplaceStr", operator: 1.} =
## Replaces `sub` in `s` by the string `by`.
var a {.noinit.}: TSkipTable
result = ""
@@ -1023,7 +1023,7 @@ type
ffScientific ## use scientific notation (using ``e`` character)
proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
precision = 16): string {.noSideEffect,
precision = 16): string {.noSideEffect, operator: 2,
rtl, extern: "nsu$1".} =
## converts a floating point value `f` to a string.
##
@@ -1054,7 +1054,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
result = $buf
proc formatFloat*(f: float, format: TFloatFormat = ffDefault,
precision = 16): string {.noSideEffect,
precision = 16): string {.noSideEffect, operator: 2,
rtl, extern: "nsu$1".} =
## converts a floating point value `f` to a string.
##

View File

@@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@@ -42,3 +42,5 @@ else:
{.pragma: inl, inline.}
{.pragma: compilerRtl, compilerproc.}
when not defined(nimsuperops):
{.pragma: operator.}