summary refs log tree commit diff stats
path: root/compiler/jsgen.nim
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-04-28 23:41:10 +0200
committerAraq <rumpf_a@web.de>2013-04-28 23:41:10 +0200
commit3897a8c44b4a9f91fe1562e3c658f33501d6fcef (patch)
treef0a0f8fc2349b15707d698c52c0ef50ecec6ae7b /compiler/jsgen.nim
parentf182cefc08929334d4ca70c73b0f37cd3a288b8e (diff)
downloadNim-3897a8c44b4a9f91fe1562e3c658f33501d6fcef.tar.gz
new JS code generator
Diffstat (limited to 'compiler/jsgen.nim')
-rw-r--r--compiler/jsgen.nim1224
1 files changed, 535 insertions, 689 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index f2e317f47..2b5e2c1bd 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -8,18 +8,17 @@
 #
 
 # This is the EMCAScript (also known as JavaScript) code generator.
-# **Invariant: each expression occurs only once in the generated
-# code!**
+# Soon also a Luajit code generator. ;-)
 
-import 
+import
   ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
   options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
   times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils,
   intsets, cgmeth
 
-# implementation
-
-type 
+type
+  TTarget = enum
+    targetJS, targetLua
   TJSGen = object of TPassContext
     module: PSym
 
@@ -34,36 +33,45 @@ type
     etyString,                # JavaScript's string
     etyObject,                # JavaScript's reference to an object
     etyBaseIndex              # base + index needed
-  TCompRes{.final.} = object 
-    kind: TJSTypeKind
-    com: PRope               # computation part
-                             # address if this is a (address, index)-tuple
+  TResKind = enum
+    resNone,                  # not set
+    resExpr,                  # is some complex expression
+    resVal                    # is a temporary/value/l-value
+  TCompRes = object
+    kind: TResKind
+    typ: TJSTypeKind
     res: PRope               # result part; index if this is an
                              # (address, index)-tuple
+    address: PRope           # address of an (address, index)-tuple
   
-  TBlock{.final.} = object 
+  TBlock = object 
     id: int                  # the ID of the label; positive means that it
                              # has been used (i.e. the label should be emitted)
     isLoop: bool             # whether it's a 'block' or 'while'
   
-  TGlobals{.final.} = object 
+  TGlobals = object 
     typeInfo, code: PRope
     forwarded: seq[PSym]
     generatedSyms: TIntSet
     typeInfoGenerated: TIntSet
 
   PGlobals = ref TGlobals
-  TProc{.final.} = object 
+  PProc = ref TProc
+  TProc = object
     procDef: PNode
     prc: PSym
-    locals: PRope
+    locals, body: PRope
     options: TOptions
     module: BModule
     g: PGlobals
     BeforeRetNeeded: bool
-    unique: int
+    target: TTarget # duplicated here for faster dispatching
+    unique: int    # for temp identifier generation
     blocks: seq[TBlock]
+    up: PProc     # up the call chain; required for closure support
 
+template `|`(a, b: expr): expr {.immediate.} =
+  (if p.target == targetJS: a else: b)
 
 proc newGlobals(): PGlobals = 
   new(result)
@@ -72,25 +80,35 @@ proc newGlobals(): PGlobals =
   result.typeInfoGenerated = initIntSet()
 
 proc initCompRes(r: var TCompRes) = 
-  r.com = nil
+  r.address = nil
   r.res = nil
-  r.kind = etyNone
-
-proc initProc(p: var TProc, globals: PGlobals, module: BModule, procDef: PNode, 
-              options: TOptions) = 
-  p.blocks = @[]
-  p.options = options
-  p.module = module
-  p.procDef = procDef
-  p.g = globals
-  if procDef != nil: p.prc = procDef.sons[namePos].sym
+  r.typ = etyNone
+  r.kind = resNone
+
+proc rdLoc(a: TCompRes): PRope {.inline.} =
+  result = a.res
+  when false:
+    if a.typ != etyBaseIndex:
+      result = a.res
+    else:
+      result = ropef("$1[$2]", a.address, a.res)
+
+proc newProc(globals: PGlobals, module: BModule, procDef: PNode, 
+              options: TOptions): PProc =
+  result = PProc(
+    blocks: @[],
+    options: options,
+    module: module,
+    procDef: procDef,
+    g: globals)
+  if procDef != nil: result.prc = procDef.sons[namePos].sym
   
 const 
   MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, 
     tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
 
 proc mapType(typ: PType): TJSTypeKind = 
-  var t = skipTypes(typ, abstractInst)
+  let t = skipTypes(typ, abstractInst)
   case t.kind
   of tyVar, tyRef, tyPtr: 
     if skipTypes(t.sons[0], abstractInst).kind in mappedToObject: 
@@ -140,173 +158,20 @@ proc mangleName(s: PSym): PRope =
 
 proc makeJSString(s: string): PRope = strutils.escape(s).toRope
 
-proc genTypeInfo(p: var TProc, typ: PType): PRope
-proc genObjectFields(p: var TProc, typ: PType, n: PNode): PRope = 
-  var 
-    s, u: PRope
-    length: int
-    field: PSym
-    b: PNode
-  result = nil
-  case n.kind
-  of nkRecList: 
-    length = sonsLen(n)
-    if length == 1: 
-      result = genObjectFields(p, typ, n.sons[0])
-    else: 
-      s = nil
-      for i in countup(0, length - 1): 
-        if i > 0: app(s, ", " & tnl)
-        app(s, genObjectFields(p, typ, n.sons[i]))
-      result = ropef("{kind: 2, len: $1, offset: 0, " &
-          "typ: null, name: null, sons: [$2]}", [toRope(length), s])
-  of nkSym: 
-    field = n.sym
-    s = genTypeInfo(p, field.typ)
-    result = ropef("{kind: 1, offset: \"$1\", len: 0, " &
-        "typ: $2, name: $3, sons: null}", 
-                   [mangleName(field), s, makeJSString(field.name.s)])
-  of nkRecCase: 
-    length = sonsLen(n)
-    if (n.sons[0].kind != nkSym): InternalError(n.info, "genObjectFields")
-    field = n.sons[0].sym
-    s = genTypeInfo(p, field.typ)
-    for i in countup(1, length - 1): 
-      b = n.sons[i]           # branch
-      u = nil
-      case b.kind
-      of nkOfBranch: 
-        if sonsLen(b) < 2: 
-          internalError(b.info, "genObjectFields; nkOfBranch broken")
-        for j in countup(0, sonsLen(b) - 2): 
-          if u != nil: app(u, ", ")
-          if b.sons[j].kind == nkRange: 
-            appf(u, "[$1, $2]", [toRope(getOrdValue(b.sons[j].sons[0])), 
-                                 toRope(getOrdValue(b.sons[j].sons[1]))])
-          else: 
-            app(u, toRope(getOrdValue(b.sons[j])))
-      of nkElse: 
-        u = toRope(lengthOrd(field.typ))
-      else: internalError(n.info, "genObjectFields(nkRecCase)")
-      if result != nil: app(result, ", " & tnl)
-      appf(result, "[SetConstr($1), $2]", 
-           [u, genObjectFields(p, typ, lastSon(b))])
-    result = ropef("{kind: 3, offset: \"$1\", len: $3, " &
-        "typ: $2, name: $4, sons: [$5]}", [mangleName(field), s, 
-        toRope(lengthOrd(field.typ)), makeJSString(field.name.s), result])
-  else: internalError(n.info, "genObjectFields")
+include jstypes
   
-proc genObjectInfo(p: var TProc, typ: PType, name: PRope) = 
-  var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
-                "finalizer: null};$n", [name, toRope(ord(typ.kind))])
-  prepend(p.g.typeInfo, s)
-  appf(p.g.typeInfo, "var NNI$1 = $2;$n", 
-       [toRope(typ.id), genObjectFields(p, typ, typ.n)])
-  appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
-  if (typ.kind == tyObject) and (typ.sons[0] != nil): 
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
-         [name, genTypeInfo(p, typ.sons[0])])
-
-proc genTupleFields(p: var TProc, typ: PType): PRope =
-  var s: PRope = nil
-  for i in 0 .. <typ.len:
-    if i > 0: app(s, ", " & tnl)
-    s.appf("{kind: 1, offset: \"Field$1\", len: 0, " &
-           "typ: $2, name: \"Field$1\", sons: null}",
-           [i.toRope, genTypeInfo(p, typ.sons[i])])
-  result = ropef("{kind: 2, len: $1, offset: 0, " &
-                 "typ: null, name: null, sons: [$2]}", [toRope(typ.len), s])
-
-proc genTupleInfo(p: var TProc, typ: PType, name: PRope) = 
-  var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
-                "finalizer: null};$n", [name, toRope(ord(typ.kind))])
-  prepend(p.g.typeInfo, s)
-  appf(p.g.typeInfo, "var NNI$1 = $2;$n", 
-       [toRope(typ.id), genTupleFields(p, typ)])
-  appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
-
-proc genEnumInfo(p: var TProc, typ: PType, name: PRope) =
-  let length = sonsLen(typ.n)
-  var s: PRope = nil
-  for i in countup(0, length - 1): 
-    if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo")
-    let field = typ.n.sons[i].sym
-    if i > 0: app(s, ", " & tnl)
-    let extName = if field.ast == nil: field.name.s else: field.ast.strVal
-    appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}", 
-         [toRope(field.position), name, makeJSString(extName)])
-  var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " &
-      "name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s])
-  s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " &
-      "finalizer: null};$n", [name, toRope(ord(typ.kind))])
-  prepend(p.g.typeInfo, s)
-  app(p.g.typeInfo, n)
-  appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
-  if typ.sons[0] != nil:
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
-         [name, genTypeInfo(p, typ.sons[0])])
-
-proc genTypeInfo(p: var TProc, typ: PType): PRope = 
-  var t = typ
-  if t.kind == tyGenericInst: t = lastSon(t)
-  result = ropef("NTI$1", [toRope(t.id)])
-  if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return 
-  case t.kind
-  of tyDistinct: 
-    result = genTypeInfo(p, typ.sons[0])
-  of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyFloat128: 
-    var s = ropef(
-      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", 
-              [result, toRope(ord(t.kind))])
-    prepend(p.g.typeInfo, s)
-  of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet: 
-    var s = ropef(
-      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", 
-              [result, toRope(ord(t.kind))])
-    prepend(p.g.typeInfo, s)
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
-         [result, genTypeInfo(p, typ.sons[0])])
-  of tyArrayConstr, tyArray: 
-    var s = ropef(
-      "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n",
-              [result, toRope(ord(t.kind))])
-    prepend(p.g.typeInfo, s)
-    appf(p.g.typeInfo, "$1.base = $2;$n", 
-         [result, genTypeInfo(p, typ.sons[1])])
-  of tyEnum: genEnumInfo(p, t, result)
-  of tyObject: genObjectInfo(p, t, result)
-  of tyTuple: genTupleInfo(p, t, result)
-  else: InternalError("genTypeInfo(" & $t.kind & ')')
-  
-proc gen(p: var TProc, n: PNode, r: var TCompRes)
-proc genStmt(p: var TProc, n: PNode, r: var TCompRes)
-proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes)
-proc genConstant(p: var TProc, c: PSym, r: var TCompRes)
-
-proc mergeExpr(a, b: PRope): PRope = 
-  if (a != nil): 
-    if b != nil: result = ropef("($1, $2)", [a, b])
-    else: result = a
-  else: 
-    result = b
-  
-proc mergeExpr(r: TCompRes): PRope = 
-  result = mergeExpr(r.com, r.res)
+proc gen(p: PProc, n: PNode, r: var TCompRes)
+proc genStmt(p: PProc, n: PNode, r: var TCompRes)
+proc genProc(oldProc: PProc, prc: PSym): PRope
+proc genConstant(p: PProc, c: PSym)
 
-proc mergeStmt(r: TCompRes): PRope = 
-  if r.res == nil: result = r.com
-  elif r.com == nil: result = r.res
-  else: result = ropef("$1$2", [r.com, r.res])
-  
-proc useMagic(p: var TProc, name: string) =
+proc useMagic(p: PProc, name: string) =
   if name.len == 0: return
   var s = magicsys.getCompilerProc(name)
   if s != nil:
     internalAssert s.kind in {skProc, skMethod, skConverter}
     if not p.g.generatedSyms.containsOrIncl(s.id):
-      var r: TCompRes
-      genProc(p, s, r)
-      app(p.g.code, mergeStmt(r))
+      app(p.g.code, genProc(p, s))
   else:
     # we used to exclude the system module from this check, but for DLL
     # generation support this sloppyness leads to hard to detect bugs, so
@@ -314,19 +179,67 @@ proc useMagic(p: var TProc, name: string) =
     if p.prc != nil: GlobalError(p.prc.info, errSystemNeeds, name)
     else: rawMessage(errSystemNeeds, name)
 
-proc genAnd(p: var TProc, a, b: PNode, r: var TCompRes) = 
-  var x, y: TCompRes
-  gen(p, a, x)
-  gen(p, b, y)
-  r.res = ropef("($1 && $2)", [mergeExpr(x), mergeExpr(y)])
+proc isSimpleExpr(n: PNode): bool =
+  # calls all the way down --> can stay expression based
+  if n.kind in nkCallKinds+{nkBracketExpr, nkBracket, nkCurly, nkDotExpr, nkPar,
+                            nkObjConstr}:
+    for c in n:
+      if not c.isSimpleExpr: return false
+    result = true
+  elif n.isAtom:
+    result = true
+
+proc getTemp(p: PProc): PRope =
+  inc(p.unique)
+  result = ropef("Tmp$1", [toRope(p.unique)])
+  appf(p.locals, "var $1;$n" | "local $1;$n", [result])
 
-proc genOr(p: var TProc, a, b: PNode, r: var TCompRes) = 
+proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
+  assert r.kind == resNone
   var x, y: TCompRes
-  gen(p, a, x)
-  gen(p, b, y)
-  r.res = ropef("($1 || $2)", [mergeExpr(x), mergeExpr(y)])
-
-type 
+  if a.isSimpleExpr and b.isSimpleExpr:
+    gen(p, a, x)
+    gen(p, b, y)
+    r.kind = resExpr
+    r.res = ropef("($1 && $2)" | "($1 and $2)", [x.rdLoc, y.rdLoc])
+  else:
+    r.res = p.getTemp
+    r.kind = resVal
+    # while a and b:
+    # -->
+    # while true:
+    #   aa
+    #   if not a: tmp = false
+    #   else:
+    #     bb
+    #     tmp = b
+    # tmp
+    gen(p, a, x)
+    p.body.appf("if (!$1) $2 = false; else {" |
+                "if not $1 then $2 = false; else", x.rdLoc, r.rdLoc)
+    gen(p, b, y)
+    p.body.appf("$2 = $1; }" |
+                "$2 = $1 end", y.rdLoc, r.rdLoc)
+
+proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
+  assert r.kind == resNone
+  var x, y: TCompRes
+  if a.isSimpleExpr and b.isSimpleExpr:
+    gen(p, a, x)
+    gen(p, b, y)
+    r.kind = resExpr
+    r.res = ropef("($1 || $2)" | "($1 or $2)", [x.rdLoc, y.rdLoc])
+  else:
+    r.res = p.getTemp
+    r.kind = resVal
+    gen(p, a, x)
+    p.body.appf("if ($1) $2 = true; else {" |
+                "if $1 then $2 = true; else", x.rdLoc, r.rdLoc)
+    gen(p, b, y)
+    p.body.appf("$2 = $1; }" |
+                "$2 = $1 end", y.rdLoc, r.rdLoc)
+
+type
   TMagicFrmt = array[0..3, string]
 
 const # magic checked op; magic unchecked op; checked op; unchecked op
@@ -430,86 +343,83 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
     ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"], 
     ["", "", "$1", "$1"]]
 
-proc binaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = 
-  var x, y: TCompRes
-  useMagic(p, magic)
-  gen(p, n.sons[1], x)
-  gen(p, n.sons[2], y)
-  r.res = ropef(frmt, [x.res, y.res])
-  r.com = mergeExpr(x.com, y.com)
-
-proc binaryStmt(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = 
+proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   var x, y: TCompRes
   useMagic(p, magic)
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
-  if x.com != nil: appf(r.com, "$1;$n", [x.com])
-  if y.com != nil: appf(r.com, "$1;$n", [y.com])
-  appf(r.com, frmt, [x.res, y.res])
+  r.res = ropef(frmt, [x.rdLoc, y.rdLoc])
+  r.kind = resExpr
 
-proc unaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = 
+proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
   useMagic(p, magic)
   gen(p, n.sons[1], r)
-  r.res = ropef(frmt, [r.res])
+  r.res = ropef(frmt, [r.rdLoc])
+  r.kind = resExpr
 
-proc arith(p: var TProc, n: PNode, r: var TCompRes, op: TMagic) = 
-  var 
+proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
+  var
     x, y: TCompRes
-    i: int
-  if optOverflowCheck in p.options: i = 0
-  else: i = 1
+  let i = ord(optOverflowCheck notin p.options)
   useMagic(p, ops[op][i])
-  if sonsLen(n) > 2: 
+  if sonsLen(n) > 2:
     gen(p, n.sons[1], x)
     gen(p, n.sons[2], y)
-    r.res = ropef(ops[op][i + 2], [x.res, y.res])
-    r.com = mergeExpr(x.com, y.com)
-  else: 
+    r.res = ropef(ops[op][i + 2], [x.rdLoc, y.rdLoc])
+  else:
     gen(p, n.sons[1], r)
-    r.res = ropef(ops[op][i + 2], [r.res])
+    r.res = ropef(ops[op][i + 2], [r.rdLoc])
+  r.kind = resExpr
 
-proc genLineDir(p: var TProc, n: PNode, r: var TCompRes) = 
-  var line: int
-  line = toLinenumber(n.info)
-  if optLineDir in p.Options: 
-    appf(r.com, "// line $2 \"$1\"$n", 
+proc genLineDir(p: PProc, n: PNode) =
+  let line = toLinenumber(n.info)
+  if optLineDir in p.Options:
+    appf(p.body, "// line $2 \"$1\"$n",
          [toRope(toFilename(n.info)), toRope(line)])
-  if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
-      ((p.prc == nil) or not (sfPure in p.prc.flags)): 
+  if {optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb} and
+      ((p.prc == nil) or sfPure notin p.prc.flags):
     useMagic(p, "endb")
-    appf(r.com, "endb($1);$n", [toRope(line)])
+    appf(p.body, "endb($1);$n", [toRope(line)])
   elif ({optLineTrace, optStackTrace} * p.Options ==
       {optLineTrace, optStackTrace}) and
       ((p.prc == nil) or not (sfPure in p.prc.flags)): 
-    appf(r.com, "F.line = $1;$n", [toRope(line)])
+    appf(p.body, "F.line = $1;$n", [toRope(line)])
   
-proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
+proc genWhileStmt(p: PProc, n: PNode) =
+  var
     cond, stmt: TCompRes
-    length, labl: int
-  genLineDir(p, n, r)
+  internalAssert isEmptyType(n.typ)
+  genLineDir(p, n)
   inc(p.unique)
-  length = len(p.blocks)
+  var length = len(p.blocks)
   setlen(p.blocks, length + 1)
   p.blocks[length].id = - p.unique
   p.blocks[length].isLoop = true
-  labl = p.unique
+  let labl = p.unique.toRope
+  appf(p.body, "L$1: while (true) {$n" | "while true do$n", labl)
   gen(p, n.sons[0], cond)
+  appf(p.body, "if (!$1) break L$2;$n" | "if not $1 then goto ::L$2:: end;$n",
+       [cond.res, labl])
   genStmt(p, n.sons[1], stmt)
-  if p.blocks[length].id > 0: 
-    appf(r.com, "L$3: while ($1) {$n$2}$n", 
-         [mergeExpr(cond), mergeStmt(stmt), toRope(labl)])
-  else: 
-    appf(r.com, "while ($1) {$n$2}$n", [mergeExpr(cond), mergeStmt(stmt)])
+  internalAssert stmt.res.isNil
+  appf(p.body, "}$n" | "end$n", [])
   setlen(p.blocks, length)
 
-proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) = 
+proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
+  if src.kind != resNone:
+    assert dest.kind != resNone
+    p.body.appf("$1 = $2;$n", dest.rdLoc, src.rdLoc)
+    src.kind = resNone
+    src.res = nil
+
+proc genTry(p: PProc, n: PNode, r: var TCompRes) = 
   # code to generate:
   #
   #  var sp = {prev: excHandler, exc: null};
   #  excHandler = sp;
   #  try {
   #    stmts;
+  #    TMP = e
   #  } catch (e) {
   #    if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
   #      stmts;
@@ -522,116 +432,113 @@ proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) =
   #    stmts;
   #    excHandler = excHandler.prev;
   #  }
-  #
-  var 
-    i, length, blen: int
-    safePoint, orExpr, epart: PRope
-    a: TCompRes
-  genLineDir(p, n, r)
+  genLineDir(p, n)
   inc(p.unique)
-  safePoint = ropef("Tmp$1", [toRope(p.unique)])
-  appf(r.com, 
+  var safePoint = ropef("Tmp$1", [toRope(p.unique)])
+  appf(p.body, 
        "var $1 = {prev: excHandler, exc: null};$n" & "excHandler = $1;$n", 
        [safePoint])
-  if optStackTrace in p.Options: app(r.com, "framePtr = F;" & tnl)
-  app(r.com, "try {" & tnl)
-  length = sonsLen(n)
+  if optStackTrace in p.Options: app(p.body, "framePtr = F;" & tnl)
+  app(p.body, "try {" & tnl)
+  var length = sonsLen(n)
+  var a: TCompRes
   genStmt(p, n.sons[0], a)
-  app(r.com, mergeStmt(a))
-  i = 1
-  epart = nil
-  while (i < length) and (n.sons[i].kind == nkExceptBranch): 
-    blen = sonsLen(n.sons[i])
+  if not isEmptyType(n.typ):
+    r.kind = resVal
+    r.res = getTemp(p)
+    moveInto(p, a, r)
+  var i = 1
+  if length > 1 and n.sons[i].kind == nkExceptBranch:
+    appf(p.body, "} catch (EXC) {$n")
+  while i < length and n.sons[i].kind == nkExceptBranch: 
+    let blen = sonsLen(n.sons[i])
     if blen == 1: 
       # general except section:
-      if i > 1: app(epart, "else {" & tnl)
+      if i > 1: app(p.body, "else {" & tnl)
       genStmt(p, n.sons[i].sons[0], a)
-      app(epart, mergeStmt(a))
-      if i > 1: app(epart, '}' & tnl)
-    else: 
-      orExpr = nil
+      moveInto(p, a, r)
+      if i > 1: app(p.body, '}' & tnl)
+    else:
+      var orExpr: PRope = nil
       useMagic(p, "isObj")
       for j in countup(0, blen - 2): 
-        if (n.sons[i].sons[j].kind != nkType): 
+        if n.sons[i].sons[j].kind != nkType: 
           InternalError(n.info, "genTryStmt")
         if orExpr != nil: app(orExpr, "||")
         appf(orExpr, "isObj($1.exc.m_type, $2)", 
              [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
-      if i > 1: app(epart, "else ")
-      appf(epart, "if ($1.exc && $2) {$n", [safePoint, orExpr])
+      if i > 1: app(p.body, "else ")
+      appf(p.body, "if ($1.exc && ($2)) {$n", [safePoint, orExpr])
       genStmt(p, n.sons[i].sons[blen - 1], a)
-      appf(epart, "$1}$n", [mergeStmt(a)])
+      moveInto(p, a, r)
+      appf(p.body, "}$n")
     inc(i)
-  if epart != nil: appf(r.com, "} catch (EXC) {$n$1", [epart])
-  app(r.com, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
-  if (i < length) and (n.sons[i].kind == nkFinally): 
+  app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl)
+  if i < length and n.sons[i].kind == nkFinally:
     genStmt(p, n.sons[i].sons[0], a)
-    app(r.com, mergeStmt(a))
-  app(r.com, '}' & tnl)
+    moveInto(p, a, r)
+  app(p.body, '}' & tnl)
 
-proc genRaiseStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    a: TCompRes
-    typ: PType
-  genLineDir(p, n, r)
-  if n.sons[0].kind != nkEmpty: 
+proc genRaiseStmt(p: PProc, n: PNode) =
+  genLineDir(p, n)
+  if n.sons[0].kind != nkEmpty:
+    var a: TCompRes
     gen(p, n.sons[0], a)
-    if a.com != nil: appf(r.com, "$1;$n", [a.com])
-    typ = skipTypes(n.sons[0].typ, abstractPtrs)
+    let typ = skipTypes(n.sons[0].typ, abstractPtrs)
     useMagic(p, "raiseException")
-    appf(r.com, "raiseException($1, $2);$n", 
-         [a.res, makeJSString(typ.sym.name.s)])
-  else: 
+    appf(p.body, "raiseException($1, $2);$n",
+         [a.rdLoc, makeJSString(typ.sym.name.s)])
+  else:
     useMagic(p, "reraiseException")
-    app(r.com, "reraiseException();" & tnl)
+    app(p.body, "reraiseException();" & tnl)
 
-proc genCaseStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
+proc genCase(p: PProc, n: PNode, r: var TCompRes) = 
+  var
     cond, stmt: TCompRes
-    it, e, v: PNode
-    stringSwitch: bool
-  genLineDir(p, n, r)
+  genLineDir(p, n)
   gen(p, n.sons[0], cond)
-  if cond.com != nil: appf(r.com, "$1;$n", [cond.com])
-  stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
+  let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
   if stringSwitch: 
     useMagic(p, "toJSStr")
-    appf(r.com, "switch (toJSStr($1)) {$n", [cond.res])
-  else: 
-    appf(r.com, "switch ($1) {$n", [cond.res])
+    appf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
+  else:
+    appf(p.body, "switch ($1) {$n", [cond.rdLoc])
+  if not isEmptyType(n.typ):
+    r.kind = resVal
+    r.res = getTemp(p)
   for i in countup(1, sonsLen(n) - 1): 
-    it = n.sons[i]
+    let it = n.sons[i]
     case it.kind
     of nkOfBranch: 
       for j in countup(0, sonsLen(it) - 2): 
-        e = it.sons[j]
+        let e = it.sons[j]
         if e.kind == nkRange: 
-          v = copyNode(e.sons[0])
-          while (v.intVal <= e.sons[1].intVal): 
+          var v = copyNode(e.sons[0])
+          while v.intVal <= e.sons[1].intVal: 
             gen(p, v, cond)
-            if cond.com != nil: internalError(v.info, "jsgen.genCaseStmt")
-            appf(r.com, "case $1: ", [cond.res])
+            appf(p.body, "case $1: ", [cond.rdLoc])
             Inc(v.intVal)
-        else: 
-          gen(p, e, cond)
-          if cond.com != nil: internalError(e.info, "jsgen.genCaseStmt")
+        else:
           if stringSwitch: 
             case e.kind
-            of nkStrLit..nkTripleStrLit: appf(r.com, "case $1: ", 
+            of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ", 
                 [makeJSString(e.strVal)])
             else: InternalError(e.info, "jsgen.genCaseStmt: 2")
           else: 
-            appf(r.com, "case $1: ", [cond.res])
+            gen(p, e, cond)
+            appf(p.body, "case $1: ", [cond.rdLoc])
       genStmt(p, lastSon(it), stmt)
-      appf(r.com, "$n$1break;$n", [mergeStmt(stmt)])
-    of nkElse: 
+      moveInto(p, stmt, r)
+      appf(p.body, "$nbreak;$n")
+    of nkElse:
+      appf(p.body, "default: $n")
       genStmt(p, it.sons[0], stmt)
-      appf(r.com, "default: $n$1break;$n", [mergeStmt(stmt)])
+      moveInto(p, stmt, r)
+      appf(p.body, "break;$n")
     else: internalError(it.info, "jsgen.genCaseStmt")
-  appf(r.com, "}$n", [])
+  appf(p.body, "}$n")
 
-proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes)
-proc genBlock(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genBlock(p: PProc, n: PNode, r: var TCompRes) = 
   var 
     idx, labl: int
     sym: PSym
@@ -646,22 +553,18 @@ proc genBlock(p: var TProc, n: PNode, r: var TCompRes) =
   setlen(p.blocks, idx + 1)
   p.blocks[idx].id = - p.unique # negative because it isn't used yet
   labl = p.unique
-  if n.kind == nkBlockExpr: genStmtListExpr(p, n.sons[1], r)
-  else: genStmt(p, n.sons[1], r)
-  if p.blocks[idx].id > 0: 
-    # label has been used:
-    r.com = ropef("L$1: do {$n$2} while(false);$n", [toRope(labl), r.com])
+  appf(p.body, "L$1: do {$n", toRope(labl))
+  genStmt(p, n.sons[1], r)
+  appf(p.body, "} while(false);$n")
   setlen(p.blocks, idx)
 
-proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    idx: int
-    sym: PSym
-  genLineDir(p, n, r)
+proc genBreakStmt(p: PProc, n: PNode) = 
+  var idx: int
+  genLineDir(p, n)
   if n.sons[0].kind != nkEmpty: 
     # named break?
     assert(n.sons[0].kind == nkSym)
-    sym = n.sons[0].sym
+    let sym = n.sons[0].sym
     assert(sym.loc.k == locOther)
     idx = sym.loc.a
   else:
@@ -671,73 +574,47 @@ proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) =
     if idx < 0 or not p.blocks[idx].isLoop:
       InternalError(n.info, "no loop to break")
   p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
-  appf(r.com, "break L$1;$n", [toRope(p.blocks[idx].id)])
+  appf(p.body, "break L$1;$n", [toRope(p.blocks[idx].id)])
 
-proc genAsmStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  genLineDir(p, n, r)
+proc genAsmStmt(p: PProc, n: PNode) = 
+  genLineDir(p, n)
   assert(n.kind == nkAsmStmt)
   for i in countup(0, sonsLen(n) - 1): 
     case n.sons[i].Kind
-    of nkStrLit..nkTripleStrLit: app(r.com, n.sons[i].strVal)
-    of nkSym: app(r.com, mangleName(n.sons[i].sym))
+    of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal)
+    of nkSym: app(p.body, mangleName(n.sons[i].sym))
     else: InternalError(n.sons[i].info, "jsgen: genAsmStmt()")
   
-proc genIfStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    toClose: int
-    cond, stmt: TCompRes
-    it: PNode
-  toClose = 0
+proc genIf(p: PProc, n: PNode, r: var TCompRes) = 
+  var cond, stmt: TCompRes
+  var toClose = 0
+  if not isEmptyType(n.typ):
+    r.kind = resVal
+    r.res = getTemp(p)
   for i in countup(0, sonsLen(n) - 1): 
-    it = n.sons[i]
+    let it = n.sons[i]
     if sonsLen(it) != 1: 
+      if i > 0:
+        appf(p.body, "else {$n", [])
+        inc(toClose)
       gen(p, it.sons[0], cond)
+      appf(p.body, "if ($1) {$n", cond.rdLoc)
       genStmt(p, it.sons[1], stmt)
-      if i > 0: 
-        appf(r.com, "else {$n", [])
-        inc(toClose)
-      if cond.com != nil: appf(r.com, "$1;$n", [cond.com])
-      appf(r.com, "if ($1) {$n$2}", [cond.res, mergeStmt(stmt)])
-    else: 
+    else:
       # else part:
+      appf(p.body, "else {$n")
       genStmt(p, it.sons[0], stmt)
-      appf(r.com, "else {$n$1}$n", [mergeStmt(stmt)])
-  app(r.com, repeatChar(toClose, '}') & tnl)
-
-proc genIfExpr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    toClose: int
-    cond, stmt: TCompRes
-    it: PNode
-  toClose = 0
-  for i in countup(0, sonsLen(n) - 1): 
-    it = n.sons[i]
-    if sonsLen(it) != 1: 
-      gen(p, it.sons[0], cond)
-      gen(p, it.sons[1], stmt)
-      if i > 0: 
-        app(r.res, ": (")
-        inc(toClose)
-      r.com = mergeExpr(r.com, cond.com)
-      r.com = mergeExpr(r.com, stmt.com)
-      appf(r.res, "($1) ? ($2)", [cond.res, stmt.res])
-    else: 
-      # else part:
-      gen(p, it.sons[0], stmt)
-      r.com = mergeExpr(r.com, stmt.com)
-      appf(r.res, ": ($1)", [stmt.res])
-  app(r.res, repeatChar(toClose, ')'))
+    moveInto(p, stmt, r)
+    appf(p.body, "}$n")
+  app(p.body, repeatChar(toClose, '}') & tnl)
 
-proc generateHeader(p: var TProc, typ: PType): PRope = 
-  var 
-    param: PSym
-    name: PRope
+proc generateHeader(p: PProc, typ: PType): PRope =
   result = nil
   for i in countup(1, sonsLen(typ.n) - 1): 
     if result != nil: app(result, ", ")
     assert(typ.n.sons[i].kind == nkSym)
-    param = typ.n.sons[i].sym
-    name = mangleName(param)
+    var param = typ.n.sons[i].sym
+    var name = mangleName(param)
     app(result, name)
     if mapType(param.typ) == etyBaseIndex: 
       app(result, ", ")
@@ -754,56 +631,49 @@ proc needsNoCopy(y: PNode): bool =
   result = (y.kind in nodeKindsNeedNoCopy) or
       (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyVar})
 
-proc genAsgnAux(p: var TProc, x, y: PNode, r: var TCompRes, 
-                noCopyNeeded: bool) = 
+proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
   var a, b: TCompRes
   gen(p, x, a)
   gen(p, y, b)
   case mapType(x.typ)
-  of etyObject: 
-    if a.com != nil: appf(r.com, "$1;$n", [a.com])
-    if b.com != nil: appf(r.com, "$1;$n", [b.com])
-    if needsNoCopy(y) or noCopyNeeded: 
-      appf(r.com, "$1 = $2;$n", [a.res, b.res])
-    else: 
+  of etyObject:
+    if needsNoCopy(y) or noCopyNeeded:
+      appf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
+    else:
       useMagic(p, "NimCopy")
-      appf(r.com, "$1 = NimCopy($2, $3);$n", 
+      appf(p.body, "$1 = NimCopy($2, $3);$n",
            [a.res, b.res, genTypeInfo(p, y.typ)])
   of etyBaseIndex: 
-    if (a.kind != etyBaseIndex) or (b.kind != etyBaseIndex): 
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex: 
       internalError(x.info, "genAsgn")
-    appf(r.com, "$1 = $2; $3 = $4;$n", [a.com, b.com, a.res, b.res])
-  else: 
-    if a.com != nil: appf(r.com, "$1;$n", [a.com])
-    if b.com != nil: appf(r.com, "$1;$n", [b.com])
-    appf(r.com, "$1 = $2;$n", [a.res, b.res])
+    appf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
+  else:
+    appf(p.body, "$1 = $2;$n", [a.res, b.res])
 
-proc genAsgn(p: var TProc, n: PNode, r: var TCompRes) = 
-  genLineDir(p, n, r)
-  genAsgnAux(p, n.sons[0], n.sons[1], r, false)
+proc genAsgn(p: PProc, n: PNode) = 
+  genLineDir(p, n)
+  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
 
-proc genFastAsgn(p: var TProc, n: PNode, r: var TCompRes) = 
-  genLineDir(p, n, r)
-  genAsgnAux(p, n.sons[0], n.sons[1], r, true)
+proc genFastAsgn(p: PProc, n: PNode) = 
+  genLineDir(p, n)
+  genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true)
 
-proc genSwap(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genSwap(p: PProc, n: PNode) = 
   var a, b: TCompRes
   gen(p, n.sons[1], a)
   gen(p, n.sons[2], b)
   inc(p.unique)
-  var tmp = ropef("Tmp$1", [toRope(p.unique)])
+  let tmp = ropef("Tmp$1", [toRope(p.unique)])
   case mapType(skipTypes(n.sons[1].typ, abstractVar))
   of etyBaseIndex: 
     inc(p.unique)
-    var tmp2 = ropef("Tmp$1", [toRope(p.unique)])
-    if (a.kind != etyBaseIndex) or (b.kind != etyBaseIndex): 
+    let tmp2 = ropef("Tmp$1", [toRope(p.unique)])
+    if a.typ != etyBaseIndex or b.typ != etyBaseIndex: 
       internalError(n.info, "genSwap")
-    appf(r.com, "var $1 = $2; $2 = $3; $3 = $1;$n", [tmp, a.com, b.com])
-    appf(r.com, "var $1 = $2; $2 = $3; $3 = $1", [tmp2, a.res, b.res])
-  else: 
-    if a.com != nil: appf(r.com, "$1;$n", [a.com])
-    if b.com != nil: appf(r.com, "$1;$n", [b.com])
-    appf(r.com, "var $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res])
+    appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n", [tmp, a.address, b.address])
+    appf(p.body, "var $1 = $2; $2 = $3; $3 = $1", [tmp2, a.res, b.res])
+  else:
+    appf(p.body, "var $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res])
 
 proc getFieldPosition(f: PNode): int =
   case f.kind
@@ -811,10 +681,10 @@ proc getFieldPosition(f: PNode): int =
   of nkSym: result = f.sym.position
   else: InternalError(f.info, "genFieldPosition")
 
-proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = 
   var a: TCompRes
-  r.kind = etyBaseIndex
-  var b = if n.kind == nkHiddenAddr: n.sons[0] else: n
+  r.typ = etyBaseIndex
+  let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
   gen(p, b.sons[0], a)
   if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
     r.res = makeJSString("Field" & $getFieldPosition(b.sons[1]))
@@ -823,10 +693,12 @@ proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) =
     var f = b.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(f)
     r.res = makeJSString(ropeToStr(f.loc.r))
-  r.com = mergeExpr(a)
+  InternalAssert a.typ != etyBaseIndex
+  r.address = a.res
+  r.kind = resExpr
 
-proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = 
-  r.kind = etyNone
+proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = 
+  r.typ = etyNone
   gen(p, n.sons[0], r)
   if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
     r.res = ropef("$1.Field$2", [r.res, getFieldPosition(n.sons[1]).toRope])
@@ -835,34 +707,37 @@ proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) =
     var f = n.sons[1].sym
     if f.loc.r == nil: f.loc.r = mangleName(f)
     r.res = ropef("$1.$2", [r.res, f.loc.r])
+  r.kind = resExpr
 
-proc genCheckedFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) = 
   genFieldAddr(p, n.sons[0], r) # XXX
   
-proc genCheckedFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) = 
   genFieldAccess(p, n.sons[0], r) # XXX
   
-proc genArrayAddr(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = 
   var 
     a, b: TCompRes
     first: biggestInt
-  r.kind = etyBaseIndex
+  r.typ = etyBaseIndex
   gen(p, n.sons[0], a)
   gen(p, n.sons[1], b)
-  r.com = mergeExpr(a)
+  InternalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex
+  r.address = a.res
   var typ = skipTypes(n.sons[0].typ, abstractPtrs)
   if typ.kind in {tyArray, tyArrayConstr}: first = FirstOrd(typ.sons[0])
   else: first = 0
   if optBoundsCheck in p.options and not isConstExpr(n.sons[1]): 
     useMagic(p, "chckIndx")
-    b.res = ropef("chckIndx($1, $2, $3.length)-$2", 
-                  [b.res, toRope(first), a.res]) 
-    # XXX: BUG: a.res evaluated twice!
-  elif first != 0: 
-    b.res = ropef("($1)-$2", [b.res, toRope(first)])
-  r.res = mergeExpr(b)
-
-proc genArrayAccess(p: var TProc, n: PNode, r: var TCompRes) = 
+    r.res = ropef("chckIndx($1, $2, $3.length)-$2", 
+                  [b.res, toRope(first), a.res])
+  elif first != 0:
+    r.res = ropef("($1)-$2", [b.res, toRope(first)])
+  else:
+    r.res = b.res
+  r.kind = resExpr
+
+proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = 
   var ty = skipTypes(n.sons[0].typ, abstractVarRange)
   if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange)
   case ty.kind
@@ -872,38 +747,40 @@ proc genArrayAccess(p: var TProc, n: PNode, r: var TCompRes) =
   of tyTuple: 
     genFieldAddr(p, n, r)
   else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
-  r.kind = etyNone
-  r.res = ropef("$1[$2]", [r.com, r.res])
-  r.com = nil
+  r.typ = etyNone
+  if r.res == nil: InternalError(n.info, "genArrayAccess")
+  r.res = ropef("$1[$2]", [r.address, r.res])
+  r.address = nil
+  r.kind = resExpr
 
-proc genAddr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var s: PSym
+proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
   case n.sons[0].kind
-  of nkSym: 
-    s = n.sons[0].sym
+  of nkSym:
+    let s = n.sons[0].sym
     if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
     case s.kind
-    of skVar, skLet, skResult: 
-      if mapType(n.typ) == etyObject: 
+    of skVar, skLet, skResult:
+      r.kind = resExpr
+      if mapType(n.typ) == etyObject:
         # make addr() a no-op:
-        r.kind = etyNone
+        r.typ = etyNone
         r.res = s.loc.r
-        r.com = nil
-      elif sfGlobal in s.flags: 
+        r.address = nil
+      elif sfGlobal in s.flags:
         # globals are always indirect accessible
-        r.kind = etyBaseIndex
-        r.com = toRope("Globals")
+        r.typ = etyBaseIndex
+        r.address = toRope("Globals")
         r.res = makeJSString(ropeToStr(s.loc.r))
-      elif sfAddrTaken in s.flags: 
-        r.kind = etyBaseIndex
-        r.com = s.loc.r
+      elif sfAddrTaken in s.flags:
+        r.typ = etyBaseIndex
+        r.address = s.loc.r
         r.res = toRope("0")
-      else: 
+      else:
         InternalError(n.info, "genAddr: 4")
     else: InternalError(n.info, "genAddr: 2")
-  of nkCheckedFieldExpr: 
+  of nkCheckedFieldExpr:
     genCheckedFieldAddr(p, n, r)
-  of nkDotExpr: 
+  of nkDotExpr:
     genFieldAddr(p, n, r)
   of nkBracketExpr:
     var ty = skipTypes(n.sons[0].typ, abstractVarRange)
@@ -917,27 +794,27 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) =
     else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
   else: InternalError(n.info, "genAddr")
   
-proc genSym(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genSym(p: PProc, n: PNode, r: var TCompRes) = 
   var s = n.sym
   case s.kind
-  of skVar, skLet, skParam, skTemp, skResult: 
-    if s.loc.r == nil: 
+  of skVar, skLet, skParam, skTemp, skResult:
+    if s.loc.r == nil:
       InternalError(n.info, "symbol has no generated name: " & s.name.s)
     var k = mapType(s.typ)
-    if k == etyBaseIndex: 
-      r.kind = etyBaseIndex
-      if {sfAddrTaken, sfGlobal} * s.flags != {}: 
-        r.com = ropef("$1[0]", [s.loc.r])
+    if k == etyBaseIndex:
+      r.typ = etyBaseIndex
+      if {sfAddrTaken, sfGlobal} * s.flags != {}:
+        r.address = ropef("$1[0]", [s.loc.r])
         r.res = ropef("$1[1]", [s.loc.r])
-      else: 
-        r.com = s.loc.r
+      else:
+        r.address = s.loc.r
         r.res = con(s.loc.r, "_Idx")
-    elif (k != etyObject) and (sfAddrTaken in s.flags): 
+    elif k != etyObject and sfAddrTaken in s.flags:
       r.res = ropef("$1[0]", [s.loc.r])
-    else: 
+    else:
       r.res = s.loc.r
   of skConst:
-    genConstant(p, s, r)
+    genConstant(p, s)
     if s.loc.r == nil:
       InternalError(n.info, "symbol has no generated name: " & s.name.s)
     r.res = s.loc.r
@@ -953,64 +830,70 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
     elif sfForward in s.flags:
       p.g.forwarded.add(s)
     elif not p.g.generatedSyms.containsOrIncl(s.id):
-      var r2: TCompRes
-      genProc(p, s, r2)
-      app(p.locals, mergeStmt(r2))
-      #app(r.com, mergeStmt(r2))
+      let newp = genProc(p, s)
+      var owner = p
+      while owner != nil and owner.prc != s.owner:
+        owner = owner.up
+      if owner != nil: app(owner.locals, newp)
+      else: app(p.g.code, newp)
   else:
     if s.loc.r == nil:
       InternalError(n.info, "symbol has no generated name: " & s.name.s)
     r.res = s.loc.r
+  r.kind = resVal
   
-proc genDeref(p: var TProc, n: PNode, r: var TCompRes) = 
-  var a: TCompRes
+proc genDeref(p: PProc, n: PNode, r: var TCompRes) = 
   if mapType(n.sons[0].typ) == etyObject: 
     gen(p, n.sons[0], r)
-  else: 
+  else:
+    var a: TCompRes
     gen(p, n.sons[0], a)
-    if a.kind != etyBaseIndex: InternalError(n.info, "genDeref")
-    r.res = ropef("$1[$2]", [a.com, a.res])
+    if a.typ != etyBaseIndex: InternalError(n.info, "genDeref")
+    r.res = ropef("$1[$2]", [a.address, a.res])
 
-proc genArg(p: var TProc, n: PNode, r: var TCompRes) =
+proc genArg(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
   gen(p, n, a)
-  if a.kind == etyBaseIndex: 
-    app(r.res, a.com)
+  if a.typ == etyBaseIndex:
+    app(r.res, a.address)
     app(r.res, ", ")
     app(r.res, a.res)
   else:
-    app(r.res, mergeExpr(a))
+    app(r.res, a.res)
 
-proc genArgs(p: var TProc, n: PNode, r: var TCompRes) =
+proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
   app(r.res, "(")
   for i in countup(1, sonsLen(n) - 1): 
     if i > 1: app(r.res, ", ")
     genArg(p, n.sons[i], r)
   app(r.res, ")")
+  r.kind = resExpr
 
-proc genCall(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genCall(p: PProc, n: PNode, r: var TCompRes) = 
   gen(p, n.sons[0], r)
   genArgs(p, n, r)
 
-proc genInfixCall(p: var TProc, n: PNode, r: var TCompRes) =
+proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
   gen(p, n.sons[1], r)
-  if r.kind == etyBaseIndex:
-    if r.com == nil:
+  if r.typ == etyBaseIndex:
+    if r.address == nil:
       GlobalError(n.info, "cannot invoke with infix syntax")
-    r.res = ropef("$1[0]", [r.res, r.com])
-    r.com = nil
+    r.res = ropef("$1[$2]", [r.address, r.res])
+    r.address = nil
+    r.typ = etyNone
   app(r.res, ".")
   var op: TCompRes
   gen(p, n.sons[0], op)
-  app(r.res, mergeExpr(op))
+  app(r.res, op.res)
   
   app(r.res, "(")
   for i in countup(2, sonsLen(n) - 1):
     if i > 2: app(r.res, ", ")
     genArg(p, n.sons[i], r)
   app(r.res, ")")
+  r.kind = resExpr
 
-proc genEcho(p: var TProc, n: PNode, r: var TCompRes) =
+proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
   useMagic(p, "rawEcho")
   app(r.res, "rawEcho")
   genArgs(p, n, r)
@@ -1019,8 +902,8 @@ proc putToSeq(s: string, indirect: bool): PRope =
   result = toRope(s)
   if indirect: result = ropef("[$1]", [result])
   
-proc createVar(p: var TProc, typ: PType, indirect: bool): PRope
-proc createRecordVarAux(p: var TProc, rec: PNode, c: var int): PRope = 
+proc createVar(p: PProc, typ: PType, indirect: bool): PRope
+proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope = 
   result = nil
   case rec.kind
   of nkRecList: 
@@ -1038,7 +921,7 @@ proc createRecordVarAux(p: var TProc, rec: PNode, c: var int): PRope =
     inc(c)
   else: InternalError(rec.info, "createRecordVarAux")
   
-proc createVar(p: var TProc, typ: PType, indirect: bool): PRope = 
+proc createVar(p: PProc, typ: PType, indirect: bool): PRope = 
   var t = skipTypes(typ, abstractInst)
   case t.kind
   of tyInt..tyInt64, tyEnum, tyChar: 
@@ -1075,7 +958,7 @@ proc createVar(p: var TProc, typ: PType, indirect: bool): PRope =
   of tyObject: 
     result = toRope("{")
     var c = 0
-    if not (tfFinal in t.flags) or (t.sons[0] != nil): 
+    if tfFinal notin t.flags or t.sons[0] != nil:
       inc(c)
       appf(result, "m_type: $1", [genTypeInfo(p, t)])
     while t != nil: 
@@ -1095,38 +978,37 @@ proc isIndirect(v: PSym): bool =
   result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and
     v.kind notin {skProc, skConverter, skMethod, skIterator}
 
-proc genVarInit(p: var TProc, v: PSym, n: PNode, r: var TCompRes) = 
+proc genVarInit(p: PProc, v: PSym, n: PNode) = 
   var 
     a: TCompRes
     s: PRope
   if n.kind == nkEmpty: 
-    appf(r.com, "var $1 = $2;$n", 
+    appf(p.body, "var $1 = $2;$n", 
          [mangleName(v), createVar(p, v.typ, isIndirect(v))])
   else: 
     discard mangleName(v)
     gen(p, n, a)
     case mapType(v.typ)
     of etyObject: 
-      if a.com != nil: appf(r.com, "$1;$n", [a.com])
       if needsNoCopy(n): 
         s = a.res
       else: 
         useMagic(p, "NimCopy")
         s = ropef("NimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)])
     of etyBaseIndex: 
-      if (a.kind != etyBaseIndex): InternalError(n.info, "genVarInit")
+      if (a.typ != etyBaseIndex): InternalError(n.info, "genVarInit")
       if {sfAddrTaken, sfGlobal} * v.flags != {}: 
-        appf(r.com, "var $1 = [$2, $3];$n", [v.loc.r, a.com, a.res])
+        appf(p.body, "var $1 = [$2, $3];$n", [v.loc.r, a.address, a.res])
       else: 
-        appf(r.com, "var $1 = $2; var $1_Idx = $3;$n", [v.loc.r, a.com, a.res])
-      return 
-    else: 
-      if a.com != nil: appf(r.com, "$1;$n", [a.com])
+        appf(p.body, "var $1 = $2; var $1_Idx = $3;$n", [
+             v.loc.r, a.address, a.res])
+      return
+    else:
       s = a.res
-    if isIndirect(v): appf(r.com, "var $1 = [$2];$n", [v.loc.r, s])
-    else: appf(r.com, "var $1 = $2;$n", [v.loc.r, s])
+    if isIndirect(v): appf(p.body, "var $1 = [$2];$n", [v.loc.r, s])
+    else: appf(p.body, "var $1 = $2;$n", [v.loc.r, s])
   
-proc genVarStmt(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genVarStmt(p: PProc, n: PNode) = 
   for i in countup(0, sonsLen(n) - 1): 
     var a = n.sons[i]
     if a.kind == nkCommentStmt: continue 
@@ -1134,56 +1016,43 @@ proc genVarStmt(p: var TProc, n: PNode, r: var TCompRes) =
     assert(a.sons[0].kind == nkSym)
     var v = a.sons[0].sym
     if lfNoDecl in v.loc.flags: continue 
-    genLineDir(p, a, r)
-    genVarInit(p, v, a.sons[2], r)
+    genLineDir(p, a)
+    genVarInit(p, v, a.sons[2])
 
-proc genConstant(p: var TProc, c: PSym, r: var TCompRes) =
+proc genConstant(p: PProc, c: PSym) =
   if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id):
-    genLineDir(p, c.ast, r)
-    genVarInit(p, c, c.ast, r)
-    app(p.g.code, r.com)
-    r.com = nil
-
-when false:
-  proc genConstStmt(p: var TProc, n: PNode, r: var TCompRes) =
-    genLineDir(p, n, r)
-    for i in countup(0, sonsLen(n) - 1):
-      if n.sons[i].kind == nkCommentStmt: continue
-      assert(n.sons[i].kind == nkConstDef)
-      var c = n.sons[i].sons[0].sym
-      if c.ast != nil and c.typ.kind in ConstantDataTypes and
-          lfNoDecl notin c.loc.flags:
-        genLineDir(p, n.sons[i], r)
-        genVarInit(p, c, c.ast, r)
-
-proc genNew(p: var TProc, n: PNode, r: var TCompRes) =
+    let oldBody = p.body
+    p.body = nil
+    genLineDir(p, c.ast)
+    genVarInit(p, c, c.ast)
+    app(p.g.code, p.body)
+    p.body = oldBody
+
+proc genNew(p: PProc, n: PNode) =
   var a: TCompRes
   gen(p, n.sons[1], a)
   var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  if a.com != nil: appf(r.com, "$1;$n", [a.com])
-  appf(r.com, "$1 = $2;$n", [a.res, createVar(p, t, true)])
+  appf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, true)])
 
-proc genNewSeq(p: var TProc, n: PNode, r: var TCompRes) =
+proc genNewSeq(p: PProc, n: PNode) =
   var x, y: TCompRes
   gen(p, n.sons[1], x)
   gen(p, n.sons[2], y)
-  if x.com != nil: appf(r.com, "$1;$n", [x.com])
-  if y.com != nil: appf(r.com, "$1;$n", [y.com])
-  var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
-  appf(r.com, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
-    x.res, y.res, createVar(p, t, false)])
+  let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
+  appf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
+    x.rdLoc, y.rdLoc, createVar(p, t, false)])
 
-proc genOrd(p: var TProc, n: PNode, r: var TCompRes) =
+proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
   case skipTypes(n.sons[1].typ, abstractVar).kind
   of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r)
   of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)")
   else: InternalError(n.info, "genOrd")
   
-proc genConStrStr(p: var TProc, n: PNode, r: var TCompRes) =
+proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
   var a: TCompRes
 
   gen(p, n.sons[1], a)
-  r.com = mergeExpr(r.com, a.com)
+  r.kind = resExpr
   if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar:
     r.res.app(ropef("[$1].concat(", [a.res]))
   else:
@@ -1191,21 +1060,18 @@ proc genConStrStr(p: var TProc, n: PNode, r: var TCompRes) =
 
   for i in countup(2, sonsLen(n) - 2):
     gen(p, n.sons[i], a)
-    r.com = mergeExpr(r.com, a.com)
-
     if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar:
       r.res.app(ropef("[$1],", [a.res]))
     else:
       r.res.app(ropef("$1.slice(0,-1),", [a.res]))
 
   gen(p, n.sons[sonsLen(n) - 1], a)
-  r.com = mergeExpr(r.com, a.com)
   if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar:
     r.res.app(ropef("[$1, 0])", [a.res]))
   else:
     r.res.app(ropef("$1)", [a.res]))
 
-proc genRepr(p: var TProc, n: PNode, r: var TCompRes) =
+proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
   var t = skipTypes(n.sons[1].typ, abstractVarRange)
   case t.kind
   of tyInt..tyUInt64:
@@ -1213,13 +1079,14 @@ proc genRepr(p: var TProc, n: PNode, r: var TCompRes) =
   of tyEnum, tyOrdinal:
     gen(p, n.sons[1], r)
     useMagic(p, "cstrToNimstr")
+    r.kind = resExpr
     r.res = ropef("cstrToNimstr($1.node.sons[$2].name)", 
                  [genTypeInfo(p, t), r.res])
   else:
     # XXX:
     internalError(n.info, "genRepr: Not implemented")
 
-proc genOf(p: var TProc, n: PNode, r: var TCompRes) =
+proc genOf(p: PProc, n: PNode, r: var TCompRes) =
   var x: TCompRes
   let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr, tyTypeDesc})
   gen(p, n.sons[1], x)
@@ -1228,17 +1095,16 @@ proc genOf(p: var TProc, n: PNode, r: var TCompRes) =
   else:
     useMagic(p, "isObj")
     r.res = ropef("isObj($1.m_type, $2)", [x.res, genTypeInfo(p, t)])
-  r.com = mergeExpr(r.com, x.com)
+  r.kind = resExpr
 
-proc genReset(p: var TProc, n: PNode, r: var TCompRes) =
+proc genReset(p: PProc, n: PNode) =
   var x: TCompRes
   useMagic(p, "genericReset")
   gen(p, n.sons[1], x)
-  r.res = ropef("$1 = genericReset($1, $2)", [x.res, 
+  appf(p.body, "$1 = genericReset($1, $2);$n", [x.res, 
                 genTypeInfo(p, n.sons[1].typ)])
-  r.com = mergeExpr(r.com, x.com)
 
-proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
+proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
   var 
     a: TCompRes
     line, filen: PRope
@@ -1248,7 +1114,7 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
   of mAnd: genAnd(p, n.sons[1], n.sons[2], r)
   of mAddi..mStrToStr: arith(p, n, r, op)
   of mRepr: genRepr(p, n, r)
-  of mSwap: genSwap(p, n, r)
+  of mSwap: genSwap(p, n)
   of mUnaryLt:
     # XXX: range checking?
     if not (optOverflowCheck in p.Options): unaryExpr(p, n, r, "", "$1 - 1")
@@ -1261,21 +1127,21 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
     # XXX: range checking?
     if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 - $2")
     else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)")
-  of mAppendStrCh: binaryStmt(p, n, r, "addChar", "$1 = addChar($1, $2)")
+  of mAppendStrCh: binaryExpr(p, n, r, "addChar", "$1 = addChar($1, $2)")
   of mAppendStrStr:
     if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
-        binaryStmt(p, n, r, "", "$1 += $2")
+        binaryExpr(p, n, r, "", "$1 += $2")
     else:
-      binaryStmt(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)")
+      binaryExpr(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)")
     # XXX: make a copy of $2, because of Javascript's sucking semantics
-  of mAppendSeqElem: binaryStmt(p, n, r, "", "$1.push($2)")
+  of mAppendSeqElem: binaryExpr(p, n, r, "", "$1.push($2)")
   of mConStrStr: genConStrStr(p, n, r)
   of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)")
   of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)")
   of mLtStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)")
   of mIsNil: unaryExpr(p, n, r, "", "$1 == null")
   of mEnumToStr: genRepr(p, n, r)
-  of mNew, mNewFinalize: genNew(p, n, r)
+  of mNew, mNewFinalize: genNew(p, n)
   of mSizeOf: r.res = toRope(getSize(n.sons[1].typ))
   of mChr, mArrToSeq: gen(p, n.sons[1], r)      # nothing to do
   of mOrd: genOrd(p, n, r)
@@ -1288,13 +1154,13 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
     else:
       unaryExpr(p, n, r, "", "($1.length-1)")
   of mInc:
-    if not (optOverflowCheck in p.Options): binaryStmt(p, n, r, "", "$1 += $2")
-    else: binaryStmt(p, n, r, "addInt", "$1 = addInt($1, $2)")
+    if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 += $2")
+    else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)")
   of ast.mDec:
-    if not (optOverflowCheck in p.Options): binaryStmt(p, n, r, "", "$1 -= $2")
-    else: binaryStmt(p, n, r, "subInt", "$1 = subInt($1, $2)")
-  of mSetLengthStr: binaryStmt(p, n, r, "", "$1.length = ($2)-1")
-  of mSetLengthSeq: binaryStmt(p, n, r, "", "$1.length = $2")
+    if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 -= $2")
+    else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)")
+  of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = ($2)-1")
+  of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2")
   of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)")
   of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)")
   of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)")
@@ -1302,14 +1168,14 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
   of mMulSet: binaryExpr(p, n, r, "SetMul", "SetMul($1, $2)")
   of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)")
   of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)")
-  of mIncl: binaryStmt(p, n, r, "", "$1[$2] = true")
-  of mExcl: binaryStmt(p, n, r, "", "delete $1[$2]")
+  of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true")
+  of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]")
   of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)")
   of mNLen..mNError:
     localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s)
-  of mNewSeq: genNewSeq(p, n, r)
+  of mNewSeq: genNewSeq(p, n)
   of mOf: genOf(p, n, r)
-  of mReset: genReset(p, n, r)
+  of mReset: genReset(p, n)
   of mEcho: genEcho(p, n, r)
   of mSlurp, mStaticExec:
     localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
@@ -1317,94 +1183,95 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
     genCall(p, n, r)
     #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
   
-proc genSetConstr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
+proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = 
+  var
     a, b: TCompRes
   useMagic(p, "SetConstr")
   r.res = toRope("SetConstr(")
+  r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1): 
     if i > 0: app(r.res, ", ")
     var it = n.sons[i]
     if it.kind == nkRange: 
       gen(p, it.sons[0], a)
       gen(p, it.sons[1], b)
-      r.com = mergeExpr(r.com, mergeExpr(a.com, b.com))
       appf(r.res, "[$1, $2]", [a.res, b.res])
     else: 
       gen(p, it, a)
-      r.com = mergeExpr(r.com, a.com)
       app(r.res, a.res)
   app(r.res, ")")
 
-proc genArrayConstr(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = 
   var a: TCompRes
   r.res = toRope("[")
+  r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1): 
     if i > 0: app(r.res, ", ")
     gen(p, n.sons[i], a)
-    r.com = mergeExpr(r.com, a.com)
     app(r.res, a.res)
   app(r.res, "]")
 
-proc genTupleConstr(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) = 
   var a: TCompRes
   r.res = toRope("{")
+  r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1):
     if i > 0: app(r.res, ", ")
     var it = n.sons[i]
     if it.kind == nkExprColonExpr: it = it.sons[1]
     gen(p, it, a)
-    r.com = mergeExpr(r.com, a.com)
     appf(r.res, "Field$1: $2", [i.toRope, a.res])
   r.res.app("}")
 
-proc genObjConstr(p: var TProc, n: PNode, r: var TCompRes) =
+proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
   # XXX inheritance?
   var a: TCompRes
   r.res = toRope("{")
+  r.kind = resExpr
   for i in countup(0, sonsLen(n) - 1):
     if i > 0: app(r.res, ", ")
     var it = n.sons[i]
     InternalAssert it.kind == nkExprColonExpr
     gen(p, it.sons[1], a)
-    r.com = mergeExpr(r.com, a.com)
     var f = it.sons[0].sym
     if f.loc.r == nil: f.loc.r = mangleName(f)
     appf(r.res, "$1: $2", [f.loc.r, a.res])
   r.res.app("}")
 
-proc genConv(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genConv(p: PProc, n: PNode, r: var TCompRes) = 
   var dest = skipTypes(n.typ, abstractVarRange)
   var src = skipTypes(n.sons[1].typ, abstractVarRange)
   gen(p, n.sons[1], r)
   if (dest.kind != src.kind) and (src.kind == tyBool): 
     r.res = ropef("(($1)? 1:0)", [r.res])
+    r.kind = resExpr
   
-proc upConv(p: var TProc, n: PNode, r: var TCompRes) = 
+proc upConv(p: PProc, n: PNode, r: var TCompRes) = 
   gen(p, n.sons[0], r)        # XXX
   
-proc genRangeChck(p: var TProc, n: PNode, r: var TCompRes, magic: string) = 
+proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = 
   var a, b: TCompRes
   gen(p, n.sons[0], r)
   if optRangeCheck in p.options: 
     gen(p, n.sons[1], a)
     gen(p, n.sons[2], b)
-    r.com = mergeExpr(r.com, mergeExpr(a.com, b.com))
     useMagic(p, "chckRange")
     r.res = ropef("chckRange($1, $2, $3)", [r.res, a.res, b.res])
+    r.kind = resExpr
 
-proc convStrToCStr(p: var TProc, n: PNode, r: var TCompRes) = 
+proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) = 
   # we do an optimization here as this is likely to slow down
   # much of the code otherwise:
   if n.sons[0].kind == nkCStringToString: 
     gen(p, n.sons[0].sons[0], r)
-  else: 
+  else:
     gen(p, n.sons[0], r)
     if r.res == nil: InternalError(n.info, "convStrToCStr")
     useMagic(p, "toJSStr")
     r.res = ropef("toJSStr($1)", [r.res])
+    r.kind = resExpr
 
-proc convCStrToStr(p: var TProc, n: PNode, r: var TCompRes) = 
+proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) = 
   # we do an optimization here as this is likely to slow down
   # much of the code otherwise:
   if n.sons[0].kind == nkStringToCString: 
@@ -1414,44 +1281,45 @@ proc convCStrToStr(p: var TProc, n: PNode, r: var TCompRes) =
     if r.res == nil: InternalError(n.info, "convCStrToStr")
     useMagic(p, "cstrToNimstr")
     r.res = ropef("cstrToNimstr($1)", [r.res])
+    r.kind = resExpr
 
-proc genReturnStmt(p: var TProc, n: PNode, r: var TCompRes) = 
+proc genReturnStmt(p: PProc, n: PNode) = 
   var a: TCompRes
   if p.procDef == nil: InternalError(n.info, "genReturnStmt")
   p.BeforeRetNeeded = true
   if (n.sons[0].kind != nkEmpty): 
     genStmt(p, n.sons[0], a)
-    if a.com != nil: appf(r.com, "$1;$n", mergeStmt(a))
   else: 
-    genLineDir(p, n, r)
-  app(r.com, "break BeforeRet;" & tnl)
+    genLineDir(p, n)
+  app(p.body, "break BeforeRet;" & tnl)
 
-proc genProcBody(p: var TProc, prc: PSym, r: TCompRes): PRope = 
-  if optStackTrace in prc.options: 
+proc genProcBody(p: PProc, prc: PSym): PRope = 
+  if optStackTrace in prc.options:
     result = ropef("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" &
         "framePtr = F;$n", [makeJSString(prc.owner.name.s & '.' & prc.name.s), 
                             makeJSString(toFilename(prc.info))])
-  else: 
+  else:
     result = nil
-  if p.beforeRetNeeded: 
-    appf(result, "BeforeRet: do {$n$1} while (false); $n", [mergeStmt(r)])
+  if p.beforeRetNeeded:
+    appf(result, "BeforeRet: do {$n$1} while (false); $n", [p.body])
   else: 
-    app(result, mergeStmt(r))
+    app(result, p.body)
   if prc.typ.callConv == ccSysCall: 
     result = ropef("try {$n$1} catch (e) {$n" &
         " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}", [result])
   if optStackTrace in prc.options: 
     app(result, "framePtr = framePtr.prev;" & tnl)
 
-proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) = 
-  var 
-    p: TProc
+proc genProc(oldProc: PProc, prc: PSym): PRope = 
+  var
     resultSym: PSym
     name, returnStmt, resultAsgn, header: PRope
-    a: TCompRes
+    a, r: TCompRes
   #if gVerbosity >= 3: 
   #  echo "BEGIN generating code for: " & prc.name.s
-  initProc(p, oldProc.g, oldProc.module, prc.ast, prc.options)
+  var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
+  p.target = oldProc.target
+  p.up = oldProc
   returnStmt = nil
   resultAsgn = nil
   name = mangleName(prc)
@@ -1461,112 +1329,57 @@ proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) =
     resultAsgn = ropef("var $# = $#;$n", [mangleName(resultSym), 
         createVar(p, resultSym.typ, isIndirect(resultSym))])
     gen(p, prc.ast.sons[resultPos], a)
-    if a.com != nil: appf(returnStmt, "$1;$n", [a.com])
     returnStmt = ropef("return $#;$n", [a.res])
   genStmt(p, prc.getBody, r)
-  r.com = ropef("function $#($#) {$n$#$#$#$#}$n",
+  if r.res != nil: app(p.body, r.res)
+  result = ropef("function $#($#) {$n$#$#$#$#}$n",
                 [name, header, p.locals, resultAsgn, 
-                 genProcBody(p, prc, r), returnStmt])
-  r.res = nil  
+                 genProcBody(p, prc), returnStmt])
   #if gVerbosity >= 3:
   #  echo "END   generated code for: " & prc.name.s
   
-proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var a: TCompRes
-  # watch out this trick: ``function () { stmtList; return expr; }()``
-  r.res = toRope("function () {")
-  for i in countup(0, sonsLen(n) - 2): 
-    genStmt(p, n.sons[i], a)
-    app(r.res, mergeStmt(a))
-  gen(p, lastSon(n), a)
-  if a.com != nil: appf(r.res, "$1;$n", [a.com])
-  appf(r.res, "return $1; }()", [a.res])
-
-proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var a: TCompRes
-  r.kind = etyNone
-  r.com = nil
-  r.res = nil
-  case n.kind
-  of nkNilLit, nkEmpty: nil
-  of nkStmtList: 
-    for i in countup(0, sonsLen(n) - 1): 
-      genStmt(p, n.sons[i], a)
-      app(r.com, mergeStmt(a))
-  of nkBlockStmt: genBlock(p, n, r)
-  of nkIfStmt: genIfStmt(p, n, r)
-  of nkWhileStmt: genWhileStmt(p, n, r)
-  of nkVarSection, nkLetSection: genVarStmt(p, n, r)
-  of nkConstSection: nil
-  of nkForStmt, nkParForStmt: 
-    internalError(n.info, "for statement not eliminated")
-  of nkCaseStmt: genCaseStmt(p, n, r)
-  of nkReturnStmt: genReturnStmt(p, n, r)
-  of nkBreakStmt: genBreakStmt(p, n, r)
-  of nkAsgn: genAsgn(p, n, r)
-  of nkFastAsgn: genFastAsgn(p, n, r)
-  of nkDiscardStmt: 
-    if n.sons[0].kind != nkEmpty:
-      genLineDir(p, n, r)
-      gen(p, n.sons[0], r)
-      app(r.res, ';' & tnl)
-  of nkAsmStmt: genAsmStmt(p, n, r)
-  of nkTryStmt: genTryStmt(p, n, r)
-  of nkRaiseStmt: genRaiseStmt(p, n, r)
-  of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, 
-     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, 
-     nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil
-  of nkProcDef, nkMethodDef, nkConverterDef:
-    var s = n.sons[namePos].sym
-    if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
-      #var r2: TCompRes
-      genSym(p, n.sons[namePos], r)
-      r.res = nil
-  of nkGotoState, nkState:
-    internalError(n.info, "first class iterators not implemented")
-  else:
-    genLineDir(p, n, r)
-    gen(p, n, r)
-    app(r.res, ';' & tnl)
-
-proc gen(p: var TProc, n: PNode, r: var TCompRes) = 
-  var f: BiggestFloat
-  r.kind = etyNone
-  r.com = nil
+proc genStmt(p: PProc, n: PNode, r: var TCompRes) = 
+  gen(p, n, r)
+
+proc gen(p: PProc, n: PNode, r: var TCompRes) =
+  r.typ = etyNone
+  r.kind = resNone
+  #r.address = nil
   r.res = nil
   case n.kind
-  of nkSym: 
+  of nkSym:
     genSym(p, n, r)
-  of nkCharLit..nkInt64Lit: 
+  of nkCharLit..nkInt64Lit:
     r.res = toRope(n.intVal)
-  of nkNilLit: 
-    if mapType(n.typ) == etyBaseIndex: 
-      r.kind = etyBaseIndex
-      r.com = toRope"null"
+  of nkNilLit:
+    if isEmptyType(n.typ):
+      nil
+    elif mapType(n.typ) == etyBaseIndex:
+      r.typ = etyBaseIndex
+      r.address = toRope"null"
       r.res = toRope"0"
-    else: 
+    else:
       r.res = toRope"null"
-  of nkStrLit..nkTripleStrLit: 
+  of nkStrLit..nkTripleStrLit:
     if skipTypes(n.typ, abstractVarRange).kind == tyString: 
       useMagic(p, "cstrToNimstr")
       r.res = ropef("cstrToNimstr($1)", [makeJSString(n.strVal)])
     else: 
       r.res = makeJSString(n.strVal)
+    r.kind = resExpr
   of nkFloatLit..nkFloat64Lit: 
-    f = n.floatVal
+    let f = n.floatVal
     if f != f: r.res = toRope"NaN"
     elif f == 0.0: r.res = toRope"0.0"
     elif f == 0.5 * f: 
       if f > 0.0: r.res = toRope"Infinity"
       else: r.res = toRope"-Infinity"
     else: r.res = toRope(f.ToStrMaxPrecision)
-  of nkBlockExpr: genBlock(p, n, r)
-  of nkIfExpr: genIfExpr(p, n, r)
   of nkCallKinds:
     if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): 
       genMagic(p, n, r)
     elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
-      n.len >= 2:
+        n.len >= 2:
       genInfixCall(p, n, r)
     else: 
       genCall(p, n, r)
@@ -1588,7 +1401,6 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
   of nkChckRange: genRangeChck(p, n, r, "chckRange")
   of nkStringToCString: convStrToCStr(p, n, r)
   of nkCStringToString: convCStrToStr(p, n, r)
-  of nkStmtListExpr: genStmtListExpr(p, n, r)
   of nkEmpty: nil
   of nkLambdaKinds: 
     let s = n.sons[namePos].sym
@@ -1596,11 +1408,51 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
     r.res = s.loc.r
     if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s): nil
     elif not p.g.generatedSyms.containsOrIncl(s.id):
-      var r2: TCompRes
-      genProc(p, s, r2)
-      app(r.com, mergeStmt(r2))
+      app(p.locals, genProc(p, s))
   of nkMetaNode: gen(p, n.sons[0], r)
   of nkType: r.res = genTypeInfo(p, n.typ)
+  of nkStmtList, nkStmtListExpr:
+    # this shows the distinction is nice for backends and should be kept
+    # in the frontend
+    let isExpr = not isEmptyType(n.typ)
+    var a: TCompRes
+    for i in countup(0, sonsLen(n) - 1 - isExpr.ord):
+      a.res = nil
+      genStmt(p, n.sons[i], a)
+      if a.res != nil:
+        app(p.body, a.res)
+        app(p.body, ";" & tnl)
+    if isExpr:
+      genStmt(p, lastSon(n), r)
+  of nkBlockStmt, nkBlockExpr: genBlock(p, n, r)
+  of nkIfStmt, nkIfExpr: genIf(p, n, r)
+  of nkWhileStmt: genWhileStmt(p, n)
+  of nkVarSection, nkLetSection: genVarStmt(p, n)
+  of nkConstSection: nil
+  of nkForStmt, nkParForStmt: 
+    internalError(n.info, "for statement not eliminated")
+  of nkCaseStmt: genCase(p, n, r)
+  of nkReturnStmt: genReturnStmt(p, n)
+  of nkBreakStmt: genBreakStmt(p, n)
+  of nkAsgn: genAsgn(p, n)
+  of nkFastAsgn: genFastAsgn(p, n)
+  of nkDiscardStmt:
+    if n.sons[0].kind != nkEmpty:
+      genLineDir(p, n)
+      gen(p, n.sons[0], r)
+  of nkAsmStmt: genAsmStmt(p, n)
+  of nkTryStmt: genTry(p, n, r)
+  of nkRaiseStmt: genRaiseStmt(p, n)
+  of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, 
+     nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, 
+     nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil
+  of nkProcDef, nkMethodDef, nkConverterDef:
+    var s = n.sons[namePos].sym
+    if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
+      genSym(p, n.sons[namePos], r)
+      r.res = nil
+  of nkGotoState, nkState:
+    internalError(n.info, "first class iterators not implemented")
   else: InternalError(n.info, "gen: unknown node type: " & $n.kind)
   
 var globals: PGlobals
@@ -1616,26 +1468,28 @@ proc genHeader(): PRope =
       "var framePtr = null;$n" & "var excHandler = null;$n", 
                  [toRope(versionAsString)])
 
-proc genModule(p: var TProc, n: PNode, r: var TCompRes) = 
-  genStmt(p, n, r)
-  if optStackTrace in p.options: 
-    r.com = ropef("var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
-        "framePtr = F;$n" & "$3" & "framePtr = framePtr.prev;$n", [
+proc genModule(p: PProc, n: PNode) = 
+  if optStackTrace in p.options:
+    appf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
+                 "framePtr = F;$n", [
         makeJSString("module " & p.module.module.name.s), 
-        makeJSString(toFilename(p.module.module.info)), r.com])
+        makeJSString(toFilename(p.module.module.info))])
+  var r: TCompRes
+  genStmt(p, n, r)
+  if r.res != nil:
+    appf(p.body, "$#;$n", r.res)
+  if optStackTrace in p.options:
+    appf(p.body, "framePtr = framePtr.prev;$n")
 
 proc myProcess(b: PPassContext, n: PNode): PNode = 
   if passes.skipCodegen(n): return n
-  var 
-    p: TProc
-    r: TCompRes
   result = n
   var m = BModule(b)
   if m.module == nil: InternalError(n.info, "myProcess")
-  initProc(p, globals, m, nil, m.module.options)
-  genModule(p, n, r)
+  var p = newProc(globals, m, nil, m.module.options)
+  genModule(p, n)
   app(p.g.code, p.locals)
-  app(p.g.code, mergeStmt(r))
+  app(p.g.code, p.body)
 
 proc myClose(b: PPassContext, n: PNode): PNode = 
   if passes.skipCodegen(n): return n
@@ -1644,23 +1498,15 @@ proc myClose(b: PPassContext, n: PNode): PNode =
   if sfMainModule in m.module.flags:
     for prc in globals.forwarded:
       if not globals.generatedSyms.containsOrIncl(prc.id):
-        var 
-          p: TProc
-          r: TCompRes
-        initProc(p, globals, m, nil, m.module.options)
-        genProc(p, prc, r)
-        app(p.g.code, mergeStmt(r))
+        var p = newProc(globals, m, nil, m.module.options)
+        app(p.g.code, genProc(p, prc))
     
     var disp = generateMethodDispatchers()
     for i in 0..sonsLen(disp)-1: 
       let prc = disp.sons[i].sym
       if not globals.generatedSyms.containsOrIncl(prc.id):
-        var 
-          p: TProc
-          r: TCompRes
-        initProc(p, globals, m, nil, m.module.options)
-        genProc(p, prc, r)
-        app(p.g.code, mergeStmt(r))
+        var p = newProc(globals, m, nil, m.module.options)
+        app(p.g.code, genProc(p, prc))
 
     # write the file:
     var code = con(globals.typeInfo, globals.code)