This commit is contained in:
Araq 2014-03-22 11:50:42 +01:00
commit 5f478e5aa1
4 changed files with 51 additions and 28 deletions

View file

@ -202,7 +202,7 @@ const
errXExpectsArrayType: "\'$1\' expects an array type", errXExpectsArrayType: "\'$1\' expects an array type",
errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet", errIteratorCannotBeInstantiated: "'$1' cannot be instantiated because its body has not been compiled yet",
errExprXAmbiguous: "expression '$1' ambiguous in this context", errExprXAmbiguous: "expression '$1' ambiguous in this context",
errConstantDivisionByZero: "constant division by zero", errConstantDivisionByZero: "division by zero",
errOrdinalTypeExpected: "ordinal type expected", errOrdinalTypeExpected: "ordinal type expected",
errOrdinalOrFloatTypeExpected: "ordinal or float type expected", errOrdinalOrFloatTypeExpected: "ordinal or float type expected",
errOverOrUnderflow: "over- or underflow", errOverOrUnderflow: "over- or underflow",

View file

@ -10,6 +10,8 @@
## This file implements the new evaluation engine for Nimrod code. ## This file implements the new evaluation engine for Nimrod code.
## An instruction is 1-3 int32s in memory, it is a register based VM. ## An instruction is 1-3 int32s in memory, it is a register based VM.
const debugEchoCode = false
import ast except getstr import ast except getstr
import import
@ -328,6 +330,7 @@ proc opConv*(dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType): bool =
proc compile(c: PCtx, s: PSym): int = proc compile(c: PCtx, s: PSym): int =
result = vmgen.genProc(c, s) result = vmgen.genProc(c, s)
when debugEchoCode: c.echoCode result
#c.echoCode #c.echoCode
proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg = proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
@ -381,18 +384,23 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcNodeToReg: of opcNodeToReg:
let ra = instr.regA let ra = instr.regA
let rb = instr.regB let rb = instr.regB
assert regs[rb].kind == rkNode # opcDeref might already have loaded it into a register. XXX Let's hope
let nb = regs[rb].node # this is still correct this way:
case nb.kind if regs[rb].kind != rkNode:
of nkCharLit..nkInt64Lit: regs[ra] = regs[rb]
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:
ensureKind(rkFloat)
regs[ra].floatVal = nb.floatVal
else: else:
ensureKind(rkNode) assert regs[rb].kind == rkNode
regs[ra].node = nb let nb = regs[rb].node
case nb.kind
of nkCharLit..nkInt64Lit:
ensureKind(rkInt)
regs[ra].intVal = nb.intVal
of nkFloatLit..nkFloat64Lit:
ensureKind(rkFloat)
regs[ra].floatVal = nb.floatVal
else:
ensureKind(rkNode)
regs[ra].node = nb
of opcLdArr: of opcLdArr:
# a = b[c] # a = b[c]
decodeBC(rkNode) decodeBC(rkNode)
@ -520,10 +528,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].intVal = regs[rb].intVal * regs[rc].intVal regs[ra].intVal = regs[rb].intVal * regs[rc].intVal
of opcDivInt: of opcDivInt:
decodeBC(rkInt) decodeBC(rkInt)
regs[ra].intVal = regs[rb].intVal div regs[rc].intVal if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
else: regs[ra].intVal = regs[rb].intVal div regs[rc].intVal
of opcModInt: of opcModInt:
decodeBC(rkInt) decodeBC(rkInt)
regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
else: regs[ra].intVal = regs[rb].intVal mod regs[rc].intVal
of opcAddFloat: of opcAddFloat:
decodeBC(rkFloat) decodeBC(rkFloat)
regs[ra].floatVal = regs[rb].floatVal + regs[rc].floatVal regs[ra].floatVal = regs[rb].floatVal + regs[rc].floatVal
@ -1174,12 +1184,6 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
regs[ra].node.strVal = typ.typeToString(preferExported) regs[ra].node.strVal = typ.typeToString(preferExported)
inc pc inc pc
proc fixType(result, n: PNode) {.inline.} =
# XXX do it deeply for complex values; there seems to be no simple
# solution except to check it deeply here.
#if result.typ.isNil: result.typ = n.typ
discard
proc execute(c: PCtx, start: int): PNode = proc execute(c: PCtx, start: int): PNode =
var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil) var tos = PStackFrame(prc: nil, comesFrom: 0, next: nil)
newSeq(tos.slots, c.prc.maxSlots) newSeq(tos.slots, c.prc.maxSlots)
@ -1198,8 +1202,6 @@ proc evalExpr*(c: PCtx, n: PNode): PNode =
let start = genExpr(c, n) let start = genExpr(c, n)
assert c.code[start].opcode != opcEof assert c.code[start].opcode != opcEof
result = execute(c, start) result = execute(c, start)
if not result.isNil:
fixType(result, n)
# for now we share the 'globals' environment. XXX Coming soon: An API for # for now we share the 'globals' environment. XXX Coming soon: An API for
# storing&loading the 'globals' environment to get what a component system # storing&loading the 'globals' environment to get what a component system
@ -1243,11 +1245,11 @@ proc evalConstExprAux(module, prc: PSym, n: PNode, mode: TEvalMode): PNode =
let start = genExpr(c, n, requiresValue = mode!=emStaticStmt) let start = genExpr(c, n, requiresValue = mode!=emStaticStmt)
if c.code[start].opcode == opcEof: return emptyNode if c.code[start].opcode == opcEof: return emptyNode
assert c.code[start].opcode != opcEof assert c.code[start].opcode != opcEof
when debugEchoCode: c.echoCode start
var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil) var tos = PStackFrame(prc: prc, comesFrom: 0, next: nil)
newSeq(tos.slots, c.prc.maxSlots) newSeq(tos.slots, c.prc.maxSlots)
#for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty) #for i in 0 .. <c.prc.maxSlots: tos.slots[i] = newNode(nkEmpty)
result = rawExecute(c, start, tos).regToNode result = rawExecute(c, start, tos).regToNode
fixType(result, n)
proc evalConstExpr*(module: PSym, e: PNode): PNode = proc evalConstExpr*(module: PSym, e: PNode): PNode =
result = evalConstExprAux(module, nil, e, emConst) result = evalConstExprAux(module, nil, e, emConst)
@ -1264,6 +1266,7 @@ proc setupCompileTimeVar*(module: PSym, n: PNode) =
proc setupMacroParam(x: PNode): PNode = proc setupMacroParam(x: PNode): PNode =
result = x result = x
if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1] if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
result = canonValue(result)
result.flags.incl nfIsRef result.flags.incl nfIsRef
result.typ = x.typ result.typ = x.typ

View file

@ -308,20 +308,20 @@ proc genAndOr(c: PCtx; n: PNode; opc: TOpcode; dest: var TDest) =
c.gen(n.sons[2], dest) c.gen(n.sons[2], dest)
c.patch(L1) c.patch(L1)
proc canonConst(n: PNode): PNode = proc canonValue*(n: PNode): PNode =
if n.kind == nkExprColonExpr: if n.kind == nkExprColonExpr:
result = n.sons[1] result = n.sons[1]
elif n.hasSubnodeWith(nkExprColonExpr): elif n.hasSubnodeWith(nkExprColonExpr):
result = n.copyNode result = n.copyNode
newSeq(result.sons, n.len) newSeq(result.sons, n.len)
for i in 0.. <n.len: for i in 0.. <n.len:
result.sons[i] = canonConst(n.sons[i]) result.sons[i] = canonValue(n.sons[i])
else: else:
result = n result = n
proc rawGenLiteral(c: PCtx; n: PNode): int = proc rawGenLiteral(c: PCtx; n: PNode): int =
result = c.constants.len result = c.constants.len
c.constants.add n.canonConst c.constants.add n.canonValue
internalAssert result < 0x7fff internalAssert result < 0x7fff
proc sameConstant*(a, b: PNode): bool = proc sameConstant*(a, b: PNode): bool =
@ -1227,7 +1227,7 @@ proc genVarSection(c: PCtx; n: PNode) =
if sfImportc in s.flags: c.importcSym(a.info, s) if sfImportc in s.flags: c.importcSym(a.info, s)
else: else:
let sa = if s.ast.isNil: getNullValue(s.typ, a.info) let sa = if s.ast.isNil: getNullValue(s.typ, a.info)
else: canonConst(s.ast) else: canonValue(s.ast)
c.globals.add(sa) c.globals.add(sa)
s.position = c.globals.len s.position = c.globals.len
if a.sons[2].kind == nkEmpty: if a.sons[2].kind == nkEmpty:

View file

@ -14,7 +14,8 @@ discard """
aa aa
bb bb
aa aa
bb''' bb
24'''
""" """
const s = @[1,2,3] const s = @[1,2,3]
@ -53,3 +54,22 @@ macro ff(d: static[TData]): stmt =
echo x echo x
ff(data) ff(data)
# bug #1010
proc `*==`(x: var int, y: int) {.inline, noSideEffect.} =
## Binary `*=` operator for ordinals
x = x * y
proc fac: int =
var x = 1;
for i in 1..4:
x *== i;
return x
const y = fac()
static:
echo y