summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim3
-rw-r--r--compiler/lambdalifting.nim4
-rw-r--r--compiler/transf.nim5
-rw-r--r--compiler/vm.nim60
-rw-r--r--compiler/vmgen.nim27
-rw-r--r--todo.txt1
6 files changed, 71 insertions, 29 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 2a7d8a551..9d85e8ff2 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -357,6 +357,7 @@ type
     nfSem       # node has been checked for semantics
     nfDelegate  # the call can use a delegator
     nfExprCall  # this is an attempt to call a regular expression
+    nfIsRef     # this node is a 'ref' node; used for the VM
 
   TNodeFlags* = set[TNodeFlag]
   TTypeFlag* = enum   # keep below 32 for efficiency reasons (now: 23)
@@ -785,7 +786,7 @@ const
   ExportableSymKinds* = {skVar, skConst, skProc, skMethod, skType, skIterator, 
     skMacro, skTemplate, skConverter, skEnumField, skLet, skStub}
   PersistentNodeFlags*: TNodeFlags = {nfBase2, nfBase8, nfBase16,
-                                      nfAllConst, nfDelegate}
+                                      nfAllConst, nfDelegate, nfIsRef}
   namePos* = 0
   patternPos* = 1    # empty except for term rewriting macros
   genericParamsPos* = 2
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 96eb3a5f4..11188267d 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -207,7 +207,7 @@ proc newCall(a, b: PSym): PNode =
 
 proc addHiddenParam(routine: PSym, param: PSym) =
   var params = routine.ast.sons[paramsPos]
-  param.position = params.len
+  param.position = params.len-1
   addSon(params, newSymNode(param))
   incl(routine.typ.flags, tfCapturesEnv)
   #echo "produced environment: ", param.id, " for ", routine.name.s
@@ -549,6 +549,8 @@ proc transformOuterProc(o: POuterContext, n: PNode): PNode =
       if x != nil: n.sons[i] = x
 
 proc liftLambdas*(fn: PSym, body: PNode): PNode =
+  # XXX gCmd == cmdCompileToJS does not suffice! The compiletime stuff needs
+  # the transformation even when compiling to JS ...
   if body.kind == nkEmpty or gCmd == cmdCompileToJS:
     # ignore forward declaration:
     result = body
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 206c21c3d..77642a3b8 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -735,12 +735,9 @@ proc transformBody*(module: PSym, n: PNode, prc: PSym): PNode =
   if nfTransf in n.flags or prc.kind in {skTemplate}:
     result = n
   else:
-    #when useEffectSystem: trackProc(prc, n)
     var c = openTransf(module, "")
     result = processTransf(c, n, prc)
-    if prc.kind != skMacro:
-      # XXX no closures yet for macros:
-      result = liftLambdas(prc, result)
+    result = liftLambdas(prc, result)
     if prc.kind == skIterator and prc.typ.callConv == ccClosure:
       result = lambdalifting.liftIterator(prc, result)
     incl(result.flags, nfTransf)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 49314e899..c70f8b41e 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -133,6 +133,27 @@ proc moveConst(x, y: PNode) =
 # of PNimrodNode:
 template asgnRef(x, y: expr) = moveConst(x, y)
 
+proc copyValue(src: PNode): PNode =
+  if src == nil or nfIsRef in src.flags:
+    return src
+  result = newNode(src.kind)
+  result.info = src.info
+  result.typ = src.typ
+  result.flags = src.flags * PersistentNodeFlags
+  when defined(useNodeIds):
+    if result.id == nodeIdToDebug:
+      echo "COMES FROM ", src.id
+  case src.Kind
+  of nkCharLit..nkUInt64Lit: result.intVal = src.intVal
+  of nkFloatLit..nkFloat128Lit: result.floatVal = src.floatVal
+  of nkSym: result.sym = src.sym
+  of nkIdent: result.ident = src.ident
+  of nkStrLit..nkTripleStrLit: result.strVal = src.strVal
+  else:
+    newSeq(result.sons, sonsLen(src))
+    for i in countup(0, sonsLen(src) - 1):
+      result.sons[i] = copyValue(src.sons[i])
+
 proc asgnComplex(x, y: PNode) =
   if x.kind != y.kind:
     myreset(x)
@@ -149,7 +170,7 @@ proc asgnComplex(x, y: PNode) =
     else: x.sons[0] = y.sons[0]
   else:
     if x.kind notin {nkEmpty..nkNilLit}:
-      let y = y.copyTree
+      let y = y.copyValue
       for i in countup(0, sonsLen(y) - 1): addSon(x, y.sons[i])
 
 template getstr(a: expr): expr =
@@ -306,9 +327,9 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
     of opcAsgnRef:
       asgnRef(regs[ra], regs[instr.regB])
     of opcWrGlobalRef:
-      asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra].skipMeta)
+      asgnRef(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
     of opcWrGlobal:
-      asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra].skipMeta)
+      asgnComplex(c.globals.sons[instr.regBx-wordExcess-1], regs[ra])
     of opcLdArr:
       # a = b[c]
       let rb = instr.regB
@@ -326,12 +347,12 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       let rb = instr.regB
       let rc = instr.regC
       let idx = regs[rb].intVal
-      asgnComplex(regs[ra].sons[idx.int], regs[rc].skipMeta)
+      asgnComplex(regs[ra].sons[idx.int], regs[rc])
     of opcWrArrRef:
       let rb = instr.regB
       let rc = instr.regC
       let idx = regs[rb].intVal
-      asgnRef(regs[ra].sons[idx.int], regs[rc].skipMeta)
+      asgnRef(regs[ra].sons[idx.int], regs[rc])
     of opcLdObj:
       # a = b.c
       let rb = instr.regB
@@ -343,11 +364,16 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # a.b = c
       let rb = instr.regB
       let rc = instr.regC
-      asgnComplex(regs[ra].sons[rb], regs[rc].skipMeta)
+      #if regs[ra].isNil or regs[ra].sons.isNil or rb >= len(regs[ra]):
+      #  debug regs[ra]
+      #  debug regs[rc]
+      #  echo "RB ", rb
+      #  internalError(c.debug[pc], "argl")
+      asgnComplex(regs[ra].sons[rb], regs[rc])
     of opcWrObjRef:
       let rb = instr.regB
       let rc = instr.regC
-      asgnRef(regs[ra].sons[rb], regs[rc].skipMeta)
+      asgnRef(regs[ra].sons[rb], regs[rc])
     of opcWrStrIdx:
       decodeBC(nkStrLit)
       let idx = regs[rb].intVal.int
@@ -580,7 +606,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # dest = call regStart, n; where regStart = fn, arg1, ...
       let rb = instr.regB
       let rc = instr.regC
-      let prc = regs[rb].sym
+      let isClosure = regs[rb].kind == nkPar
+      let prc = if not isClosure: regs[rb].sym else: regs[rb].sons[0].sym
       let newPc = compile(c, prc)
       #echo "new pc ", newPc, " calling: ", prc.name.s
       var newFrame = PStackFrame(prc: prc, comesFrom: pc, next: tos)
@@ -590,8 +617,10 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       # pass every parameter by var (the language definition allows this):
       for i in 1 .. rc-1:
         newFrame.slots[i] = regs[rb+i]
+      if isClosure:
+        newFrame.slots[rc] = regs[rb].sons[1]
       # allocate the temporaries:
-      for i in rc .. <prc.position:
+      for i in rc+ord(isClosure) .. <prc.position:
         newFrame.slots[i] = newNode(nkEmpty)
       tos = newFrame
       move(regs, newFrame.slots)
@@ -656,6 +685,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
     of opcNew:
       let typ = c.types[instr.regBx - wordExcess]
       regs[ra] = getNullValue(typ, regs[ra].info)
+      regs[ra].flags.incl nfIsRef
     of opcNewSeq:
       let typ = c.types[instr.regBx - wordExcess]
       inc pc
@@ -724,6 +754,8 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
       setMeta(regs[ra], regs[rb].skipMeta.sons[1])
     of opcNChild:
       decodeBC(nkMetaNode)
+      if regs[rb].kind != nkMetaNode:
+        internalError(c.debug[pc], "no MetaNode")
       setMeta(regs[ra], regs[rb].uast.sons[regs[rc].intVal.int])
     of opcNSetChild:
       decodeBC(nkMetaNode)
@@ -886,19 +918,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): PNode =
          regs[rb].kind in {nkStrLit..nkTripleStrLit}:
         dest.strVal = regs[rb].strVal
       else:
-        #c.echoCode
-        #debug regs[ra]
-        #debug regs[rb]
         stackTrace(c, tos, pc, errFieldXNotFound, "strVal")
     of opcNNewNimNode:
       decodeBC(nkMetaNode)
       var k = regs[rb].intVal
-      if k < 0 or k > ord(high(TNodeKind)): 
+      if k < 0 or k > ord(high(TNodeKind)) or k == ord(nkMetaNode):
         internalError(c.debug[pc],
           "request to create a NimNode of invalid kind")
       let cc = regs[rc].skipMeta
       setMeta(regs[ra], newNodeI(TNodeKind(int(k)), 
         if cc.kind == nkNilLit: c.debug[pc] else: cc.info))
+      regs[ra].sons[0].flags.incl nfIsRef
     of opcNCopyNimNode:
       decodeB(nkMetaNode)
       setMeta(regs[ra], copyNode(regs[rb]))
@@ -1006,6 +1036,7 @@ proc setupMacroParam(x: PNode): PNode =
   result = x
   if result.kind in {nkHiddenSubConv, nkHiddenStdConv}: result = result.sons[1]
   let y = result
+  y.flags.incl nfIsRef
   result = newNode(nkMetaNode)
   result.add y
 
@@ -1039,6 +1070,5 @@ proc evalMacroCall*(module: PSym, n, nOrig: PNode, sym: PSym): PNode =
   if cyclicTree(result): GlobalError(n.info, errCyclicTree)
   dec(evalMacroCounter)
   if result != nil:
-    internalAssert result.kind == nkMetaNode
-    result = result.sons[0]
+    result = result.skipMeta
   c.callsite = nil
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index 175cae2f5..332184e0d 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -948,8 +948,15 @@ proc getNullValue(typ: PType, info: TLineInfo): PNode =
   of tyFloat..tyFloat128: 
     result = newNodeIt(nkFloatLit, info, t)
   of tyVar, tyPointer, tyPtr, tyCString, tySequence, tyString, tyExpr, 
-     tyStmt, tyTypeDesc, tyProc, tyRef:
+     tyStmt, tyTypeDesc, tyRef:
     result = newNodeIT(nkNilLit, info, t)
+  of tyProc:
+    if t.callConv != ccClosure:
+      result = newNodeIT(nkNilLit, info, t)
+    else:
+      result = newNodeIT(nkPar, info, t)
+      result.add(newNodeIT(nkNilLit, info, t))
+      result.add(newNodeIT(nkNilLit, info, t))
   of tyObject: 
     result = newNodeIT(nkPar, info, t)
     getNullValueAux(t.n, result)
@@ -1071,7 +1078,8 @@ proc genObjConstr(c: PCtx, n: PNode, dest: var TDest) =
 
 proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
   if dest < 0: dest = c.getTemp(n.typ)
-  var idx = getTemp(c, getSysType(tyInt))
+  c.gABx(n, opcLdNull, dest, c.genType(n.typ))
+  # XXX x = (x.old, 22)  produces wrong code ... stupid self assignments
   for i in 0.. <n.len:
     let it = n.sons[i]
     if it.kind == nkExprColonExpr:
@@ -1082,10 +1090,8 @@ proc genTupleConstr(c: PCtx, n: PNode, dest: var TDest) =
       c.freeTemp(idx)
     else:
       let tmp = c.genx(it)
-      c.gABx(it, opcLdImmInt, idx, i)
-      c.gABC(it, whichAsgnOpc(it, opcWrObj), dest, idx, tmp)
+      c.gABC(it, whichAsgnOpc(it, opcWrObj), dest, i.TRegister, tmp)
       c.freeTemp(tmp)
-  c.freeTemp(idx)
 
 proc genProc*(c: PCtx; s: PSym): int
 
@@ -1280,7 +1286,8 @@ proc optimizeJumps(c: PCtx; start: int) =
 proc genProc(c: PCtx; s: PSym): int =
   let x = s.ast.sons[optimizedCodePos]
   if x.kind == nkEmpty:
-    #echo "GENERATING CODE FOR ", s.name.s
+    #if s.name.s == "outterMacro" or s.name.s == "innerProc":
+    #  echo "GENERATING CODE FOR ", s.name.s
     let last = c.code.len-1
     var eofInstr: TInstr
     if last >= 0 and c.code[last].opcode == opcEof:
@@ -1299,6 +1306,11 @@ proc genProc(c: PCtx; s: PSym): int =
     c.prc = p
     # iterate over the parameters and allocate space for them:
     genParams(c, s.typ.n)
+    if tfCapturesEnv in s.typ.flags:
+      #let env = s.ast.sons[paramsPos].lastSon.sym
+      #assert env.position == 2
+      c.prc.slots[c.prc.maxSlots] = (inUse: true, kind: slotFixedLet)
+      inc c.prc.maxSlots
     gen(c, body)
     # generate final 'return' statement:
     c.gABC(body, opcRet)
@@ -1306,8 +1318,9 @@ proc genProc(c: PCtx; s: PSym): int =
     c.gABC(body, opcEof, eofInstr.regA)
     c.optimizeJumps(result)
     s.position = c.prc.maxSlots
-    #if s.name.s == "temp":
+    #if s.name.s == "innerProc":
     #  c.echoCode
+    #  echo renderTree(body)
     c.prc = oldPrc
   else:
     c.prc.maxSlots = s.position
diff --git a/todo.txt b/todo.txt
index 1a75ab66f..94b3d5135 100644
--- a/todo.txt
+++ b/todo.txt
@@ -3,7 +3,6 @@ version 0.9.4
 
 - new VM:
   - tcntseq fails
-  - new VM requires lambda lifting
   - implement overflow checking
   - implement the FFI