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,16 +186,23 @@ 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:
result = semExprWithType(c, evaluated) when true:
#result = fitNode(c, e.typ, result) inlined with special case: if eOrig.typ.kind in {tyExpr, tyStmt, tyTypeDesc}:
let arg = result result = semExprWithType(c, evaluated)
result = indexTypesMatch(c, eOrig.typ, arg.typ, arg) else:
if result == nil: result = evaluated
result = arg semmacrosanity.annotateType(result, eOrig.typ)
# for 'tcnstseq' we support [] to become 'seq' else:
if eOrig.typ.skipTypes(abstractInst).kind == tySequence and result = semExprWithType(c, evaluated)
arg.typ.skipTypes(abstractInst).kind == tyArrayConstr: #result = fitNode(c, e.typ, result) inlined with special case:
arg.typ = eOrig.typ 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 = proc tryConstExpr(c: PContext, n: PNode): PNode =
var e = semExprWithType(c, n) var e = semExprWithType(c, n)

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,8 +321,11 @@ 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:
decodeB(nkStrLit) if regs[instr.regB].kind == nkNilLit:
regs[ra].strVal = regs[rb].strVal decodeB(nkNilLit)
else:
decodeB(nkStrLit)
regs[ra].strVal = regs[rb].strVal
of opcAsgnFloat: of opcAsgnFloat:
decodeB(nkFloatLit) decodeB(nkFloatLit)
regs[ra].floatVal = regs[rb].floatVal regs[ra].floatVal = regs[rb].floatVal
@ -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,8 +434,11 @@ 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)
assert regs[rb].kind in {nkStrLit..nkTripleStrLit} if regs[rb].kind == nkNilLit:
regs[ra].intVal = regs[rb].strVal.len - imm stackTrace(c, tos, pc, errNilAccess)
else:
assert regs[rb].kind in {nkStrLit..nkTripleStrLit}
regs[ra].intVal = regs[rb].strVal.len - imm
of opcIncl: of opcIncl:
decodeB(nkCurly) decodeB(nkCurly)
if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb])) 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 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

@ -47,39 +47,57 @@ div.tabContent.hide { display: none; }
function init() { function init() {
// Grab the tab links and content divs from the page // Grab the tab links and content divs from the page
var tabListItems = document.getElementById('tabs').childNodes; var tabListItems = document.getElementById('tabs').childNodes;
for ( var i = 0; i < tabListItems.length; i++ ) { for (var i = 0; i < tabListItems.length; i++) {
if ( tabListItems[i].nodeName == "LI" ) { if (tabListItems[i].nodeName == "LI") {
var tabLink = getFirstChildWithTagName( tabListItems[i], 'A' ); var tabLink = getFirstChildWithTagName(tabListItems[i], 'A');
var id = getHash( tabLink.getAttribute('href') ); var id = getHash(tabLink.getAttribute('href'));
tabLinks[id] = tabLink; tabLinks[id] = tabLink;
contentDivs[id] = document.getElementById( id ); contentDivs[id] = document.getElementById(id);
} }
} }
// Assign onclick events to the tab links, and // Assign onclick events to the tab links, and
// highlight the first tab // highlight the first tab
var i = 0; var i = 0;
for ( var id in tabLinks ) { for (var id in tabLinks) {
tabLinks[id].onclick = showTab; tabLinks[id].onclick = showTab;
tabLinks[id].onfocus = function() { this.blur() }; tabLinks[id].onfocus = function() { this.blur() };
if ( i == 0 ) tabLinks[id].className = 'selected'; if (i == 0) tabLinks[id].className = 'selected';
i++; i++;
} }
// Hide all content divs except the first // Hide all content divs except the first
var i = 0; var i = 0;
for ( var id in contentDivs ) { for (var id in contentDivs) {
if ( i != 0 ) contentDivs[id].className = 'tabContent hide'; if (i != 0) contentDivs[id].className = 'tabContent hide';
i++; i++;
} }
} }
function getFirstChildWithTagName( element, tagName ) { function showTab() {
for ( var i = 0; i < element.childNodes.length; i++ ) { var selectedId = getHash(this.getAttribute('href'));
if ( element.childNodes[i].nodeName == tagName ) return element.childNodes[i];
// 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) {
for (var i = 0; i < element.childNodes.length; i++) {
if (element.childNodes[i].nodeName == tagName) return element.childNodes[i];
} }
} }
function getHash( url ) { function getHash(url) {
var hashPos = url.lastIndexOf ( '#' ); var hashPos = url.lastIndexOf('#');
return url.substring( hashPos + 1 ); return url.substring(hashPos + 1);
} }
</script> </script>

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)