diff options
Diffstat (limited to 'rod/ecmasgen.nim')
-rwxr-xr-x | rod/ecmasgen.nim | 1447 |
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 |