mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
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:
@@ -138,6 +138,13 @@ proc ropecg(m: BModule, frmt: FormatStr, args: varargs[Rope]): Rope =
|
||||
template rfmt(m: BModule, fmt: string, args: varargs[Rope]): untyped =
|
||||
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,
|
||||
args: varargs[Rope]) =
|
||||
add(c, ropecg(m, frmt, args))
|
||||
@@ -150,11 +157,6 @@ proc appcg(p: BProc, s: TCProcSection, frmt: FormatStr,
|
||||
args: varargs[Rope]) =
|
||||
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) =
|
||||
add(p.s(s), indentLine(p, r))
|
||||
|
||||
|
||||
@@ -94,12 +94,39 @@ type
|
||||
target: TTarget # duplicated here for faster dispatching
|
||||
unique: int # for temp identifier generation
|
||||
blocks: seq[TBlock]
|
||||
extraIndent: int
|
||||
up: PProc # up the call chain; required for closure support
|
||||
declaredGlobals: IntSet
|
||||
|
||||
template `|`(a, b: untyped): untyped {.dirty.} =
|
||||
(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 =
|
||||
new(result)
|
||||
result.forwarded = @[]
|
||||
@@ -129,7 +156,8 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||
module: module,
|
||||
procDef: procDef,
|
||||
g: globals,
|
||||
target: module.target)
|
||||
target: module.target,
|
||||
extraIndent: int(procDef != nil))
|
||||
if procDef != nil: result.prc = procDef.sons[namePos].sym
|
||||
if result.target == targetPHP:
|
||||
result.declaredGlobals = initIntSet()
|
||||
@@ -290,7 +318,7 @@ proc getTemp(p: PProc, defineInLocals: bool = true): Rope =
|
||||
if p.target == targetJS:
|
||||
result = "Tmp$1" % [rope(p.unique)]
|
||||
if defineInLocals:
|
||||
addf(p.locals, "var $1;$n", [result])
|
||||
add(p.locals, p.indentLine("var $1;$n" % [result]))
|
||||
else:
|
||||
result = "$$Tmp$1" % [rope(p.unique)]
|
||||
|
||||
@@ -315,9 +343,11 @@ proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
# tmp = b
|
||||
# tmp
|
||||
gen(p, a, x)
|
||||
p.body.addf("if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
||||
gen(p, b, y)
|
||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
||||
lineF(p, "if (!$1) $2 = false; else {", [x.rdLoc, r.rdLoc])
|
||||
p.nested:
|
||||
gen(p, b, y)
|
||||
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||
line(p, "}")
|
||||
|
||||
proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
assert r.kind == resNone
|
||||
@@ -331,9 +361,11 @@ proc genOr(p: PProc, a, b: PNode, r: var TCompRes) =
|
||||
r.res = p.getTemp
|
||||
r.kind = resVal
|
||||
gen(p, a, x)
|
||||
p.body.addf("if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
||||
gen(p, b, y)
|
||||
p.body.addf("$2 = $1; }", [y.rdLoc, r.rdLoc])
|
||||
lineF(p, "if ($1) $2 = true; else {", [x.rdLoc, r.rdLoc])
|
||||
p.nested:
|
||||
gen(p, b, y)
|
||||
lineF(p, "$2 = $1;", [y.rdLoc, r.rdLoc])
|
||||
line(p, "}")
|
||||
|
||||
type
|
||||
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)"], # ToBiggestInt
|
||||
["nimCharToStr", "nimCharToStr", "nimCharToStr($1)", "nimCharToStr($1)"],
|
||||
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"], [
|
||||
"cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")",
|
||||
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr", "cstrToNimstr",
|
||||
"cstrToNimstr(($1)+\"\")",
|
||||
"cstrToNimstr(($1)+\"\")"], ["cstrToNimstr",
|
||||
"cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["nimBoolToStr", "nimBoolToStr", "nimBoolToStr($1)", "nimBoolToStr($1)"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr(($1)+\"\")", "cstrToNimstr(($1)+\"\")"],
|
||||
["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"],
|
||||
["", "", "$1", "$1"]]
|
||||
|
||||
@@ -475,18 +505,18 @@ proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) =
|
||||
r.res = frmt % [r.rdLoc]
|
||||
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
|
||||
x, y: TCompRes
|
||||
let i = ord(optOverflowCheck notin p.options)
|
||||
useMagic(p, ops[op][i])
|
||||
useMagic(p, jsOps[op][i])
|
||||
if sonsLen(n) > 2:
|
||||
gen(p, n.sons[1], x)
|
||||
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:
|
||||
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) =
|
||||
case op
|
||||
@@ -501,7 +531,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
gen(p, n.sons[2], y)
|
||||
r.res = "intval($1 / $2)" % [x.rdLoc, y.rdLoc]
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
of mModI:
|
||||
if p.target == targetPHP:
|
||||
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)
|
||||
r.res = "($1 % $2)" % [x.rdLoc, y.rdLoc]
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
of mShrI:
|
||||
var x, y: TCompRes
|
||||
gen(p, n.sons[1], x)
|
||||
@@ -534,9 +564,9 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||
else:
|
||||
gen(p, n.sons[1], r)
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
else:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
arithAux(p, n, r, op)
|
||||
r.kind = resExpr
|
||||
|
||||
proc hasFrameInfo(p: PProc): bool =
|
||||
@@ -546,14 +576,14 @@ proc hasFrameInfo(p: PProc): bool =
|
||||
proc genLineDir(p: PProc, n: PNode) =
|
||||
let line = toLinenumber(n.info)
|
||||
if optLineDir in p.options:
|
||||
addf(p.body, "// line $2 \"$1\"$n",
|
||||
lineF(p, "// line $2 \"$1\"$n",
|
||||
[rope(toFilename(n.info)), rope(line)])
|
||||
if {optStackTrace, optEndb} * p.options == {optStackTrace, optEndb} and
|
||||
((p.prc == nil) or sfPure notin p.prc.flags):
|
||||
useMagic(p, "endb")
|
||||
addf(p.body, "endb($1);$n", [rope(line)])
|
||||
lineF(p, "endb($1);$n", [rope(line)])
|
||||
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) =
|
||||
var
|
||||
@@ -566,20 +596,20 @@ proc genWhileStmt(p: PProc, n: PNode) =
|
||||
p.blocks[length].id = -p.unique
|
||||
p.blocks[length].isLoop = true
|
||||
let labl = p.unique.rope
|
||||
addf(p.body, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
||||
gen(p, n.sons[0], cond)
|
||||
addf(p.body, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
||||
lineF(p, "L$1: while (true) {$n" | "while (true) {$n", [labl])
|
||||
p.nested: gen(p, n.sons[0], cond)
|
||||
lineF(p, "if (!$1) break L$2;$n" | "if (!$1) goto L$2;$n",
|
||||
[cond.res, labl])
|
||||
genStmt(p, n.sons[1])
|
||||
addf(p.body, "}$n" | "}L$#:;$n", [labl])
|
||||
p.nested: genStmt(p, n.sons[1])
|
||||
lineF(p, "}$n" | "}L$#:;$n", [labl])
|
||||
setLen(p.blocks, length)
|
||||
|
||||
proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) =
|
||||
if src.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:
|
||||
p.body.addf("$1;$n", [src.rdLoc])
|
||||
lineF(p, "$1;$n", [src.rdLoc])
|
||||
src.kind = resNone
|
||||
src.res = nil
|
||||
|
||||
@@ -620,8 +650,8 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var tmpFramePtr = rope"F"
|
||||
if optStackTrace notin p.options:
|
||||
tmpFramePtr = p.getTemp(true)
|
||||
add(p.body, tmpFramePtr & " = framePtr;" & tnl)
|
||||
addf(p.body, "try {$n", [])
|
||||
line(p, tmpFramePtr & " = framePtr;" & tnl)
|
||||
lineF(p, "try {$n", [])
|
||||
if p.target == targetPHP and p.globals == nil:
|
||||
p.globals = "global $lastJSError; global $prevJSError;".rope
|
||||
var a: TCompRes
|
||||
@@ -632,18 +662,18 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if p.target == targetJS and catchBranchesExist:
|
||||
addf(p.body, "--excHandler;$n} catch (EXC) {$n var prevJSError = lastJSError;$n" &
|
||||
" lastJSError = EXC;$n --excHandler;$n", [])
|
||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
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:
|
||||
let blen = sonsLen(n.sons[i])
|
||||
if blen == 1:
|
||||
# general except section:
|
||||
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)
|
||||
moveInto(p, a, r)
|
||||
if i > 1: addf(p.body, "}$n", [])
|
||||
if i > 1: lineF(p, "}$n", [])
|
||||
else:
|
||||
var orExpr: Rope = nil
|
||||
useMagic(p, "isObj")
|
||||
@@ -653,30 +683,32 @@ proc genTry(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if orExpr != nil: add(orExpr, "||")
|
||||
addf(orExpr, "isObj($2lastJSError.m_type, $1)",
|
||||
[genTypeInfo(p, n.sons[i].sons[j].typ), dollar])
|
||||
if i > 1: add(p.body, "else ")
|
||||
addf(p.body, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
||||
if i > 1: line(p, "else ")
|
||||
lineF(p, "if ($1lastJSError && ($2)) {$n", [dollar, orExpr])
|
||||
gen(p, n.sons[i].sons[blen - 1], a)
|
||||
moveInto(p, a, r)
|
||||
addf(p.body, "}$n", [])
|
||||
lineF(p, "}$n", [])
|
||||
inc(i)
|
||||
if catchBranchesExist:
|
||||
if not generalCatchBranchExists:
|
||||
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])
|
||||
if p.target == targetJS:
|
||||
add(p.body, "} finally {" & tnl)
|
||||
add(p.body, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
line(p, "} finally {" & tnl)
|
||||
line(p, "framePtr = $1;$n" % [tmpFramePtr])
|
||||
if p.target == targetPHP:
|
||||
# XXX ugly hack for PHP codegen
|
||||
add(p.body, "}" & tnl)
|
||||
line(p, "}" & tnl)
|
||||
if i < length and n.sons[i].kind == nkFinally:
|
||||
genStmt(p, n.sons[i].sons[0])
|
||||
if p.target == targetPHP:
|
||||
# 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:
|
||||
add(p.body, "}" & tnl)
|
||||
line(p, "}" & tnl)
|
||||
|
||||
proc genRaiseStmt(p: PProc, n: PNode) =
|
||||
genLineDir(p, n)
|
||||
@@ -685,11 +717,11 @@ proc genRaiseStmt(p: PProc, n: PNode) =
|
||||
gen(p, n.sons[0], a)
|
||||
let typ = skipTypes(n.sons[0].typ, abstractPtrs)
|
||||
useMagic(p, "raiseException")
|
||||
addf(p.body, "raiseException($1, $2);$n",
|
||||
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
||||
lineF(p, "raiseException($1, $2);$n",
|
||||
[a.rdLoc, makeJSString(typ.sym.name.s)])
|
||||
else:
|
||||
useMagic(p, "reraiseException")
|
||||
add(p.body, "reraiseException();" & tnl)
|
||||
line(p, "reraiseException();" & tnl)
|
||||
|
||||
proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
@@ -699,9 +731,9 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString
|
||||
if stringSwitch and p.target == targetJS:
|
||||
useMagic(p, "toJSStr")
|
||||
addf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
||||
lineF(p, "switch (toJSStr($1)) {$n", [cond.rdLoc])
|
||||
else:
|
||||
addf(p.body, "switch ($1) {$n", [cond.rdLoc])
|
||||
lineF(p, "switch ($1) {$n", [cond.rdLoc])
|
||||
if not isEmptyType(n.typ):
|
||||
r.kind = resVal
|
||||
r.res = getTemp(p)
|
||||
@@ -715,27 +747,29 @@ proc genCaseJS(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var v = copyNode(e.sons[0])
|
||||
while v.intVal <= e.sons[1].intVal:
|
||||
gen(p, v, cond)
|
||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
||||
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||
inc(v.intVal)
|
||||
else:
|
||||
if stringSwitch:
|
||||
case e.kind
|
||||
of nkStrLit..nkTripleStrLit: addf(p.body, "case $1: ",
|
||||
of nkStrLit..nkTripleStrLit: lineF(p, "case $1:$n",
|
||||
[makeJSString(e.strVal, false)])
|
||||
else: internalError(e.info, "jsgen.genCaseStmt: 2")
|
||||
else:
|
||||
gen(p, e, cond)
|
||||
addf(p.body, "case $1: ", [cond.rdLoc])
|
||||
gen(p, lastSon(it), stmt)
|
||||
moveInto(p, stmt, r)
|
||||
addf(p.body, "$nbreak;$n", [])
|
||||
lineF(p, "case $1:$n", [cond.rdLoc])
|
||||
p.nested:
|
||||
gen(p, lastSon(it), stmt)
|
||||
moveInto(p, stmt, r)
|
||||
lineF(p, "break;$n", [])
|
||||
of nkElse:
|
||||
addf(p.body, "default: $n", [])
|
||||
gen(p, it.sons[0], stmt)
|
||||
moveInto(p, stmt, r)
|
||||
addf(p.body, "break;$n", [])
|
||||
lineF(p, "default: $n", [])
|
||||
p.nested:
|
||||
gen(p, it.sons[0], stmt)
|
||||
moveInto(p, stmt, r)
|
||||
lineF(p, "break;$n", [])
|
||||
else: internalError(it.info, "jsgen.genCaseStmt")
|
||||
addf(p.body, "}$n", [])
|
||||
lineF(p, "}$n", [])
|
||||
|
||||
proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||
inc(p.unique)
|
||||
@@ -746,13 +780,13 @@ proc genBlock(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var sym = n.sons[0].sym
|
||||
sym.loc.k = locOther
|
||||
sym.position = idx+1
|
||||
let labl = p.unique
|
||||
lineF(p, "L$1: do {$n" | "", [labl.rope])
|
||||
setLen(p.blocks, idx + 1)
|
||||
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)
|
||||
addf(p.body, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
||||
setLen(p.blocks, idx)
|
||||
lineF(p, "} while(false);$n" | "$nL$#:;$n", [labl.rope])
|
||||
|
||||
proc genBreakStmt(p: PProc, n: PNode) =
|
||||
var idx: int
|
||||
@@ -770,19 +804,23 @@ proc genBreakStmt(p: PProc, n: PNode) =
|
||||
if idx < 0 or not p.blocks[idx].isLoop:
|
||||
internalError(n.info, "no loop to break")
|
||||
p.blocks[idx].id = abs(p.blocks[idx].id) # label is used
|
||||
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) =
|
||||
genLineDir(p, n)
|
||||
p.body.add p.indentLine(nil)
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
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:
|
||||
let v = n.sons[i].sym
|
||||
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||
add(p.body, "$")
|
||||
add(p.body, mangleName(v, p.target))
|
||||
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
||||
p.body.add "$"
|
||||
p.body.add mangleName(v, p.target)
|
||||
else:
|
||||
internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
||||
p.body.add tnl
|
||||
|
||||
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var cond, stmt: TCompRes
|
||||
@@ -794,18 +832,18 @@ proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let it = n.sons[i]
|
||||
if sonsLen(it) != 1:
|
||||
if i > 0:
|
||||
addf(p.body, "else {$n", [])
|
||||
lineF(p, "else {$n", [])
|
||||
inc(toClose)
|
||||
gen(p, it.sons[0], cond)
|
||||
addf(p.body, "if ($1) {$n", [cond.rdLoc])
|
||||
p.nested: gen(p, it.sons[0], cond)
|
||||
lineF(p, "if ($1) {$n", [cond.rdLoc])
|
||||
gen(p, it.sons[1], stmt)
|
||||
else:
|
||||
# else part:
|
||||
addf(p.body, "else {$n", [])
|
||||
gen(p, it.sons[0], stmt)
|
||||
lineF(p, "else {$n", [])
|
||||
p.nested: gen(p, it.sons[0], stmt)
|
||||
moveInto(p, stmt, r)
|
||||
addf(p.body, "}$n", [])
|
||||
add(p.body, repeat('}', toClose) & tnl)
|
||||
lineF(p, "}$n", [])
|
||||
line(p, repeat('}', toClose) & tnl)
|
||||
|
||||
proc generateHeader(p: PProc, typ: PType): Rope =
|
||||
result = nil
|
||||
@@ -854,7 +892,7 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
gen(p, x[0], a)
|
||||
gen(p, x[1], b)
|
||||
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
|
||||
|
||||
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:
|
||||
gen(p, x.sons[0], a)
|
||||
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]
|
||||
else:
|
||||
gen(p, x, a)
|
||||
@@ -876,29 +914,29 @@ proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) =
|
||||
case xtyp
|
||||
of etySeq:
|
||||
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:
|
||||
useMagic(p, "nimCopy")
|
||||
addf(p.body, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
lineF(p, "$1 = nimCopy(null, $2, $3);$n",
|
||||
[a.rdLoc, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyObject:
|
||||
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:
|
||||
useMagic(p, "nimCopy")
|
||||
addf(p.body, "nimCopy($1, $2, $3);$n",
|
||||
[a.res, b.res, genTypeInfo(p, y.typ)])
|
||||
lineF(p, "nimCopy($1, $2, $3);$n",
|
||||
[a.res, b.res, genTypeInfo(p, y.typ)])
|
||||
of etyBaseIndex:
|
||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||
if y.kind == nkCall:
|
||||
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:
|
||||
internalError(x.info, "genAsgn")
|
||||
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:
|
||||
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) =
|
||||
genLineDir(p, n)
|
||||
@@ -917,12 +955,13 @@ proc genSwap(p: PProc, n: PNode) =
|
||||
let tmp2 = p.getTemp(false)
|
||||
if a.typ != etyBaseIndex or b.typ != etyBaseIndex:
|
||||
internalError(n.info, "genSwap")
|
||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;$n", [
|
||||
tmp, a.address, b.address])
|
||||
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;$n" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;$n",
|
||||
[tmp, a.address, b.address])
|
||||
tmp = tmp2
|
||||
addf(p.body, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;", [tmp, a.res, b.res])
|
||||
lineF(p, "var $1 = $2; $2 = $3; $3 = $1;" |
|
||||
"$1 = $2; $2 = $3; $3 = $1;",
|
||||
[tmp, a.res, b.res])
|
||||
|
||||
proc getFieldPosition(f: PNode): int =
|
||||
case f.kind
|
||||
@@ -1483,10 +1522,10 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
s: Rope
|
||||
if n.kind == nkEmpty:
|
||||
let mname = mangleName(v, p.target)
|
||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||
[mname, createVar(p, v.typ, isIndirect(v))])
|
||||
lineF(p, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||
[mname, createVar(p, v.typ, isIndirect(v))])
|
||||
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:
|
||||
discard mangleName(v, p.target)
|
||||
gen(p, n, a)
|
||||
@@ -1501,25 +1540,25 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
let targetBaseIndex = {sfAddrTaken, sfGlobal} * v.flags == {}
|
||||
if a.typ == etyBaseIndex:
|
||||
if targetBaseIndex:
|
||||
addf(p.body, "var $1 = $2, $1_Idx = $3;$n", [
|
||||
v.loc.r, a.address, a.res])
|
||||
lineF(p, "var $1 = $2, $1_Idx = $3;$n",
|
||||
[v.loc.r, a.address, a.res])
|
||||
else:
|
||||
addf(p.body, "var $1 = [$2, $3];$n",
|
||||
[v.loc.r, a.address, a.res])
|
||||
lineF(p, "var $1 = [$2, $3];$n",
|
||||
[v.loc.r, a.address, a.res])
|
||||
else:
|
||||
if targetBaseIndex:
|
||||
let tmp = p.getTemp
|
||||
addf(p.body, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
||||
[tmp, a.res, v.loc.r])
|
||||
lineF(p, "var $1 = $2, $3 = $1[0], $3_Idx = $1[1];$n",
|
||||
[tmp, a.res, v.loc.r])
|
||||
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
|
||||
else:
|
||||
s = a.res
|
||||
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:
|
||||
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) =
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
@@ -1550,17 +1589,17 @@ proc genNew(p: PProc, n: PNode) =
|
||||
gen(p, n.sons[1], a)
|
||||
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
|
||||
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:
|
||||
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) =
|
||||
var x, y: TCompRes
|
||||
gen(p, n.sons[1], x)
|
||||
gen(p, n.sons[2], y)
|
||||
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;}" |
|
||||
"$1 = array(); for ($$i=0;$$i<$2;++$$i) {$1[]=$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;}", [
|
||||
x.rdLoc, y.rdLoc, createVar(p, t, false)])
|
||||
|
||||
proc genOrd(p: PProc, n: PNode, r: var TCompRes) =
|
||||
@@ -1986,15 +2025,18 @@ proc genReturnStmt(p: PProc, n: PNode) =
|
||||
genStmt(p, n.sons[0])
|
||||
else:
|
||||
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 =
|
||||
result = (("var F={procname:$1,prev:framePtr,filename:$2,line:0};$nframePtr = F;$n" |
|
||||
"global $$framePtr; $$F=array('procname'=>$#,'prev'=>$$framePtr,'filename'=>$#,'line'=>0);$n$$framePtr = &$$F;$n")) % [
|
||||
procname, filename]
|
||||
let frameFmt =
|
||||
"var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" |
|
||||
"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 =
|
||||
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 =
|
||||
if hasFrameInfo(p):
|
||||
@@ -2004,8 +2046,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||
else:
|
||||
result = nil
|
||||
if p.beforeRetNeeded:
|
||||
addf(result, "BeforeRet: do {$n$1} while (false); $n" |
|
||||
"$# BeforeRet:;$n", [p.body])
|
||||
if p.target == targetJS:
|
||||
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:
|
||||
add(result, p.body)
|
||||
if prc.typ.callConv == ccSysCall and p.target == targetJS:
|
||||
@@ -2014,6 +2060,12 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||
if hasFrameInfo(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 =
|
||||
var
|
||||
resultSym: PSym
|
||||
@@ -2029,29 +2081,37 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast.sons[resultPos].sym
|
||||
let mname = mangleName(resultSym, p.target)
|
||||
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
||||
mname,
|
||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
||||
let resVar = createVar(p, resultSym.typ, isIndirect(resultSym))
|
||||
resultAsgn = p.indentLine(("var $# = $#;$n" | "$$$# = $#;$n") % [mname, resVar])
|
||||
if resultSym.typ.kind in { tyVar, tyPtr, tyRef } and mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
resultAsgn.add "var $#_Idx = 0;$n" % [
|
||||
mname ];
|
||||
resultAsgn.add p.indentLine("var $#_Idx = 0;$n" % [mname])
|
||||
gen(p, prc.ast.sons[resultPos], a)
|
||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
returnStmt = "return [$#, $#];$n" % [a.address, a.res]
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
genStmt(p, prc.getBody)
|
||||
|
||||
result = "function $#($#) {$n$#$n$#$#$#$#}$n" %
|
||||
[name, header, p.globals, p.locals, resultAsgn,
|
||||
genProcBody(p, prc), returnStmt]
|
||||
p.nested: genStmt(p, prc.getBody)
|
||||
let def = "function $#($#) {$n$#$#$#$#$#" %
|
||||
[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:
|
||||
# echo "END generated code for: " & prc.name.s
|
||||
|
||||
proc genStmt(p: PProc, n: PNode) =
|
||||
var r: TCompRes
|
||||
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) =
|
||||
for it in n.sons:
|
||||
@@ -2211,7 +2271,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkPragma: genPragma(p, n)
|
||||
of nkProcDef, nkMethodDef, nkConverterDef:
|
||||
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)
|
||||
r.res = nil
|
||||
of nkGotoState, nkState:
|
||||
@@ -2342,3 +2402,4 @@ proc myOpen(graph: ModuleGraph; s: PSym; cache: IdentCache): PPassContext =
|
||||
result = r
|
||||
|
||||
const JSgenPass* = makePass(myOpen, myOpenCached, myProcess, myClose)
|
||||
|
||||
|
||||
@@ -186,6 +186,9 @@ var
|
||||
|
||||
const oKeepVariableNames* = true
|
||||
|
||||
template compilingLib*: bool =
|
||||
gGlobalOptions * {optGenGuiApp, optGenDynLib} != {}
|
||||
|
||||
proc mainCommandArg*: string =
|
||||
## This is intended for commands like check or parse
|
||||
## 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 ---------------------------------------------
|
||||
|
||||
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
|
||||
GC_Strategy* = enum ## the strategy the GC should use for the application
|
||||
gcThroughput, ## optimize for throughput
|
||||
@@ -2470,33 +2458,87 @@ when not defined(nimscript) and hasAlloc:
|
||||
|
||||
{.deprecated: [TGC_Strategy: GC_Strategy].}
|
||||
|
||||
proc GC_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
|
||||
## tells the GC the desired strategy for the application.
|
||||
## **Deprecated** since version 0.8.14. This has always been a nop.
|
||||
when not defined(JS):
|
||||
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_enableMarkAndSweep*() {.rtl, benign.}
|
||||
proc GC_disableMarkAndSweep*() {.rtl, benign.}
|
||||
## 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_enable*() {.rtl, inl, benign.}
|
||||
## enables the GC again.
|
||||
|
||||
proc GC_getStatistics*(): string {.rtl, benign.}
|
||||
## returns an informative string about the GC's activity. This may be useful
|
||||
## for tweaking.
|
||||
proc GC_fullCollect*() {.rtl, benign.}
|
||||
## forces a full garbage collection pass.
|
||||
## Ordinary code does not need to call this (and should not).
|
||||
|
||||
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_setStrategy*(strategy: GC_Strategy) {.rtl, deprecated, benign.}
|
||||
## tells the GC the desired strategy for the application.
|
||||
## **Deprecated** since version 0.8.14. This has always been a nop.
|
||||
|
||||
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`.
|
||||
proc GC_enableMarkAndSweep*() {.rtl, benign.}
|
||||
proc GC_disableMarkAndSweep*() {.rtl, benign.}
|
||||
## 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.}
|
||||
## 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) =
|
||||
## helps to convert an iterator to a proc.
|
||||
@@ -3231,16 +3273,6 @@ when not defined(JS): #and not defined(nimscript):
|
||||
|
||||
elif defined(JS):
|
||||
# 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 getFreeMem(): 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
|
||||
msg*: string
|
||||
ccodeCheck*: string
|
||||
maxCodeSize*: int
|
||||
err*: TResultEnum
|
||||
substr*, sortoutput*: bool
|
||||
targets*: set[TTarget]
|
||||
@@ -109,6 +110,7 @@ proc specDefaults*(result: var TSpec) =
|
||||
result.tfile = ""
|
||||
result.tline = 0
|
||||
result.tcolumn = 0
|
||||
result.maxCodeSize = 0
|
||||
|
||||
proc parseTargets*(value: string): set[TTarget] =
|
||||
for v in value.normalize.split:
|
||||
@@ -180,6 +182,7 @@ proc parseSpec*(filename: string): TSpec =
|
||||
else:
|
||||
result.cmd = e.value
|
||||
of "ccodecheck": result.ccodeCheck = e.value
|
||||
of "maxcodesize": discard parseInt(e.value, result.maxCodeSize)
|
||||
of "target", "targets":
|
||||
for v in e.value.normalize.split:
|
||||
case v
|
||||
|
||||
@@ -212,20 +212,31 @@ proc cmpMsgs(r: var TResults, expected, given: TSpec, test: TTest) =
|
||||
proc generatedFile(path, name: string, target: TTarget): string =
|
||||
let ext = targetToExt[target]
|
||||
result = path / "nimcache" /
|
||||
(if target == targetJS: path.splitPath.tail & "_" else: "compiler_") &
|
||||
(if target == targetJS: "" else: "compiler_") &
|
||||
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:
|
||||
let (path, name, _) = test.name.splitFile
|
||||
let genFile = generatedFile(path, name, test.target)
|
||||
let contents = readFile(genFile).string
|
||||
if check[0] == '\\':
|
||||
# little hack to get 'match' support:
|
||||
if not contents.match(check.peg):
|
||||
let check = spec.ccodeCheck
|
||||
if check.len > 0:
|
||||
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
|
||||
elif contents.find(check.peg) < 0:
|
||||
expectedMsg = check
|
||||
if spec.maxCodeSize > 0 and contents.len > spec.maxCodeSize:
|
||||
given.err = reCodegenFailure
|
||||
given.msg = "generated code size: " & $contents.len
|
||||
expectedMsg = "max allowed size: " & $spec.maxCodeSize
|
||||
except ValueError:
|
||||
given.err = reInvalidPeg
|
||||
echo getCurrentExceptionMsg()
|
||||
@@ -248,9 +259,8 @@ proc compilerOutputTests(test: TTest, given: var TSpec, expected: TSpec;
|
||||
var expectedmsg: string = ""
|
||||
var givenmsg: string = ""
|
||||
if given.err == reSuccess:
|
||||
if expected.ccodeCheck.len > 0:
|
||||
codegenCheck(test, expected.ccodeCheck, given)
|
||||
expectedmsg = expected.ccodeCheck
|
||||
if expected.needsCodegenCheck:
|
||||
codegenCheck(test, expected, expectedmsg, given)
|
||||
givenmsg = given.msg
|
||||
if expected.nimout.len > 0:
|
||||
expectedmsg = expected.nimout
|
||||
|
||||
Reference in New Issue
Block a user