diff options
-rw-r--r-- | compiler/semexprs.nim | 6 | ||||
-rw-r--r-- | compiler/semmagic.nim | 17 | ||||
-rw-r--r-- | compiler/vm.nim | 78 | ||||
-rw-r--r-- | compiler/vmdef.nim | 3 | ||||
-rw-r--r-- | compiler/vmgen.nim | 60 | ||||
-rw-r--r-- | tests/compile/tircbot.nim | 6 | ||||
-rw-r--r-- | todo.txt | 1 |
7 files changed, 114 insertions, 57 deletions
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 13bfddab7..4b263b3a3 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -300,11 +300,11 @@ proc semOf(c: PContext, n: PNode): PNode = result = n proc isOpImpl(c: PContext, n: PNode): PNode = - InternalAssert n.sonsLen == 3 and - n[1].kind == nkSym and n[1].sym.kind == skType and + internalAssert n.sonsLen == 3 and + n[1].typ != nil and n[2].kind in {nkStrLit..nkTripleStrLit, nkType} - let t1 = n[1].sym.typ.skipTypes({tyTypeDesc}) + let t1 = n[1].typ.skipTypes({tyTypeDesc}) if n[2].kind in {nkStrLit..nkTripleStrLit}: case n[2].strVal.normalize diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim index 44e106678..a5f763519 100644 --- a/compiler/semmagic.nim +++ b/compiler/semmagic.nim @@ -33,10 +33,8 @@ proc semInstantiationInfo(c: PContext, n: PNode): PNode = result.add(line) -proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode = - InternalAssert operand.kind == nkSym - - let typ = operand.sym.typ.skipTypes({tyTypeDesc}) +proc evalTypeTrait(trait: PNode, operand: PType, context: PSym): PNode = + let typ = operand.skipTypes({tyTypeDesc}) case trait.sym.name.s.normalize of "name": result = newStrNode(nkStrLit, typ.typeToString(preferName)) @@ -51,13 +49,10 @@ proc evalTypeTrait(trait, operand: PNode, context: PSym): PNode = proc semTypeTraits(c: PContext, n: PNode): PNode = checkMinSonsLen(n, 2) - internalAssert n.sons[1].kind == nkSym - let typArg = n.sons[1].sym - if typArg.kind == skType or - (typArg.kind == skParam and typArg.typ.sonsLen > 0): - # This is either a type known to sem or a typedesc - # param to a regular proc (again, known at instantiation) - result = evalTypeTrait(n[0], n[1], GetCurrOwner()) + let t = n.sons[1].typ + internalAssert t != nil + if not containsGenericType(t): + result = evalTypeTrait(n[0], t, GetCurrOwner()) else: # a typedesc variable, pass unmodified to evals result = n diff --git a/compiler/vm.nim b/compiler/vm.nim index 94ff8a4c7..984cc4bb8 100644 --- a/compiler/vm.nim +++ b/compiler/vm.nim @@ -52,9 +52,9 @@ proc stackTraceAux(c: PCtx; x: PStackFrame; pc: int) = proc stackTrace(c: PCtx, tos: PStackFrame, pc: int, msg: TMsgKind, arg = "") = - MsgWriteln("stack trace: (most recent call last)") + msgWriteln("stack trace: (most recent call last)") stackTraceAux(c, tos, pc) - LocalError(c.debug[pc], msg, arg) + localError(c.debug[pc], msg, arg) proc bailOut(c: PCtx; tos: PStackFrame) = stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX, @@ -63,9 +63,6 @@ proc bailOut(c: PCtx; tos: PStackFrame) = when not defined(nimComputedGoto): {.pragma: computedGoto.} -template inc(pc: ptr TInstr, diff = 1) = - inc cast[TAddress](pc), TInstr.sizeof * diff - proc myreset(n: PNode) = when defined(system.reset): var oldInfo = n.info @@ -299,6 +296,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = let instr = c.code[pc] let ra = instr.regA #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra + #message(c.debug[pc], warnUser, "gah") case instr.opcode of opcEof: return regs[ra] of opcRet: @@ -338,25 +336,38 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = # a = b[c] let rb = instr.regB let rc = instr.regC - let idx = regs[rc].intVal + 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 - asgnComplex(regs[ra], regs[rb].sons[idx.int]) + let src = regs[rb] + if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len: + asgnComplex(regs[ra], src.sons[idx]) + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcLdStrIdx: decodeBC(nkIntLit) - let idx = regs[rc].intVal - regs[ra].intVal = regs[rb].strVal[idx.int].ord + let idx = regs[rc].intVal.int + if idx <=% regs[rb].strVal.len: + regs[ra].intVal = regs[rb].strVal[idx].ord + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcWrArr: # a[b] = c let rb = instr.regB let rc = instr.regC - let idx = regs[rb].intVal - asgnComplex(regs[ra].sons[idx.int], regs[rc]) + let idx = regs[rb].intVal.int + if idx <% regs[ra].len: + asgnComplex(regs[ra].sons[idx], regs[rc]) + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcWrArrRef: let rb = instr.regB let rc = instr.regC - let idx = regs[rb].intVal - asgnRef(regs[ra].sons[idx.int], regs[rc]) + let idx = regs[rb].intVal.int + if idx <% regs[ra].len: + asgnRef(regs[ra].sons[idx], regs[rc]) + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcLdObj: # a = b.c let rb = instr.regB @@ -381,7 +392,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = of opcWrStrIdx: decodeBC(nkStrLit) let idx = regs[rb].intVal.int - regs[ra].strVal[idx] = chr(regs[rc].intVal) + if idx <% regs[ra].strVal.len: + regs[ra].strVal[idx] = chr(regs[rc].intVal) + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcAddr: decodeB(nkRefTy) if regs[ra].len == 0: regs[ra].add regs[rb] @@ -631,7 +645,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = #echo "new pc ", newPc, " calling: ", prc.name.s var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos) newSeq(newFrame.slots, prc.offset) - if not isEmptyType(prc.typ.sons[0]): + if not isEmptyType(prc.typ.sons[0]) or prc.kind == skMacro: newFrame.slots[0] = getNullValue(prc.typ.sons[0], prc.info) # pass every parameter by var (the language definition allows this): for i in 1 .. rc-1: @@ -769,7 +783,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = regs[ra].strVal.setLen(regs[rb].getOrdValue.int) of opcOf: decodeBC(nkIntLit) - regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, regs[rc].typ) >= 0) + let typ = c.types[regs[rc].intVal.int] + regs[ra].intVal = ord(inheritanceDiff(regs[rb].typ, typ) >= 0) + of opcIs: + decodeBC(nkIntLit) + let t1 = regs[rb].typ.skipTypes({tyTypeDesc}) + let t2 = c.types[regs[rc].intVal.int] + let match = if t2.kind == tyTypeClass: matchTypeClass(t2, t1) + else: sameType(t1, t2) + regs[ra].intVal = ord(match) of opcSetLenSeq: decodeB(nkBracket) let newLen = regs[rb].getOrdValue.int @@ -787,10 +809,20 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = decodeBC(nkMetaNode) if regs[rb].kind != nkMetaNode: internalError(c.debug[pc], "no MetaNode") - setMeta(regs[ra], regs[rb].uast.sons[regs[rc].intVal.int]) + let idx = regs[rc].intVal.int + let src = regs[rb].uast + if src.kind notin {nkEmpty..nkNilLit} and idx <% src.len: + setMeta(regs[ra], src.sons[idx]) + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcNSetChild: decodeBC(nkMetaNode) - regs[ra].uast.sons[regs[rb].intVal.int] = regs[rc].uast + let idx = regs[rb].intVal.int + var dest = regs[ra].uast + if dest.kind notin {nkEmpty..nkNilLit} and idx <% dest.len: + dest.sons[idx] = regs[rc].uast + else: + stackTrace(c, tos, pc, errIndexOutOfBounds) of opcNAdd: decodeBC(nkMetaNode) var u = regs[rb].uast @@ -986,6 +1018,15 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode = decodeB(nkStrLit) let typ = regs[rb].sym.typ.skipTypes({tyTypeDesc}) regs[ra].strVal = typ.typeToString(preferExported) + of opcGlobalOnce: + let rb = instr.regBx + if c.globals.sons[rb - wordExcess - 1].kind != nkEmpty: + # skip initialization instructions: + while true: + inc pc + if c.code[pc].opcode in {opcWrGlobal, opcWrGlobalRef} and + c.code[pc].regBx == rb: + break inc pc proc fixType(result, n: PNode) {.inline.} = @@ -1073,6 +1114,7 @@ proc setupMacroParam(x: PNode): PNode = y.flags.incl nfIsRef result = newNode(nkMetaNode) result.add y + result.typ = x.typ var evalMacroCounter: int diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 290dfd38c..e31dc9de6 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -60,7 +60,7 @@ type opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet, opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr, opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq, - opcSwap, opcIsNil, opcOf, + opcSwap, opcIsNil, opcOf, opcIs, opcSubStr, opcConv, opcCast, opcQuit, opcReset, opcAddStrCh, @@ -122,6 +122,7 @@ type opcLdImmInt, # dest = immediate value opcWrGlobal, opcWrGlobalRef, + opcGlobalOnce, # used to introduce an assignment to a global once opcSetType, # dest.typ = types[Bx] opcTypeTrait diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index 62b9e7d1e..6f07a2dfe 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -301,7 +301,8 @@ proc sameConstant*(a, b: PNode): bool = of nkCharLit..nkInt64Lit: result = a.intVal == b.intVal of nkFloatLit..nkFloat64Lit: result = a.floatVal == b.floatVal of nkStrLit..nkTripleStrLit: result = a.strVal == b.strVal - of nkEmpty, nkNilLit, nkType: result = true + of nkType: result = a.typ == b.typ + of nkEmpty, nkNilLit: result = true else: if sonsLen(a) == sonsLen(b): for i in countup(0, sonsLen(a) - 1): @@ -674,12 +675,16 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = unused(n, dest) var d = c.genx(n.sons[1]) c.gABC(n, opcReset, d) - of mOf: + of mOf, mIs: if dest < 0: dest = c.getTemp(n.typ) var tmp = c.genx(n.sons[1]) - c.gABC(n, opcOf, dest, tmp) - c.gABx(n, opcOf, 0, c.genType(n.sons[2].typ.skipTypes(abstractPtrs))) + var idx = c.getTemp(getSysType(tyInt)) + var typ = n.sons[2].typ + if m == mOf: typ = typ.skipTypes(abstractPtrs) + c.gABx(n, opcLdImmInt, idx, c.genType(typ)) + c.gABC(n, if m == mOf: opcOf else: opcIs, dest, tmp, idx) c.freeTemp(tmp) + c.freeTemp(idx) of mSizeOf: GlobalError(n.info, errCannotInterpretNodeX, renderTree(n)) of mHigh: @@ -717,8 +722,6 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) = c.gABx(n, opcSetType, tmp, c.genType(n.sons[1].typ)) c.gABC(n, opcTypeTrait, dest, tmp) c.freeTemp(tmp) - of mIs: - InternalError(n.info, "cannot generate code for: " & $m) of mSlurp: genUnaryABC(c, n, dest, opcSlurp) of mStaticExec: genBinaryABC(c, n, dest, opcGorge) of mNLen: genUnaryABI(c, n, dest, opcLenSeq) @@ -905,6 +908,11 @@ proc genLit(c: PCtx; n: PNode; dest: var TDest) = let lit = genLiteral(c, n) c.gABx(n, opc, dest, lit) +proc genTypeLit(c: PCtx; t: PType; dest: var TDest) = + var n = newNode(nkType) + n.typ = t + genLit(c, n, dest) + proc importcSym(c: PCtx; info: TLineInfo; s: PSym) = when hasFFI: if allowFFI in c.features: @@ -920,6 +928,17 @@ proc cannotEval(n: PNode) {.noinline.} = globalError(n.info, errGenerated, "cannot evaluate at compile time: " & n.renderTree) +proc genGlobalInit(c: PCtx; n: PNode; s: PSym) = + c.globals.add(emptyNode) + s.position = c.globals.len + # This is rather hard to support, due to the laziness of the VM code + # generator. See tests/compile/tmacro2 for why this is necesary: + # var decls{.compileTime.}: seq[PNimrodNode] = @[] + c.gABx(n, opcGlobalOnce, 0, s.position) + let tmp = c.genx(s.ast) + c.gABx(n, whichAsgnOpc(n, opcWrGlobal), tmp, s.position) + c.freeTemp(tmp) + proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = let s = n.sym if s.isGlobal: @@ -930,10 +949,7 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) = if dest < 0: dest = c.getTemp(s.typ) if s.position == 0: if sfImportc in s.flags: c.importcSym(n.info, s) - else: - c.globals.add(s.ast) - s.position = c.globals.len - # XXX var g = codeHere() ? + else: genGlobalInit(c, n, s) c.gABx(n, opcLdGlobal, dest, s.position) else: if s.position > 0 or (s.position == 0 and s.kind in {skParam, skResult}): @@ -1052,6 +1068,7 @@ proc genVarSection(c: PCtx; n: PNode) = let sa = if s.ast.isNil: getNullValue(s.typ, a.info) else: s.ast c.globals.add(sa) s.position = c.globals.len + # "Once support" is unnecessary here if a.sons[2].kind == nkEmpty: when false: withTemp(tmp, s.typ): @@ -1079,15 +1096,16 @@ proc genVarSection(c: PCtx; n: PNode) = proc genArrayConstr(c: PCtx, n: PNode, dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) c.gABx(n, opcLdNull, dest, c.genType(n.typ)) - let intType = getSysType(tyInt) - var tmp = getTemp(c, intType) - c.gABx(n, opcLdNull, tmp, c.genType(intType)) - for x in n: - let a = c.genx(x) - c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a) - c.gABI(n, opcAddImmInt, tmp, tmp, 1) - c.freeTemp(a) - c.freeTemp(tmp) + if n.len > 0: + let intType = getSysType(tyInt) + var tmp = getTemp(c, intType) + c.gABx(n, opcLdNull, tmp, c.genType(intType)) + for x in n: + let a = c.genx(x) + c.gABC(n, whichAsgnOpc(x, opcWrArr), dest, tmp, a) + c.gABI(n, opcAddImmInt, tmp, tmp, 1) + c.freeTemp(a) + c.freeTemp(tmp) proc genSetConstr(c: PCtx, n: PNode, dest: var TDest) = if dest < 0: dest = c.getTemp(n.typ) @@ -1167,6 +1185,8 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) = InternalError(n.info, "too large offset! cannot generate code for: " & s.name.s) dest = s.position + of skType: + genTypeLit(c, s.typ, dest) else: InternalError(n.info, "cannot generate code for: " & s.name.s) of nkCallKinds: @@ -1371,7 +1391,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 == "treeRepr" or s.name.s == "traverse": + #if s.name.s == "importImpl_forward" or s.name.s == "importImpl": # c.echoCode(result) # echo renderTree(body) c.prc = oldPrc diff --git a/tests/compile/tircbot.nim b/tests/compile/tircbot.nim index d16c99b69..6008838ff 100644 --- a/tests/compile/tircbot.nim +++ b/tests/compile/tircbot.nim @@ -257,7 +257,7 @@ proc limitCommitMsg(m: string): string = proc handleWebMessage(state: PState, line: string) = echo("Got message from hub: " & line) var json = parseJson(line) - if json.existsKey("payload"): + if json.hasKey("payload"): for i in 0..min(4, json["payload"]["commits"].len-1): var commit = json["payload"]["commits"][i] # Create the message @@ -273,8 +273,8 @@ proc handleWebMessage(state: PState, line: string) = # Send message to #nimrod. state.ircClient.privmsg(joinChans[0], message) - elif json.existsKey("redisinfo"): - assert json["redisinfo"].existsKey("port") + elif json.hasKey("redisinfo"): + assert json["redisinfo"].hasKey("port") #let redisPort = json["redisinfo"]["port"].num state.dbConnected = true diff --git a/todo.txt b/todo.txt index 91df38a14..4c999226f 100644 --- a/todo.txt +++ b/todo.txt @@ -20,7 +20,6 @@ Bugs - bug: 'type T = ref T' not recognized as illegal recursion - bug: type conversions concerning proc types are weird - compilation of niminst takes way too long. looks like a regression -- simple closure iterator doesn't work - docgen: sometimes effects are listed twice - 'result' is not properly cleaned for NRVO --> use uninit checking instead - sneaking with qualifiedLookup() is really broken! |