This commit is contained in:
Araq 2015-03-12 10:55:55 +01:00
commit f88678bed4

View file

@ -62,13 +62,13 @@ type
res: PRope # result part; index if this is an res: PRope # result part; index if this is an
# (address, index)-tuple # (address, index)-tuple
address: PRope # address of an (address, index)-tuple address: PRope # address of an (address, index)-tuple
TBlock = object TBlock = object
id: int # the ID of the label; positive means that it id: int # the ID of the label; positive means that it
# has been used (i.e. the label should be emitted) # has been used (i.e. the label should be emitted)
isLoop: bool # whether it's a 'block' or 'while' isLoop: bool # whether it's a 'block' or 'while'
TGlobals = object TGlobals = object
typeInfo, code: PRope typeInfo, code: PRope
forwarded: seq[PSym] forwarded: seq[PSym]
generatedSyms: IntSet generatedSyms: IntSet
@ -98,7 +98,7 @@ proc newGlobals(): PGlobals =
result.generatedSyms = initIntSet() result.generatedSyms = initIntSet()
result.typeInfoGenerated = initIntSet() result.typeInfoGenerated = initIntSet()
proc initCompRes(r: var TCompRes) = proc initCompRes(r: var TCompRes) =
r.address = nil r.address = nil
r.res = nil r.res = nil
r.typ = etyNone r.typ = etyNone
@ -112,7 +112,7 @@ proc rdLoc(a: TCompRes): PRope {.inline.} =
else: else:
result = ropef("$1[$2]", a.address, a.res) result = ropef("$1[$2]", a.address, a.res)
proc newProc(globals: PGlobals, module: BModule, procDef: PNode, proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
options: TOptions): PProc = options: TOptions): PProc =
result = PProc( result = PProc(
blocks: @[], blocks: @[],
@ -121,30 +121,30 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
procDef: procDef, procDef: procDef,
g: globals) g: globals)
if procDef != nil: result.prc = procDef.sons[namePos].sym if procDef != nil: result.prc = procDef.sons[namePos].sym
const const
MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs} tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs}
proc mapType(typ: PType): TJSTypeKind = proc mapType(typ: PType): TJSTypeKind =
let t = skipTypes(typ, abstractInst) let t = skipTypes(typ, abstractInst)
case t.kind case t.kind
of tyVar, tyRef, tyPtr: of tyVar, tyRef, tyPtr:
if skipTypes(t.lastSon, abstractInst).kind in MappedToObject: if skipTypes(t.lastSon, abstractInst).kind in MappedToObject:
result = etyObject result = etyObject
else: else:
result = etyBaseIndex result = etyBaseIndex
of tyPointer: of tyPointer:
# treat a tyPointer like a typed pointer to an array of bytes # treat a tyPointer like a typed pointer to an array of bytes
result = etyInt result = etyInt
of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy: of tyRange, tyDistinct, tyOrdinal, tyConst, tyMutable, tyIter, tyProxy:
result = mapType(t.sons[0]) result = mapType(t.sons[0])
of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt of tyInt..tyInt64, tyUInt..tyUInt64, tyEnum, tyChar: result = etyInt
of tyBool: result = etyBool of tyBool: result = etyBool
of tyFloat..tyFloat128: result = etyFloat of tyFloat..tyFloat128: result = etyFloat
of tySet: result = etyObject # map a set to a table of tySet: result = etyObject # map a set to a table
of tyString, tySequence: result = etyInt # little hack to get right semantics of tyString, tySequence: result = etyInt # little hack to get right semantics
of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum, of tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tyBigNum,
tyVarargs: tyVarargs:
result = etyObject result = etyObject
of tyNil: result = etyNull of tyNil: result = etyNull
@ -154,10 +154,10 @@ proc mapType(typ: PType): TJSTypeKind =
result = etyNone result = etyNone
of tyProc: result = etyProc of tyProc: result = etyProc
of tyCString: result = etyString of tyCString: result = etyString
proc mangleName(s: PSym): PRope = proc mangleName(s: PSym): PRope =
result = s.loc.r result = s.loc.r
if result == nil: if result == nil:
result = toRope(mangle(s.name.s)) result = toRope(mangle(s.name.s))
app(result, "_") app(result, "_")
app(result, toRope(s.id)) app(result, toRope(s.id))
@ -166,7 +166,7 @@ proc mangleName(s: PSym): PRope =
proc makeJSString(s: string): PRope = strutils.escape(s).toRope proc makeJSString(s: string): PRope = strutils.escape(s).toRope
include jstypes include jstypes
proc gen(p: PProc, n: PNode, r: var TCompRes) proc gen(p: PProc, n: PNode, r: var TCompRes)
proc genStmt(p: PProc, n: PNode) proc genStmt(p: PProc, n: PNode)
proc genProc(oldProc: PProc, prc: PSym): PRope proc genProc(oldProc: PProc, prc: PSym): PRope
@ -341,14 +341,14 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "$1", "$1"], # ToBiggestFloat ["", "", "$1", "$1"], # ToBiggestFloat
["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [ ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
"cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
"cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")",
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
"cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"], "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"], ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
["", "", "$1", "$1"]] ["", "", "$1", "$1"]]
luaOps: TMagicOps = [ luaOps: TMagicOps = [
@ -441,14 +441,14 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["", "", "$1", "$1"], # ToBiggestFloat ["", "", "$1", "$1"], # ToBiggestFloat
["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt ["", "", "Math.floor($1)", "Math.floor($1)"], # ToInt
["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt ["", "", "Math.floor($1)", "Math.floor($1)"], # ToBiggestInt
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"], ["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [ ["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
"cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
"cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")",
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
"cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"], "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"], ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
["", "", "$1", "$1"]] ["", "", "$1", "$1"]]
proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
@ -502,9 +502,9 @@ proc genLineDir(p: PProc, n: PNode) =
appf(p.body, "endb($1);$n", [toRope(line)]) appf(p.body, "endb($1);$n", [toRope(line)])
elif ({optLineTrace, optStackTrace} * p.options == elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and {optLineTrace, optStackTrace}) and
((p.prc == nil) or not (sfPure in p.prc.flags)): ((p.prc == nil) or not (sfPure in p.prc.flags)):
appf(p.body, "F.line = $1;$n", [toRope(line)]) appf(p.body, "F.line = $1;$n", [toRope(line)])
proc genWhileStmt(p: PProc, n: PNode) = proc genWhileStmt(p: PProc, n: PNode) =
var var
cond: TCompRes cond: TCompRes
@ -533,7 +533,7 @@ proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
src.kind = resNone src.kind = resNone
src.res = nil src.res = nil
proc genTry(p: PProc, n: PNode, r: var TCompRes) = proc genTry(p: PProc, n: PNode, r: var TCompRes) =
# code to generate: # code to generate:
# #
# var sp = {prev: excHandler, exc: null}; # var sp = {prev: excHandler, exc: null};
@ -560,8 +560,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
inc(p.unique) inc(p.unique)
var safePoint = ropef("Tmp$1", [toRope(p.unique)]) var safePoint = ropef("Tmp$1", [toRope(p.unique)])
appf(p.body, appf(p.body,
"var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" | "var $1 = {prev: excHandler, exc: null};$nexcHandler = $1;$n" |
"local $1 = pcall(", "local $1 = pcall(",
[safePoint]) [safePoint])
if optStackTrace in p.options: app(p.body, "framePtr = F;" & tnl) if optStackTrace in p.options: app(p.body, "framePtr = F;" & tnl)
appf(p.body, "try {$n" | "function()$n") appf(p.body, "try {$n" | "function()$n")
@ -574,9 +574,9 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
appf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n") appf(p.body, "} catch (EXC) {$n lastJSError = EXC;$n")
elif p.target == targetLua: elif p.target == targetLua:
appf(p.body, "end)$n") appf(p.body, "end)$n")
while i < length and n.sons[i].kind == nkExceptBranch: while i < length and n.sons[i].kind == nkExceptBranch:
let blen = sonsLen(n.sons[i]) let blen = sonsLen(n.sons[i])
if blen == 1: if blen == 1:
# general except section: # general except section:
if i > 1: appf(p.body, "else {$n" | "else$n") if i > 1: appf(p.body, "else {$n" | "else$n")
gen(p, n.sons[i].sons[0], a) gen(p, n.sons[i].sons[0], a)
@ -585,11 +585,11 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
else: else:
var orExpr: PRope = nil var orExpr: PRope = nil
useMagic(p, "isObj") useMagic(p, "isObj")
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
if n.sons[i].sons[j].kind != nkType: if n.sons[i].sons[j].kind != nkType:
internalError(n.info, "genTryStmt") internalError(n.info, "genTryStmt")
if orExpr != nil: app(orExpr, "||" | " or ") if orExpr != nil: app(orExpr, "||" | " or ")
appf(orExpr, "isObj($1.exc.m_type, $2)", appf(orExpr, "isObj($1.exc.m_type, $2)",
[safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)]) [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
if i > 1: app(p.body, "else ") if i > 1: app(p.body, "else ")
appf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n", appf(p.body, "if ($1.exc && ($2)) {$n" | "if $1.exc and ($2) then$n",
@ -622,13 +622,13 @@ proc genRaiseStmt(p: PProc, n: PNode) =
useMagic(p, "reraiseException") useMagic(p, "reraiseException")
app(p.body, "reraiseException();" & tnl) app(p.body, "reraiseException();" & tnl)
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) = proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
var var
cond, stmt: TCompRes cond, stmt: TCompRes
genLineDir(p, n) genLineDir(p, n)
gen(p, n.sons[0], cond) gen(p, n.sons[0], cond)
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
if stringSwitch: if stringSwitch:
useMagic(p, "toJSStr") useMagic(p, "toJSStr")
appf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc]) appf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
else: else:
@ -636,25 +636,25 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
if not isEmptyType(n.typ): if not isEmptyType(n.typ):
r.kind = resVal r.kind = resVal
r.res = getTemp(p) r.res = getTemp(p)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
case it.kind case it.kind
of nkOfBranch: of nkOfBranch:
for j in countup(0, sonsLen(it) - 2): for j in countup(0, sonsLen(it) - 2):
let e = it.sons[j] let e = it.sons[j]
if e.kind == nkRange: if e.kind == nkRange:
var v = copyNode(e.sons[0]) var v = copyNode(e.sons[0])
while v.intVal <= e.sons[1].intVal: while v.intVal <= e.sons[1].intVal:
gen(p, v, cond) gen(p, v, cond)
appf(p.body, "case $1: ", [cond.rdLoc]) appf(p.body, "case $1: ", [cond.rdLoc])
inc(v.intVal) inc(v.intVal)
else: else:
if stringSwitch: if stringSwitch:
case e.kind case e.kind
of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ", of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ",
[makeJSString(e.strVal)]) [makeJSString(e.strVal)])
else: internalError(e.info, "jsgen.genCaseStmt: 2") else: internalError(e.info, "jsgen.genCaseStmt: 2")
else: else:
gen(p, e, cond) gen(p, e, cond)
appf(p.body, "case $1: ", [cond.rdLoc]) appf(p.body, "case $1: ", [cond.rdLoc])
gen(p, lastSon(it), stmt) gen(p, lastSon(it), stmt)
@ -668,7 +668,7 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
else: internalError(it.info, "jsgen.genCaseStmt") else: internalError(it.info, "jsgen.genCaseStmt")
appf(p.body, "}$n") appf(p.body, "}$n")
proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) = proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
var var
cond, stmt: TCompRes cond, stmt: TCompRes
genLineDir(p, n) genLineDir(p, n)
@ -681,13 +681,13 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
if not isEmptyType(n.typ): if not isEmptyType(n.typ):
r.kind = resVal r.kind = resVal
r.res = getTemp(p) r.res = getTemp(p)
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
case it.kind case it.kind
of nkOfBranch: of nkOfBranch:
if i != 1: appf(p.body, "$nelsif ") if i != 1: appf(p.body, "$nelsif ")
else: appf(p.body, "if ") else: appf(p.body, "if ")
for j in countup(0, sonsLen(it) - 2): for j in countup(0, sonsLen(it) - 2):
if j != 0: app(p.body, " or ") if j != 0: app(p.body, " or ")
let e = it.sons[j] let e = it.sons[j]
if e.kind == nkRange: if e.kind == nkRange:
@ -696,7 +696,7 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
gen(p, e.sons[1], ib) gen(p, e.sons[1], ib)
appf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc]) appf(p.body, "$1 >= $2 and $1 <= $3", [tmp, ia.rdLoc, ib.rdLoc])
else: else:
if stringSwitch: if stringSwitch:
case e.kind case e.kind
of nkStrLit..nkTripleStrLit: appf(p.body, "eqStr($1, $2)", of nkStrLit..nkTripleStrLit: appf(p.body, "eqStr($1, $2)",
[tmp, makeJSString(e.strVal)]) [tmp, makeJSString(e.strVal)])
@ -713,11 +713,11 @@ proc genCaseLua(p: PProc, n: PNode, r: var TCompRes) =
moveInto(p, stmt, r) moveInto(p, stmt, r)
else: internalError(it.info, "jsgen.genCaseStmt") else: internalError(it.info, "jsgen.genCaseStmt")
appf(p.body, "$nend$n") appf(p.body, "$nend$n")
proc genBlock(p: PProc, n: PNode, r: var TCompRes) = proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
inc(p.unique) inc(p.unique)
let idx = len(p.blocks) let idx = len(p.blocks)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
# named block? # named block?
if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock") if (n.sons[0].kind != nkSym): internalError(n.info, "genBlock")
var sym = n.sons[0].sym var sym = n.sons[0].sym
@ -731,10 +731,10 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
appf(p.body, "} while(false);$n" | "$n::L$#::$n", labl.toRope) appf(p.body, "} while(false);$n" | "$n::L$#::$n", labl.toRope)
setLen(p.blocks, idx) setLen(p.blocks, idx)
proc genBreakStmt(p: PProc, n: PNode) = proc genBreakStmt(p: PProc, n: PNode) =
var idx: int var idx: int
genLineDir(p, n) genLineDir(p, n)
if n.sons[0].kind != nkEmpty: if n.sons[0].kind != nkEmpty:
# named break? # named break?
assert(n.sons[0].kind == nkSym) assert(n.sons[0].kind == nkSym)
let sym = n.sons[0].sym let sym = n.sons[0].sym
@ -749,24 +749,24 @@ proc genBreakStmt(p: PProc, n: PNode) =
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
appf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [toRope(p.blocks[idx].id)]) appf(p.body, "break L$1;$n" | "goto ::L$1::;$n", [toRope(p.blocks[idx].id)])
proc genAsmStmt(p: PProc, n: PNode) = proc genAsmStmt(p: PProc, n: PNode) =
genLineDir(p, n) genLineDir(p, n)
assert(n.kind == nkAsmStmt) assert(n.kind == nkAsmStmt)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
case n.sons[i].kind case n.sons[i].kind
of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal) of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal)
of nkSym: app(p.body, mangleName(n.sons[i].sym)) of nkSym: app(p.body, mangleName(n.sons[i].sym))
else: internalError(n.sons[i].info, "jsgen: genAsmStmt()") else: internalError(n.sons[i].info, "jsgen: genAsmStmt()")
proc genIf(p: PProc, n: PNode, r: var TCompRes) = proc genIf(p: PProc, n: PNode, r: var TCompRes) =
var cond, stmt: TCompRes var cond, stmt: TCompRes
var toClose = 0 var toClose = 0
if not isEmptyType(n.typ): if not isEmptyType(n.typ):
r.kind = resVal r.kind = resVal
r.res = getTemp(p) r.res = getTemp(p)
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
if sonsLen(it) != 1: if sonsLen(it) != 1:
if i > 0: if i > 0:
appf(p.body, "else {$n" | "else$n", []) appf(p.body, "else {$n" | "else$n", [])
inc(toClose) inc(toClose)
@ -793,18 +793,18 @@ proc generateHeader(p: PProc, typ: PType): PRope =
if isCompileTimeOnly(param.typ): continue if isCompileTimeOnly(param.typ): continue
var name = mangleName(param) var name = mangleName(param)
app(result, name) app(result, name)
if mapType(param.typ) == etyBaseIndex: if mapType(param.typ) == etyBaseIndex:
app(result, ", ") app(result, ", ")
app(result, name) app(result, name)
app(result, "_Idx") app(result, "_Idx")
const const
nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit, nodeKindsNeedNoCopy = {nkCharLit..nkInt64Lit, nkStrLit..nkTripleStrLit,
nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString, nkFloatLit..nkFloat64Lit, nkCurly, nkPar, nkObjConstr, nkStringToCString,
nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix, nkCStringToString, nkCall, nkPrefix, nkPostfix, nkInfix,
nkCommand, nkHiddenCallConv, nkCallStrLit} nkCommand, nkHiddenCallConv, nkCallStrLit}
proc needsNoCopy(y: PNode): bool = proc needsNoCopy(y: PNode): bool =
result = (y.kind in nodeKindsNeedNoCopy) or result = (y.kind in nodeKindsNeedNoCopy) or
(skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}) (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyVar})
@ -820,22 +820,22 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
useMagic(p, "nimCopy") useMagic(p, "nimCopy")
appf(p.body, "$1 = nimCopy($2, $3);$n", appf(p.body, "$1 = nimCopy($2, $3);$n",
[a.res, b.res, genTypeInfo(p, y.typ)]) [a.res, b.res, genTypeInfo(p, y.typ)])
of etyBaseIndex: of etyBaseIndex:
if a.typ != etyBaseIndex or b.typ != etyBaseIndex: if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
internalError(x.info, "genAsgn") internalError(x.info, "genAsgn")
appf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) appf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
else: else:
appf(p.body, "$1 = $2;$n", [a.res, b.res]) appf(p.body, "$1 = $2;$n", [a.res, b.res])
proc genAsgn(p: PProc, n: PNode) = proc genAsgn(p: PProc, n: PNode) =
genLineDir(p, n) genLineDir(p, n)
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false) genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false)
proc genFastAsgn(p: PProc, n: PNode) = proc genFastAsgn(p: PProc, n: PNode) =
genLineDir(p, n) genLineDir(p, n)
genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true) genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true)
proc genSwap(p: PProc, n: PNode) = proc genSwap(p: PProc, n: PNode) =
var a, b: TCompRes var a, b: TCompRes
gen(p, n.sons[1], a) gen(p, n.sons[1], a)
gen(p, n.sons[2], b) gen(p, n.sons[2], b)
@ -844,7 +844,7 @@ proc genSwap(p: PProc, n: PNode) =
if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex: if mapType(skipTypes(n.sons[1].typ, abstractVar)) == etyBaseIndex:
inc(p.unique) inc(p.unique)
let tmp2 = ropef("Tmp$1", [toRope(p.unique)]) let tmp2 = ropef("Tmp$1", [toRope(p.unique)])
if a.typ != etyBaseIndex or b.typ != etyBaseIndex: if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
internalError(n.info, "genSwap") internalError(n.info, "genSwap")
appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" | appf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
"local $1 = $2; $2 = $3; $3 = $1;$n", [ "local $1 = $2; $2 = $3; $3 = $1;$n", [
@ -859,7 +859,7 @@ proc getFieldPosition(f: PNode): int =
of nkSym: result = f.sym.position of nkSym: result = f.sym.position
else: internalError(f.info, "genFieldPosition") else: internalError(f.info, "genFieldPosition")
proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes var a: TCompRes
r.typ = etyBaseIndex r.typ = etyBaseIndex
let b = if n.kind == nkHiddenAddr: n.sons[0] else: n let b = if n.kind == nkHiddenAddr: n.sons[0] else: n
@ -875,7 +875,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
r.address = a.res r.address = a.res
r.kind = resExpr r.kind = resExpr
proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
r.typ = etyNone r.typ = etyNone
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple: if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
@ -887,14 +887,16 @@ proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
r.res = ropef("$1.$2", [r.res, f.loc.r]) r.res = ropef("$1.$2", [r.res, f.loc.r])
r.kind = resExpr r.kind = resExpr
proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) = proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
genFieldAddr(p, n.sons[0], r) # XXX let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
internalAssert m.kind == nkCheckedFieldExpr
proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) = genFieldAddr(p, m.sons[0], r) # XXX
proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
genFieldAccess(p, n.sons[0], r) # XXX genFieldAccess(p, n.sons[0], r) # XXX
proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
var var
a, b: TCompRes a, b: TCompRes
first: BiggestInt first: BiggestInt
r.typ = etyBaseIndex r.typ = etyBaseIndex
@ -908,7 +910,7 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
else: first = 0 else: first = 0
if optBoundsCheck in p.options and not isConstExpr(m.sons[1]): if optBoundsCheck in p.options and not isConstExpr(m.sons[1]):
useMagic(p, "chckIndx") useMagic(p, "chckIndx")
r.res = ropef("chckIndx($1, $2, $3.length)-$2", r.res = ropef("chckIndx($1, $2, $3.length)-$2",
[b.res, toRope(first), a.res]) [b.res, toRope(first), a.res])
elif first != 0: elif first != 0:
r.res = ropef("($1)-$2", [b.res, toRope(first)]) r.res = ropef("($1)-$2", [b.res, toRope(first)])
@ -916,14 +918,14 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
r.res = b.res r.res = b.res
r.kind = resExpr r.kind = resExpr
proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) =
var ty = skipTypes(n.sons[0].typ, abstractVarRange) var ty = skipTypes(n.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange) if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
case ty.kind case ty.kind
of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString, of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
tyVarargs: tyVarargs:
genArrayAddr(p, n, r) genArrayAddr(p, n, r)
of tyTuple: of tyTuple:
genFieldAddr(p, n, r) genFieldAddr(p, n, r)
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
r.typ = etyNone r.typ = etyNone
@ -967,12 +969,12 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString, of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString,
tyVarargs: tyVarargs:
genArrayAddr(p, n, r) genArrayAddr(p, n, r)
of tyTuple: of tyTuple:
genFieldAddr(p, n, r) genFieldAddr(p, n, r)
else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: internalError(n.info, "genAddr") else: internalError(n.info, "genAddr")
proc genSym(p: PProc, n: PNode, r: var TCompRes) = proc genSym(p: PProc, n: PNode, r: var TCompRes) =
var s = n.sym var s = n.sym
case s.kind case s.kind
of skVar, skLet, skParam, skTemp, skResult: of skVar, skLet, skParam, skTemp, skResult:
@ -1019,9 +1021,9 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
internalError(n.info, "symbol has no generated name: " & s.name.s) internalError(n.info, "symbol has no generated name: " & s.name.s)
r.res = s.loc.r r.res = s.loc.r
r.kind = resVal r.kind = resVal
proc genDeref(p: PProc, n: PNode, r: var TCompRes) = proc genDeref(p: PProc, n: PNode, r: var TCompRes) =
if mapType(n.sons[0].typ) == etyObject: if mapType(n.sons[0].typ) == etyObject:
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
else: else:
var a: TCompRes var a: TCompRes
@ -1041,15 +1043,15 @@ proc genArg(p: PProc, n: PNode, r: var TCompRes) =
proc genArgs(p: PProc, n: PNode, r: var TCompRes) = proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
app(r.res, "(") app(r.res, "(")
for i in countup(1, sonsLen(n) - 1): for i in countup(1, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
if it.typ.isCompileTimeOnly: continue if it.typ.isCompileTimeOnly: continue
if i > 1: app(r.res, ", ") if i > 1: app(r.res, ", ")
genArg(p, it, r) genArg(p, it, r)
app(r.res, ")") app(r.res, ")")
r.kind = resExpr r.kind = resExpr
proc genCall(p: PProc, n: PNode, r: var TCompRes) = proc genCall(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
genArgs(p, n, r) genArgs(p, n, r)
@ -1065,7 +1067,7 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
var op: TCompRes var op: TCompRes
gen(p, n.sons[0], op) gen(p, n.sons[0], op)
app(r.res, op.res) app(r.res, op.res)
app(r.res, "(") app(r.res, "(")
for i in countup(2, sonsLen(n) - 1): for i in countup(2, sonsLen(n) - 1):
if i > 2: app(r.res, ", ") if i > 2: app(r.res, ", ")
@ -1080,88 +1082,88 @@ proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
internalAssert n.kind == nkBracket internalAssert n.kind == nkBracket
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
let it = n.sons[i] let it = n.sons[i]
if it.typ.isCompileTimeOnly: continue if it.typ.isCompileTimeOnly: continue
if i > 0: app(r.res, ", ") if i > 0: app(r.res, ", ")
genArg(p, it, r) genArg(p, it, r)
app(r.res, ")") app(r.res, ")")
r.kind = resExpr r.kind = resExpr
proc putToSeq(s: string, indirect: bool): PRope = proc putToSeq(s: string, indirect: bool): PRope =
result = toRope(s) result = toRope(s)
if indirect: result = ropef("[$1]", [result]) if indirect: result = ropef("[$1]", [result])
proc createVar(p: PProc, typ: PType, indirect: bool): PRope proc createVar(p: PProc, typ: PType, indirect: bool): PRope
proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope = proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope =
result = nil result = nil
case rec.kind case rec.kind
of nkRecList: of nkRecList:
for i in countup(0, sonsLen(rec) - 1): for i in countup(0, sonsLen(rec) - 1):
app(result, createRecordVarAux(p, rec.sons[i], c)) app(result, createRecordVarAux(p, rec.sons[i], c))
of nkRecCase: of nkRecCase:
app(result, createRecordVarAux(p, rec.sons[0], c)) app(result, createRecordVarAux(p, rec.sons[0], c))
for i in countup(1, sonsLen(rec) - 1): for i in countup(1, sonsLen(rec) - 1):
app(result, createRecordVarAux(p, lastSon(rec.sons[i]), c)) app(result, createRecordVarAux(p, lastSon(rec.sons[i]), c))
of nkSym: of nkSym:
if c > 0: app(result, ", ") if c > 0: app(result, ", ")
app(result, mangleName(rec.sym)) app(result, mangleName(rec.sym))
app(result, ": ") app(result, ": ")
app(result, createVar(p, rec.sym.typ, false)) app(result, createVar(p, rec.sym.typ, false))
inc(c) inc(c)
else: internalError(rec.info, "createRecordVarAux") else: internalError(rec.info, "createRecordVarAux")
proc createVar(p: PProc, typ: PType, indirect: bool): PRope = proc createVar(p: PProc, typ: PType, indirect: bool): PRope =
var t = skipTypes(typ, abstractInst) var t = skipTypes(typ, abstractInst)
case t.kind case t.kind
of tyInt..tyInt64, tyEnum, tyChar: of tyInt..tyInt64, tyEnum, tyChar:
result = putToSeq("0", indirect) result = putToSeq("0", indirect)
of tyFloat..tyFloat128: of tyFloat..tyFloat128:
result = putToSeq("0.0", indirect) result = putToSeq("0.0", indirect)
of tyRange, tyGenericInst: of tyRange, tyGenericInst:
result = createVar(p, lastSon(typ), indirect) result = createVar(p, lastSon(typ), indirect)
of tySet: of tySet:
result = toRope("{}") result = toRope("{}")
of tyBool: of tyBool:
result = putToSeq("false", indirect) result = putToSeq("false", indirect)
of tyArray, tyArrayConstr: of tyArray, tyArrayConstr:
var length = int(lengthOrd(t)) var length = int(lengthOrd(t))
var e = elemType(t) var e = elemType(t)
if length > 32: if length > 32:
useMagic(p, "arrayConstr") useMagic(p, "arrayConstr")
# XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary. # XXX: arrayConstr depends on nimCopy. This line shouldn't be necessary.
useMagic(p, "nimCopy") useMagic(p, "nimCopy")
result = ropef("arrayConstr($1, $2, $3)", [toRope(length), result = ropef("arrayConstr($1, $2, $3)", [toRope(length),
createVar(p, e, false), genTypeInfo(p, e)]) createVar(p, e, false), genTypeInfo(p, e)])
else: else:
result = toRope("[") result = toRope("[")
var i = 0 var i = 0
while i < length: while i < length:
if i > 0: app(result, ", ") if i > 0: app(result, ", ")
app(result, createVar(p, e, false)) app(result, createVar(p, e, false))
inc(i) inc(i)
app(result, "]") app(result, "]")
of tyTuple: of tyTuple:
result = toRope("{") result = toRope("{")
for i in 0.. <t.sonsLen: for i in 0.. <t.sonsLen:
if i > 0: app(result, ", ") if i > 0: app(result, ", ")
appf(result, "Field$1: $2" | "Field$# = $#", i.toRope, appf(result, "Field$1: $2" | "Field$# = $#", i.toRope,
createVar(p, t.sons[i], false)) createVar(p, t.sons[i], false))
app(result, "}") app(result, "}")
of tyObject: of tyObject:
result = toRope("{") result = toRope("{")
var c = 0 var c = 0
if tfFinal notin t.flags or t.sons[0] != nil: if tfFinal notin t.flags or t.sons[0] != nil:
inc(c) inc(c)
appf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)]) appf(result, "m_type: $1" | "m_type = $#", [genTypeInfo(p, t)])
while t != nil: while t != nil:
app(result, createRecordVarAux(p, t.n, c)) app(result, createRecordVarAux(p, t.n, c))
t = t.sons[0] t = t.sons[0]
app(result, "}") app(result, "}")
of tyVar, tyPtr, tyRef: of tyVar, tyPtr, tyRef:
if mapType(t) == etyBaseIndex: if mapType(t) == etyBaseIndex:
result = putToSeq("[null, 0]" | "{nil, 0}", indirect) result = putToSeq("[null, 0]" | "{nil, 0}", indirect)
else: else:
result = putToSeq("null" | "nil", indirect) result = putToSeq("null" | "nil", indirect)
of tySequence, tyString, tyCString, tyPointer, tyProc: of tySequence, tyString, tyCString, tyPointer, tyProc:
result = putToSeq("null" | "nil", indirect) result = putToSeq("null" | "nil", indirect)
else: else:
internalError("createVar: " & $t.kind) internalError("createVar: " & $t.kind)
@ -1172,42 +1174,42 @@ proc isIndirect(v: PSym): bool =
(mapType(v.typ) != etyObject) and (mapType(v.typ) != etyObject) and
v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator} v.kind notin {skProc, skConverter, skMethod, skIterator, skClosureIterator}
proc genVarInit(p: PProc, v: PSym, n: PNode) = proc genVarInit(p: PProc, v: PSym, n: PNode) =
var var
a: TCompRes a: TCompRes
s: PRope s: PRope
if n.kind == nkEmpty: if n.kind == nkEmpty:
appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n",
[mangleName(v), createVar(p, v.typ, isIndirect(v))]) [mangleName(v), createVar(p, v.typ, isIndirect(v))])
else: else:
discard mangleName(v) discard mangleName(v)
gen(p, n, a) gen(p, n, a)
case mapType(v.typ) case mapType(v.typ)
of etyObject: of etyObject:
if needsNoCopy(n): if needsNoCopy(n):
s = a.res s = a.res
else: else:
useMagic(p, "nimCopy") useMagic(p, "nimCopy")
s = ropef("nimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)]) s = ropef("nimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)])
of etyBaseIndex: of etyBaseIndex:
if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit") if (a.typ != etyBaseIndex): internalError(n.info, "genVarInit")
if {sfAddrTaken, sfGlobal} * v.flags != {}: if {sfAddrTaken, sfGlobal} * v.flags != {}:
appf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n", appf(p.body, "var $1 = [$2, $3];$n" | "local $1 = {$2, $3};$n",
[v.loc.r, a.address, a.res]) [v.loc.r, a.address, a.res])
else: else:
appf(p.body, "var $1 = $2; var $1_Idx = $3;$n" | appf(p.body, "var $1 = $2; var $1_Idx = $3;$n" |
"local $1 = $2; local $1_Idx = $3;$n", [ "local $1 = $2; local $1_Idx = $3;$n", [
v.loc.r, a.address, a.res]) v.loc.r, a.address, a.res])
return return
else: else:
s = a.res s = a.res
if isIndirect(v): if isIndirect(v):
appf(p.body, "var $1 = [$2];$n" | "local $1 = {$2};$n", [v.loc.r, s]) appf(p.body, "var $1 = [$2];$n" | "local $1 = {$2};$n", [v.loc.r, s])
else: else:
appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s]) appf(p.body, "var $1 = $2;$n" | "local $1 = $2;$n", [v.loc.r, s])
proc genVarStmt(p: PProc, n: PNode) = proc genVarStmt(p: PProc, n: PNode) =
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
var a = n.sons[i] var a = n.sons[i]
if a.kind != nkCommentStmt: if a.kind != nkCommentStmt:
if a.kind == nkVarTuple: if a.kind == nkVarTuple:
@ -1249,7 +1251,7 @@ proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r) of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r)
of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)" | "toBool($#)") of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)" | "toBool($#)")
else: internalError(n.info, "genOrd") else: internalError(n.info, "genOrd")
proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes var a: TCompRes
@ -1282,7 +1284,7 @@ proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[1], r) gen(p, n.sons[1], r)
useMagic(p, "cstrToNimstr") useMagic(p, "cstrToNimstr")
r.kind = resExpr r.kind = resExpr
r.res = ropef("cstrToNimstr($1.node.sons[$2].name)", r.res = ropef("cstrToNimstr($1.node.sons[$2].name)",
[genTypeInfo(p, t), r.res]) [genTypeInfo(p, t), r.res])
else: else:
# XXX: # XXX:
@ -1303,11 +1305,11 @@ proc genReset(p: PProc, n: PNode) =
var x: TCompRes var x: TCompRes
useMagic(p, "genericReset") useMagic(p, "genericReset")
gen(p, n.sons[1], x) gen(p, n.sons[1], x)
appf(p.body, "$1 = genericReset($1, $2);$n", [x.res, appf(p.body, "$1 = genericReset($1, $2);$n", [x.res,
genTypeInfo(p, n.sons[1].typ)]) genTypeInfo(p, n.sons[1].typ)])
proc genMagic(p: PProc, n: PNode, r: var TCompRes) = proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
var var
a: TCompRes a: TCompRes
line, filen: PRope line, filen: PRope
var op = n.sons[0].sym.magic var op = n.sons[0].sym.magic
@ -1384,34 +1386,34 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))") of mCopyStr: binaryExpr(p, n, r, "", "($1.slice($2))")
of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))") of mCopyStrLast: ternaryExpr(p, n, r, "", "($1.slice($2, ($3)+1).concat(0))")
of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)") of mNewString: unaryExpr(p, n, r, "mnewString", "mnewString($1)")
of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)") of mNewStringOfCap: unaryExpr(p, n, r, "mnewString", "mnewString(0)")
else: else:
genCall(p, n, r) genCall(p, n, r)
#else internalError(e.info, 'genMagic: ' + magicToStr[op]); #else internalError(e.info, 'genMagic: ' + magicToStr[op]);
proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) =
var var
a, b: TCompRes a, b: TCompRes
useMagic(p, "SetConstr") useMagic(p, "SetConstr")
r.res = toRope("SetConstr(") r.res = toRope("SetConstr(")
r.kind = resExpr r.kind = resExpr
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(r.res, ", ") if i > 0: app(r.res, ", ")
var it = n.sons[i] var it = n.sons[i]
if it.kind == nkRange: if it.kind == nkRange:
gen(p, it.sons[0], a) gen(p, it.sons[0], a)
gen(p, it.sons[1], b) gen(p, it.sons[1], b)
appf(r.res, "[$1, $2]", [a.res, b.res]) appf(r.res, "[$1, $2]", [a.res, b.res])
else: else:
gen(p, it, a) gen(p, it, a)
app(r.res, a.res) app(r.res, a.res)
app(r.res, ")") app(r.res, ")")
proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) =
var a: TCompRes var a: TCompRes
r.res = toRope("[") r.res = toRope("[")
r.kind = resExpr r.kind = resExpr
for i in countup(0, sonsLen(n) - 1): for i in countup(0, sonsLen(n) - 1):
if i > 0: app(r.res, ", ") if i > 0: app(r.res, ", ")
gen(p, n.sons[i], a) gen(p, n.sons[i], a)
app(r.res, a.res) app(r.res, a.res)
@ -1444,7 +1446,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
appf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res]) appf(r.res, "$#: $#" | "$# = $#" , [f.loc.r, a.res])
r.res.app("}") r.res.app("}")
proc genConv(p: PProc, n: PNode, r: var TCompRes) = proc genConv(p: PProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange) var dest = skipTypes(n.typ, abstractVarRange)
var src = skipTypes(n.sons[1].typ, abstractVarRange) var src = skipTypes(n.sons[1].typ, abstractVarRange)
gen(p, n.sons[1], r) gen(p, n.sons[1], r)
@ -1460,24 +1462,24 @@ proc genConv(p: PProc, n: PNode, r: var TCompRes) =
else: else:
# TODO: What types must we handle here? # TODO: What types must we handle here?
discard discard
proc upConv(p: PProc, n: PNode, r: var TCompRes) = proc upConv(p: PProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[0], r) # XXX gen(p, n.sons[0], r) # XXX
proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) =
var a, b: TCompRes var a, b: TCompRes
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
if optRangeCheck in p.options: if optRangeCheck in p.options:
gen(p, n.sons[1], a) gen(p, n.sons[1], a)
gen(p, n.sons[2], b) gen(p, n.sons[2], b)
useMagic(p, "chckRange") useMagic(p, "chckRange")
r.res = ropef("chckRange($1, $2, $3)", [r.res, a.res, b.res]) r.res = ropef("chckRange($1, $2, $3)", [r.res, a.res, b.res])
r.kind = resExpr r.kind = resExpr
proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) = proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
# we do an optimization here as this is likely to slow down # we do an optimization here as this is likely to slow down
# much of the code otherwise: # much of the code otherwise:
if n.sons[0].kind == nkCStringToString: if n.sons[0].kind == nkCStringToString:
gen(p, n.sons[0].sons[0], r) gen(p, n.sons[0].sons[0], r)
else: else:
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
@ -1486,22 +1488,22 @@ proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) =
r.res = ropef("toJSStr($1)", [r.res]) r.res = ropef("toJSStr($1)", [r.res])
r.kind = resExpr r.kind = resExpr
proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) = proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) =
# we do an optimization here as this is likely to slow down # we do an optimization here as this is likely to slow down
# much of the code otherwise: # much of the code otherwise:
if n.sons[0].kind == nkStringToCString: if n.sons[0].kind == nkStringToCString:
gen(p, n.sons[0].sons[0], r) gen(p, n.sons[0].sons[0], r)
else: else:
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
if r.res == nil: internalError(n.info, "convCStrToStr") if r.res == nil: internalError(n.info, "convCStrToStr")
useMagic(p, "cstrToNimstr") useMagic(p, "cstrToNimstr")
r.res = ropef("cstrToNimstr($1)", [r.res]) r.res = ropef("cstrToNimstr($1)", [r.res])
r.kind = resExpr r.kind = resExpr
proc genReturnStmt(p: PProc, n: PNode) = proc genReturnStmt(p: PProc, n: PNode) =
if p.procDef == nil: internalError(n.info, "genReturnStmt") if p.procDef == nil: internalError(n.info, "genReturnStmt")
p.beforeRetNeeded = true p.beforeRetNeeded = true
if (n.sons[0].kind != nkEmpty): if (n.sons[0].kind != nkEmpty):
genStmt(p, n.sons[0]) genStmt(p, n.sons[0])
else: else:
genLineDir(p, n) genLineDir(p, n)
@ -1517,22 +1519,22 @@ proc genProcBody(p: PProc, prc: PSym): PRope =
else: else:
result = nil result = nil
if p.beforeRetNeeded: if p.beforeRetNeeded:
appf(result, "BeforeRet: do {$n$1} while (false); $n" | appf(result, "BeforeRet: do {$n$1} while (false); $n" |
"$#;::BeforeRet::$n", [p.body]) "$#;::BeforeRet::$n", [p.body])
else: else:
app(result, p.body) app(result, p.body)
if prc.typ.callConv == ccSysCall and p.target == targetJS: if prc.typ.callConv == ccSysCall and p.target == targetJS:
result = ropef("try {$n$1} catch (e) {$n" & result = ropef("try {$n$1} catch (e) {$n" &
" alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}", [result]) " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}", [result])
if optStackTrace in prc.options: if optStackTrace in prc.options:
app(result, "framePtr = framePtr.prev;" & tnl) app(result, "framePtr = framePtr.prev;" & tnl)
proc genProc(oldProc: PProc, prc: PSym): PRope = proc genProc(oldProc: PProc, prc: PSym): PRope =
var var
resultSym: PSym resultSym: PSym
name, returnStmt, resultAsgn, header: PRope name, returnStmt, resultAsgn, header: PRope
a: TCompRes a: TCompRes
#if gVerbosity >= 3: #if gVerbosity >= 3:
# echo "BEGIN generating code for: " & prc.name.s # echo "BEGIN generating code for: " & prc.name.s
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options) var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
p.target = oldProc.target p.target = oldProc.target
@ -1541,17 +1543,17 @@ proc genProc(oldProc: PProc, prc: PSym): PRope =
resultAsgn = nil resultAsgn = nil
name = mangleName(prc) name = mangleName(prc)
header = generateHeader(p, prc.typ) header = generateHeader(p, prc.typ)
if prc.typ.sons[0] != nil and sfPure notin prc.flags: if prc.typ.sons[0] != nil and sfPure notin prc.flags:
resultSym = prc.ast.sons[resultPos].sym resultSym = prc.ast.sons[resultPos].sym
resultAsgn = ropef("var $# = $#;$n" | "local $# = $#;$n", [ resultAsgn = ropef("var $# = $#;$n" | "local $# = $#;$n", [
mangleName(resultSym), mangleName(resultSym),
createVar(p, resultSym.typ, isIndirect(resultSym))]) createVar(p, resultSym.typ, isIndirect(resultSym))])
gen(p, prc.ast.sons[resultPos], a) gen(p, prc.ast.sons[resultPos], a)
returnStmt = ropef("return $#;$n", [a.res]) returnStmt = ropef("return $#;$n", [a.res])
genStmt(p, prc.getBody) genStmt(p, prc.getBody)
result = ropef("function $#($#) {$n$#$#$#$#}$n" | result = ropef("function $#($#) {$n$#$#$#$#}$n" |
"function $#($#) $n$#$#$#$#$nend$n", "function $#($#) $n$#$#$#$#$nend$n",
[name, header, p.locals, resultAsgn, [name, header, p.locals, resultAsgn,
genProcBody(p, prc), returnStmt]) genProcBody(p, prc), returnStmt])
#if gVerbosity >= 3: #if gVerbosity >= 3:
# echo "END generated code for: " & prc.name.s # echo "END generated code for: " & prc.name.s
@ -1584,28 +1586,28 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
r.res = toRope"null" | toRope"nil" r.res = toRope"null" | toRope"nil"
r.kind = resExpr r.kind = resExpr
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
if skipTypes(n.typ, abstractVarRange).kind == tyString: if skipTypes(n.typ, abstractVarRange).kind == tyString:
useMagic(p, "cstrToNimstr") useMagic(p, "cstrToNimstr")
r.res = ropef("cstrToNimstr($1)", [makeJSString(n.strVal)]) r.res = ropef("cstrToNimstr($1)", [makeJSString(n.strVal)])
else: else:
r.res = makeJSString(n.strVal) r.res = makeJSString(n.strVal)
r.kind = resExpr r.kind = resExpr
of nkFloatLit..nkFloat64Lit: of nkFloatLit..nkFloat64Lit:
let f = n.floatVal let f = n.floatVal
if f != f: r.res = toRope"NaN" if f != f: r.res = toRope"NaN"
elif f == 0.0: r.res = toRope"0.0" elif f == 0.0: r.res = toRope"0.0"
elif f == 0.5 * f: elif f == 0.5 * f:
if f > 0.0: r.res = toRope"Infinity" if f > 0.0: r.res = toRope"Infinity"
else: r.res = toRope"-Infinity" else: r.res = toRope"-Infinity"
else: r.res = toRope(f.toStrMaxPrecision) else: r.res = toRope(f.toStrMaxPrecision)
r.kind = resExpr r.kind = resExpr
of nkCallKinds: of nkCallKinds:
if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone):
genMagic(p, n, r) genMagic(p, n, r)
elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and
n.len >= 2: n.len >= 2:
genInfixCall(p, n, r) genInfixCall(p, n, r)
else: else:
genCall(p, n, r) genCall(p, n, r)
of nkCurly: genSetConstr(p, n, r) of nkCurly: genSetConstr(p, n, r)
of nkBracket: genArrayConstr(p, n, r) of nkBracket: genArrayConstr(p, n, r)
@ -1626,7 +1628,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkStringToCString: convStrToCStr(p, n, r) of nkStringToCString: convStrToCStr(p, n, r)
of nkCStringToString: convCStrToStr(p, n, r) of nkCStringToString: convCStrToStr(p, n, r)
of nkEmpty: discard of nkEmpty: discard
of nkLambdaKinds: of nkLambdaKinds:
let s = n.sons[namePos].sym let s = n.sons[namePos].sym
discard mangleName(s) discard mangleName(s)
r.res = s.loc.r r.res = s.loc.r
@ -1647,9 +1649,9 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkWhileStmt: genWhileStmt(p, n) of nkWhileStmt: genWhileStmt(p, n)
of nkVarSection, nkLetSection: genVarStmt(p, n) of nkVarSection, nkLetSection: genVarStmt(p, n)
of nkConstSection: discard of nkConstSection: discard
of nkForStmt, nkParForStmt: of nkForStmt, nkParForStmt:
internalError(n.info, "for statement not eliminated") internalError(n.info, "for statement not eliminated")
of nkCaseStmt: of nkCaseStmt:
if p.target == targetJS: genCaseJS(p, n, r) if p.target == targetJS: genCaseJS(p, n, r)
else: genCaseLua(p, n, r) else: genCaseLua(p, n, r)
of nkReturnStmt: genReturnStmt(p, n) of nkReturnStmt: genReturnStmt(p, n)
@ -1663,8 +1665,8 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
of nkAsmStmt: genAsmStmt(p, n) of nkAsmStmt: genAsmStmt(p, n)
of nkTryStmt: genTry(p, n, r) of nkTryStmt: genTry(p, n, r)
of nkRaiseStmt: genRaiseStmt(p, n) of nkRaiseStmt: genRaiseStmt(p, n)
of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt,
nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt,
nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: discard
of nkProcDef, nkMethodDef, nkConverterDef: of nkProcDef, nkMethodDef, nkConverterDef:
var s = n.sons[namePos].sym var s = n.sons[namePos].sym
@ -1675,33 +1677,33 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
internalError(n.info, "first class iterators not implemented") internalError(n.info, "first class iterators not implemented")
of nkPragmaBlock: gen(p, n.lastSon, r) of nkPragmaBlock: gen(p, n.lastSon, r)
else: internalError(n.info, "gen: unknown node type: " & $n.kind) else: internalError(n.info, "gen: unknown node type: " & $n.kind)
var globals: PGlobals var globals: PGlobals
proc newModule(module: PSym): BModule = proc newModule(module: PSym): BModule =
new(result) new(result)
result.module = module result.module = module
if globals == nil: globals = newGlobals() if globals == nil: globals = newGlobals()
proc genHeader(): PRope = proc genHeader(): PRope =
result = ropef("/* Generated by the Nim Compiler v$1 */$n" & result = ropef("/* Generated by the Nim Compiler v$1 */$n" &
"/* (c) 2015 Andreas Rumpf */$n$n" & "/* (c) 2015 Andreas Rumpf */$n$n" &
"var framePtr = null;$n" & "var framePtr = null;$n" &
"var excHandler = null;$n" & "var excHandler = null;$n" &
"var lastJSError = null;$n", "var lastJSError = null;$n",
[toRope(VersionAsString)]) [toRope(VersionAsString)])
proc genModule(p: PProc, n: PNode) = proc genModule(p: PProc, n: PNode) =
if optStackTrace in p.options: if optStackTrace in p.options:
appf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" & appf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" &
"framePtr = F;$n", [ "framePtr = F;$n", [
makeJSString("module " & p.module.module.name.s), makeJSString("module " & p.module.module.name.s),
makeJSString(toFilename(p.module.module.info))]) makeJSString(toFilename(p.module.module.info))])
genStmt(p, n) genStmt(p, n)
if optStackTrace in p.options: if optStackTrace in p.options:
appf(p.body, "framePtr = framePtr.prev;$n") appf(p.body, "framePtr = framePtr.prev;$n")
proc myProcess(b: PPassContext, n: PNode): PNode = proc myProcess(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n if passes.skipCodegen(n): return n
result = n result = n
var m = BModule(b) var m = BModule(b)
@ -1716,17 +1718,17 @@ proc wholeCode*(m: BModule): PRope =
if not globals.generatedSyms.containsOrIncl(prc.id): if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options) var p = newProc(globals, m, nil, m.module.options)
app(p.g.code, genProc(p, prc)) app(p.g.code, genProc(p, prc))
var disp = generateMethodDispatchers() var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1: for i in 0..sonsLen(disp)-1:
let prc = disp.sons[i].sym let prc = disp.sons[i].sym
if not globals.generatedSyms.containsOrIncl(prc.id): if not globals.generatedSyms.containsOrIncl(prc.id):
var p = newProc(globals, m, nil, m.module.options) var p = newProc(globals, m, nil, m.module.options)
app(p.g.code, genProc(p, prc)) app(p.g.code, genProc(p, prc))
result = con(globals.typeInfo, globals.code) result = con(globals.typeInfo, globals.code)
proc myClose(b: PPassContext, n: PNode): PNode = proc myClose(b: PPassContext, n: PNode): PNode =
if passes.skipCodegen(n): return n if passes.skipCodegen(n): return n
result = myProcess(b, n) result = myProcess(b, n)
var m = BModule(b) var m = BModule(b)
@ -1740,11 +1742,11 @@ proc myClose(b: PPassContext, n: PNode): PNode =
changeFileExt(completeCFilePath(m.module.filename), "js") changeFileExt(completeCFilePath(m.module.filename), "js")
discard writeRopeIfNotEqual(con(genHeader(), code), outfile) discard writeRopeIfNotEqual(con(genHeader(), code), outfile)
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext = proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
internalError("symbol files are not possible with the JS code generator") internalError("symbol files are not possible with the JS code generator")
result = nil result = nil
proc myOpen(s: PSym): PPassContext = proc myOpen(s: PSym): PPassContext =
result = newModule(s) result = newModule(s)
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose) const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)