review and merge zahary's work (#5849)
* proper indentation for the generated JS code * improved dead-code elimination for JavaScript * test the JS dead-code elimination A new test spec has been added - "maxcodesize". It specifies the maximum size of the generated code in bytes.
This commit is contained in:
parent
eb8e267ff6
commit
39aef12446
7 changed files with 308 additions and 187 deletions
|
|
@ -138,6 +138,13 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||||
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
|
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
|
||||||
ropecg(m, fmt, args)
|
ropecg(m, fmt, args)
|
||||||
|
|
||||||
|
var indent = "\t".rope
|
||||||
|
|
||||||
|
proc indentLine(p: BProc, r: Rope): Rope =
|
||||||
|
result = r
|
||||||
|
for i in countup(0, p.blocks.len-1):
|
||||||
|
prepend(result, indent)
|
||||||
|
|
||||||
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
proc appcg(m: BModule, c: var Rope, frmt: FormatStr,
|
||||||
args: varargs[Rope]) =
|
args: varargs[Rope]) =
|
||||||
add(c, ropecg(m, frmt, args))
|
add(c, ropecg(m, frmt, args))
|
||||||
|
|
@ -150,11 +157,6 @@ proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||||
args: varargs[Rope]) =
|
args: varargs[Rope]) =
|
||||||
add(p.s(s), ropecg(p.module, frmt, args))
|
add(p.s(s), ropecg(p.module, frmt, args))
|
||||||
|
|
||||||
var indent = "\t".rope
|
|
||||||
proc indentLine(p: BProc, r: Rope): Rope =
|
|
||||||
result = r
|
|
||||||
for i in countup(0, p.blocks.len-1): prepend(result, indent)
|
|
||||||
|
|
||||||
proc line(p: BProc, s: TCProcSection, r: Rope) =
|
proc line(p: BProc, s: TCProcSection, r: Rope) =
|
||||||
add(p.s(s), indentLine(p, r))
|
add(p.s(s), indentLine(p, r))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -94,12 +94,39 @@ type
|
||||||
target: TTarget # duplicated here for faster dispatching
|
target: TTarget # duplicated here for faster dispatching
|
||||||
unique: int # for temp identifier generation
|
unique: int # for temp identifier generation
|
||||||
blocks: seq[TBlock]
|
blocks: seq[TBlock]
|
||||||
|
extraIndent: int
|
||||||
up: PProc # up the call chain; required for closure support
|
up: PProc # up the call chain; required for closure support
|
||||||
declaredGlobals: IntSet
|
declaredGlobals: IntSet
|
||||||
|
|
||||||
template `|`(a, b: untyped): untyped {.dirty.} =
|
template `|`(a, b: untyped): untyped {.dirty.} =
|
||||||
(if p.target == targetJS: a else: b)
|
(if p.target == targetJS: a else: b)
|
||||||
|
|
||||||
|
var indent = "\t".rope
|
||||||
|
|
||||||
|
proc indentLine(p: PProc, r: Rope): Rope =
|
||||||
|
result = r
|
||||||
|
var p = p
|
||||||
|
while true:
|
||||||
|
for i in countup(0, p.blocks.len - 1 + p.extraIndent):
|
||||||
|
prepend(result, indent)
|
||||||
|
if p.up == nil or p.up.prc != p.prc.owner:
|
||||||
|
break
|
||||||
|
p = p.up
|
||||||
|
|
||||||
|
template line(p: PProc, added: string) =
|
||||||
|
add(p.body, indentLine(p, rope(added)))
|
||||||
|
|
||||||
|
template line(p: PProc, added: Rope) =
|
||||||
|
add(p.body, indentLine(p, added))
|
||||||
|
|
||||||
|
template lineF(p: PProc, frmt: FormatStr, args: varargs[Rope]) =
|
||||||
|
add(p.body, indentLine(p, ropes.`%`(frmt, args)))
|
||||||
|
|
||||||
|
template nested(p, body) =
|
||||||
|
inc p.extraIndent
|
||||||
|
body
|
||||||
|
dec p.extraIndent
|
||||||
|
|
||||||
proc newGlobals(): PGlobals =
|
proc newGlobals(): PGlobals =
|
||||||
new(result)
|
new(result)
|
||||||
result.forwarded = @[]
|
result.forwarded = @[]
|
||||||
|
|
@ -129,7 +156,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||||
module: module,
|
module: module,
|
||||||
procDef: procDef,
|
procDef: procDef,
|
||||||
g: globals,
|
g: globals,
|
||||||
target: module.target)
|
target: module.target,
|
||||||
|
extraIndent: int(procDef != nil))
|
||||||
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
||||||
if result.target == targetPHP:
|
if result.target == targetPHP:
|
||||||
result.declaredGlobals = initIntSet()
|
result.declaredGlobals = initIntSet()
|
||||||
|
|
@ -290,7 +318,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
result = "Tmp$1" % [rope(p.unique)]
|
result = "Tmp$1" % [rope(p.unique)]
|
||||||
if defineInLocals:
|
if defineInLocals:
|
||||||
addf(p.locals, "var $1;$n", [result])
|
add(p.locals, p.indentLine("var $1;$n" % [result]))
|
||||||
else:
|
else:
|
||||||
result = "$$Tmp$1" % [rope(p.unique)]
|
result = "$$Tmp$1" % [rope(p.unique)]
|
||||||
|
|
||||||
|
|
@ -315,9 +343,11 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||||
# tmp = b
|
# tmp = b
|
||||||
# tmp
|
# tmp
|
||||||
gen(p, a, x)
|
gen(p, a, x)
|
||||||
p.body.addf("if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
lineF(p, "if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
||||||
gen(p, b, y)
|
p.nested:
|
||||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
gen(p, b, y)
|
||||||
|
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||||
|
line(p, "}")
|
||||||
|
|
||||||
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||||
assert r.kind == resNone
|
assert r.kind == resNone
|
||||||
|
|
@ -331,9 +361,11 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||||
r.res = p.getTemp
|
r.res = p.getTemp
|
||||||
r.kind = resVal
|
r.kind = resVal
|
||||||
gen(p, a, x)
|
gen(p, a, x)
|
||||||
p.body.addf("if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
lineF(p, "if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
||||||
gen(p, b, y)
|
p.nested:
|
||||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
gen(p, b, y)
|
||||||
|
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||||
|
line(p, "}")
|
||||||
|
|
||||||
type
|
type
|
||||||
TMagicFrmt = array[0..3, string]
|
TMagicFrmt = array[0..3, string]
|
||||||
|
|
@ -415,12 +447,10 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
|
||||||
["", "", "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(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
|
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||||
"cstrToNimstr(($1)+\"\")",
|
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||||
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
|
|
||||||
"cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
|
||||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
|
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
|
||||||
["", "", "$1", "$1"]]
|
["", "", "$1", "$1"]]
|
||||||
|
|
||||||
|
|
@ -475,18 +505,18 @@ proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||||
r.res = frmt % [r.rdLoc]
|
r.res = frmt % [r.rdLoc]
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic, ops: TMagicOps) =
|
proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
var
|
var
|
||||||
x, y: TCompRes
|
x, y: TCompRes
|
||||||
let i = ord(optOverflowCheck notin p.options)
|
let i = ord(optOverflowCheck notin p.options)
|
||||||
useMagic(p, ops[op][i])
|
useMagic(p, jsOps[op][i])
|
||||||
if sonsLen(n) > 2:
|
if sonsLen(n) > 2:
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
r.res = ops[op][i + 2] % [x.rdLoc, y.rdLoc]
|
r.res = jsOps[op][i + 2] % [x.rdLoc, y.rdLoc]
|
||||||
else:
|
else:
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
r.res = ops[op][i + 2] % [r.rdLoc]
|
r.res = jsOps[op][i + 2] % [r.rdLoc]
|
||||||
|
|
||||||
proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
case op
|
case op
|
||||||
|
|
@ -501,7 +531,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
|
r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
of mModI:
|
of mModI:
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
|
|
@ -509,7 +539,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
|
r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
of mShrI:
|
of mShrI:
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
|
|
@ -534,9 +564,9 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
else:
|
else:
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op)
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc hasFrameInfo(p: PProc): bool =
|
proc hasFrameInfo(p: PProc): bool =
|
||||||
|
|
@ -546,14 +576,14 @@ proc hasFrameInfo(p: PProc): bool =
|
||||||
proc genLineDir(p: PProc, n: PNode) =
|
proc genLineDir(p: PProc, n: PNode) =
|
||||||
let line = toLinenumber(n.info)
|
let line = toLinenumber(n.info)
|
||||||
if optLineDir in p.options:
|
if optLineDir in p.options:
|
||||||
addf(p.body, "// line $2 \"$1\"$n",
|
lineF(p, "// line $2 \"$1\"$n",
|
||||||
[rope(toFilename(n.info)), rope(line)])
|
[rope(toFilename(n.info)), rope(line)])
|
||||||
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
|
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
|
||||||
((p.prc == nil) or sfPure notin p.prc.flags):
|
((p.prc == nil) or sfPure notin p.prc.flags):
|
||||||
useMagic(p, "endb")
|
useMagic(p, "endb")
|
||||||
addf(p.body, "endb($1);$n", [rope(line)])
|
lineF(p, "endb($1);$n", [rope(line)])
|
||||||
elif hasFrameInfo(p):
|
elif hasFrameInfo(p):
|
||||||
addf(p.body, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
|
lineF(p, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
|
||||||
|
|
||||||
proc genWhileStmt(p: PProc, n: PNode) =
|
proc genWhileStmt(p: PProc, n: PNode) =
|
||||||
var
|
var
|
||||||
|
|
@ -566,20 +596,20 @@ proc genWhileStmt(p: PProc, n: PNode) =
|
||||||
p.blocks[length].id = -p.unique
|
p.blocks[length].id = -p.unique
|
||||||
p.blocks[length].isLoop = true
|
p.blocks[length].isLoop = true
|
||||||
let labl = p.unique.rope
|
let labl = p.unique.rope
|
||||||
addf(p.body, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
||||||
gen(p, n.sons[0], cond)
|
p.nested: gen(p, n.sons[0], cond)
|
||||||
addf(p.body, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
||||||
[cond.res, labl])
|
[cond.res, labl])
|
||||||
genStmt(p, n.sons[1])
|
p.nested: genStmt(p, n.sons[1])
|
||||||
addf(p.body, "}$n" | "}L$#:;$n", [labl])
|
lineF(p, "}$n" | "}L$#:;$n", [labl])
|
||||||
setLen(p.blocks, length)
|
setLen(p.blocks, length)
|
||||||
|
|
||||||
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
||||||
if src.kind != resNone:
|
if src.kind != resNone:
|
||||||
if dest.kind != resNone:
|
if dest.kind != resNone:
|
||||||
p.body.addf("$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
lineF(p, "$1 = $2;$n", [dest.rdLoc, src.rdLoc])
|
||||||
else:
|
else:
|
||||||
p.body.addf("$1;$n", [src.rdLoc])
|
lineF(p, "$1;$n", [src.rdLoc])
|
||||||
src.kind = resNone
|
src.kind = resNone
|
||||||
src.res = nil
|
src.res = nil
|
||||||
|
|
||||||
|
|
@ -620,8 +650,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var tmpFramePtr = rope"F"
|
var tmpFramePtr = rope"F"
|
||||||
if optStackTrace notin p.options:
|
if optStackTrace notin p.options:
|
||||||
tmpFramePtr = p.getTemp(true)
|
tmpFramePtr = p.getTemp(true)
|
||||||
add(p.body, tmpFramePtr & " = framePtr;" & tnl)
|
line(p, tmpFramePtr & " = framePtr;" & tnl)
|
||||||
addf(p.body, "try {$n", [])
|
lineF(p, "try {$n", [])
|
||||||
if p.target == targetPHP and p.globals == nil:
|
if p.target == targetPHP and p.globals == nil:
|
||||||
p.globals = "global $lastJSError; global $prevJSError;".rope
|
p.globals = "global $lastJSError; global $prevJSError;".rope
|
||||||
var a: TCompRes
|
var a: TCompRes
|
||||||
|
|
@ -632,18 +662,18 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if p.target == targetJS and catchBranchesExist:
|
if p.target == targetJS and catchBranchesExist:
|
||||||
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||||
elif p.target == targetPHP:
|
elif p.target == targetPHP:
|
||||||
addf(p.body, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$n", [])
|
lineF(p, "} catch (Exception $$EXC) {$n $$prevJSError = $$lastJSError;$n $$lastJSError = $$EXC;$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:
|
||||||
generalCatchBranchExists = true
|
generalCatchBranchExists = true
|
||||||
if i > 1: addf(p.body, "else {$n", [])
|
if i > 1: lineF(p, "else {$n", [])
|
||||||
gen(p, n.sons[i].sons[0], a)
|
gen(p, n.sons[i].sons[0], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
if i > 1: addf(p.body, "}$n", [])
|
if i > 1: lineF(p, "}$n", [])
|
||||||
else:
|
else:
|
||||||
var orExpr: Rope = nil
|
var orExpr: Rope = nil
|
||||||
useMagic(p, "isObj")
|
useMagic(p, "isObj")
|
||||||
|
|
@ -653,30 +683,32 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if orExpr != nil: add(orExpr, "||")
|
if orExpr != nil: add(orExpr, "||")
|
||||||
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
|
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
|
||||||
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
|
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
|
||||||
if i > 1: add(p.body, "else ")
|
if i > 1: line(p, "else ")
|
||||||
addf(p.body, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
lineF(p, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
||||||
gen(p, n.sons[i].sons[blen - 1], a)
|
gen(p, n.sons[i].sons[blen - 1], a)
|
||||||
moveInto(p, a, r)
|
moveInto(p, a, r)
|
||||||
addf(p.body, "}$n", [])
|
lineF(p, "}$n", [])
|
||||||
inc(i)
|
inc(i)
|
||||||
if catchBranchesExist:
|
if catchBranchesExist:
|
||||||
if not generalCatchBranchExists:
|
if not generalCatchBranchExists:
|
||||||
useMagic(p, "reraiseException")
|
useMagic(p, "reraiseException")
|
||||||
add(p.body, "else {" & tnl & "reraiseException();" & tnl & "}" & tnl)
|
line(p, "else {" & tnl)
|
||||||
|
line(p, indent & "reraiseException();" & tnl)
|
||||||
|
line(p, "}" & tnl)
|
||||||
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
|
addf(p.body, "$1lastJSError = $1prevJSError;$n", [dollar])
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
add(p.body, "} finally {" & tnl)
|
line(p, "} finally {" & tnl)
|
||||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
# XXX ugly hack for PHP codegen
|
# XXX ugly hack for PHP codegen
|
||||||
add(p.body, "}" & tnl)
|
line(p, "}" & tnl)
|
||||||
if i < length and n.sons[i].kind == nkFinally:
|
if i < length and n.sons[i].kind == nkFinally:
|
||||||
genStmt(p, n.sons[i].sons[0])
|
genStmt(p, n.sons[i].sons[0])
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
# XXX ugly hack for PHP codegen
|
# XXX ugly hack for PHP codegen
|
||||||
add(p.body, "if($lastJSError) throw($lastJSError);" & tnl)
|
line(p, "if($lastJSError) throw($lastJSError);" & tnl)
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
add(p.body, "}" & tnl)
|
line(p, "}" & tnl)
|
||||||
|
|
||||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
|
@ -685,11 +717,11 @@ proc genRaiseStmt(p: PProc, n: PNode) =
|
||||||
gen(p, n.sons[0], a)
|
gen(p, n.sons[0], a)
|
||||||
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
||||||
useMagic(p, "raiseException")
|
useMagic(p, "raiseException")
|
||||||
addf(p.body, "raiseException($1, $2);$n",
|
lineF(p, "raiseException($1, $2);$n",
|
||||||
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
||||||
else:
|
else:
|
||||||
useMagic(p, "reraiseException")
|
useMagic(p, "reraiseException")
|
||||||
add(p.body, "reraiseException();" & tnl)
|
line(p, "reraiseException();" & tnl)
|
||||||
|
|
||||||
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var
|
var
|
||||||
|
|
@ -699,9 +731,9 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
||||||
if stringSwitch and p.target == targetJS:
|
if stringSwitch and p.target == targetJS:
|
||||||
useMagic(p, "toJSStr")
|
useMagic(p, "toJSStr")
|
||||||
addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "switch ($1) {$n", [cond.rdLoc])
|
lineF(p, "switch ($1) {$n", [cond.rdLoc])
|
||||||
if not isEmptyType(n.typ):
|
if not isEmptyType(n.typ):
|
||||||
r.kind = resVal
|
r.kind = resVal
|
||||||
r.res = getTemp(p)
|
r.res = getTemp(p)
|
||||||
|
|
@ -715,27 +747,29 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
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)
|
||||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||||
inc(v.intVal)
|
inc(v.intVal)
|
||||||
else:
|
else:
|
||||||
if stringSwitch:
|
if stringSwitch:
|
||||||
case e.kind
|
case e.kind
|
||||||
of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
|
of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
|
||||||
[makeJSString(e.strVal, false)])
|
[makeJSString(e.strVal, false)])
|
||||||
else: internalError(e.info, "jsgen.genCaseStmt: 2")
|
else: internalError(e.info, "jsgen.genCaseStmt: 2")
|
||||||
else:
|
else:
|
||||||
gen(p, e, cond)
|
gen(p, e, cond)
|
||||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||||
gen(p, lastSon(it), stmt)
|
p.nested:
|
||||||
moveInto(p, stmt, r)
|
gen(p, lastSon(it), stmt)
|
||||||
addf(p.body, "$nbreak;$n", [])
|
moveInto(p, stmt, r)
|
||||||
|
lineF(p, "break;$n", [])
|
||||||
of nkElse:
|
of nkElse:
|
||||||
addf(p.body, "default: $n", [])
|
lineF(p, "default: $n", [])
|
||||||
gen(p, it.sons[0], stmt)
|
p.nested:
|
||||||
moveInto(p, stmt, r)
|
gen(p, it.sons[0], stmt)
|
||||||
addf(p.body, "break;$n", [])
|
moveInto(p, stmt, r)
|
||||||
|
lineF(p, "break;$n", [])
|
||||||
else: internalError(it.info, "jsgen.genCaseStmt")
|
else: internalError(it.info, "jsgen.genCaseStmt")
|
||||||
addf(p.body, "}$n", [])
|
lineF(p, "}$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)
|
||||||
|
|
@ -746,13 +780,13 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var sym = n.sons[0].sym
|
var sym = n.sons[0].sym
|
||||||
sym.loc.k = locOther
|
sym.loc.k = locOther
|
||||||
sym.position = idx+1
|
sym.position = idx+1
|
||||||
|
let labl = p.unique
|
||||||
|
lineF(p, "L$1: do {$n" | "", [labl.rope])
|
||||||
setLen(p.blocks, idx + 1)
|
setLen(p.blocks, idx + 1)
|
||||||
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
p.blocks[idx].id = - p.unique # negative because it isn't used yet
|
||||||
let labl = p.unique
|
|
||||||
addf(p.body, "L$1: do {$n" | "", [labl.rope])
|
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
addf(p.body, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
|
||||||
setLen(p.blocks, idx)
|
setLen(p.blocks, idx)
|
||||||
|
lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
||||||
|
|
||||||
proc genBreakStmt(p: PProc, n: PNode) =
|
proc genBreakStmt(p: PProc, n: PNode) =
|
||||||
var idx: int
|
var idx: int
|
||||||
|
|
@ -770,19 +804,23 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
||||||
if idx < 0 or not p.blocks[idx].isLoop:
|
if idx < 0 or not p.blocks[idx].isLoop:
|
||||||
internalError(n.info, "no loop to break")
|
internalError(n.info, "no loop to break")
|
||||||
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||||
addf(p.body, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
|
lineF(p, "break L$1;$n" | "goto L$1;$n", [rope(p.blocks[idx].id)])
|
||||||
|
|
||||||
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
|
p.body.add p.indentLine(nil)
|
||||||
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: add(p.body, n.sons[i].strVal)
|
of nkStrLit..nkTripleStrLit:
|
||||||
|
p.body.add(n.sons[i].strVal)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let v = n.sons[i].sym
|
let v = n.sons[i].sym
|
||||||
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||||
add(p.body, "$")
|
p.body.add "$"
|
||||||
add(p.body, mangleName(v, p.target))
|
p.body.add mangleName(v, p.target)
|
||||||
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
else:
|
||||||
|
internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
||||||
|
p.body.add tnl
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -794,18 +832,18 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
if sonsLen(it) != 1:
|
if sonsLen(it) != 1:
|
||||||
if i > 0:
|
if i > 0:
|
||||||
addf(p.body, "else {$n", [])
|
lineF(p, "else {$n", [])
|
||||||
inc(toClose)
|
inc(toClose)
|
||||||
gen(p, it.sons[0], cond)
|
p.nested: gen(p, it.sons[0], cond)
|
||||||
addf(p.body, "if ($1) {$n", [cond.rdLoc])
|
lineF(p, "if ($1) {$n", [cond.rdLoc])
|
||||||
gen(p, it.sons[1], stmt)
|
gen(p, it.sons[1], stmt)
|
||||||
else:
|
else:
|
||||||
# else part:
|
# else part:
|
||||||
addf(p.body, "else {$n", [])
|
lineF(p, "else {$n", [])
|
||||||
gen(p, it.sons[0], stmt)
|
p.nested: gen(p, it.sons[0], stmt)
|
||||||
moveInto(p, stmt, r)
|
moveInto(p, stmt, r)
|
||||||
addf(p.body, "}$n", [])
|
lineF(p, "}$n", [])
|
||||||
add(p.body, repeat('}', toClose) & tnl)
|
line(p, repeat('}', toClose) & tnl)
|
||||||
|
|
||||||
proc generateHeader(p: PProc, typ: PType): Rope =
|
proc generateHeader(p: PProc, typ: PType): Rope =
|
||||||
result = nil
|
result = nil
|
||||||
|
|
@ -854,7 +892,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
gen(p, x[0], a)
|
gen(p, x[0], a)
|
||||||
gen(p, x[1], b)
|
gen(p, x[1], b)
|
||||||
gen(p, y, c)
|
gen(p, y, c)
|
||||||
addf(p.body, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
|
lineF(p, "$#[$#] = chr($#);$n", [a.rdLoc, b.rdLoc, c.rdLoc])
|
||||||
return
|
return
|
||||||
|
|
||||||
var xtyp = mapType(p, x.typ)
|
var xtyp = mapType(p, x.typ)
|
||||||
|
|
@ -862,7 +900,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
|
if x.kind == nkHiddenDeref and x.sons[0].kind == nkCall and xtyp != etyObject:
|
||||||
gen(p, x.sons[0], a)
|
gen(p, x.sons[0], a)
|
||||||
let tmp = p.getTemp(false)
|
let tmp = p.getTemp(false)
|
||||||
addf(p.body, "var $1 = $2;$n", [tmp, a.rdLoc])
|
lineF(p, "var $1 = $2;$n", [tmp, a.rdLoc])
|
||||||
a.res = "$1[0][$1[1]]" % [tmp]
|
a.res = "$1[0][$1[1]]" % [tmp]
|
||||||
else:
|
else:
|
||||||
gen(p, x, a)
|
gen(p, x, a)
|
||||||
|
|
@ -876,29 +914,29 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||||
case xtyp
|
case xtyp
|
||||||
of etySeq:
|
of etySeq:
|
||||||
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||||
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||||
else:
|
else:
|
||||||
useMagic(p, "nimCopy")
|
useMagic(p, "nimCopy")
|
||||||
addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
|
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
|
||||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||||
of etyObject:
|
of etyObject:
|
||||||
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
if (needsNoCopy(p, y) and needsNoCopy(p, x)) or noCopyNeeded:
|
||||||
addf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
lineF(p, "$1 = $2;$n", [a.rdLoc, b.rdLoc])
|
||||||
else:
|
else:
|
||||||
useMagic(p, "nimCopy")
|
useMagic(p, "nimCopy")
|
||||||
addf(p.body, "nimCopy($1, $2, $3);$n",
|
lineF(p, "nimCopy($1, $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:
|
||||||
if y.kind == nkCall:
|
if y.kind == nkCall:
|
||||||
let tmp = p.getTemp(false)
|
let tmp = p.getTemp(false)
|
||||||
addf(p.body, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
|
lineF(p, "var $1 = $4; $2 = $1[0]; $3 = $1[1];$n", [tmp, a.address, a.res, b.rdLoc])
|
||||||
else:
|
else:
|
||||||
internalError(x.info, "genAsgn")
|
internalError(x.info, "genAsgn")
|
||||||
else:
|
else:
|
||||||
addf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
lineF(p, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "$1 = $2;$n", [a.res, b.res])
|
lineF(p, "$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)
|
||||||
|
|
@ -917,12 +955,13 @@ proc genSwap(p: PProc, n: PNode) =
|
||||||
let tmp2 = p.getTemp(false)
|
let tmp2 = p.getTemp(false)
|
||||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||||
internalError(n.info, "genSwap")
|
internalError(n.info, "genSwap")
|
||||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
||||||
"$1 = $2; $2 = $3; $3 = $1;$n", [
|
"$1 = $2; $2 = $3; $3 = $1;$n",
|
||||||
tmp, a.address, b.address])
|
[tmp, a.address, b.address])
|
||||||
tmp = tmp2
|
tmp = tmp2
|
||||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
|
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||||
"$1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
|
"$1 = $2; $2 = $3; $3 = $1;",
|
||||||
|
[tmp, a.res, b.res])
|
||||||
|
|
||||||
proc getFieldPosition(f: PNode): int =
|
proc getFieldPosition(f: PNode): int =
|
||||||
case f.kind
|
case f.kind
|
||||||
|
|
@ -1483,10 +1522,10 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
s: Rope
|
s: Rope
|
||||||
if n.kind == nkEmpty:
|
if n.kind == nkEmpty:
|
||||||
let mname = mangleName(v, p.target)
|
let mname = mangleName(v, p.target)
|
||||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
lineF(p, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||||
[mname, createVar(p, v.typ, isIndirect(v))])
|
[mname, createVar(p, v.typ, isIndirect(v))])
|
||||||
if v.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, v.typ) == etyBaseIndex:
|
if v.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, v.typ) == etyBaseIndex:
|
||||||
addf(p.body, "var $1_Idx = 0;$n", [ mname ])
|
lineF(p, "var $1_Idx = 0;$n", [ mname ])
|
||||||
else:
|
else:
|
||||||
discard mangleName(v, p.target)
|
discard mangleName(v, p.target)
|
||||||
gen(p, n, a)
|
gen(p, n, a)
|
||||||
|
|
@ -1501,25 +1540,25 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
|
let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
|
||||||
if a.typ == etyBaseIndex:
|
if a.typ == etyBaseIndex:
|
||||||
if targetBaseIndex:
|
if targetBaseIndex:
|
||||||
addf(p.body, "var $1 = $2, $1_Idx = $3;$n", [
|
lineF(p, "var $1 = $2, $1_Idx = $3;$n",
|
||||||
v.loc.r, a.address, a.res])
|
[v.loc.r, a.address, a.res])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "var $1 = [$2, $3];$n",
|
lineF(p, "var $1 = [$2, $3];$n",
|
||||||
[v.loc.r, a.address, a.res])
|
[v.loc.r, a.address, a.res])
|
||||||
else:
|
else:
|
||||||
if targetBaseIndex:
|
if targetBaseIndex:
|
||||||
let tmp = p.getTemp
|
let tmp = p.getTemp
|
||||||
addf(p.body, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
||||||
[tmp, a.res, v.loc.r])
|
[tmp, a.res, v.loc.r])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "var $1 = $2;$n", [v.loc.r, a.res])
|
lineF(p, "var $1 = $2;$n", [v.loc.r, a.res])
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
s = a.res
|
s = a.res
|
||||||
if isIndirect(v):
|
if isIndirect(v):
|
||||||
addf(p.body, "var $1 = /**/[$2];$n", [v.loc.r, s])
|
lineF(p, "var $1 = [$2];$n", [v.loc.r, s])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n", [v.loc.r, s])
|
lineF(p, "var $1 = $2;$n" | "$$$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):
|
||||||
|
|
@ -1550,17 +1589,17 @@ proc genNew(p: PProc, n: PNode) =
|
||||||
gen(p, n.sons[1], a)
|
gen(p, n.sons[1], a)
|
||||||
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
addf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, false)])
|
lineF(p, "$1 = $2;$n", [a.res, createVar(p, t, false)])
|
||||||
else:
|
else:
|
||||||
addf(p.body, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
|
lineF(p, "$3 = $2; $1 = &$3;$n", [a.res, createVar(p, t, false), getTemp(p)])
|
||||||
|
|
||||||
proc genNewSeq(p: PProc, n: PNode) =
|
proc genNewSeq(p: PProc, n: PNode) =
|
||||||
var x, y: TCompRes
|
var x, y: TCompRes
|
||||||
gen(p, n.sons[1], x)
|
gen(p, n.sons[1], x)
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
let t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||||
addf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
|
lineF(p, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}" |
|
||||||
"$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
|
"$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$3;}", [
|
||||||
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
||||||
|
|
||||||
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
|
@ -1986,15 +2025,18 @@ proc genReturnStmt(p: PProc, n: PNode) =
|
||||||
genStmt(p, n.sons[0])
|
genStmt(p, n.sons[0])
|
||||||
else:
|
else:
|
||||||
genLineDir(p, n)
|
genLineDir(p, n)
|
||||||
addf(p.body, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
|
lineF(p, "break BeforeRet;$n" | "goto BeforeRet;$n", [])
|
||||||
|
|
||||||
proc frameCreate(p: PProc; procname, filename: Rope): Rope =
|
proc frameCreate(p: PProc; procname, filename: Rope): Rope =
|
||||||
result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$nframePtr = F;$n" |
|
let frameFmt =
|
||||||
"global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n$$framePtr = &$$F;$n")) % [
|
"var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
|
||||||
procname, filename]
|
"global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n"
|
||||||
|
|
||||||
|
result = p.indentLine(frameFmt % [procname, filename])
|
||||||
|
result.add p.indentLine(ropes.`%`("framePtr = F;$n" | "$$framePtr = &$$F;$n", []))
|
||||||
|
|
||||||
proc frameDestroy(p: PProc): Rope =
|
proc frameDestroy(p: PProc): Rope =
|
||||||
result = rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
|
result = p.indentLine rope(("framePtr = F.prev;" | "$framePtr = $F['prev'];") & tnl)
|
||||||
|
|
||||||
proc genProcBody(p: PProc, prc: PSym): Rope =
|
proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
if hasFrameInfo(p):
|
if hasFrameInfo(p):
|
||||||
|
|
@ -2004,8 +2046,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
else:
|
else:
|
||||||
result = nil
|
result = nil
|
||||||
if p.beforeRetNeeded:
|
if p.beforeRetNeeded:
|
||||||
addf(result, "BeforeRet: do {$n$1} while (false); $n" |
|
if p.target == targetJS:
|
||||||
"$# BeforeRet:;$n", [p.body])
|
result.add p.indentLine(~"BeforeRet: do {$n")
|
||||||
|
result.add p.body
|
||||||
|
result.add p.indentLine(~"} while (false);$n")
|
||||||
|
else:
|
||||||
|
addF(result, "$# BeforeRet:;$n", [p.body])
|
||||||
else:
|
else:
|
||||||
add(result, p.body)
|
add(result, p.body)
|
||||||
if prc.typ.callConv == ccSysCall and p.target == targetJS:
|
if prc.typ.callConv == ccSysCall and p.target == targetJS:
|
||||||
|
|
@ -2014,6 +2060,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
if hasFrameInfo(p):
|
if hasFrameInfo(p):
|
||||||
add(result, frameDestroy(p))
|
add(result, frameDestroy(p))
|
||||||
|
|
||||||
|
proc optionaLine(p: Rope): Rope =
|
||||||
|
if p == nil:
|
||||||
|
return nil
|
||||||
|
else:
|
||||||
|
return p & tnl
|
||||||
|
|
||||||
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||||
var
|
var
|
||||||
resultSym: PSym
|
resultSym: PSym
|
||||||
|
|
@ -2029,29 +2081,37 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||||
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
|
||||||
let mname = mangleName(resultSym, p.target)
|
let mname = mangleName(resultSym, p.target)
|
||||||
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
||||||
mname,
|
resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar])
|
||||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
|
||||||
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
|
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
|
||||||
resultAsgn.add "var $#_Idx = 0;$n" % [
|
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||||
mname ];
|
|
||||||
gen(p, prc.ast.sons[resultPos], a)
|
gen(p, prc.ast.sons[resultPos], a)
|
||||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||||
else:
|
else:
|
||||||
returnStmt = "return $#;$n" % [a.res]
|
returnStmt = "return $#;$n" % [a.res]
|
||||||
genStmt(p, prc.getBody)
|
|
||||||
|
|
||||||
result = "function $#($#) {$n$#$n$#$#$#$#}$n" %
|
p.nested: genStmt(p, prc.getBody)
|
||||||
[name, header, p.globals, p.locals, resultAsgn,
|
let def = "function $#($#) {$n$#$#$#$#$#" %
|
||||||
genProcBody(p, prc), returnStmt]
|
[name, header,
|
||||||
|
optionaLine(p.globals),
|
||||||
|
optionaLine(p.locals),
|
||||||
|
optionaLine(resultAsgn),
|
||||||
|
optionaLine(genProcBody(p, prc)),
|
||||||
|
optionaLine(p.indentLine(returnStmt))]
|
||||||
|
|
||||||
|
dec p.extraIndent
|
||||||
|
result = ~tnl
|
||||||
|
result.add p.indentLine(def)
|
||||||
|
result.add p.indentLine(~"}$n")
|
||||||
|
|
||||||
#if gVerbosity >= 3:
|
#if gVerbosity >= 3:
|
||||||
# echo "END generated code for: " & prc.name.s
|
# echo "END generated code for: " & prc.name.s
|
||||||
|
|
||||||
proc genStmt(p: PProc, n: PNode) =
|
proc genStmt(p: PProc, n: PNode) =
|
||||||
var r: TCompRes
|
var r: TCompRes
|
||||||
gen(p, n, r)
|
gen(p, n, r)
|
||||||
if r.res != nil: addf(p.body, "$#;$n", [r.res])
|
if r.res != nil: lineF(p, "$#;$n", [r.res])
|
||||||
|
|
||||||
proc genPragma(p: PProc, n: PNode) =
|
proc genPragma(p: PProc, n: PNode) =
|
||||||
for it in n.sons:
|
for it in n.sons:
|
||||||
|
|
@ -2211,7 +2271,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of nkPragma: genPragma(p, n)
|
of nkPragma: genPragma(p, n)
|
||||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||||
var s = n.sons[namePos].sym
|
var s = n.sons[namePos].sym
|
||||||
if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}:
|
if sfExportc in s.flags and compilingLib:
|
||||||
genSym(p, n.sons[namePos], r)
|
genSym(p, n.sons[namePos], r)
|
||||||
r.res = nil
|
r.res = nil
|
||||||
of nkGotoState, nkState:
|
of nkGotoState, nkState:
|
||||||
|
|
@ -2342,3 +2402,4 @@ proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
|
||||||
result = r
|
result = r
|
||||||
|
|
||||||
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,9 @@ var
|
||||||
|
|
||||||
const oKeepVariableNames* = true
|
const oKeepVariableNames* = true
|
||||||
|
|
||||||
|
template compilingLib*: bool =
|
||||||
|
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
|
||||||
|
|
||||||
proc mainCommandArg*: string =
|
proc mainCommandArg*: string =
|
||||||
## This is intended for commands like check or parse
|
## This is intended for commands like check or parse
|
||||||
## which will work on the main project file unless
|
## which will work on the main project file unless
|
||||||
|
|
|
||||||
122
lib/system.nim
122
lib/system.nim
|
|
@ -2449,18 +2449,6 @@ when false:
|
||||||
# ----------------- GC interface ---------------------------------------------
|
# ----------------- GC interface ---------------------------------------------
|
||||||
|
|
||||||
when not defined(nimscript) and hasAlloc:
|
when not defined(nimscript) and hasAlloc:
|
||||||
proc GC_disable*() {.rtl, inl, benign.}
|
|
||||||
## disables the GC. If called n-times, n calls to `GC_enable` are needed to
|
|
||||||
## reactivate the GC. Note that in most circumstances one should only disable
|
|
||||||
## the mark and sweep phase with `GC_disableMarkAndSweep`.
|
|
||||||
|
|
||||||
proc GC_enable*() {.rtl, inl, benign.}
|
|
||||||
## enables the GC again.
|
|
||||||
|
|
||||||
proc GC_fullCollect*() {.rtl, benign.}
|
|
||||||
## forces a full garbage collection pass.
|
|
||||||
## Ordinary code does not need to call this (and should not).
|
|
||||||
|
|
||||||
type
|
type
|
||||||
GC_Strategy* = enum ## the strategy the GC should use for the application
|
GC_Strategy* = enum ## the strategy the GC should use for the application
|
||||||
gcThroughput, ## optimize for throughput
|
gcThroughput, ## optimize for throughput
|
||||||
|
|
@ -2470,33 +2458,87 @@ when not defined(nimscript) and hasAlloc:
|
||||||
|
|
||||||
{.deprecated: [TGC_Strategy: GC_Strategy].}
|
{.deprecated: [TGC_Strategy: GC_Strategy].}
|
||||||
|
|
||||||
proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
|
when not defined(JS):
|
||||||
## tells the GC the desired strategy for the application.
|
proc GC_disable*() {.rtl, inl, benign.}
|
||||||
## **Deprecated** since version 0.8.14. This has always been a nop.
|
## disables the GC. If called n-times, n calls to `GC_enable` are needed to
|
||||||
|
## reactivate the GC. Note that in most circumstances one should only disable
|
||||||
|
## the mark and sweep phase with `GC_disableMarkAndSweep`.
|
||||||
|
|
||||||
proc GC_enableMarkAndSweep*() {.rtl, benign.}
|
proc GC_enable*() {.rtl, inl, benign.}
|
||||||
proc GC_disableMarkAndSweep*() {.rtl, benign.}
|
## enables the GC again.
|
||||||
## the current implementation uses a reference counting garbage collector
|
|
||||||
## with a seldomly run mark and sweep phase to free cycles. The mark and
|
|
||||||
## sweep phase may take a long time and is not needed if the application
|
|
||||||
## does not create cycles. Thus the mark and sweep phase can be deactivated
|
|
||||||
## and activated separately from the rest of the GC.
|
|
||||||
|
|
||||||
proc GC_getStatistics*(): string {.rtl, benign.}
|
proc GC_fullCollect*() {.rtl, benign.}
|
||||||
## returns an informative string about the GC's activity. This may be useful
|
## forces a full garbage collection pass.
|
||||||
## for tweaking.
|
## Ordinary code does not need to call this (and should not).
|
||||||
|
|
||||||
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
|
||||||
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
## tells the GC the desired strategy for the application.
|
||||||
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
## **Deprecated** since version 0.8.14. This has always been a nop.
|
||||||
## marks the object `x` as referenced, so that it will not be freed until
|
|
||||||
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
|
||||||
## n calls to `GC_unref` are needed to unmark `x`.
|
|
||||||
|
|
||||||
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
proc GC_enableMarkAndSweep*() {.rtl, benign.}
|
||||||
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
proc GC_disableMarkAndSweep*() {.rtl, benign.}
|
||||||
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
## the current implementation uses a reference counting garbage collector
|
||||||
## see the documentation of `GC_ref`.
|
## with a seldomly run mark and sweep phase to free cycles. The mark and
|
||||||
|
## sweep phase may take a long time and is not needed if the application
|
||||||
|
## does not create cycles. Thus the mark and sweep phase can be deactivated
|
||||||
|
## and activated separately from the rest of the GC.
|
||||||
|
|
||||||
|
proc GC_getStatistics*(): string {.rtl, benign.}
|
||||||
|
## returns an informative string about the GC's activity. This may be useful
|
||||||
|
## for tweaking.
|
||||||
|
|
||||||
|
proc GC_ref*[T](x: ref T) {.magic: "GCref", benign.}
|
||||||
|
proc GC_ref*[T](x: seq[T]) {.magic: "GCref", benign.}
|
||||||
|
proc GC_ref*(x: string) {.magic: "GCref", benign.}
|
||||||
|
## marks the object `x` as referenced, so that it will not be freed until
|
||||||
|
## it is unmarked via `GC_unref`. If called n-times for the same object `x`,
|
||||||
|
## n calls to `GC_unref` are needed to unmark `x`.
|
||||||
|
|
||||||
|
proc GC_unref*[T](x: ref T) {.magic: "GCunref", benign.}
|
||||||
|
proc GC_unref*[T](x: seq[T]) {.magic: "GCunref", benign.}
|
||||||
|
proc GC_unref*(x: string) {.magic: "GCunref", benign.}
|
||||||
|
## see the documentation of `GC_ref`.
|
||||||
|
|
||||||
|
else:
|
||||||
|
template GC_disable* =
|
||||||
|
{.warning: "GC_disable is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_enable* =
|
||||||
|
{.warning: "GC_enable is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_fullCollect* =
|
||||||
|
{.warning: "GC_fullCollect is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_setStrategy* =
|
||||||
|
{.warning: "GC_setStrategy is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_enableMarkAndSweep* =
|
||||||
|
{.warning: "GC_enableMarkAndSweep is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_disableMarkAndSweep* =
|
||||||
|
{.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_ref*[T](x: ref T) =
|
||||||
|
{.warning: "GC_ref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_ref*[T](x: seq[T]) =
|
||||||
|
{.warning: "GC_ref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_ref*(x: string) =
|
||||||
|
{.warning: "GC_ref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_unref*[T](x: ref T) =
|
||||||
|
{.warning: "GC_unref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_unref*[T](x: seq[T]) =
|
||||||
|
{.warning: "GC_unref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_unref*(x: string) =
|
||||||
|
{.warning: "GC_unref is a no-op in JavaScript".}
|
||||||
|
|
||||||
|
template GC_getStatistics*(): string =
|
||||||
|
{.warning: "GC_disableMarkAndSweep is a no-op in JavaScript".}
|
||||||
|
""
|
||||||
|
|
||||||
template accumulateResult*(iter: untyped) =
|
template accumulateResult*(iter: untyped) =
|
||||||
## helps to convert an iterator to a proc.
|
## helps to convert an iterator to a proc.
|
||||||
|
|
@ -3231,16 +3273,6 @@ when not defined(JS): #and not defined(nimscript):
|
||||||
|
|
||||||
elif defined(JS):
|
elif defined(JS):
|
||||||
# Stubs:
|
# Stubs:
|
||||||
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard
|
|
||||||
|
|
||||||
proc GC_disable() = discard
|
|
||||||
proc GC_enable() = discard
|
|
||||||
proc GC_fullCollect() = discard
|
|
||||||
proc GC_setStrategy(strategy: GC_Strategy) = discard
|
|
||||||
proc GC_enableMarkAndSweep() = discard
|
|
||||||
proc GC_disableMarkAndSweep() = discard
|
|
||||||
proc GC_getStatistics(): string = return ""
|
|
||||||
|
|
||||||
proc getOccupiedMem(): int = return -1
|
proc getOccupiedMem(): int = return -1
|
||||||
proc getFreeMem(): int = return -1
|
proc getFreeMem(): int = return -1
|
||||||
proc getTotalMem(): int = return -1
|
proc getTotalMem(): int = return -1
|
||||||
|
|
|
||||||
10
tests/js/tjshello.nim
Normal file
10
tests/js/tjshello.nim
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
discard """
|
||||||
|
output: "Hello World"
|
||||||
|
maxcodesize: 1000
|
||||||
|
ccodecheck: "!@'function'"
|
||||||
|
"""
|
||||||
|
|
||||||
|
import jsconsole
|
||||||
|
|
||||||
|
console.log "Hello World"
|
||||||
|
|
||||||
|
|
@ -52,6 +52,7 @@ type
|
||||||
exitCode*: int
|
exitCode*: int
|
||||||
msg*: string
|
msg*: string
|
||||||
ccodeCheck*: string
|
ccodeCheck*: string
|
||||||
|
maxCodeSize*: int
|
||||||
err*: TResultEnum
|
err*: TResultEnum
|
||||||
substr*, sortoutput*: bool
|
substr*, sortoutput*: bool
|
||||||
targets*: set[TTarget]
|
targets*: set[TTarget]
|
||||||
|
|
@ -109,6 +110,7 @@ proc specDefaults*(result: var TSpec) =
|
||||||
result.tfile = ""
|
result.tfile = ""
|
||||||
result.tline = 0
|
result.tline = 0
|
||||||
result.tcolumn = 0
|
result.tcolumn = 0
|
||||||
|
result.maxCodeSize = 0
|
||||||
|
|
||||||
proc parseTargets*(value: string): set[TTarget] =
|
proc parseTargets*(value: string): set[TTarget] =
|
||||||
for v in value.normalize.split:
|
for v in value.normalize.split:
|
||||||
|
|
@ -180,6 +182,7 @@ proc parseSpec*(filename: string): TSpec =
|
||||||
else:
|
else:
|
||||||
result.cmd = e.value
|
result.cmd = e.value
|
||||||
of "ccodecheck": result.ccodeCheck = e.value
|
of "ccodecheck": result.ccodeCheck = e.value
|
||||||
|
of "maxcodesize": discard parseInt(e.value, result.maxCodeSize)
|
||||||
of "target", "targets":
|
of "target", "targets":
|
||||||
for v in e.value.normalize.split:
|
for v in e.value.normalize.split:
|
||||||
case v
|
case v
|
||||||
|
|
|
||||||
|
|
@ -212,20 +212,31 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
|
||||||
proc generatedFile(path, name: string, target: TTarget): string =
|
proc generatedFile(path, name: string, target: TTarget): string =
|
||||||
let ext = targetToExt[target]
|
let ext = targetToExt[target]
|
||||||
result = path / "nimcache" /
|
result = path / "nimcache" /
|
||||||
(if target == targetJS: path.splitPath.tail & "_" else: "compiler_") &
|
(if target == targetJS: "" else: "compiler_") &
|
||||||
name.changeFileExt(ext)
|
name.changeFileExt(ext)
|
||||||
|
|
||||||
proc codegenCheck(test: TTest, check: string, given: var TSpec) =
|
proc needsCodegenCheck(spec: TSpec): bool =
|
||||||
|
result = spec.maxCodeSize > 0 or spec.ccodeCheck.len > 0
|
||||||
|
|
||||||
|
proc codegenCheck(test: TTest, spec: TSpec, expectedMsg: var string,
|
||||||
|
given: var TSpec) =
|
||||||
try:
|
try:
|
||||||
let (path, name, _) = test.name.splitFile
|
let (path, name, _) = test.name.splitFile
|
||||||
let genFile = generatedFile(path, name, test.target)
|
let genFile = generatedFile(path, name, test.target)
|
||||||
let contents = readFile(genFile).string
|
let contents = readFile(genFile).string
|
||||||
if check[0] == '\\':
|
let check = spec.ccodeCheck
|
||||||
# little hack to get 'match' support:
|
if check.len > 0:
|
||||||
if not contents.match(check.peg):
|
if check[0] == '\\':
|
||||||
|
# little hack to get 'match' support:
|
||||||
|
if not contents.match(check.peg):
|
||||||
|
given.err = reCodegenFailure
|
||||||
|
elif contents.find(check.peg) < 0:
|
||||||
given.err = reCodegenFailure
|
given.err = reCodegenFailure
|
||||||
elif contents.find(check.peg) < 0:
|
expectedMsg = check
|
||||||
|
if spec.maxCodeSize > 0 and contents.len > spec.maxCodeSize:
|
||||||
given.err = reCodegenFailure
|
given.err = reCodegenFailure
|
||||||
|
given.msg = "generated code size: " & $contents.len
|
||||||
|
expectedMsg = "max allowed size: " & $spec.maxCodeSize
|
||||||
except ValueError:
|
except ValueError:
|
||||||
given.err = reInvalidPeg
|
given.err = reInvalidPeg
|
||||||
echo getCurrentExceptionMsg()
|
echo getCurrentExceptionMsg()
|
||||||
|
|
@ -248,9 +259,8 @@ proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec;
|
||||||
var expectedmsg: string = ""
|
var expectedmsg: string = ""
|
||||||
var givenmsg: string = ""
|
var givenmsg: string = ""
|
||||||
if given.err == reSuccess:
|
if given.err == reSuccess:
|
||||||
if expected.ccodeCheck.len > 0:
|
if expected.needsCodegenCheck:
|
||||||
codegenCheck(test, expected.ccodeCheck, given)
|
codegenCheck(test, expected, expectedmsg, given)
|
||||||
expectedmsg = expected.ccodeCheck
|
|
||||||
givenmsg = given.msg
|
givenmsg = given.msg
|
||||||
if expected.nimout.len > 0:
|
if expected.nimout.len > 0:
|
||||||
expectedmsg = expected.nimout
|
expectedmsg = expected.nimout
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue