summary refs log tree commit diff stats
path: root/rod/ecmasgen.nim
diff options
context:
space:
mode:
Diffstat (limited to 'rod/ecmasgen.nim')
-rwxr-xr-xrod/ecmasgen.nim1447
1 files changed, 0 insertions, 1447 deletions
diff --git a/rod/ecmasgen.nim b/rod/ecmasgen.nim
deleted file mode 100755
index ca3ab8ddb..000000000
--- a/rod/ecmasgen.nim
+++ /dev/null
@@ -1,1447 +0,0 @@
-#
-#
-#           The Nimrod Compiler
-#        (c) Copyright 2010 Andreas Rumpf
-#
-#    See the file "copying.txt", included in this
-#    distribution, for details about the copyright.
-#
-
-# This is the EMCAScript (also known as JavaScript) code generator.
-# **Invariant: each expression only occurs once in the generated
-# code!**
-
-import 
-  ast, astalgo, strutils, nhashes, trees, platform, magicsys, extccomp,
-  options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os,
-  times, ropes, math, passes, ccgutils, wordrecg, rnimsyn, rodread, rodutils
-
-proc ecmasgenPass*(): TPass
-# implementation
-
-type 
-  TEcmasGen = object of TPassContext
-    filename*: string
-    module*: PSym
-
-  BModule = ref TEcmasGen
-  TEcmasTypeKind = enum 
-    etyNone,                  # no type
-    etyNull,                  # null type
-    etyProc,                  # proc type
-    etyBool,                  # bool type
-    etyInt,                   # Ecmascript's int
-    etyFloat,                 # Ecmascript's float
-    etyString,                # Ecmascript's string
-    etyObject,                # Ecmascript's reference to an object
-    etyBaseIndex              # base + index needed
-  TCompRes{.final.} = object 
-    kind*: TEcmasTypeKind
-    com*: PRope               # computation part
-                              # address if this is a (address, index)-tuple
-    res*: PRope               # result part; index if this is an
-                              # (address, index)-tuple
-  
-  TBlock{.final.} = object 
-    id*: int                  # the ID of the label; positive means that it
-                              # has been used (i.e. the label should be emitted)
-    nestedTryStmts*: int      # how many try statements is it nested into
-  
-  TGlobals{.final.} = object 
-    typeInfo*, code*: PRope
-    typeInfoGenerated*: TIntSet
-
-  PGlobals = ref TGlobals
-  TProc{.final.} = object 
-    procDef*: PNode
-    prc*: PSym
-    data*: PRope
-    options*: TOptions
-    module*: BModule
-    globals*: PGlobals
-    BeforeRetNeeded*: bool
-    nestedTryStmts*: int
-    unique*: int
-    blocks*: seq[TBlock]
-
-
-proc newGlobals(): PGlobals = 
-  new(result)
-  IntSetInit(result.typeInfoGenerated)
-
-proc initCompRes(r: var TCompRes) = 
-  r.com = 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.globals = globals
-  if procDef != nil: p.prc = procDef.sons[namePos].sym
-  
-const 
-  MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, 
-    tySet, tyVar, tyRef, tyPtr}
-
-proc mapType(typ: PType): TEcmasTypeKind = 
-  var t = skipTypes(typ, abstractInst)
-  case t.kind
-  of tyVar, tyRef, tyPtr: 
-    if skipTypes(t.sons[0], abstractInst).kind in mappedToObject: 
-      result = etyObject
-    else: 
-      result = etyBaseIndex
-  of tyPointer: 
-    # treat a tyPointer like a typed pointer to an array of bytes
-    result = etyInt
-  of tyRange, tyDistinct, tyOrdinal: result = mapType(t.sons[0])
-  of tyInt..tyInt64, tyEnum, tyChar: result = etyInt
-  of tyBool: result = etyBool
-  of tyFloat..tyFloat128: result = etyFloat
-  of tySet: result = etyObject # map a set to a table
-  of tyString, tySequence: result = etyInt # little hack to get right semantics
-  of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray: 
-    result = etyObject
-  of tyNil: result = etyNull
-  of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone, 
-     tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc: 
-    result = etyNone
-  of tyProc: result = etyProc
-  of tyCString: result = etyString
-  
-proc mangle(name: string): string = 
-  result = ""
-  for i in countup(0, len(name) - 1): 
-    case name[i]
-    of 'A'..'Z': 
-      add(result, chr(ord(name[i]) - ord('A') + ord('a')))
-    of '_': 
-      nil
-    of 'a'..'z', '0'..'9': 
-      add(result, name[i])
-    else: add(result, 'X' & toHex(ord(name[i]), 2))
-  
-proc mangleName(s: PSym): PRope = 
-  result = s.loc.r
-  if result == nil: 
-    result = toRope(mangle(s.name.s))
-    app(result, "_")
-    app(result, toRope(s.id))
-    s.loc.r = result
-
-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, makeCString(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)), makeCString(field.name.s), result])
-  else: internalError(n.info, "genObjectFields")
-  
-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.globals.typeInfo, s)
-  appf(p.globals.typeInfo, "var NNI$1 = $2;$n", 
-       [toRope(typ.id), genObjectFields(p, typ, typ.n)])
-  appf(p.globals.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
-  if (typ.kind == tyObject) and (typ.sons[0] != nil): 
-    appf(p.globals.typeInfo, "$1.base = $2;$n", 
-         [name, genTypeInfo(p, typ.sons[0])])
-
-proc genEnumInfo(p: var TProc, typ: PType, name: PRope) = 
-  var 
-    s, n: PRope
-    length: int
-    field: PSym
-  length = sonsLen(typ.n)
-  s = nil
-  for i in countup(0, length - 1): 
-    if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo")
-    field = typ.n.sons[i].sym
-    if i > 0: app(s, ", " & tnl)
-    appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}", 
-         [toRope(field.position), name, makeCString(field.name.s)])
-  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.globals.typeInfo, s)
-  app(p.globals.typeInfo, n)
-  appf(p.globals.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)])
-  if typ.sons[0] != nil: 
-    appf(p.globals.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 IntSetContainsOrIncl(p.globals.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.globals.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.globals.typeInfo, s)
-    appf(p.globals.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.globals.typeInfo, s)
-    appf(p.globals.typeInfo, "$1.base = $2;$n", 
-         [result, genTypeInfo(p, typ.sons[1])])
-  of tyEnum: genEnumInfo(p, t, result)
-  of tyObject, tyTuple: genObjectInfo(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 useMagic(p: var TProc, ident: string) =
-  nil 
-  # to implement
-  
-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 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 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 genOr(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)])
-
-type 
-  TMagicFrmt = array[0..3, string]
-
-const # magic checked op; magic unchecked op; checked op; unchecked op
-  ops: array[mAddi..mStrToStr, TMagicFrmt] = [
-    ["addInt", "", "addInt($1, $2)", "($1 + $2)"], # AddI
-    ["subInt", "", "subInt($1, $2)", "($1 - $2)"], # SubI
-    ["mulInt", "", "mulInt($1, $2)", "($1 * $2)"], # MulI
-    ["divInt", "", "divInt($1, $2)", "Math.floor($1 / $2)"], # DivI
-    ["modInt", "", "modInt($1, $2)", "Math.floor($1 % $2)"], # ModI
-    ["addInt64", "", "addInt64($1, $2)", "($1 + $2)"], # AddI64
-    ["subInt64", "", "subInt64($1, $2)", "($1 - $2)"], # SubI64
-    ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
-    ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
-    ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
-    ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
-    ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
-    ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
-    ["", "", "($1 / $2)", "($1 / $2)"], # DivF64
-    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI
-    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI
-    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI
-    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI
-    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI
-    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI
-    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI
-    ["", "", "($1 >>> $2)", "($1 >>> $2)"], # ShrI64
-    ["", "", "($1 << $2)", "($1 << $2)"], # ShlI64
-    ["", "", "($1 & $2)", "($1 & $2)"], # BitandI64
-    ["", "", "($1 | $2)", "($1 | $2)"], # BitorI64
-    ["", "", "($1 ^ $2)", "($1 ^ $2)"], # BitxorI64
-    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinI64
-    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxI64
-    ["nimMin", "nimMin", "nimMin($1, $2)", "nimMin($1, $2)"], # MinF64
-    ["nimMax", "nimMax", "nimMax($1, $2)", "nimMax($1, $2)"], # MaxF64
-    ["AddU", "AddU", "AddU($1, $2)", "AddU($1, $2)"], # AddU
-    ["SubU", "SubU", "SubU($1, $2)", "SubU($1, $2)"], # SubU
-    ["MulU", "MulU", "MulU($1, $2)", "MulU($1, $2)"], # MulU
-    ["DivU", "DivU", "DivU($1, $2)", "DivU($1, $2)"], # DivU
-    ["ModU", "ModU", "ModU($1, $2)", "ModU($1, $2)"], # ModU
-    ["AddU64", "AddU64", "AddU64($1, $2)", "AddU64($1, $2)"], # AddU64
-    ["SubU64", "SubU64", "SubU64($1, $2)", "SubU64($1, $2)"], # SubU64
-    ["MulU64", "MulU64", "MulU64($1, $2)", "MulU64($1, $2)"], # MulU64
-    ["DivU64", "DivU64", "DivU64($1, $2)", "DivU64($1, $2)"], # DivU64
-    ["ModU64", "ModU64", "ModU64($1, $2)", "ModU64($1, $2)"], # ModU64
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqI
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtI
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqI64
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeI64
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtI64
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqF64
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeF64
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtF64
-    ["LeU", "LeU", "LeU($1, $2)", "LeU($1, $2)"], # LeU
-    ["LtU", "LtU", "LtU($1, $2)", "LtU($1, $2)"], # LtU
-    ["LeU64", "LeU64", "LeU64($1, $2)", "LeU64($1, $2)"], # LeU64
-    ["LtU64", "LtU64", "LtU64($1, $2)", "LtU64($1, $2)"], # LtU64
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqEnum
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeEnum
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtEnum
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqCh
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeCh
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtCh
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqB
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LeB
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtB
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqRef
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqProc
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqUntracedRef
-    ["", "", "($1 <= $2)", "($1 <= $2)"], # LePtr
-    ["", "", "($1 < $2)", "($1 < $2)"], # LtPtr
-    ["", "", "($1 == $2)", "($1 == $2)"], # EqCString
-    ["", "", "($1 != $2)", "($1 != $2)"], # Xor
-    ["NegInt", "", "NegInt($1)", "-($1)"], # UnaryMinusI
-    ["NegInt64", "", "NegInt64($1)", "-($1)"], # UnaryMinusI64
-    ["AbsInt", "", "AbsInt($1)", "Math.abs($1)"], # AbsI
-    ["AbsInt64", "", "AbsInt64($1)", "Math.abs($1)"], # AbsI64
-    ["", "", "!($1)", "!($1)"], # Not
-    ["", "", "+($1)", "+($1)"], # UnaryPlusI
-    ["", "", "~($1)", "~($1)"], # BitnotI
-    ["", "", "+($1)", "+($1)"], # UnaryPlusI64
-    ["", "", "~($1)", "~($1)"], # BitnotI64
-    ["", "", "+($1)", "+($1)"], # UnaryPlusF64
-    ["", "", "-($1)", "-($1)"], # UnaryMinusF64
-    ["", "", "Math.abs($1)", "Math.abs($1)"], # AbsF64
-    ["Ze8ToI", "Ze8ToI", "Ze8ToI($1)", "Ze8ToI($1)"], # mZe8ToI
-    ["Ze8ToI64", "Ze8ToI64", "Ze8ToI64($1)", "Ze8ToI64($1)"], # mZe8ToI64
-    ["Ze16ToI", "Ze16ToI", "Ze16ToI($1)", "Ze16ToI($1)"], # mZe16ToI
-    ["Ze16ToI64", "Ze16ToI64", "Ze16ToI64($1)", "Ze16ToI64($1)"], # mZe16ToI64
-    ["Ze32ToI64", "Ze32ToI64", "Ze32ToI64($1)", "Ze32ToI64($1)"], # mZe32ToI64
-    ["ZeIToI64", "ZeIToI64", "ZeIToI64($1)", "ZeIToI64($1)"], # mZeIToI64
-    ["ToU8", "ToU8", "ToU8($1)", "ToU8($1)"], # ToU8
-    ["ToU16", "ToU16", "ToU16($1)", "ToU16($1)"], # ToU16
-    ["ToU32", "ToU32", "ToU32($1)", "ToU32($1)"], # ToU32
-    ["", "", "$1", "$1"],     # ToFloat
-    ["", "", "$1", "$1"],     # ToBiggestFloat
-    ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
-    ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
-    ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], 
-    ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
-      "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", 
-      "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr", 
-                                   "cstrToNimstr(($1)+\"\")", 
-                                   "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", 
-      "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"], 
-    ["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
-  if magic != "": 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) = 
-  var x, y: TCompRes
-  if magic != "": 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])
-
-proc unaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = 
-  if magic != "": useMagic(p, magic)
-  gen(p, n.sons[1], r)
-  r.res = ropef(frmt, [r.res])
-
-proc arith(p: var TProc, n: PNode, r: var TCompRes, op: TMagic) = 
-  var 
-    x, y: TCompRes
-    i: int
-  if optOverflowCheck in p.options: i = 0
-  else: i = 1
-  useMagic(p, ops[op][i])
-  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: 
-    gen(p, n.sons[1], r)
-    r.res = ropef(ops[op][i + 2], [r.res])
-
-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", 
-         [toRope(toFilename(n.info)), toRope(line)])
-  if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and
-      ((p.prc == nil) or not (sfPure in p.prc.flags)): 
-    useMagic(p, "endb")
-    appf(r.com, "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)])
-  
-proc finishTryStmt(p: var TProc, r: var TCompRes, howMany: int) = 
-  for i in countup(1, howMany):
-    app(r.com, "excHandler = excHandler.prev;" & tnl)
-  
-proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    cond, stmt: TCompRes
-    length, labl: int
-  genLineDir(p, n, r)
-  inc(p.unique)
-  length = len(p.blocks)
-  setlen(p.blocks, length + 1)
-  p.blocks[length].id = - p.unique
-  p.blocks[length].nestedTryStmts = p.nestedTryStmts
-  labl = p.unique
-  gen(p, n.sons[0], cond)
-  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)])
-  setlen(p.blocks, length)
-
-proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  # code to generate:
-  #
-  #  var sp = {prev: excHandler, exc: null};
-  #  excHandler = sp;
-  #  try {
-  #    stmts;
-  #  } catch (e) {
-  #    if (e.typ && e.typ == NTI433 || e.typ == NTI2321) {
-  #      stmts;
-  #    } else if (e.typ && e.typ == NTI32342) {
-  #      stmts;
-  #    } else {
-  #      stmts;
-  #    }
-  #  } finally {
-  #    stmts;
-  #    excHandler = excHandler.prev;
-  #  }
-  #
-  var 
-    i, length, blen: int
-    safePoint, orExpr, epart: PRope
-    a: TCompRes
-  genLineDir(p, n, r)
-  inc(p.unique)
-  safePoint = ropef("Tmp$1", [toRope(p.unique)])
-  appf(r.com, 
-       "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)
-  inc(p.nestedTryStmts)
-  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 blen == 1: 
-      # general except section:
-      if i > 1: app(epart, "else {" & tnl)
-      genStmt(p, n.sons[i].sons[0], a)
-      app(epart, mergeStmt(a))
-      if i > 1: app(epart, '}' & tnl)
-    else: 
-      orExpr = nil
-      for j in countup(0, blen - 2): 
-        if (n.sons[i].sons[j].kind != nkType): 
-          InternalError(n.info, "genTryStmt")
-        if orExpr != nil: app(orExpr, "||")
-        appf(orExpr, "($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])
-      genStmt(p, n.sons[i].sons[blen - 1], a)
-      appf(epart, "$1}$n", [mergeStmt(a)])
-    inc(i)
-  if epart != nil: appf(r.com, "} catch (EXC) {$n$1", [epart])
-  finishTryStmt(p, r, p.nestedTryStmts)
-  dec(p.nestedTryStmts)
-  app(r.com, "} 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)
-
-proc genRaiseStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    a: TCompRes
-    typ: PType
-  genLineDir(p, n, r)
-  if n.sons[0] != nil: 
-    gen(p, n.sons[0], a)
-    if a.com != nil: appf(r.com, "$1;$n", [a.com])
-    typ = skipTypes(n.sons[0].typ, abstractPtrs)
-    useMagic(p, "raiseException")
-    appf(r.com, "raiseException($1, $2);$n", 
-         [a.res, makeCString(typ.sym.name.s)])
-  else: 
-    useMagic(p, "reraiseException")
-    app(r.com, "reraiseException();" & tnl)
-
-proc genCaseStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    cond, stmt: TCompRes
-    it, e, v: PNode
-    stringSwitch: bool
-  genLineDir(p, n, r)
-  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
-  if stringSwitch: 
-    useMagic(p, "toEcmaStr")
-    appf(r.com, "switch (toEcmaStr($1)) {$n", [cond.res])
-  else: 
-    appf(r.com, "switch ($1) {$n", [cond.res])
-  for i in countup(1, sonsLen(n) - 1): 
-    it = n.sons[i]
-    case it.kind
-    of nkOfBranch: 
-      for j in countup(0, sonsLen(it) - 2): 
-        e = it.sons[j]
-        if e.kind == nkRange: 
-          v = copyNode(e.sons[0])
-          while (v.intVal <= e.sons[1].intVal): 
-            gen(p, v, cond)
-            if cond.com != nil: internalError(v.info, "ecmasgen.genCaseStmt")
-            appf(r.com, "case $1: ", [cond.res])
-            Inc(v.intVal)
-        else: 
-          gen(p, e, cond)
-          if cond.com != nil: internalError(e.info, "ecmasgen.genCaseStmt")
-          if stringSwitch: 
-            case e.kind
-            of nkStrLit..nkTripleStrLit: appf(r.com, "case $1: ", 
-                [makeCString(e.strVal)])
-            else: InternalError(e.info, "ecmasgen.genCaseStmt: 2")
-          else: 
-            appf(r.com, "case $1: ", [cond.res])
-      genStmt(p, lastSon(it), stmt)
-      appf(r.com, "$n$1break;$n", [mergeStmt(stmt)])
-    of nkElse: 
-      genStmt(p, it.sons[0], stmt)
-      appf(r.com, "default: $n$1break;$n", [mergeStmt(stmt)])
-    else: internalError(it.info, "ecmasgen.genCaseStmt")
-  appf(r.com, "}$n", [])
-
-proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes)
-proc genBlock(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    idx, labl: int
-    sym: PSym
-  inc(p.unique)
-  idx = len(p.blocks)
-  if n.sons[0] != nil: 
-    # named block?
-    if (n.sons[0].kind != nkSym): InternalError(n.info, "genBlock")
-    sym = n.sons[0].sym
-    sym.loc.k = locOther
-    sym.loc.a = idx
-  setlen(p.blocks, idx + 1)
-  p.blocks[idx].id = - p.unique # negative because it isn't used yet
-  p.blocks[idx].nestedTryStmts = p.nestedTryStmts
-  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])
-  setlen(p.blocks, idx)
-
-proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    idx: int
-    sym: PSym
-  genLineDir(p, n, r)
-  idx = len(p.blocks) - 1
-  if n.sons[0] != nil: 
-    # named break?
-    assert(n.sons[0].kind == nkSym)
-    sym = n.sons[0].sym
-    assert(sym.loc.k == locOther)
-    idx = sym.loc.a
-  p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
-  finishTryStmt(p, r, p.nestedTryStmts - p.blocks[idx].nestedTryStmts)
-  appf(r.com, "break L$1;$n", [toRope(p.blocks[idx].id)])
-
-proc genAsmStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  genLineDir(p, n, r)
-  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))
-    else: InternalError(n.sons[i].info, "ecmasgen: genAsmStmt()")
-  
-proc genIfStmt(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)
-      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 part:
-      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, ')'))
-
-proc generateHeader(p: var TProc, typ: PType): PRope = 
-  var 
-    param: PSym
-    name: 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)
-    app(result, name)
-    if mapType(param.typ) == etyBaseIndex: 
-      app(result, ", ")
-      app(result, name)
-      app(result, "_Idx")
-
-const 
-  nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, 
-    nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkStringToCString, 
-    nkCStringToString, nkCall, nkCommand, nkHiddenCallConv, nkCallStrLit}
-
-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) = 
-  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: 
-      useMagic(p, "NimCopy")
-      appf(r.com, "$1 = NimCopy($2, $3);$n", 
-           [a.res, b.res, genTypeInfo(p, y.typ)])
-  of etyBaseIndex: 
-    if (a.kind != etyBaseIndex) or (b.kind != 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])
-
-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 genFastAsgn(p: var TProc, n: PNode, r: var TCompRes) = 
-  genLineDir(p, n, r)
-  genAsgnAux(p, n.sons[0], n.sons[1], r, true)
-
-proc genSwap(p: var TProc, n: PNode, r: var TCompRes) = 
-  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)])
-  case mapType(n.sons[1].typ)
-  of etyBaseIndex: 
-    inc(p.unique)
-    var tmp2 = ropef("Tmp$1", [toRope(p.unique)])
-    if (a.kind != etyBaseIndex) or (b.kind != 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])
-
-proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var a: TCompRes
-  r.kind = etyBaseIndex
-  gen(p, n.sons[0], a)
-  if n.sons[1].kind != nkSym: InternalError(n.sons[1].info, "genFieldAddr")
-  var f = n.sons[1].sym
-  if f.loc.r == nil: f.loc.r = mangleName(f)
-  r.res = makeCString(ropeToStr(f.loc.r))
-  r.com = mergeExpr(a)
-
-proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = 
-  r.kind = etyNone
-  gen(p, n.sons[0], r)
-  if n.sons[1].kind != nkSym: InternalError(n.sons[1].info, "genFieldAddr")
-  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])
-
-proc genCheckedFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = 
-  genFieldAddr(p, n.sons[0], r) # XXX
-  
-proc genCheckedFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = 
-  genFieldAccess(p, n.sons[0], r) # XXX
-  
-proc genArrayAddr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    a, b: TCompRes
-    first: biggestInt
-  r.kind = etyBaseIndex
-  gen(p, n.sons[0], a)
-  gen(p, n.sons[1], b)
-  r.com = mergeExpr(a)
-  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) = 
-  genArrayAddr(p, n, r)
-  r.kind = etyNone
-  r.res = ropef("$1[$2]", [r.com, r.res])
-  r.com = nil
-
-proc genAddr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var s: PSym
-  case n.sons[0].kind
-  of nkSym: 
-    s = n.sons[0].sym
-    if s.loc.r == nil: InternalError(n.info, "genAddr: 3")
-    case s.kind
-    of skVar: 
-      if mapType(n.typ) == etyObject: 
-        # make addr() a no-op:
-        r.kind = etyNone
-        r.res = s.loc.r
-        r.com = nil
-      elif sfGlobal in s.flags: 
-        # globals are always indirect accessible
-        r.kind = etyBaseIndex
-        r.com = toRope("Globals")
-        r.res = makeCString(ropeToStr(s.loc.r))
-      elif sfAddrTaken in s.flags: 
-        r.kind = etyBaseIndex
-        r.com = s.loc.r
-        r.res = toRope("0")
-      else: 
-        InternalError(n.info, "genAddr: 4")
-    else: InternalError(n.info, "genAddr: 2")
-  of nkCheckedFieldExpr: 
-    genCheckedFieldAddr(p, n, r)
-  of nkDotExpr: 
-    genFieldAddr(p, n, r)
-  of nkBracketExpr: 
-    genArrayAddr(p, n, r)
-  else: InternalError(n.info, "genAddr")
-  
-proc genSym(p: var TProc, n: PNode, r: var TCompRes) = 
-  var s = n.sym
-  if s.loc.r == nil: 
-    InternalError(n.info, "symbol has no generated name: " & s.name.s)
-  case s.kind
-  of skVar, skParam, skTemp: 
-    var k = mapType(s.typ)
-    if k == etyBaseIndex: 
-      r.kind = etyBaseIndex
-      if {sfAddrTaken, sfGlobal} * s.flags != {}: 
-        r.com = ropef("$1[0]", [s.loc.r])
-        r.res = ropef("$1[1]", [s.loc.r])
-      else: 
-        r.com = s.loc.r
-        r.res = con(s.loc.r, "_Idx")
-    elif (k != etyObject) and (sfAddrTaken in s.flags): 
-      r.res = ropef("$1[0]", [s.loc.r])
-    else: 
-      r.res = s.loc.r
-  else: r.res = s.loc.r
-  
-proc genDeref(p: var TProc, n: PNode, r: var TCompRes) = 
-  var a: TCompRes
-  if mapType(n.sons[0].typ) == etyObject: 
-    gen(p, n.sons[0], r)
-  else: 
-    gen(p, n.sons[0], a)
-    if a.kind != etyBaseIndex: InternalError(n.info, "genDeref")
-    r.res = ropef("$1[$2]", [a.com, a.res])
-
-proc genArgs(p: var TProc, n: PNode, r: var TCompRes) =
-  app(r.res, "(")
-  for i in countup(1, sonsLen(n) - 1): 
-    if i > 1: app(r.res, ", ")
-    var a: TCompRes
-    gen(p, n.sons[i], a)
-    if a.kind == etyBaseIndex: 
-      app(r.res, a.com)
-      app(r.res, ", ")
-      app(r.res, a.res)
-    else: 
-      app(r.res, mergeExpr(a))
-  app(r.res, ")")
-
-proc genCall(p: var TProc, n: PNode, r: var TCompRes) = 
-  gen(p, n.sons[0], r)
-  genArgs(p, n, r)
-
-proc genEcho(p: var TProc, n: PNode, r: var TCompRes) =
-  app(r.res, "rawEcho")
-  genArgs(p, n, r)
-
-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 = 
-  result = nil
-  case rec.kind
-  of nkRecList: 
-    for i in countup(0, sonsLen(rec) - 1): 
-      app(result, createRecordVarAux(p, rec.sons[i], c))
-  of nkRecCase: 
-    app(result, createRecordVarAux(p, rec.sons[0], c))
-    for i in countup(1, sonsLen(rec) - 1): 
-      app(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
-  of nkSym: 
-    if c > 0: app(result, ", ")
-    app(result, mangleName(rec.sym))
-    app(result, ": ")
-    app(result, createVar(p, rec.sym.typ, false))
-    inc(c)
-  else: InternalError(rec.info, "createRecordVarAux")
-  
-proc createVar(p: var TProc, typ: PType, indirect: bool): PRope = 
-  var t = skipTypes(typ, abstractInst)
-  case t.kind
-  of tyInt..tyInt64, tyEnum, tyChar: 
-    result = putToSeq("0", indirect)
-  of tyFloat..tyFloat128: 
-    result = putToSeq("0.0", indirect)
-  of tyRange: 
-    result = createVar(p, typ.sons[0], indirect)
-  of tySet: 
-    result = toRope("{}")
-  of tyBool: 
-    result = putToSeq("false", indirect)
-  of tyArray, tyArrayConstr: 
-    var length = int(lengthOrd(t))
-    var e = elemType(t)
-    if length > 32: 
-      useMagic(p, "ArrayConstr")
-      result = ropef("ArrayConstr($1, $2, $3)", [toRope(length), 
-          createVar(p, e, false), genTypeInfo(p, e)])
-    else: 
-      result = toRope("[")
-      var i = 0
-      while i < length: 
-        if i > 0: app(result, ", ")
-        app(result, createVar(p, e, false))
-        inc(i)
-      app(result, "]")
-  of tyTuple: 
-    result = toRope("{")
-    var c = 0
-    app(result, createRecordVarAux(p, t.n, c))
-    app(result, "}")
-  of tyObject: 
-    result = toRope("{")
-    var c = 0
-    if not (tfFinal in t.flags) or (t.sons[0] != nil): 
-      inc(c)
-      appf(result, "m_type: $1", [genTypeInfo(p, t)])
-    while t != nil: 
-      app(result, createRecordVarAux(p, t.n, c))
-      t = t.sons[0]
-    app(result, "}")
-  of tyVar, tyPtr, tyRef: 
-    if mapType(t) == etyBaseIndex: result = putToSeq("[null, 0]", indirect)
-    else: result = putToSeq("null", indirect)
-  of tySequence, tyString, tyCString, tyPointer: 
-    result = putToSeq("null", indirect)
-  else: 
-    internalError("createVar: " & $t.kind)
-    result = nil
-
-proc isIndirect(v: PSym): bool = 
-  result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject)
-
-proc genVarInit(p: var TProc, v: PSym, n: PNode, r: var TCompRes) = 
-  var 
-    a: TCompRes
-    s: PRope
-  if n == nil: 
-    appf(r.com, "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 {sfAddrTaken, sfGlobal} * v.flags != {}: 
-        appf(r.com, "var $1 = [$2, $3];$n", [v.loc.r, a.com, 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])
-      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])
-  
-proc genVarStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  for i in countup(0, sonsLen(n) - 1): 
-    var a = n.sons[i]
-    if a.kind == nkCommentStmt: continue 
-    assert(a.kind == nkIdentDefs)
-    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)
-
-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
-        not (lfNoDecl in 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) = 
-  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)])
-
-proc genOrd(p: var TProc, 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) = 
-  var a, b: TCompRes
-  gen(p, n.sons[1], a)
-  gen(p, n.sons[2], b)
-  r.com = mergeExpr(a.com, b.com)
-  if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar: 
-    a.res = ropef("[$1, 0]", [a.res])
-  if skipTypes(n.sons[2].typ, abstractVarRange).kind == tyChar: 
-    b.res = ropef("[$1, 0]", [b.res])
-  r.res = ropef("($1.slice(0,-1)).concat($2)", [a.res, b.res])
-
-proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    a: TCompRes
-    line, filen: PRope
-  var op = n.sons[0].sym.magic
-  case op
-  of mOr: genOr(p, n.sons[1], n.sons[2], r)
-  of mAnd: genAnd(p, n.sons[1], n.sons[2], r)
-  of mAddi..mStrToStr: arith(p, n, r, op)        #mRepr: genRepr(p, n, r);
-  of mSwap: genSwap(p, n, r)
-  of mPred: 
-    # XXX: range checking?
-    if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 - $2")
-    else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)")
-  of mSucc: 
-    # 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 mAppendStrStr: 
-    binaryStmt(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)") 
-    # XXX: make a copy of $2, because of EMCAScript's sucking semantics
-  of mAppendSeqElem: binaryStmt(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 mAssert: 
-    if (optAssert in p.Options): 
-      useMagic(p, "internalAssert")
-      gen(p, n.sons[1], a)
-      line = toRope(toLinenumber(n.info))
-      filen = makeCString(ToFilename(n.info))
-      appf(r.com, "if (!($3)) internalAssert($1, $2)", 
-           [filen, line, mergeExpr(a)])
-  of mNew, mNewFinalize: genNew(p, n, r)
-  of mSizeOf: r.res = toRope(getSize(n.sons[1].typ))
-  of mChr: gen(p, n.sons[1], r)      # nothing to do
-  of mOrd: genOrd(p, n, r)
-  of mLengthStr: unaryExpr(p, n, r, "", "($1.length-1)")
-  of mLengthSeq, mLengthOpenArray, mLengthArray: 
-    unaryExpr(p, n, r, "", "$1.length")
-  of mHigh: 
-    if skipTypes(n.sons[0].typ, abstractVar).kind == tyString: 
-      unaryExpr(p, n, r, "", "($1.length-2)")
-    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)")
-  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")
-  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)")
-  of mEqSet: binaryExpr(p, n, r, "SetEq", "SetEq($1, $2)")
-  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 mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)")
-  of mNLen..mNError: 
-    liMessage(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s)
-  of mNewSeq: binaryStmt(p, n, r, "", "$1 = new Array($2)")
-  of mEcho: genEcho(p, n, r)
-  else: 
-    genCall(p, n, r)          
-    #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
-  
-proc genSetConstr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var 
-    a, b: TCompRes
-  useMagic(p, "SetConstr")
-  r.res = toRope("SetConstr(")
-  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) = 
-  var a: TCompRes
-  r.res = toRope("[")
-  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 genRecordConstr(p: var TProc, n: PNode, r: var TCompRes) = 
-  var a: TCompRes
-  var i = 0
-  var length = sonsLen(n)
-  r.res = toRope("{")
-  while i < length: 
-    if i > 0: app(r.res, ", ")
-    if (n.sons[i].kind != nkSym): 
-      internalError(n.sons[i].info, "genRecordConstr")
-    gen(p, n.sons[i + 1], a)
-    r.com = mergeExpr(r.com, a.com)
-    appf(r.res, "$1: $2", [mangleName(n.sons[i].sym), a.res])
-    inc(i, 2)
-
-proc genConv(p: var TProc, 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])
-  
-proc upConv(p: var TProc, n: PNode, r: var TCompRes) = 
-  gen(p, n.sons[0], r)        # XXX
-  
-proc genRangeChck(p: var TProc, 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])
-
-proc convStrToCStr(p: var TProc, 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: 
-    gen(p, n.sons[0], r)
-    if r.res == nil: InternalError(n.info, "convStrToCStr")
-    useMagic(p, "toEcmaStr")
-    r.res = ropef("toEcmaStr($1)", [r.res])
-
-proc convCStrToStr(p: var TProc, 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: 
-    gen(p, n.sons[0].sons[0], r)
-  else: 
-    gen(p, n.sons[0], r)
-    if r.res == nil: InternalError(n.info, "convCStrToStr")
-    useMagic(p, "cstrToNimstr")
-    r.res = ropef("cstrToNimstr($1)", [r.res])
-
-proc genReturnStmt(p: var TProc, n: PNode, r: var TCompRes) = 
-  var a: TCompRes
-  if p.procDef == nil: InternalError(n.info, "genReturnStmt")
-  p.BeforeRetNeeded = true
-  if (n.sons[0] != nil): 
-    genStmt(p, n.sons[0], a)
-    if a.com != nil: appf(r.com, "$1;$n", mergeStmt(a))
-  else: 
-    genLineDir(p, n, r)
-  finishTryStmt(p, r, p.nestedTryStmts)
-  app(r.com, "break BeforeRet;" & tnl)
-
-proc genProcBody(p: var TProc, prc: PSym, r: TCompRes): PRope = 
-  if optStackTrace in prc.options: 
-    result = ropef("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" &
-        "framePtr = F;$n", [makeCString(prc.owner.name.s & '.' & prc.name.s), 
-                            makeCString(toFilename(prc.info))])
-  else: 
-    result = nil
-  if p.beforeRetNeeded: 
-    appf(result, "BeforeRet: do {$n$1} while (false); $n", [mergeStmt(r)])
-  else: 
-    app(result, mergeStmt(r))
-  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, n: PNode, r: var TCompRes) = 
-  var 
-    p: TProc
-    resultSym: PSym
-    name, returnStmt, resultAsgn, header: PRope
-    a: TCompRes
-  var prc = n.sons[namePos].sym
-  initProc(p, oldProc.globals, oldProc.module, n, prc.options)
-  returnStmt = nil
-  resultAsgn = nil
-  name = mangleName(prc)
-  header = generateHeader(p, prc.typ)
-  if (prc.typ.sons[0] != nil) and not (sfPure in prc.flags): 
-    resultSym = n.sons[resultPos].sym
-    resultAsgn = ropef("var $1 = $2;$n", [mangleName(resultSym), 
-        createVar(p, resultSym.typ, isIndirect(resultSym))])
-    gen(p, n.sons[resultPos], a)
-    if a.com != nil: appf(returnStmt, "$1;$n", [a.com])
-    returnStmt = ropef("return $1;$n", [a.res])
-  genStmt(p, n.sons[codePos], r)
-  r.com = ropef("function $1($2) {$n$3$4$5}$n", 
-                [name, header, resultAsgn, genProcBody(p, prc, r), returnStmt])
-  r.res = nil
-
-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: 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: genVarStmt(p, n, r)
-  of nkConstSection: genConstStmt(p, n, r)
-  of nkForStmt: 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: 
-    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, 
-     nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: 
-    nil
-  of nkProcDef, nkMethodDef, nkConverterDef: 
-    if (n.sons[genericParamsPos] == nil): 
-      var prc = n.sons[namePos].sym
-      if (n.sons[codePos] != nil) and not (lfNoDecl in prc.loc.flags): 
-        genProc(p, n, r)
-      else: 
-        discard mangleName(prc)
-  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
-  r.res = nil
-  case n.kind
-  of nkSym: 
-    genSym(p, n, r)
-  of nkCharLit..nkInt64Lit: 
-    r.res = toRope(n.intVal)
-  of nkNilLit: 
-    if mapType(n.typ) == etyBaseIndex: 
-      r.kind = etyBaseIndex
-      r.com = toRope("null")
-      r.res = toRope("0")
-    else: 
-      r.res = toRope("null")
-  of nkStrLit..nkTripleStrLit: 
-    if skipTypes(n.typ, abstractVarRange).kind == tyString: 
-      useMagic(p, "cstrToNimstr")
-      r.res = ropef("cstrToNimstr($1)", [makeCString(n.strVal)])
-    else: 
-      r.res = makeCString(n.strVal)
-  of nkFloatLit..nkFloat64Lit: 
-    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 nkCall, nkHiddenCallConv, nkCommand, nkCallStrLit: 
-    if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): 
-      genMagic(p, n, r)
-    else: 
-      genCall(p, n, r)
-  of nkCurly: genSetConstr(p, n, r)
-  of nkBracket: genArrayConstr(p, n, r)
-  of nkPar: genRecordConstr(p, n, r)
-  of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
-  of nkAddr, nkHiddenAddr: genAddr(p, n, r)
-  of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
-  of nkBracketExpr: genArrayAccess(p, n, r)
-  of nkDotExpr: genFieldAccess(p, n, r)
-  of nkCheckedFieldExpr: genCheckedFieldAccess(p, n, r)
-  of nkObjDownConv: gen(p, n.sons[0], r)
-  of nkObjUpConv: upConv(p, n, r)
-  of nkChckRangeF: genRangeChck(p, n, r, "chckRangeF")
-  of nkChckRange64: genRangeChck(p, n, r, "chckRange64")
-  of nkChckRange: genRangeChck(p, n, r, "chckRange")
-  of nkStringToCString: convStrToCStr(p, n, r)
-  of nkCStringToString: convCStrToStr(p, n, r)
-  of nkPassAsOpenArray: gen(p, n.sons[0], r)
-  of nkStmtListExpr: genStmtListExpr(p, n, r)
-  else: InternalError(n.info, "gen: unknown node type: " & $n.kind)
-  
-var globals: PGlobals
-
-proc newModule(module: PSym, filename: string): BModule = 
-  new(result)
-  result.filename = filename
-  result.module = module
-  if globals == nil: globals = newGlobals()
-  
-proc genHeader(): PRope = 
-  result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" &
-      "/*   (c) 2010 Andreas Rumpf */$n$n" & "$nvar Globals = this;$n" &
-      "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", [
-        makeCString("module " & p.module.module.name.s), 
-        makeCString(toFilename(p.module.module.info)), r.com])
-
-proc myProcess(b: PPassContext, n: PNode): PNode = 
-  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)
-  app(p.globals.code, p.data)
-  app(p.globals.code, mergeStmt(r))
-
-proc myClose(b: PPassContext, n: PNode): PNode = 
-  result = myProcess(b, n)
-  var m = BModule(b)
-  if sfMainModule in m.module.flags: 
-    # write the file:
-    var code = con(globals.typeInfo, globals.code)
-    var outfile = changeFileExt(completeCFilePath(m.filename), "js")
-    discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
-
-proc myOpenCached(s: PSym, filename: string, rd: PRodReader): PPassContext = 
-  InternalError("symbol files are not possible with the Ecmas code generator")
-  result = nil
-
-proc myOpen(s: PSym, filename: string): PPassContext = 
-  result = newModule(s, filename)
-
-proc ecmasgenPass(): TPass = 
-  InitPass(result)
-  result.open = myOpen
-  result.close = myClose
-  result.openCached = myOpenCached
-  result.process = myProcess