better html generator for the tester; fixes some VM bugs

This commit is contained in:
Araq 2014-01-17 01:18:57 +01:00
commit fc452787e7
10 changed files with 202 additions and 46 deletions

View file

@ -15,7 +15,7 @@ import
magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
semthreads, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, pretty
evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity
# implementation
@ -186,16 +186,23 @@ when false:
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
# recompute the types as 'eval' isn't guaranteed to construct types nor
# that the types are sound:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
let arg = result
result = indexTypesMatch(c, eOrig.typ, arg.typ, arg)
if result == nil:
result = arg
# for 'tcnstseq' we support [] to become 'seq'
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
arg.typ = eOrig.typ
when true:
if eOrig.typ.kind in {tyExpr, tyStmt, tyTypeDesc}:
result = semExprWithType(c, evaluated)
else:
result = evaluated
semmacrosanity.annotateType(result, eOrig.typ)
else:
result = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case:
let arg = result
result = indexTypesMatch(c, eOrig.typ, arg.typ, arg)
if result == nil:
result = arg
# for 'tcnstseq' we support [] to become 'seq'
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr:
arg.typ = eOrig.typ
proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n)

View file

@ -1068,7 +1068,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
else:
localError(n.info, errIndexTypesDoNotMatch)
result = n
else: nil
else: discard
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = semSubscript(c, n, flags)

View file

@ -0,0 +1,89 @@
#
#
# The Nimrod Compiler
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Implements type sanity checking for ASTs resulting from macros. Lots of
## room for improvement here.
import ast, astalgo, msgs, types
proc ithField(n: PNode, field: int): PSym =
result = nil
case n.kind
of nkRecList:
for i in countup(0, sonsLen(n) - 1):
result = ithField(n.sons[i], field-i)
if result != nil: return
of nkRecCase:
if n.sons[0].kind != nkSym: internalError(n.info, "ithField")
result = ithField(n.sons[0], field-1)
if result != nil: return
for i in countup(1, sonsLen(n) - 1):
case n.sons[i].kind
of nkOfBranch, nkElse:
result = ithField(lastSon(n.sons[i]), field-1)
if result != nil: return
else: internalError(n.info, "ithField(record case branch)")
of nkSym:
if field == 0: result = n.sym
else: discard
proc annotateType*(n: PNode, t: PType) =
let x = t.skipTypes(abstractInst)
# Note: x can be unequal to t and we need to be careful to use 't'
# to not to skip tyGenericInst
case n.kind
of nkPar:
if x.kind == tyObject:
n.typ = t
for i in 0 .. <n.len:
let field = x.n.ithField(i)
if field.isNil: globalError n.info, "invalid " & $i & "th field"
else: annotateType(n.sons[i], field.typ)
elif x.kind == tyTuple:
n.typ = t
for i in 0 .. <n.len:
if i >= x.len: globalError n.info, "invalid " & $i & "th field"
else: annotateType(n.sons[i], x.sons[i])
elif x.kind == tyProc and x.callConv == ccClosure:
n.typ = t
else:
globalError(n.info, "() must have an object or tuple type")
of nkBracket:
if x.kind in {tyArrayConstr, tyArray, tySequence, tyOpenarray}:
n.typ = t
for m in n: annotateType(m, x.elemType)
else:
globalError(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)
else:
globalError(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")
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")
of nkStrLit..nkTripleStrLit:
if x.kind in {tyString, tyCString}:
n.typ = t
else:
globalError(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")
else: discard

View file

@ -172,7 +172,9 @@ proc asgnComplex(x, y: PNode) =
else:
if x.kind notin {nkEmpty..nkNilLit}:
let y = y.copyValue
for i in countup(0, sonsLen(y) - 1): addSon(x, y.sons[i])
for i in countup(0, sonsLen(y) - 1):
if i < x.len: x.sons[i] = y.sons[i]
else: addSon(x, y.sons[i])
template getstr(a: expr): expr =
(if a.kind in {nkStrLit..nkTripleStrLit}: a.strVal else: $chr(int(a.intVal)))
@ -319,8 +321,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeB(nkIntLit)
regs[ra].intVal = regs[rb].intVal
of opcAsgnStr:
decodeB(nkStrLit)
regs[ra].strVal = regs[rb].strVal
if regs[instr.regB].kind == nkNilLit:
decodeB(nkNilLit)
else:
decodeB(nkStrLit)
regs[ra].strVal = regs[rb].strVal
of opcAsgnFloat:
decodeB(nkFloatLit)
regs[ra].floatVal = regs[rb].floatVal
@ -336,6 +341,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
# a = b[c]
let rb = instr.regB
let rc = instr.regC
if regs[rc].intVal > high(int):
stackTrace(c, tos, pc, errIndexOutOfBounds)
let idx = regs[rc].intVal.int
# XXX what if the array is not 0-based? -> codegen should insert a sub
assert regs[rb].kind != nkMetaNode
@ -373,7 +380,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
let rb = instr.regB
let rc = instr.regC
# XXX this creates a wrong alias
#Message(c.debug[pc], warnUser, $regs[rb].len & " " & $rc)
#Message(c.debug[pc], warnUser, $regs[rb].safeLen & " " & $rc)
asgnComplex(regs[ra], regs[rb].sons[rc])
of opcWrObj:
# a.b = c
@ -427,8 +434,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
regs[ra].intVal = regs[rb].skipMeta.len - imm
of opcLenStr:
decodeBImm(nkIntLit)
assert regs[rb].kind in {nkStrLit..nkTripleStrLit}
regs[ra].intVal = regs[rb].strVal.len - imm
if regs[rb].kind == nkNilLit:
stackTrace(c, tos, pc, errNilAccess)
else:
assert regs[rb].kind in {nkStrLit..nkTripleStrLit}
regs[ra].intVal = regs[rb].strVal.len - imm
of opcIncl:
decodeB(nkCurly)
if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb]))
@ -738,11 +748,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
inc pc
ensureKind(nkBracket)
let instr2 = c.code[pc]
let rb = instr2.regA
let count = regs[instr2.regA].intVal.int
regs[ra].typ = typ
newSeq(regs[ra].sons, rb)
for i in 0 .. <rb:
regs[ra].sons[i] = getNullValue(typ, regs[ra].info)
newSeq(regs[ra].sons, count)
for i in 0 .. <count:
regs[ra].sons[i] = getNullValue(typ.sons[0], regs[ra].info)
of opcNewStr:
decodeB(nkStrLit)
regs[ra].strVal = newString(regs[rb].intVal.int)
@ -1044,7 +1054,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
inc pc
proc fixType(result, n: PNode) {.inline.} =
# XXX do it deeply for complex values
# 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
proc execute(c: PCtx, start: int): PNode =

View file

@ -444,21 +444,43 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
c.freeTempRange(x, n.len)
clearDest(n, dest)
proc needsAsgnPatch(n: PNode): bool =
n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr}
proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
case le.kind
of nkBracketExpr:
let dest = c.genx(le.sons[0])
let idx = c.genx(le.sons[1])
c.gABC(le, opcWrArrRef, dest, idx, value)
of nkDotExpr, nkCheckedFieldExpr:
# XXX field checks here
let left = if le.kind == nkDotExpr: le else: le.sons[0]
let dest = c.genx(left.sons[0])
let idx = c.genx(left.sons[1])
c.gABC(left, opcWrObjRef, dest, idx, value)
else:
discard
proc genNew(c: PCtx; n: PNode) =
let dest = c.genx(n.sons[1])
let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
else: c.genx(n.sons[1])
# we use the ref's base type here as the VM conflates 'ref object'
# and 'object' since internally we already have a pointer.
c.gABx(n, opcNew, dest,
c.genType(n.sons[1].typ.skipTypes(abstractVar).sons[0]))
c.genAsgnPatch(n.sons[1], dest)
c.freeTemp(dest)
proc genNewSeq(c: PCtx; n: PNode) =
let dest = c.genx(n.sons[1])
let dest = if needsAsgnPatch(n.sons[1]): c.getTemp(n.sons[1].typ)
else: c.genx(n.sons[1])
c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(abstractVar)))
let tmp = c.genx(n.sons[2])
c.gABx(n, opcNewSeq, tmp, 0)
c.freeTemp(dest)
c.freeTemp(tmp)
c.genAsgnPatch(n.sons[1], dest)
c.freeTemp(dest)
proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
let tmp = c.genx(n.sons[1])
@ -1428,7 +1450,7 @@ proc genProc(c: PCtx; s: PSym): int =
c.gABC(body, opcEof, eofInstr.regA)
c.optimizeJumps(result)
s.offset = c.prc.maxSlots
#if s.name.s == "importImpl_forward" or s.name.s == "importImpl":
#if s.name.s == "rawGet":
# c.echoCode(result)
# echo renderTree(body)
c.prc = oldPrc