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, magicsys, parser, nversion, nimsets, semfold, importer,
procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch, procfind, lookups, rodread, pragmas, passes, semdata, semtypinst, sigmatch,
semthreads, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting, semthreads, intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
evaltempl, patterns, parampatterns, sempass2, pretty evaltempl, patterns, parampatterns, sempass2, pretty, semmacrosanity
# implementation # implementation
@ -186,6 +186,13 @@ when false:
proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode = proc fixupTypeAfterEval(c: PContext, evaluated, eOrig: PNode): PNode =
# recompute the types as 'eval' isn't guaranteed to construct types nor # recompute the types as 'eval' isn't guaranteed to construct types nor
# that the types are sound: # that the types are sound:
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 = semExprWithType(c, evaluated)
#result = fitNode(c, e.typ, result) inlined with special case: #result = fitNode(c, e.typ, result) inlined with special case:
let arg = result let arg = result

View file

@ -1068,7 +1068,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
else: else:
localError(n.info, errIndexTypesDoNotMatch) localError(n.info, errIndexTypesDoNotMatch)
result = n result = n
else: nil else: discard
proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode = proc semArrayAccess(c: PContext, n: PNode, flags: TExprFlags): PNode =
result = semSubscript(c, n, flags) 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: else:
if x.kind notin {nkEmpty..nkNilLit}: if x.kind notin {nkEmpty..nkNilLit}:
let y = y.copyValue 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 = template getstr(a: expr): expr =
(if a.kind in {nkStrLit..nkTripleStrLit}: a.strVal else: $chr(int(a.intVal))) (if a.kind in {nkStrLit..nkTripleStrLit}: a.strVal else: $chr(int(a.intVal)))
@ -319,6 +321,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
decodeB(nkIntLit) decodeB(nkIntLit)
regs[ra].intVal = regs[rb].intVal regs[ra].intVal = regs[rb].intVal
of opcAsgnStr: of opcAsgnStr:
if regs[instr.regB].kind == nkNilLit:
decodeB(nkNilLit)
else:
decodeB(nkStrLit) decodeB(nkStrLit)
regs[ra].strVal = regs[rb].strVal regs[ra].strVal = regs[rb].strVal
of opcAsgnFloat: of opcAsgnFloat:
@ -336,6 +341,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
# a = b[c] # a = b[c]
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
if regs[rc].intVal > high(int):
stackTrace(c, tos, pc, errIndexOutOfBounds)
let idx = regs[rc].intVal.int let idx = regs[rc].intVal.int
# XXX what if the array is not 0-based? -> codegen should insert a sub # XXX what if the array is not 0-based? -> codegen should insert a sub
assert regs[rb].kind != nkMetaNode assert regs[rb].kind != nkMetaNode
@ -373,7 +380,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
let rb = instr.regB let rb = instr.regB
let rc = instr.regC let rc = instr.regC
# XXX this creates a wrong alias # 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]) asgnComplex(regs[ra], regs[rb].sons[rc])
of opcWrObj: of opcWrObj:
# a.b = c # a.b = c
@ -427,6 +434,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
regs[ra].intVal = regs[rb].skipMeta.len - imm regs[ra].intVal = regs[rb].skipMeta.len - imm
of opcLenStr: of opcLenStr:
decodeBImm(nkIntLit) decodeBImm(nkIntLit)
if regs[rb].kind == nkNilLit:
stackTrace(c, tos, pc, errNilAccess)
else:
assert regs[rb].kind in {nkStrLit..nkTripleStrLit} assert regs[rb].kind in {nkStrLit..nkTripleStrLit}
regs[ra].intVal = regs[rb].strVal.len - imm regs[ra].intVal = regs[rb].strVal.len - imm
of opcIncl: of opcIncl:
@ -738,11 +748,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
inc pc inc pc
ensureKind(nkBracket) ensureKind(nkBracket)
let instr2 = c.code[pc] let instr2 = c.code[pc]
let rb = instr2.regA let count = regs[instr2.regA].intVal.int
regs[ra].typ = typ regs[ra].typ = typ
newSeq(regs[ra].sons, rb) newSeq(regs[ra].sons, count)
for i in 0 .. <rb: for i in 0 .. <count:
regs[ra].sons[i] = getNullValue(typ, regs[ra].info) regs[ra].sons[i] = getNullValue(typ.sons[0], regs[ra].info)
of opcNewStr: of opcNewStr:
decodeB(nkStrLit) decodeB(nkStrLit)
regs[ra].strVal = newString(regs[rb].intVal.int) regs[ra].strVal = newString(regs[rb].intVal.int)
@ -1044,7 +1054,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
inc pc inc pc
proc fixType(result, n: PNode) {.inline.} = 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 #if result.typ.isNil: result.typ = n.typ
proc execute(c: PCtx, start: int): PNode = 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) c.freeTempRange(x, n.len)
clearDest(n, dest) 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) = 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' # we use the ref's base type here as the VM conflates 'ref object'
# and 'object' since internally we already have a pointer. # and 'object' since internally we already have a pointer.
c.gABx(n, opcNew, dest, c.gABx(n, opcNew, dest,
c.genType(n.sons[1].typ.skipTypes(abstractVar).sons[0])) c.genType(n.sons[1].typ.skipTypes(abstractVar).sons[0]))
c.genAsgnPatch(n.sons[1], dest)
c.freeTemp(dest) c.freeTemp(dest)
proc genNewSeq(c: PCtx; n: PNode) = 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))) c.gABx(n, opcNewSeq, dest, c.genType(n.sons[1].typ.skipTypes(abstractVar)))
let tmp = c.genx(n.sons[2]) let tmp = c.genx(n.sons[2])
c.gABx(n, opcNewSeq, tmp, 0) c.gABx(n, opcNewSeq, tmp, 0)
c.freeTemp(dest)
c.freeTemp(tmp) c.freeTemp(tmp)
c.genAsgnPatch(n.sons[1], dest)
c.freeTemp(dest)
proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) = proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
let tmp = c.genx(n.sons[1]) 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.gABC(body, opcEof, eofInstr.regA)
c.optimizeJumps(result) c.optimizeJumps(result)
s.offset = c.prc.maxSlots s.offset = c.prc.maxSlots
#if s.name.s == "importImpl_forward" or s.name.s == "importImpl": #if s.name.s == "rawGet":
# c.echoCode(result) # c.echoCode(result)
# echo renderTree(body) # echo renderTree(body)
c.prc = oldPrc c.prc = oldPrc

View file

@ -153,7 +153,7 @@ proc add*[A, B](t: var TTable[A, B], key: A, val: B) =
proc del*[A, B](t: var TTable[A, B], key: A) = proc del*[A, B](t: var TTable[A, B], key: A) =
## deletes `key` from hash table `t`. ## deletes `key` from hash table `t`.
var index = rawGet(t, key) let index = rawGet(t, key)
if index >= 0: if index >= 0:
t.data[index].slot = seDeleted t.data[index].slot = seDeleted
dec(t.counter) dec(t.counter)

View file

@ -77,7 +77,8 @@ proc getMachine*: MachineId =
name, system.hostOS, system.hostCPU).MachineId name, system.hostOS, system.hostCPU).MachineId
proc getCommit: CommitId = proc getCommit: CommitId =
let hash = "git log -n 1"() const commLen = "commit ".len
let hash = "git log -n 1"()[commLen..commLen+10]
let branch = "git symbolic-ref --short HEAD"() let branch = "git symbolic-ref --short HEAD"()
if hash.len == 0 or branch.len == 0: quit "cannot determine git HEAD" if hash.len == 0 or branch.len == 0: quit "cannot determine git HEAD"

View file

@ -221,6 +221,14 @@ proc testStdlib(r: var TResults, pattern, options: string, cat: Category) =
const AdditionalCategories = ["debugger", "tools", "examples", "stdlib"] const AdditionalCategories = ["debugger", "tools", "examples", "stdlib"]
proc `&.?`(a, b: string): string =
# candidate for the stdlib?
result = if b.startswith(a): b else: a & b
proc `&?.`(a, b: string): string =
# candidate for the stdlib?
result = if a.endswith(b): a else: a & b
proc processCategory(r: var TResults, cat: Category, options: string) = proc processCategory(r: var TResults, cat: Category, options: string) =
case cat.string.normalize case cat.string.normalize
of "rodfiles": of "rodfiles":
@ -252,5 +260,5 @@ proc processCategory(r: var TResults, cat: Category, options: string) =
compileExample(r, "examples/gtk/*.nim", options, cat) compileExample(r, "examples/gtk/*.nim", options, cat)
compileExample(r, "examples/talk/*.nim", options, cat) compileExample(r, "examples/talk/*.nim", options, cat)
else: else:
for name in os.walkFiles(cat.string / "t*.nim"): for name in os.walkFiles("tests" & DirSep &.? cat.string / "t*.nim"):
testSpec r, makeTest(name, options, cat) testSpec r, makeTest(name, options, cat)

View file

@ -72,6 +72,24 @@ div.tabContent.hide { display: none; }
} }
} }
function showTab() {
var selectedId = getHash(this.getAttribute('href'));
// Highlight the selected tab, and dim all others.
// Also show the selected content div, and hide all others.
for (var id in contentDivs) {
if (id == selectedId) {
tabLinks[id].className = 'selected';
contentDivs[id].className = 'tabContent';
} else {
tabLinks[id].className = '';
contentDivs[id].className = 'tabContent hide';
}
}
// Stop the browser following the link
return false;
}
function getFirstChildWithTagName(element, tagName) { function getFirstChildWithTagName(element, tagName) {
for (var i = 0; i < element.childNodes.length; i++) { for (var i = 0; i < element.childNodes.length; i++) {
if (element.childNodes[i].nodeName == tagName) return element.childNodes[i]; if (element.childNodes[i].nodeName == tagName) return element.childNodes[i];

View file

@ -245,7 +245,7 @@ proc main() =
case action case action
of "all": of "all":
for kind, dir in walkDir("tests"): for kind, dir in walkDir("tests"):
if kind == pcDir and dir != "testament": if kind == pcDir and dir notin ["testament", "testdata", "nimcache"]:
processCategory(r, Category(dir), p.cmdLineRest.string) processCategory(r, Category(dir), p.cmdLineRest.string)
for a in AdditionalCategories: for a in AdditionalCategories:
processCategory(r, Category(a), p.cmdLineRest.string) processCategory(r, Category(a), p.cmdLineRest.string)