JS codegen improvements; barely usable now

This commit is contained in:
Araq 2012-07-02 01:41:16 +02:00
commit f2af2fb478
4 changed files with 71 additions and 25 deletions

View file

@ -22,8 +22,8 @@ proc ecmasgenPass*(): TPass
type type
TEcmasGen = object of TPassContext TEcmasGen = object of TPassContext
filename*: string filename: string
module*: PSym module: PSym
BModule = ref TEcmasGen BModule = ref TEcmasGen
TEcmasTypeKind = enum # necessary JS "types" TEcmasTypeKind = enum # necessary JS "types"
@ -37,17 +37,17 @@ type
etyObject, # Ecmascript's reference to an object etyObject, # Ecmascript's reference to an object
etyBaseIndex # base + index needed etyBaseIndex # base + index needed
TCompRes{.final.} = object TCompRes{.final.} = object
kind*: TEcmasTypeKind kind: TEcmasTypeKind
com*: PRope # computation part com: PRope # computation part
# address if this is a (address, index)-tuple # address if this is a (address, index)-tuple
res*: PRope # result part; index if this is an res: PRope # result part; index if this is an
# (address, index)-tuple # (address, index)-tuple
TBlock{.final.} = object TBlock{.final.} = object
id*: int # the ID of the label; positive means that it id: int # the ID of the label; positive means that it
# has been used (i.e. the label should be emitted) # has been used (i.e. the label should be emitted)
nestedTryStmts*: int # how many try statements is it nested into nestedTryStmts: int # how many try statements is it nested into
isLoop: bool # whether it's a 'block' or 'while' isLoop: bool # whether it's a 'block' or 'while'
TGlobals{.final.} = object TGlobals{.final.} = object
typeInfo, code: PRope typeInfo, code: PRope
@ -863,7 +863,14 @@ proc genArrayAddr(p: var TProc, n: PNode, r: var TCompRes) =
r.res = mergeExpr(b) r.res = mergeExpr(b)
proc genArrayAccess(p: var TProc, n: PNode, r: var TCompRes) = proc genArrayAccess(p: var TProc, n: PNode, r: var TCompRes) =
genArrayAddr(p, n, r) 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)
of tyTuple:
genFieldAddr(p, n, r)
else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
r.kind = etyNone r.kind = etyNone
r.res = ropef("$1[$2]", [r.com, r.res]) r.res = ropef("$1[$2]", [r.com, r.res])
r.com = nil r.com = nil
@ -936,6 +943,9 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) =
discard mangleName(s) discard mangleName(s)
r.res = s.loc.r r.res = s.loc.r
if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s): nil if lfNoDecl in s.loc.flags or s.magic != mNone or isGenericRoutine(s): nil
elif s.kind == skMethod and s.getBody.kind == nkEmpty:
# we cannot produce code for the dispatcher yet:
nil
elif sfForward in s.flags: elif sfForward in s.flags:
p.g.forwarded.add(s) p.g.forwarded.add(s)
elif not p.g.generatedSyms.containsOrIncl(s.id): elif not p.g.generatedSyms.containsOrIncl(s.id):
@ -1032,8 +1042,9 @@ proc createVar(p: var TProc, typ: PType, indirect: bool): PRope =
app(result, "]") app(result, "]")
of tyTuple: of tyTuple:
result = toRope("{") result = toRope("{")
var c = 0 for i in 0.. <t.sonslen:
app(result, createRecordVarAux(p, t.n, c)) if i > 0: app(result, ", ")
appf(result, "Field$1: $2", i.toRope, createVar(p, t.sons[i], false))
app(result, "}") app(result, "}")
of tyObject: of tyObject:
result = toRope("{") result = toRope("{")
@ -1123,6 +1134,16 @@ proc genNew(p: var TProc, n: PNode, r: var TCompRes) =
if a.com != nil: appf(r.com, "$1;$n", [a.com]) if a.com != nil: appf(r.com, "$1;$n", [a.com])
appf(r.com, "$1 = $2;$n", [a.res, createVar(p, t, true)]) appf(r.com, "$1 = $2;$n", [a.res, createVar(p, t, true)])
proc genNewSeq(p: var TProc, n: PNode, r: var TCompRes) =
var x, y: TCompRes
gen(p, n.sons[1], x)
gen(p, n.sons[2], y)
if x.com != nil: appf(r.com, "$1;$n", [x.com])
if y.com != nil: appf(r.com, "$1;$n", [y.com])
var t = skipTypes(n.sons[1].typ, abstractVar).sons[0]
appf(r.com, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [
x.res, y.res, createVar(p, t, false)])
proc genOrd(p: var TProc, n: PNode, r: var TCompRes) = proc genOrd(p: var TProc, n: PNode, r: var TCompRes) =
case skipTypes(n.sons[1].typ, abstractVar).kind case skipTypes(n.sons[1].typ, abstractVar).kind
of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r) of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r)
@ -1168,7 +1189,7 @@ proc genRepr(p: var TProc, n: PNode, r: var TCompRes) =
proc genOf(p: var TProc, n: PNode, r: var TCompRes) = proc genOf(p: var TProc, n: PNode, r: var TCompRes) =
var x: TCompRes var x: TCompRes
let t = n.sons[2].typ let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr})
gen(p, n.sons[1], x) gen(p, n.sons[1], x)
if tfFinal in t.flags: if tfFinal in t.flags:
r.res = ropef("($1.m_type == $2)", [x.res, genTypeInfo(p, t)]) r.res = ropef("($1.m_type == $2)", [x.res, genTypeInfo(p, t)])
@ -1254,7 +1275,7 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) =
of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)") of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)")
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: genNewSeq(p, n, r)
of mOf: genOf(p, n, r) of mOf: genOf(p, n, r)
of mReset: genReset(p, n, r) of mReset: genReset(p, n, r)
of mEcho: genEcho(p, n, r) of mEcho: genEcho(p, n, r)
@ -1576,12 +1597,14 @@ proc myClose(b: PPassContext, n: PNode): PNode =
var disp = generateMethodDispatchers() var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1: for i in 0..sonsLen(disp)-1:
var let prc = disp.sons[i].sym
p: TProc if not globals.generatedSyms.containsOrIncl(prc.id):
r: TCompRes var
initProc(p, globals, m, nil, m.module.options) p: TProc
genProc(p, disp.sons[i].sym, r) r: TCompRes
app(p.g.code, mergeStmt(r)) initProc(p, globals, m, nil, m.module.options)
genProc(p, prc, r)
app(p.g.code, mergeStmt(r))
# write the file: # write the file:
var code = con(globals.typeInfo, globals.code) var code = con(globals.typeInfo, globals.code)

23
tests/js/test1.nim Normal file
View file

@ -0,0 +1,23 @@
discard """
cmd: "nimrod js --hints:on $# $#"
output: "1261129"
"""
# This file tests the ECMAScript generator
import
dom, strutils
var
inputElement = "1123"
proc OnButtonClick(inputElement: string) {.exportc.} =
let v = $inputElement
if v.allCharsInSet(whiteSpace):
echo "only whitespace, hu?"
else:
var x = parseInt(v)
echo x*x
onButtonClick(inputElement)

View file

@ -176,7 +176,7 @@ proc runJsTests(r: var TResults, options: string) =
runSingleTest(r, filename, options & " -d:nodejs", targetJS) runSingleTest(r, filename, options & " -d:nodejs", targetJS)
runSingleTest(r, filename, options & " -d:nodejs -d:release", targetJS) runSingleTest(r, filename, options & " -d:nodejs -d:release", targetJS)
# tactiontable, texceptions, texcpt1, texcsub, tfinally, tfinally2, # texceptions, texcpt1, texcsub, tfinally, tfinally2,
# tfinally3 # tfinally3
for t in os.walkFiles("tests/js/t*.nim"): for t in os.walkFiles("tests/js/t*.nim"):
test(t) test(t)

View file

@ -44,7 +44,7 @@ version 0.9.XX
- JS gen: - JS gen:
- document it - document it
- test & fix bugs - fix exception handling
- document nimdoc properly finally - document nimdoc properly finally
- implement a warning message for shadowed 'result' variable - implement a warning message for shadowed 'result' variable