diff options
Diffstat (limited to 'compiler/jsgen.nim')
-rwxr-xr-x | compiler/jsgen.nim | 1669 |
1 files changed, 1669 insertions, 0 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim new file mode 100755 index 000000000..94b662b48 --- /dev/null +++ b/compiler/jsgen.nim @@ -0,0 +1,1669 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2013 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 occurs only once in the generated +# code!** + +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 + TJSGen = object of TPassContext + module: PSym + + BModule = ref TJSGen + TJSTypeKind = enum # necessary JS "types" + etyNone, # no type + etyNull, # null type + etyProc, # proc type + etyBool, # bool type + etyInt, # JavaScript's int + etyFloat, # JavaScript's float + 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 + 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 + isLoop: bool # whether it's a 'block' or 'while' + + TGlobals{.final.} = object + typeInfo, code: PRope + forwarded: seq[PSym] + generatedSyms: TIntSet + typeInfoGenerated: TIntSet + + PGlobals = ref TGlobals + TProc{.final.} = object + procDef: PNode + prc: PSym + data: PRope + options: TOptions + module: BModule + g: PGlobals + BeforeRetNeeded: bool + nestedTryStmts: int + unique: int + blocks: seq[TBlock] + + +proc newGlobals(): PGlobals = + new(result) + result.forwarded = @[] + result.generatedSyms = initIntSet() + result.typeInfoGenerated = initIntSet() + +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.g = globals + if procDef != nil: p.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) + 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, tyConst, tyMutable, tyIter, + tyProxy: + result = mapType(t.sons[0]) + of tyInt..tyInt64, tyUInt..tyUInt64, 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, tyBigNum, + tyVarargs: + result = etyObject + of tyNil: result = etyNull + of tyGenericInst, tyGenericParam, tyGenericBody, tyGenericInvokation, tyNone, + tyForward, tyEmpty, tyExpr, tyStmt, tyTypeDesc, tyTypeClass: + 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 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") + +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 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) = + 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)) + 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 + # we're picky here for the system module too: + 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 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 + ["", "", "($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 + 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 + 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) = + 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 + p.blocks[length].isLoop = true + 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 + useMagic(p, "isObj") + 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, "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]) + 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].kind != nkEmpty: + 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, makeJSString(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, "toJSStr") + appf(r.com, "switch (toJSStr($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, "jsgen.genCaseStmt") + appf(r.com, "case $1: ", [cond.res]) + Inc(v.intVal) + else: + gen(p, e, cond) + if cond.com != nil: internalError(e.info, "jsgen.genCaseStmt") + if stringSwitch: + case e.kind + of nkStrLit..nkTripleStrLit: appf(r.com, "case $1: ", + [makeJSString(e.strVal)]) + else: InternalError(e.info, "jsgen.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, "jsgen.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].kind != nkEmpty: + # 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) + if n.sons[0].kind != nkEmpty: + # named break? + assert(n.sons[0].kind == nkSym) + sym = n.sons[0].sym + assert(sym.loc.k == locOther) + idx = sym.loc.a + else: + # an unnamed 'break' can only break a loop after 'transf' pass: + idx = len(p.blocks) - 1 + while idx >= 0 and not p.blocks[idx].isLoop: dec idx + 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 + 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, "jsgen: 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, nkPrefix, nkPostfix, nkInfix, + 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(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): + 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 getFieldPosition(f: PNode): int = + case f.kind + of nkIntLit..nkUInt64Lit: result = int(f.intVal) + of nkSym: result = f.sym.position + else: InternalError(f.info, "genFieldPosition") + +proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = + var a: TCompRes + r.kind = etyBaseIndex + var 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])) + else: + if b.sons[1].kind != nkSym: InternalError(b.sons[1].info, "genFieldAddr") + 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) + +proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = + r.kind = 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]) + else: + 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) = + var ty = skipTypes(n.sons[0].typ, abstractVarRange) + if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange) + case ty.kind + of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString, + tyVarargs: + genArrayAddr(p, n, r) + 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 + +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, skLet, skResult: + 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 = makeJSString(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: + var ty = skipTypes(n.sons[0].typ, abstractVarRange) + if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange) + case ty.kind + of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString, + tyVarargs: + genArrayAddr(p, n, r) + of tyTuple: + genFieldAddr(p, n, r) + else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') + else: InternalError(n.info, "genAddr") + +proc genSym(p: var TProc, n: PNode, r: var TCompRes) = + var s = n.sym + case s.kind + 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]) + 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 + of skConst: + genConstant(p, s, r) + if s.loc.r == nil: + InternalError(n.info, "symbol has no generated name: " & s.name.s) + r.res = s.loc.r + of skProc, skConverter, skMethod: + discard mangleName(s) + r.res = s.loc.r + if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s) or + {sfImportc, sfInfixCall} * s.flags != {}: + nil + elif s.kind == skMethod and s.getBody.kind == nkEmpty: + # we cannot produce code for the dispatcher yet: + nil + 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.g.code, mergeStmt(r2)) + else: + if s.loc.r == nil: + InternalError(n.info, "symbol has no generated name: " & s.name.s) + 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 genArg(p: var TProc, n: PNode, r: var TCompRes) = + var a: TCompRes + gen(p, n, a) + if a.kind == etyBaseIndex: + app(r.res, a.com) + app(r.res, ", ") + app(r.res, a.res) + else: + app(r.res, mergeExpr(a)) + +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, ", ") + genArg(p, n.sons[i], r) + app(r.res, ")") + +proc genCall(p: var TProc, 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) = + gen(p, n.sons[1], r) + if r.kind == etyBaseIndex: + if r.com == nil: + GlobalError(n.info, "cannot invoke with infix syntax") + r.res = ropef("$1[0]", [r.res, r.com]) + r.com = nil + app(r.res, ".") + var op: TCompRes + gen(p, n.sons[0], op) + app(r.res, mergeExpr(op)) + + 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, ")") + +proc genEcho(p: var TProc, n: PNode, r: var TCompRes) = + useMagic(p, "rawEcho") + 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, tyGenericInst: + result = createVar(p, lastSon(typ), 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("{") + for i in 0.. <t.sonslen: + if i > 0: app(result, ", ") + appf(result, "Field$1: $2", i.toRope, createVar(p, t.sons[i], false)) + 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, tyProc: + 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) and + v.kind notin {skProc, skConverter, skMethod, skIterator} + +proc genVarInit(p: var TProc, v: PSym, n: PNode, r: var TCompRes) = + var + a: TCompRes + s: PRope + if n.kind == nkEmpty: + 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 genConstant(p: var TProc, c: PSym, r: var TCompRes) = + 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) + +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) = + 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 genNewSeq(p: var TProc, n: PNode, r: var TCompRes) = + 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)]) + +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: TCompRes + + gen(p, n.sons[1], a) + r.com = mergeExpr(r.com, a.com) + if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar: + r.res.app(ropef("[$1].concat(", [a.res])) + else: + r.res.app(ropef("($1.slice(0,-1)).concat(", [a.res])) + + 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) = + var t = skipTypes(n.sons[1].typ, abstractVarRange) + case t.kind + of tyInt..tyUInt64: + unaryExpr(p, n, r, "", "(\"\"+ ($1))") + of tyEnum, tyOrdinal: + gen(p, n.sons[1], r) + useMagic(p, "cstrToNimstr") + 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) = + var x: TCompRes + let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr, tyTypeDesc}) + gen(p, n.sons[1], x) + if tfFinal in t.flags: + r.res = ropef("($1.m_type == $2)", [x.res, genTypeInfo(p, t)]) + else: + useMagic(p, "isObj") + r.res = ropef("isObj($1.m_type, $2)", [x.res, genTypeInfo(p, t)]) + r.com = mergeExpr(r.com, x.com) + +proc genReset(p: var TProc, n: PNode, r: var TCompRes) = + var x: TCompRes + useMagic(p, "genericReset") + gen(p, n.sons[1], x) + r.res = ropef("$1 = genericReset($1, $2)", [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) = + 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) + of mRepr: genRepr(p, n, r) + of mSwap: genSwap(p, n, r) + of mUnaryLt: + # XXX: range checking? + if not (optOverflowCheck in p.Options): unaryExpr(p, n, r, "", "$1 - 1") + else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)") + 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: + if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString: + binaryStmt(p, n, r, "", "$1 += $2") + else: + binaryStmt(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 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 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) + 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: + localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s) + of mNewSeq: genNewSeq(p, n, r) + of mOf: genOf(p, n, r) + of mReset: genReset(p, n, r) + of mEcho: genEcho(p, n, r) + of mSlurp, mStaticExec: + localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s) + 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 genTupleConstr(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, ", ") + 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 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, "toJSStr") + r.res = ropef("toJSStr($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].kind != nkEmpty): + 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", [makeJSString(prc.owner.name.s & '.' & prc.name.s), + makeJSString(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, prc: PSym, r: var TCompRes) = + var + p: TProc + resultSym: PSym + name, returnStmt, resultAsgn, header: PRope + a: TCompRes + #if gVerbosity >= 3: + # echo "BEGIN generating code for: " & prc.name.s + initProc(p, oldProc.g, oldProc.module, prc.ast, prc.options) + returnStmt = nil + resultAsgn = nil + name = mangleName(prc) + header = generateHeader(p, prc.typ) + if (prc.typ.sons[0] != nil) and sfPure notin prc.flags: + resultSym = prc.ast.sons[resultPos].sym + resultAsgn = ropef("var $1 = $2;$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 $1;$n", [a.res]) + genStmt(p, prc.getBody, r) + r.com = ropef("function $1($2) {$n$3$4$5}$n", + [name, header, resultAsgn, genProcBody(p, prc, r), returnStmt]) + r.res = nil + #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], r2) + 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 + 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)", [makeJSString(n.strVal)]) + else: + r.res = makeJSString(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 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: + genInfixCall(p, n, r) + else: + genCall(p, n, r) + of nkCurly: genSetConstr(p, n, r) + of nkBracket: genArrayConstr(p, n, r) + of nkPar: genTupleConstr(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 nkCast: gen(p, n.sons[1], 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 nkStmtListExpr: genStmtListExpr(p, n, r) + of nkEmpty: nil + of nkLambdaKinds: + let s = n.sons[namePos].sym + discard mangleName(s) + 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)) + of nkMetaNode: gen(p, n.sons[0], r) + of nkType: r.res = genTypeInfo(p, n.typ) + else: InternalError(n.info, "gen: unknown node type: " & $n.kind) + +var globals: PGlobals + +proc newModule(module: PSym): BModule = + new(result) + result.module = module + if globals == nil: globals = newGlobals() + +proc genHeader(): PRope = + result = ropef("/* Generated by the Nimrod Compiler v$1 */$n" & + "/* (c) 2013 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", [ + makeJSString("module " & p.module.module.name.s), + makeJSString(toFilename(p.module.module.info)), r.com]) + +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) + app(p.g.code, p.data) + app(p.g.code, mergeStmt(r)) + +proc myClose(b: PPassContext, n: PNode): PNode = + if passes.skipCodegen(n): return n + result = myProcess(b, n) + var m = BModule(b) + 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 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)) + + # write the file: + var code = con(globals.typeInfo, globals.code) + var outfile = changeFileExt(completeCFilePath(m.module.filename), "js") + discard writeRopeIfNotEqual(con(genHeader(), code), outfile) + +proc myOpenCached(s: PSym, rd: PRodReader): PPassContext = + InternalError("symbol files are not possible with the JS code generator") + result = nil + +proc myOpen(s: PSym): PPassContext = + result = newModule(s) + +const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) |