JS codegen enhancements; still unusable

This commit is contained in:
Araq 2012-07-01 19:35:19 +02:00
commit fe285b354d
9 changed files with 223 additions and 59 deletions

View file

@ -546,11 +546,12 @@ proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) =
if i > 1: app(epart, '}' & tnl) if i > 1: app(epart, '}' & tnl)
else: else:
orExpr = nil orExpr = nil
useMagic(p, "isObj")
for j in countup(0, blen - 2): for j in countup(0, blen - 2):
if (n.sons[i].sons[j].kind != nkType): if (n.sons[i].sons[j].kind != nkType):
InternalError(n.info, "genTryStmt") InternalError(n.info, "genTryStmt")
if orExpr != nil: app(orExpr, "||") if orExpr != nil: app(orExpr, "||")
appf(orExpr, "($1.exc.m_type == $2)", appf(orExpr, "isObj($1.exc.m_type, $2)",
[safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)]) [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)])
if i > 1: app(epart, "else ") if i > 1: app(epart, "else ")
appf(epart, "if ($1.exc && $2) {$n", [safePoint, orExpr]) appf(epart, "if ($1.exc && $2) {$n", [safePoint, orExpr])
@ -791,7 +792,7 @@ proc genSwap(p: var TProc, n: PNode, r: var TCompRes) =
gen(p, n.sons[2], b) gen(p, n.sons[2], b)
inc(p.unique) inc(p.unique)
var tmp = ropef("Tmp$1", [toRope(p.unique)]) var tmp = ropef("Tmp$1", [toRope(p.unique)])
case mapType(n.sons[1].typ) case mapType(skipTypes(n.sons[1].typ, abstractVar))
of etyBaseIndex: of etyBaseIndex:
inc(p.unique) inc(p.unique)
var tmp2 = ropef("Tmp$1", [toRope(p.unique)]) var tmp2 = ropef("Tmp$1", [toRope(p.unique)])
@ -804,11 +805,20 @@ proc genSwap(p: var TProc, n: PNode, r: var TCompRes) =
if b.com != nil: appf(r.com, "$1;$n", [b.com]) if b.com != nil: appf(r.com, "$1;$n", [b.com])
appf(r.com, "var $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res]) appf(r.com, "var $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res])
proc getFieldPosition(f: PNode): int =
case f.kind
of nkIntLit..nkUInt64Lit: result = int(f.intVal)
of nkSym: result = f.sym.position
else: InternalError(f.info, "genFieldPosition")
proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) =
var a: TCompRes var a: TCompRes
r.kind = etyBaseIndex r.kind = etyBaseIndex
var b = if n.kind == nkHiddenAddr: n.sons[0] else: n var b = if n.kind == nkHiddenAddr: n.sons[0] else: n
gen(p, b.sons[0], a) gen(p, b.sons[0], a)
if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple:
r.res = makeCString("Field" & $getFieldPosition(b.sons[1]))
else:
if b.sons[1].kind != nkSym: InternalError(b.sons[1].info, "genFieldAddr") if b.sons[1].kind != nkSym: InternalError(b.sons[1].info, "genFieldAddr")
var f = b.sons[1].sym var f = b.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(f) if f.loc.r == nil: f.loc.r = mangleName(f)
@ -818,6 +828,9 @@ proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) =
proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) =
r.kind = etyNone r.kind = etyNone
gen(p, n.sons[0], r) gen(p, n.sons[0], r)
if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
r.res = ropef("$1.Field$2", [r.res, getFieldPosition(n.sons[1]).toRope])
else:
if n.sons[1].kind != nkSym: InternalError(n.sons[1].info, "genFieldAddr") if n.sons[1].kind != nkSym: InternalError(n.sons[1].info, "genFieldAddr")
var f = n.sons[1].sym var f = n.sons[1].sym
if f.loc.r == nil: f.loc.r = mangleName(f) if f.loc.r == nil: f.loc.r = mangleName(f)
@ -885,10 +898,16 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) =
of nkDotExpr: of nkDotExpr:
genFieldAddr(p, n, r) genFieldAddr(p, n, r)
of nkBracketExpr: of nkBracketExpr:
var ty = skipTypes(n.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange)
case ty.kind
of tyArray, tyArrayConstr, tyOpenArray, tySequence, tyString, tyCString:
genArrayAddr(p, n, r) genArrayAddr(p, n, r)
of tyTuple:
genFieldAddr(p, n, r)
else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
else: InternalError(n.info, "genAddr") else: InternalError(n.info, "genAddr")
proc genSym(p: var TProc, n: PNode, r: var TCompRes) = proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
var s = n.sym var s = n.sym
case s.kind case s.kind
@ -956,6 +975,7 @@ proc genCall(p: var TProc, n: PNode, r: var TCompRes) =
genArgs(p, n, r) genArgs(p, n, r)
proc genEcho(p: var TProc, n: PNode, r: var TCompRes) = proc genEcho(p: var TProc, n: PNode, r: var TCompRes) =
useMagic(p, "rawEcho")
app(r.res, "rawEcho") app(r.res, "rawEcho")
genArgs(p, n, r) genArgs(p, n, r)
@ -1146,6 +1166,25 @@ proc genRepr(p: var TProc, n: PNode, r: var TCompRes) =
# XXX: # XXX:
internalError(n.info, "genRepr: Not implemented") internalError(n.info, "genRepr: Not implemented")
proc genOf(p: var TProc, n: PNode, r: var TCompRes) =
var x: TCompRes
let t = n.sons[2].typ
gen(p, n.sons[1], x)
if tfFinal in t.flags:
r.res = ropef("($1.m_type == $2)", [x.res, genTypeInfo(p, t)])
else:
useMagic(p, "isObj")
r.res = ropef("isObj($1.m_type, $2)", [x.res, genTypeInfo(p, t)])
r.com = mergeExpr(r.com, x.com)
proc genReset(p: var TProc, n: PNode, r: var TCompRes) =
var x: TCompRes
useMagic(p, "genericReset")
gen(p, n.sons[1], x)
r.res = ropef("$1 = genericReset($1, $2)", [x.res,
genTypeInfo(p, n.sons[1].typ)])
r.com = mergeExpr(r.com, x.com)
proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
var var
a: TCompRes a: TCompRes
@ -1216,6 +1255,8 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
of mNLen..mNError: of mNLen..mNError:
localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s) localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s)
of mNewSeq: binaryStmt(p, n, r, "", "$1 = new Array($2)") of mNewSeq: binaryStmt(p, n, r, "", "$1 = new Array($2)")
of mOf: genOf(p, n, r)
of mReset: genReset(p, n, r)
of mEcho: genEcho(p, n, r) of mEcho: genEcho(p, n, r)
of mSlurp, mStaticExec: of mSlurp, mStaticExec:
localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s) localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s)
@ -1252,19 +1293,17 @@ proc genArrayConstr(p: var TProc, n: PNode, r: var TCompRes) =
app(r.res, a.res) app(r.res, a.res)
app(r.res, "]") app(r.res, "]")
proc genRecordConstr(p: var TProc, n: PNode, r: var TCompRes) = proc genTupleConstr(p: var TProc, n: PNode, r: var TCompRes) =
var a: TCompRes var a: TCompRes
var i = 0
var length = sonsLen(n)
r.res = toRope("{") r.res = toRope("{")
while i < length: for i in countup(0, sonsLen(n) - 1):
if i > 0: app(r.res, ", ") if i > 0: app(r.res, ", ")
if (n.sons[i].kind != nkSym): var it = n.sons[i]
internalError(n.sons[i].info, "genRecordConstr") if it.kind == nkExprColonExpr: it = it.sons[1]
gen(p, n.sons[i + 1], a) gen(p, it, a)
r.com = mergeExpr(r.com, a.com) r.com = mergeExpr(r.com, a.com)
appf(r.res, "$1: $2", [mangleName(n.sons[i].sym), a.res]) appf(r.res, "Field$1: $2", [i.toRope, a.res])
inc(i, 2) r.res.app("}")
proc genConv(p: var TProc, n: PNode, r: var TCompRes) = proc genConv(p: var TProc, n: PNode, r: var TCompRes) =
var dest = skipTypes(n.typ, abstractVarRange) var dest = skipTypes(n.typ, abstractVarRange)
@ -1414,9 +1453,6 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) =
genSym(p, n.sons[namePos], r2) genSym(p, n.sons[namePos], r2)
else: else:
genLineDir(p, n, r) genLineDir(p, n, r)
if n.sons[0].kind == nkSym:
if n.sons[0].sym.loc.r == nil:
n.sons[0].sym.loc.r = toRope(n.sons[0].sym.name.s)
gen(p, n, r) gen(p, n, r)
app(r.res, ';' & tnl) app(r.res, ';' & tnl)
@ -1460,7 +1496,7 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
genCall(p, n, r) genCall(p, n, r)
of nkCurly: genSetConstr(p, n, r) of nkCurly: genSetConstr(p, n, r)
of nkBracket: genArrayConstr(p, n, r) of nkBracket: genArrayConstr(p, n, r)
of nkPar: genRecordConstr(p, n, r) of nkPar: genTupleConstr(p, n, r)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r) of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, r)
of nkAddr, nkHiddenAddr: genAddr(p, n, r) of nkAddr, nkHiddenAddr: genAddr(p, n, r)
of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r) of nkDerefExpr, nkHiddenDeref: genDeref(p, n, r)
@ -1477,8 +1513,14 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) =
of nkStmtListExpr: genStmtListExpr(p, n, r) of nkStmtListExpr: genStmtListExpr(p, n, r)
of nkEmpty: nil of nkEmpty: nil
of nkLambdaKinds: of nkLambdaKinds:
# XXX not correct, as we need to put it into the proper scope! let s = n.sons[namePos].sym
gen(p, n.sons[namePos], r) discard mangleName(s)
r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s): nil
elif not p.g.generatedSyms.containsOrIncl(s.id):
var r2: TCompRes
genProc(p, s, r2)
app(r.com, mergeStmt(r2))
of nkMetaNode: gen(p, n.sons[0], r) of nkMetaNode: gen(p, n.sons[0], r)
of nkType: r.res = genTypeInfo(p, n.typ) of nkType: r.res = genTypeInfo(p, n.typ)
else: InternalError(n.info, "gen: unknown node type: " & $n.kind) else: InternalError(n.info, "gen: unknown node type: " & $n.kind)

View file

@ -131,7 +131,9 @@ when has_LLVM_Backend:
proc CommandCompileToEcmaScript = proc CommandCompileToEcmaScript =
incl(gGlobalOptions, optSafeCode) incl(gGlobalOptions, optSafeCode)
setTarget(osEcmaScript, cpuEcmaScript) setTarget(osEcmaScript, cpuEcmaScript)
initDefines() #initDefines()
DefineSymbol("nimrod") # 'nimrod' is always defined
DefineSymbol("ecmascript")
semanticPasses() semanticPasses()
registerPass(ecmasgenPass()) registerPass(ecmasgenPass())
compileProject() compileProject()

View file

@ -98,6 +98,11 @@ proc HandleCmdLine() =
formatFloat(epochTime() - start, ffDecimal, 3), formatFloat(epochTime() - start, ffDecimal, 3),
formatSize(getTotalMem())]) formatSize(getTotalMem())])
if optRun in gGlobalOptions: if optRun in gGlobalOptions:
if gCmd == cmdCompileToEcmaScript:
var ex = quoteIfContainsWhite(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram("node " & ex & ' ' & arguments)
else:
var ex = quoteIfContainsWhite( var ex = quoteIfContainsWhite(
changeFileExt(gProjectFull, exeExt).prependCurDir) changeFileExt(gProjectFull, exeExt).prependCurDir)
execExternalProgram(ex & ' ' & arguments) execExternalProgram(ex & ' ' & arguments)

View file

@ -145,6 +145,7 @@ Define Effect
``useRealtimeGC`` Enables support of Nimrod's GC for *soft* realtime ``useRealtimeGC`` Enables support of Nimrod's GC for *soft* realtime
systems. See the documentation of the `gc <gc.html>`_ systems. See the documentation of the `gc <gc.html>`_
for further information. for further information.
``nodejs`` The EcmaScript target is actually ``node.js``.
================== ========================================================= ================== =========================================================

View file

@ -35,6 +35,10 @@ proc `!$`*(h: THash): THash {.inline.} =
proc hashData*(Data: Pointer, Size: int): THash = proc hashData*(Data: Pointer, Size: int): THash =
## hashes an array of bytes of size `size` ## hashes an array of bytes of size `size`
var h: THash = 0 var h: THash = 0
when defined(ecmascript):
var p: cstring
asm """`p` = `Data`;"""
else:
var p = cast[cstring](Data) var p = cast[cstring](Data)
var i = 0 var i = 0
var s = size var s = size
@ -44,8 +48,23 @@ proc hashData*(Data: Pointer, Size: int): THash =
Dec(s) Dec(s)
result = !$h result = !$h
when defined(ecmascript):
var objectID = 0
proc hash*(x: Pointer): THash {.inline.} = proc hash*(x: Pointer): THash {.inline.} =
## efficient hashing of pointers ## efficient hashing of pointers
when defined(ecmascript):
asm """
if (typeof `x` == "object") {
if ("_NimID" in `x`)
`result` = `x`["_NimID"];
else {
`result` = ++`objectID`;
`x`["_NimID"] = `result`;
}
}
"""
else:
result = (cast[THash](x)) shr 3 # skip the alignment result = (cast[THash](x)) shr 3 # skip the alignment
proc hash*(x: int): THash {.inline.} = proc hash*(x: int): THash {.inline.} =

View file

@ -7,7 +7,11 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
proc alert*(s: cstring) {.importc, nodecl.} when defined(nodejs):
proc alert*(s: cstring) {.importc: "console.log", nodecl.}
else:
proc alert*(s: cstring) {.importc, nodecl.}
proc log*(s: cstring) {.importc: "console.log", nodecl.} proc log*(s: cstring) {.importc: "console.log", nodecl.}
type type
@ -100,7 +104,7 @@ proc raiseException(e: ref E_Base, ename: cstring) {.
alert(buf) alert(buf)
asm """throw `e`;""" asm """throw `e`;"""
proc reraiseException() = proc reraiseException() {.compilerproc, noStackFrame.} =
if excHandler == nil: if excHandler == nil:
raise newException(ENoExceptionToReraise, "no exception to reraise") raise newException(ENoExceptionToReraise, "no exception to reraise")
else: else:
@ -295,10 +299,23 @@ type
setAttribute*: proc (name, value: cstring) setAttribute*: proc (name, value: cstring)
setAttributeNode*: proc (attr: ref TNode) setAttributeNode*: proc (attr: ref TNode)
var when defined(nodejs):
proc ewriteln(x: cstring) = log(x)
proc rawEcho {.compilerproc, nostackframe.} =
asm """
var buf = "";
for (var i = 0; i < arguments.length; ++i) {
buf += `toEcmaStr`(arguments[i]);
}
console.log(buf);
"""
else:
var
document {.importc, nodecl.}: ref TDocument document {.importc, nodecl.}: ref TDocument
proc ewriteln(x: cstring) = proc ewriteln(x: cstring) =
var node = document.getElementsByTagName("body")[0] var node = document.getElementsByTagName("body")[0]
if node != nil: if node != nil:
node.appendChild(document.createTextNode(x)) node.appendChild(document.createTextNode(x))
@ -306,7 +323,7 @@ proc ewriteln(x: cstring) =
else: else:
raise newException(EInvalidValue, "<body> element does not exist yet!") raise newException(EInvalidValue, "<body> element does not exist yet!")
proc rawEcho {.compilerproc.} = proc rawEcho {.compilerproc.} =
var node = document.getElementsByTagName("body")[0] var node = document.getElementsByTagName("body")[0]
if node == nil: raise newException(EIO, "<body> element does not exist yet!") if node == nil: raise newException(EIO, "<body> element does not exist yet!")
asm """ asm """
@ -474,7 +491,7 @@ proc isFatPointer(ti: PNimType): bool =
proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.} proc NimCopy(x: pointer, ti: PNimType): pointer {.compilerproc.}
proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.exportc.} = proc NimCopyAux(dest, src: Pointer, n: ptr TNimNode) {.compilerproc.} =
case n.kind case n.kind
of nkNone: sysAssert(false, "NimCopyAux") of nkNone: sysAssert(false, "NimCopyAux")
of nkSlot: of nkSlot:
@ -525,6 +542,37 @@ proc NimCopy(x: pointer, ti: PNimType): pointer =
else: else:
result = x result = x
proc genericReset(x: Pointer, ti: PNimType): pointer {.compilerproc.} =
case ti.kind
of tyPtr, tyRef, tyVar, tyNil:
if not isFatPointer(ti):
result = nil
else:
asm """
`result` = [null, 0];
"""
of tySet:
asm """
`result` = {};
"""
of tyTuple, tyObject:
if ti.kind == tyObject:
asm "`result` = {m_type: `ti`};"
else:
asm "`result` = {};"
of tySequence, tyOpenArray:
asm """
`result` = [];
"""
of tyArrayConstr, tyArray:
asm """
`result` = new Array(`x`.length);
for (var i = 0; i < `x`.length; ++i) {
`result`[i] = genericReset(`x`[i], `ti`.base);
}
"""
else:
result = nil
proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {. proc ArrayConstr(len: int, value: pointer, typ: PNimType): pointer {.
noStackFrame, compilerproc.} = noStackFrame, compilerproc.} =
@ -552,4 +600,13 @@ proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
raise newException(EInvalidObjectConversion, "invalid object conversion") raise newException(EInvalidObjectConversion, "invalid object conversion")
x = x.base x = x.base
proc isObj(obj, subclass: PNimType): bool {.compilerproc.} =
# checks if obj is of type subclass:
var x = obj
if x == subclass: return true # optimized fast path
while x != subclass:
if x == nil: return false
x = x.base
return true
{.pop.} {.pop.}

View file

@ -169,6 +169,22 @@ proc compileDebuggerTests(r: var TResults, options: string) =
compileSingleTest(r, "tools/nimgrep", options & compileSingleTest(r, "tools/nimgrep", options &
" --debugger:on") " --debugger:on")
# ------------------------- JS tests ------------------------------------------
proc runJsTests(r: var TResults, options: string) =
template test(filename: expr): stmt =
runSingleTest(r, filename, options & " -d:nodejs", targetJS)
runSingleTest(r, filename, options & " -d:nodejs -d:release", targetJS)
# tactiontable, texceptions, texcpt1, texcsub, tfinally, tfinally2,
# tfinally3
for t in os.walkFiles("tests/js/t*.nim"):
test(t)
test "tests/run/tactiontable"
test "tests/run/tmultim1"
test "tests/run/tmultim3"
test "tests/run/tmultim4"
# ------------------------- register special tests here ----------------------- # ------------------------- register special tests here -----------------------
proc runSpecialTests(r: var TResults, options: string) = proc runSpecialTests(r: var TResults, options: string) =
runRodFiles(r, options) runRodFiles(r, options)

View file

@ -261,7 +261,10 @@ proc compileSingleTest(r: var TResults, test, options: string) =
r.addResult(t, given.msg, if given.err: reFailure else: reSuccess) r.addResult(t, given.msg, if given.err: reFailure else: reSuccess)
if not given.err: inc(r.passed) if not given.err: inc(r.passed)
proc runSingleTest(r: var TResults, test, options: string) = type
TTarget = enum targetC, targetJS
proc runSingleTest(r: var TResults, test, options: string, target: TTarget) =
var test = test.addFileExt(".nim") var test = test.addFileExt(".nim")
var t = extractFilename(test) var t = extractFilename(test)
echo t echo t
@ -275,9 +278,16 @@ proc runSingleTest(r: var TResults, test, options: string) =
if given.err: if given.err:
r.addResult(t, "", given.msg, reFailure) r.addResult(t, "", given.msg, reFailure)
else: else:
var exeFile = changeFileExt(test, ExeExt) var exeFile: string
if target == targetC:
exeFile = changeFileExt(test, ExeExt)
else:
let (dir, file, ext) = splitFile(test)
exeFile = dir / "nimcache" / file & ".js"
if existsFile(exeFile): if existsFile(exeFile):
var (buf, exitCode) = execCmdEx(exeFile) var (buf, exitCode) = execCmdEx(
(if target==targetJS: "node " else: "") & exeFile)
if exitCode != expected.ExitCode: if exitCode != expected.ExitCode:
r.addResult(t, "exitcode: " & $expected.ExitCode, r.addResult(t, "exitcode: " & $expected.ExitCode,
"exitcode: " & $exitCode, reFailure) "exitcode: " & $exitCode, reFailure)
@ -291,6 +301,9 @@ proc runSingleTest(r: var TResults, test, options: string) =
else: else:
r.addResult(t, expected.outp, "executable not found", reFailure) r.addResult(t, expected.outp, "executable not found", reFailure)
proc runSingleTest(r: var TResults, test, options: string) =
runSingleTest(r, test, options, targetC)
proc run(r: var TResults, dir, options: string) = proc run(r: var TResults, dir, options: string) =
for test in os.walkFiles(dir / "t*.nim"): runSingleTest(r, test, options) for test in os.walkFiles(dir / "t*.nim"): runSingleTest(r, test, options)
@ -350,6 +363,12 @@ proc main() =
run(runRes, "tests/run", p.cmdLineRest.string) run(runRes, "tests/run", p.cmdLineRest.string)
runSpecialTests(runRes, p.cmdLineRest.string) runSpecialTests(runRes, p.cmdLineRest.string)
writeResults(runJson, runRes) writeResults(runJson, runRes)
of "js":
var runRes = initResults()
if existsFile(runJSon):
runRes = readResults(runJson)
runJsTests(runRes, p.cmdLineRest.string)
writeResults(runJson, runRes)
of "merge": of "merge":
var rejectRes = readResults(rejectJson) var rejectRes = readResults(rejectJson)
var compileRes = readResults(compileJson) var compileRes = readResults(compileJson)

View file

@ -42,6 +42,10 @@ Bugs
version 0.9.XX version 0.9.XX
============== ==============
- JS gen:
- document it
- test & fix bugs
- document nimdoc properly finally - document nimdoc properly finally
- implement a warning message for shadowed 'result' variable - implement a warning message for shadowed 'result' variable
- implement the high level optimizer - implement the high level optimizer
@ -51,7 +55,6 @@ version 0.9.XX
- implicit ref/ptr->var conversion; the compiler may store an object - implicit ref/ptr->var conversion; the compiler may store an object
implicitly on the heap for write barrier efficiency; better: implicitly on the heap for write barrier efficiency; better:
proc specialization in the code gen proc specialization in the code gen
- 'of' operator for JS backend
- tlastmod returns wrong results on BSD (Linux, MacOS X: works) - tlastmod returns wrong results on BSD (Linux, MacOS X: works)
- nested tuple unpacking; tuple unpacking in non-var-context - nested tuple unpacking; tuple unpacking in non-var-context
- 'nimrod def': does not always work? - 'nimrod def': does not always work?