summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/msgs.nim4
-rw-r--r--compiler/rodread.nim2
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semexprs.nim4
-rw-r--r--compiler/semstmts.nim9
-rw-r--r--compiler/vm.nim50
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmgen.nim59
-rw-r--r--tests/macros/tmacro5.nim2
-rw-r--r--todo.txt2
10 files changed, 98 insertions, 39 deletions
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 268205361..ae673bd0e 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -67,7 +67,7 @@ type
     errAmbiguousCallXYZ, errWrongNumberOfArguments, 
     errXCannotBePassedToProcVar, 
     errXCannotBeInParamDecl, errPragmaOnlyInHeaderOfProc, errImplOfXNotAllowed, 
-    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValue, 
+    errImplOfXexpected, errNoSymbolToBorrowFromFound, errDiscardValueX, 
     errInvalidDiscard, errIllegalConvFromXtoY, errCannotBindXTwice, 
     errInvalidOrderInArrayConstructor,
     errInvalidOrderInEnumX, errEnumXHasHoles, errExceptExpected, errInvalidTry, 
@@ -264,7 +264,7 @@ const
     errImplOfXNotAllowed: "implementation of \'$1\' is not allowed", 
     errImplOfXexpected: "implementation of \'$1\' expected", 
     errNoSymbolToBorrowFromFound: "no symbol to borrow from found", 
-    errDiscardValue: "value returned by statement has to be discarded", 
+    errDiscardValueX: "value of type '$1' has to be discarded", 
     errInvalidDiscard: "statement returns no value that can be discarded", 
     errIllegalConvFromXtoY: "conversion from $1 to $2 is invalid",
     errCannotBindXTwice: "cannot bind parameter \'$1\' twice", 
diff --git a/compiler/rodread.nim b/compiler/rodread.nim
index b53135a95..036e6cc3c 100644
--- a/compiler/rodread.nim
+++ b/compiler/rodread.nim
@@ -890,7 +890,7 @@ proc loadStub*(s: PSym) =
   
   # deactivate the GC here because we do a deep recursion and generate no
   # garbage when restoring parts of the object graph anyway.
-  # Since we die with internal errors if this fails, so no try-finally is
+  # Since we die with internal errors if this fails, no try-finally is
   # necessary.
   GC_disable()
   rawLoadStub(s)
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 09b2511f1..5ee46654e 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -220,7 +220,7 @@ proc tryConstExpr(c: PContext, n: PNode): PNode =
       return nil
 
     result = fixupTypeAfterEval(c, result, e)
-  except:
+  except ERecoverableError:
     return nil
 
 proc semConstExpr(c: PContext, n: PNode): PNode =
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index c271911ab..538489490 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -641,9 +641,11 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
       result = evalStaticExpr(c.module, call, c.p.owner)
       if result.isNil: 
         localError(n.info, errCannotInterpretNodeX, renderTree(call))
+      else: result = fixupTypeAfterEval(c, result, n)
     else:
       result = evalConstExpr(c.module, call)
       if result.isNil: result = n
+      else: result = fixupTypeAfterEval(c, result, n)
     #if result != n:
     #  echo "SUCCESS evaluated at compile time: ", call.renderTree
 
@@ -653,6 +655,8 @@ proc semStaticExpr(c: PContext, n: PNode): PNode =
   if result.isNil:
     localError(n.info, errCannotInterpretNodeX, renderTree(n))
     result = emptyNode
+  else:
+    result = fixupTypeAfterEval(c, result, a)
 
 proc semOverloadedCallAnalyseEffects(c: PContext, n: PNode, nOrig: PNode,
                                      flags: TExprFlags): PNode =
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index 503ea4bc1..1a2f9a6a6 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -126,7 +126,7 @@ proc implicitlyDiscardable(n: PNode): bool =
 proc fixNilType(n: PNode) =
   if isAtom(n):
     if n.kind != nkNilLit and n.typ != nil:
-      localError(n.info, errDiscardValue)
+      localError(n.info, errDiscardValueX, n.typ.typeToString)
   elif n.kind in {nkStmtList, nkStmtListExpr}:
     n.kind = nkStmtList
     for it in n: fixNilType(it)
@@ -154,7 +154,7 @@ proc discardCheck(c: PContext, result: PNode) =
       else:
         var n = result
         while n.kind in skipForDiscardable: n = n.lastSon
-        localError(n.info, errDiscardValue)
+        localError(n.info, errDiscardValueX, result.typ.typeToString)
 
 proc semIf(c: PContext, n: PNode): PNode = 
   result = n
@@ -331,6 +331,7 @@ proc checkNilable(v: PSym) =
 proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode = 
   var b: PNode
   result = copyNode(n)
+  var hasCompileTime = false
   for i in countup(0, sonsLen(n)-1): 
     var a = n.sons[i]
     if gCmd == cmdIdeTools: suggestStmt(c, a)
@@ -405,7 +406,9 @@ proc semVarOrLet(c: PContext, n: PNode, symkind: TSymKind): PNode =
         v.typ = tup.sons[j]
         b.sons[j] = newSymNode(v)
       checkNilable(v)
-    
+      if sfCompileTime in v.flags: hasCompileTime = true
+  if hasCompileTime: vm.setupCompileTimeVar(c.module, result)
+
 proc semConst(c: PContext, n: PNode): PNode = 
   result = copyNode(n)
   for i in countup(0, sonsLen(n) - 1): 
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 820a2022c..6277b2dc6 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -109,11 +109,17 @@ template decodeBx(k: expr) {.immediate, dirty.} =
 template move(a, b: expr) {.immediate, dirty.} = system.shallowCopy(a, b)
 # XXX fix minor 'shallowCopy' overloading bug in compiler
 
-template createStr(x) =
-  if x.node.isNil: x.node = newNode(nkStrLit)
+template createStrKeepNode(x) =
+  if x.node.isNil:
+    x.node = newNode(nkStrLit)
   elif x.node.kind == nkNilLit:
     system.reset(x.node[])
     x.node.kind = nkStrLit
+  else:
+    assert x.node.kind in {nkStrLit..nkTripleStrLit}
+
+template createStr(x) =
+  x.node = newNode(nkStrLit)
 
 proc moveConst(x: var TRegister, y: TRegister) =
   if x.kind != y.kind:
@@ -254,7 +260,7 @@ proc opConv*(dest: var TRegister, src: TRegister, desttyp, srctyp: PType): bool
     if dest.kind != rkNode:
       myreset(dest)
       dest.kind = rkNode
-      dest.node = newNode(nkStrLit)
+    dest.node = newNode(nkStrLit)
     let styp = srctyp.skipTypes(abstractRange)
     case styp.kind
     of tyEnum:
@@ -329,8 +335,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
     #{.computedGoto.}
     let instr = c.code[pc]
     let ra = instr.regA
-    #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
-    #message(c.debug[pc], warnUser, "gah")
+    #if c.traceActive:
+    #  echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
+    #  message(c.debug[pc], warnUser, "Trace")
     case instr.opcode
     of opcEof: return regs[ra]
     of opcRet:
@@ -354,7 +361,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
       regs[ra].intVal = regs[rb].intVal
     of opcAsgnStr:
       decodeB(rkNode)
-      createStr regs[ra]
+      createStrKeepNode regs[ra]
       regs[ra].node.strVal = regs[rb].node.strVal
     of opcAsgnFloat:
       decodeB(rkFloat)
@@ -454,7 +461,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
     of opcWrDeref:
       # a[] = b
       decodeBC(rkNode)
-      putIntoNode(regs[ra].node, regs[rc])
+      putIntoNode(regs[ra].node, regs[rb])
     of opcAddInt:
       decodeBC(rkInt)
       regs[ra].intVal = regs[rb].intVal + regs[rc].intVal
@@ -484,8 +491,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
     of opcInclRange:
       decodeBC(rkNode)
       var r = newNode(nkRange)
-      r.add regs[rb].node
-      r.add regs[rc].node
+      r.add regs[rb].regToNode
+      r.add regs[rc].regToNode
       addSon(regs[ra].node, r.copyTree)
     of opcExcl:
       decodeB(rkNode)
@@ -643,15 +650,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
         regs[ra].node.strVal.add getstr(regs[i])
     of opcAddStrCh:
       decodeB(rkNode)
-      createStr regs[ra]
+      createStrKeepNode regs[ra]
       regs[ra].node.strVal.add(regs[rb].intVal.chr)
     of opcAddStrStr:
       decodeB(rkNode)
-      createStr regs[ra]
+      createStrKeepNode regs[ra]
       regs[ra].node.strVal.add(regs[rb].node.strVal)
     of opcAddSeqElem:
       decodeB(rkNode)
-      regs[ra].node.add(copyTree(regs[rb].node))
+      if regs[ra].node.kind == nkBracket:
+        regs[ra].node.add(copyTree(regs[rb].regToNode))
+      else:
+        stackTrace(c, tos, pc, errNilAccess)
     of opcEcho:
       let rb = instr.regB
       for i in ra..ra+rb-1:
@@ -660,7 +670,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
       writeln(stdout, "")
     of opcContainsSet:
       decodeBC(rkInt)
-      regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].node))
+      regs[ra].intVal = ord(inSet(regs[rb].node, regs[rc].regToNode))
     of opcSubStr:
       decodeBC(rkNode)
       inc pc
@@ -815,8 +825,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
       ensureKind(rkNode)
       let typ = c.types[instr.regBx - wordExcess]
       regs[ra].node = getNullValue(typ, c.debug[pc])
-      if regs[ra].node.kind in {nkStrLit..nkTripleStrLit}:
-        regs[ra].kind = rkNode
+      # opcLdNull really is the gist of the VM's problems: should it load
+      # a fresh null to  regs[ra].node  or to regs[ra].node[]? This really
+      # depends on whether regs[ra] represents the variable itself or wether
+      # it holds the indirection! Due to the way registers are re-used we cannot
+      # say for sure here! --> The codegen has to deal with it
+      # via 'genAsgnPatch'.
     of opcLdNullReg:
       let typ = c.types[instr.regBx - wordExcess]
       if typ.skipTypes(abstractInst+{tyRange}-{tyTypeDesc}).kind in {
@@ -858,7 +872,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TRegister =
         return TRegister(kind: rkNone)
     of opcSetLenStr:
       decodeB(rkNode)
-      createStr regs[ra]
+      createStrKeepNode regs[ra]
       regs[ra].node.strVal.setLen(regs[rb].intVal.int)
     of opcOf:
       decodeBC(rkInt)
@@ -1209,6 +1223,9 @@ proc evalStaticExpr*(module: PSym, e: PNode, prc: PSym): PNode =
 proc evalStaticStmt*(module: PSym, e: PNode, prc: PSym) =
   discard evalConstExprAux(module, prc, e, emStaticStmt)
 
+proc setupCompileTimeVar*(module: PSym, n: PNode) =
+  discard evalConstExprAux(module, nil, n, emStaticStmt)
+
 proc setupMacroParam(x: PNode): PNode =
   result = x
   if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
@@ -1250,3 +1267,4 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   if cyclicTree(result): globalError(n.info, errCyclicTree)
   dec(evalMacroCounter)
   c.callsite = nil
+  #debug result
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index ea7c94856..72689c879 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -163,8 +163,6 @@ type
     blocks*: seq[TBlock]    # blocks; temp data structure
     slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
     maxSlots*: int
-    globals*: array[TRegister, int] # hack: to support passing globals byref
-                                    # we map a slot persistently to a global
     
   PCtx* = ref TCtx
   TCtx* = object of passes.TPassContext # code gen context
@@ -181,6 +179,7 @@ type
     callsite*: PNode
     mode*: TEvalMode
     features*: TSandboxFlags
+    traceActive*: bool
 
   TPosition* = distinct int
 
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index cddda7bd3..b594c00a9 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -451,9 +451,11 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
     c.gABC(n, opcIndCallAsgn, dest, x, n.len)
   c.freeTempRange(x, n.len)
 
+template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
+
 proc needsAsgnPatch(n: PNode): bool = 
   n.kind in {nkBracketExpr, nkDotExpr, nkCheckedFieldExpr,
-             nkDerefExpr, nkHiddenDeref}
+             nkDerefExpr, nkHiddenDeref} or (n.kind == nkSym and n.sym.isGlobal)
 
 proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
   case le.kind
@@ -461,15 +463,25 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
     let dest = c.genx(le.sons[0], {gfAddrOf})
     let idx = c.genx(le.sons[1])
     c.gABC(le, opcWrArr, dest, idx, value)
+    c.freeTemp(dest)
+    c.freeTemp(idx)
   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], {gfAddrOf})
     let idx = c.genx(left.sons[1])
     c.gABC(left, opcWrObj, dest, idx, value)
+    c.freeTemp(dest)
+    c.freeTemp(idx)
   of nkDerefExpr, nkHiddenDeref:
     let dest = c.genx(le.sons[0], {gfAddrOf})
     c.gABC(le, opcWrDeref, dest, value)
+    c.freeTemp(dest)
+  of nkSym:
+    if le.sym.isGlobal:
+      let dest = c.genx(le, {gfAddrOf})
+      c.gABC(le, opcWrDeref, dest, value)
+      c.freeTemp(dest)
   else:
     discard
 
@@ -608,6 +620,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.genAddSubInt(n, dest, opcAddInt)
   of mInc, mDec:
     unused(n, dest)
+    # XXX generates inefficient code for globals
     var d = c.genx(n.sons[1]).TDest
     c.genAddSubInt(n, d, if m == mInc: opcAddInt else: opcSubInt)
     c.genAsgnPatch(n.sons[1], d)
@@ -621,6 +634,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     c.genNewSeq(n)
   of mNewString:
     genUnaryABC(c, n, dest, opcNewStr)
+    # XXX buggy
   of mNewStringOfCap:
     # we ignore the 'cap' argument and translate it as 'newString(0)'.
     # eval n.sons[1] for possible side effects:
@@ -629,6 +643,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
     if dest < 0: dest = c.getTemp(n.typ)
     c.gABC(n, opcNewStr, dest, tmp)
     c.freeTemp(tmp)
+    # XXX buggy
   of mLengthOpenArray, mLengthArray, mLengthSeq:
     genUnaryABI(c, n, dest, opcLenSeq)
   of mLengthStr:
@@ -955,8 +970,6 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
   gABC(c, ri, whichAsgnOpc(ri), dest, tmp)
   c.freeTemp(tmp)
 
-template isGlobal(s: PSym): bool = sfGlobal in s.flags and s.kind != skForVar
-
 proc setSlot(c: PCtx; v: PSym) =
   # XXX generate type initialization here?
   if v.position == 0:
@@ -1035,14 +1048,22 @@ proc cannotEval(n: PNode) {.noinline.} =
   globalError(n.info, errGenerated, "cannot evaluate at compile time: " &
     n.renderTree)
 
+proc getNullValue*(typ: PType, info: TLineInfo): PNode
+
 proc genGlobalInit(c: PCtx; n: PNode; s: PSym) =
-  c.globals.add(emptyNode.copyNode)
+  c.globals.add(getNullValue(s.typ, n.info))
   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] = @[]
+  let dest = c.getTemp(s.typ)
+  c.gABx(n, opcLdGlobal, dest, s.position)
+  let tmp = c.genx(s.ast)
+  c.gABC(n, opcWrDeref, dest, tmp)
+  c.freeTemp(dest)
+  c.freeTemp(tmp)
 
-proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
+proc genRdVar(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   let s = n.sym
   if s.isGlobal:
     if sfCompileTime in s.flags or c.mode == emRepl:
@@ -1052,7 +1073,14 @@ proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
     if s.position == 0:
       if sfImportc in s.flags: c.importcSym(n.info, s)
       else: genGlobalInit(c, n, s)
-    c.gABx(n, opcLdGlobal, dest, s.position)
+    if dest < 0: dest = c.getTemp(n.typ)
+    if gfAddrOf notin flags and fitsRegister(s.typ):
+      var cc = c.getTemp(n.typ)
+      c.gABx(n, opcLdGlobal, cc, s.position)
+      c.gABC(n, opcNodeToReg, dest, cc)
+      c.freeTemp(cc)
+    else:
+      c.gABx(n, opcLdGlobal, dest, s.position)
   else:
     if s.kind == skForVar and c.mode == emRepl: c.setSlot s
     if s.position > 0 or (s.position == 0 and
@@ -1095,7 +1123,6 @@ proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
   else:
     genAccess(c, n, dest, opcLdArr, flags)
 
-proc getNullValue*(typ: PType, info: TLineInfo): PNode
 proc getNullValueAux(obj: PNode, result: PNode) = 
   case obj.kind
   of nkRecList:
@@ -1161,7 +1188,7 @@ proc genVarSection(c: PCtx; n: PNode) =
         setSlot(c, a[i].sym)
         # v = t[i]
         var v: TDest = -1
-        genRdVar(c, a[i], v)
+        genRdVar(c, a[i], v, {gfAddrOf})
         c.gABC(n, opcWrObj, v, tmp, i)
         # XXX globals?
       c.freeTemp(tmp)
@@ -1184,6 +1211,7 @@ proc genVarSection(c: PCtx; n: PNode) =
           let val = c.genx(a.sons[2])
           c.gABC(a, opcWrDeref, tmp, val)
           c.freeTemp(val)
+          c.freeTemp(tmp)
       else:
         setSlot(c, s)
         if a.sons[2].kind == nkEmpty:
@@ -1202,8 +1230,17 @@ 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)
+  let seqType = n.typ.skipTypes(abstractVar-{tyTypeDesc})
+  if seqType.kind == tySequence:
+    var tmp = c.getTemp(intType)
+    c.gABx(n, opcLdImmInt, tmp, n.len)
+    c.gABx(n, opcNewSeq, dest, c.genType(seqType))
+    c.gABx(n, opcNewSeq, tmp, 0)
+    c.freeTemp(tmp)
+  
   if n.len > 0:
-    let intType = getSysType(tyInt)
     var tmp = getTemp(c, intType)
     c.gABx(n, opcLdNullReg, tmp, c.genType(intType))
     for x in n:
@@ -1271,7 +1308,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
     let s = n.sym
     case s.kind
     of skVar, skForVar, skTemp, skLet, skParam, skResult:
-      genRdVar(c, n, dest)
+      genRdVar(c, n, dest, flags)
     of skProc, skConverter, skMacro, skTemplate, skMethod, skIterator:
       # 'skTemplate' is only allowed for 'getAst' support:
       if sfImportc in s.flags: c.importcSym(n.info, s)
@@ -1503,7 +1540,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 == "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/macros/tmacro5.nim b/tests/macros/tmacro5.nim
index 39324e497..9882ad90d 100644
--- a/tests/macros/tmacro5.nim
+++ b/tests/macros/tmacro5.nim
@@ -51,7 +51,7 @@ macro okayy:stmt =
   for node in decls: result.add node
   for node in impls: result.add node
 
-importimpl(Item, int):
+importImpl(Item, int):
   echo 42
 importImpl(Foo, int16):
   echo 77
diff --git a/todo.txt b/todo.txt
index 7009d9a84..4bee45516 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,7 +1,6 @@
 version 0.9.4
 =============
 
-- fix macros\tstringinterp.nim
 - fix GC issues
 - test and fix showoff
 
@@ -24,7 +23,6 @@ version 0.9.x
 
 - implement 'union' and 'bits' pragmas
 - fix closures
-- test and fix exception handling
 - ensure (ref T)(a, b) works as a type conversion and type constructor
 - optimize 'genericReset'; 'newException' leads to code bloat
 - stack-less GC