diff options
-rw-r--r-- | compiler/jsgen.nim | 1224 | ||||
-rw-r--r-- | compiler/jstypes.nim | 148 |
2 files changed, 683 insertions, 689 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim index f2e317f47..2b5e2c1bd 100644 --- a/compiler/jsgen.nim +++ b/compiler/jsgen.nim @@ -8,18 +8,17 @@ # # This is the EMCAScript (also known as JavaScript) code generator. -# **Invariant: each expression occurs only once in the generated -# code!** +# Soon also a Luajit code generator. ;-) -import +import ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, options, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, os, times, ropes, math, passes, ccgutils, wordrecg, renderer, rodread, rodutils, intsets, cgmeth -# implementation - -type +type + TTarget = enum + targetJS, targetLua TJSGen = object of TPassContext module: PSym @@ -34,36 +33,45 @@ type etyString, # JavaScript's string etyObject, # JavaScript's reference to an object etyBaseIndex # base + index needed - TCompRes{.final.} = object - kind: TJSTypeKind - com: PRope # computation part - # address if this is a (address, index)-tuple + TResKind = enum + resNone, # not set + resExpr, # is some complex expression + resVal # is a temporary/value/l-value + TCompRes = object + kind: TResKind + typ: TJSTypeKind res: PRope # result part; index if this is an # (address, index)-tuple + address: PRope # address of an (address, index)-tuple - TBlock{.final.} = object + TBlock = object id: int # the ID of the label; positive means that it # has been used (i.e. the label should be emitted) isLoop: bool # whether it's a 'block' or 'while' - TGlobals{.final.} = object + TGlobals = object typeInfo, code: PRope forwarded: seq[PSym] generatedSyms: TIntSet typeInfoGenerated: TIntSet PGlobals = ref TGlobals - TProc{.final.} = object + PProc = ref TProc + TProc = object procDef: PNode prc: PSym - locals: PRope + locals, body: PRope options: TOptions module: BModule g: PGlobals BeforeRetNeeded: bool - unique: int + target: TTarget # duplicated here for faster dispatching + unique: int # for temp identifier generation blocks: seq[TBlock] + up: PProc # up the call chain; required for closure support +template `|`(a, b: expr): expr {.immediate.} = + (if p.target == targetJS: a else: b) proc newGlobals(): PGlobals = new(result) @@ -72,25 +80,35 @@ proc newGlobals(): PGlobals = result.typeInfoGenerated = initIntSet() proc initCompRes(r: var TCompRes) = - r.com = nil + r.address = nil r.res = nil - r.kind = etyNone - -proc initProc(p: var TProc, globals: PGlobals, module: BModule, procDef: PNode, - options: TOptions) = - p.blocks = @[] - p.options = options - p.module = module - p.procDef = procDef - p.g = globals - if procDef != nil: p.prc = procDef.sons[namePos].sym + r.typ = etyNone + r.kind = resNone + +proc rdLoc(a: TCompRes): PRope {.inline.} = + result = a.res + when false: + if a.typ != etyBaseIndex: + result = a.res + else: + result = ropef("$1[$2]", a.address, a.res) + +proc newProc(globals: PGlobals, module: BModule, procDef: PNode, + options: TOptions): PProc = + result = PProc( + blocks: @[], + options: options, + module: module, + procDef: procDef, + g: globals) + if procDef != nil: result.prc = procDef.sons[namePos].sym const MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray, tySet, tyVar, tyRef, tyPtr, tyBigNum, tyVarargs} proc mapType(typ: PType): TJSTypeKind = - var t = skipTypes(typ, abstractInst) + let t = skipTypes(typ, abstractInst) case t.kind of tyVar, tyRef, tyPtr: if skipTypes(t.sons[0], abstractInst).kind in mappedToObject: @@ -140,173 +158,20 @@ proc mangleName(s: PSym): PRope = proc makeJSString(s: string): PRope = strutils.escape(s).toRope -proc genTypeInfo(p: var TProc, typ: PType): PRope -proc genObjectFields(p: var TProc, typ: PType, n: PNode): PRope = - var - s, u: PRope - length: int - field: PSym - b: PNode - result = nil - case n.kind - of nkRecList: - length = sonsLen(n) - if length == 1: - result = genObjectFields(p, typ, n.sons[0]) - else: - s = nil - for i in countup(0, length - 1): - if i > 0: app(s, ", " & tnl) - app(s, genObjectFields(p, typ, n.sons[i])) - result = ropef("{kind: 2, len: $1, offset: 0, " & - "typ: null, name: null, sons: [$2]}", [toRope(length), s]) - of nkSym: - field = n.sym - s = genTypeInfo(p, field.typ) - result = ropef("{kind: 1, offset: \"$1\", len: 0, " & - "typ: $2, name: $3, sons: null}", - [mangleName(field), s, makeJSString(field.name.s)]) - of nkRecCase: - length = sonsLen(n) - if (n.sons[0].kind != nkSym): InternalError(n.info, "genObjectFields") - field = n.sons[0].sym - s = genTypeInfo(p, field.typ) - for i in countup(1, length - 1): - b = n.sons[i] # branch - u = nil - case b.kind - of nkOfBranch: - if sonsLen(b) < 2: - internalError(b.info, "genObjectFields; nkOfBranch broken") - for j in countup(0, sonsLen(b) - 2): - if u != nil: app(u, ", ") - if b.sons[j].kind == nkRange: - appf(u, "[$1, $2]", [toRope(getOrdValue(b.sons[j].sons[0])), - toRope(getOrdValue(b.sons[j].sons[1]))]) - else: - app(u, toRope(getOrdValue(b.sons[j]))) - of nkElse: - u = toRope(lengthOrd(field.typ)) - else: internalError(n.info, "genObjectFields(nkRecCase)") - if result != nil: app(result, ", " & tnl) - appf(result, "[SetConstr($1), $2]", - [u, genObjectFields(p, typ, lastSon(b))]) - result = ropef("{kind: 3, offset: \"$1\", len: $3, " & - "typ: $2, name: $4, sons: [$5]}", [mangleName(field), s, - toRope(lengthOrd(field.typ)), makeJSString(field.name.s), result]) - else: internalError(n.info, "genObjectFields") +include jstypes -proc genObjectInfo(p: var TProc, typ: PType, name: PRope) = - var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & - "finalizer: null};$n", [name, toRope(ord(typ.kind))]) - prepend(p.g.typeInfo, s) - appf(p.g.typeInfo, "var NNI$1 = $2;$n", - [toRope(typ.id), genObjectFields(p, typ, typ.n)]) - appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) - if (typ.kind == tyObject) and (typ.sons[0] != nil): - appf(p.g.typeInfo, "$1.base = $2;$n", - [name, genTypeInfo(p, typ.sons[0])]) - -proc genTupleFields(p: var TProc, typ: PType): PRope = - var s: PRope = nil - for i in 0 .. <typ.len: - if i > 0: app(s, ", " & tnl) - s.appf("{kind: 1, offset: \"Field$1\", len: 0, " & - "typ: $2, name: \"Field$1\", sons: null}", - [i.toRope, genTypeInfo(p, typ.sons[i])]) - result = ropef("{kind: 2, len: $1, offset: 0, " & - "typ: null, name: null, sons: [$2]}", [toRope(typ.len), s]) - -proc genTupleInfo(p: var TProc, typ: PType, name: PRope) = - var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & - "finalizer: null};$n", [name, toRope(ord(typ.kind))]) - prepend(p.g.typeInfo, s) - appf(p.g.typeInfo, "var NNI$1 = $2;$n", - [toRope(typ.id), genTupleFields(p, typ)]) - appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) - -proc genEnumInfo(p: var TProc, typ: PType, name: PRope) = - let length = sonsLen(typ.n) - var s: PRope = nil - for i in countup(0, length - 1): - if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo") - let field = typ.n.sons[i].sym - if i > 0: app(s, ", " & tnl) - let extName = if field.ast == nil: field.name.s else: field.ast.strVal - appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}", - [toRope(field.position), name, makeJSString(extName)]) - var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " & - "name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s]) - s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & - "finalizer: null};$n", [name, toRope(ord(typ.kind))]) - prepend(p.g.typeInfo, s) - app(p.g.typeInfo, n) - appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) - if typ.sons[0] != nil: - appf(p.g.typeInfo, "$1.base = $2;$n", - [name, genTypeInfo(p, typ.sons[0])]) - -proc genTypeInfo(p: var TProc, typ: PType): PRope = - var t = typ - if t.kind == tyGenericInst: t = lastSon(t) - result = ropef("NTI$1", [toRope(t.id)]) - if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return - case t.kind - of tyDistinct: - result = genTypeInfo(p, typ.sons[0]) - of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyFloat128: - var s = ropef( - "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", - [result, toRope(ord(t.kind))]) - prepend(p.g.typeInfo, s) - of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet: - var s = ropef( - "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", - [result, toRope(ord(t.kind))]) - prepend(p.g.typeInfo, s) - appf(p.g.typeInfo, "$1.base = $2;$n", - [result, genTypeInfo(p, typ.sons[0])]) - of tyArrayConstr, tyArray: - var s = ropef( - "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", - [result, toRope(ord(t.kind))]) - prepend(p.g.typeInfo, s) - appf(p.g.typeInfo, "$1.base = $2;$n", - [result, genTypeInfo(p, typ.sons[1])]) - of tyEnum: genEnumInfo(p, t, result) - of tyObject: genObjectInfo(p, t, result) - of tyTuple: genTupleInfo(p, t, result) - else: InternalError("genTypeInfo(" & $t.kind & ')') - -proc gen(p: var TProc, n: PNode, r: var TCompRes) -proc genStmt(p: var TProc, n: PNode, r: var TCompRes) -proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) -proc genConstant(p: var TProc, c: PSym, r: var TCompRes) - -proc mergeExpr(a, b: PRope): PRope = - if (a != nil): - if b != nil: result = ropef("($1, $2)", [a, b]) - else: result = a - else: - result = b - -proc mergeExpr(r: TCompRes): PRope = - result = mergeExpr(r.com, r.res) +proc gen(p: PProc, n: PNode, r: var TCompRes) +proc genStmt(p: PProc, n: PNode, r: var TCompRes) +proc genProc(oldProc: PProc, prc: PSym): PRope +proc genConstant(p: PProc, c: PSym) -proc mergeStmt(r: TCompRes): PRope = - if r.res == nil: result = r.com - elif r.com == nil: result = r.res - else: result = ropef("$1$2", [r.com, r.res]) - -proc useMagic(p: var TProc, name: string) = +proc useMagic(p: PProc, name: string) = if name.len == 0: return var s = magicsys.getCompilerProc(name) if s != nil: internalAssert s.kind in {skProc, skMethod, skConverter} if not p.g.generatedSyms.containsOrIncl(s.id): - var r: TCompRes - genProc(p, s, r) - app(p.g.code, mergeStmt(r)) + app(p.g.code, genProc(p, s)) else: # we used to exclude the system module from this check, but for DLL # generation support this sloppyness leads to hard to detect bugs, so @@ -314,19 +179,67 @@ proc useMagic(p: var TProc, name: string) = if p.prc != nil: GlobalError(p.prc.info, errSystemNeeds, name) else: rawMessage(errSystemNeeds, name) -proc genAnd(p: var TProc, a, b: PNode, r: var TCompRes) = - var x, y: TCompRes - gen(p, a, x) - gen(p, b, y) - r.res = ropef("($1 && $2)", [mergeExpr(x), mergeExpr(y)]) +proc isSimpleExpr(n: PNode): bool = + # calls all the way down --> can stay expression based + if n.kind in nkCallKinds+{nkBracketExpr, nkBracket, nkCurly, nkDotExpr, nkPar, + nkObjConstr}: + for c in n: + if not c.isSimpleExpr: return false + result = true + elif n.isAtom: + result = true + +proc getTemp(p: PProc): PRope = + inc(p.unique) + result = ropef("Tmp$1", [toRope(p.unique)]) + appf(p.locals, "var $1;$n" | "local $1;$n", [result]) -proc genOr(p: var TProc, a, b: PNode, r: var TCompRes) = +proc genAnd(p: PProc, a, b: PNode, r: var TCompRes) = + assert r.kind == resNone var x, y: TCompRes - gen(p, a, x) - gen(p, b, y) - r.res = ropef("($1 || $2)", [mergeExpr(x), mergeExpr(y)]) - -type + if a.isSimpleExpr and b.isSimpleExpr: + gen(p, a, x) + gen(p, b, y) + r.kind = resExpr + r.res = ropef("($1 && $2)" | "($1 and $2)", [x.rdLoc, y.rdLoc]) + else: + r.res = p.getTemp + r.kind = resVal + # while a and b: + # --> + # while true: + # aa + # if not a: tmp = false + # else: + # bb + # tmp = b + # tmp + gen(p, a, x) + p.body.appf("if (!$1) $2 = false; else {" | + "if not $1 then $2 = false; else", x.rdLoc, r.rdLoc) + gen(p, b, y) + p.body.appf("$2 = $1; }" | + "$2 = $1 end", y.rdLoc, r.rdLoc) + +proc genOr(p: PProc, a, b: PNode, r: var TCompRes) = + assert r.kind == resNone + var x, y: TCompRes + if a.isSimpleExpr and b.isSimpleExpr: + gen(p, a, x) + gen(p, b, y) + r.kind = resExpr + r.res = ropef("($1 || $2)" | "($1 or $2)", [x.rdLoc, y.rdLoc]) + else: + r.res = p.getTemp + r.kind = resVal + gen(p, a, x) + p.body.appf("if ($1) $2 = true; else {" | + "if $1 then $2 = true; else", x.rdLoc, r.rdLoc) + gen(p, b, y) + p.body.appf("$2 = $1; }" | + "$2 = $1 end", y.rdLoc, r.rdLoc) + +type TMagicFrmt = array[0..3, string] const # magic checked op; magic unchecked op; checked op; unchecked op @@ -430,86 +343,83 @@ const # magic checked op; magic unchecked op; checked op; unchecked op ["cstrToNimstr", "cstrToNimstr", "cstrToNimstr($1)", "cstrToNimstr($1)"], ["", "", "$1", "$1"]] -proc binaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = - var x, y: TCompRes - useMagic(p, magic) - gen(p, n.sons[1], x) - gen(p, n.sons[2], y) - r.res = ropef(frmt, [x.res, y.res]) - r.com = mergeExpr(x.com, y.com) - -proc binaryStmt(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = +proc binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = var x, y: TCompRes useMagic(p, magic) 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]) - appf(r.com, frmt, [x.res, y.res]) + r.res = ropef(frmt, [x.rdLoc, y.rdLoc]) + r.kind = resExpr -proc unaryExpr(p: var TProc, n: PNode, r: var TCompRes, magic, frmt: string) = +proc unaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string) = useMagic(p, magic) gen(p, n.sons[1], r) - r.res = ropef(frmt, [r.res]) + r.res = ropef(frmt, [r.rdLoc]) + r.kind = resExpr -proc arith(p: var TProc, n: PNode, r: var TCompRes, op: TMagic) = - var +proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) = + var x, y: TCompRes - i: int - if optOverflowCheck in p.options: i = 0 - else: i = 1 + let i = ord(optOverflowCheck notin p.options) useMagic(p, ops[op][i]) - if sonsLen(n) > 2: + if sonsLen(n) > 2: gen(p, n.sons[1], x) gen(p, n.sons[2], y) - r.res = ropef(ops[op][i + 2], [x.res, y.res]) - r.com = mergeExpr(x.com, y.com) - else: + r.res = ropef(ops[op][i + 2], [x.rdLoc, y.rdLoc]) + else: gen(p, n.sons[1], r) - r.res = ropef(ops[op][i + 2], [r.res]) + r.res = ropef(ops[op][i + 2], [r.rdLoc]) + r.kind = resExpr -proc genLineDir(p: var TProc, n: PNode, r: var TCompRes) = - var line: int - line = toLinenumber(n.info) - if optLineDir in p.Options: - appf(r.com, "// line $2 \"$1\"$n", +proc genLineDir(p: PProc, n: PNode) = + let line = toLinenumber(n.info) + if optLineDir in p.Options: + appf(p.body, "// line $2 \"$1\"$n", [toRope(toFilename(n.info)), toRope(line)]) - if ({optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb}) and - ((p.prc == nil) or not (sfPure in p.prc.flags)): + if {optStackTrace, optEndb} * p.Options == {optStackTrace, optEndb} and + ((p.prc == nil) or sfPure notin p.prc.flags): useMagic(p, "endb") - appf(r.com, "endb($1);$n", [toRope(line)]) + appf(p.body, "endb($1);$n", [toRope(line)]) elif ({optLineTrace, optStackTrace} * p.Options == {optLineTrace, optStackTrace}) and ((p.prc == nil) or not (sfPure in p.prc.flags)): - appf(r.com, "F.line = $1;$n", [toRope(line)]) + appf(p.body, "F.line = $1;$n", [toRope(line)]) -proc genWhileStmt(p: var TProc, n: PNode, r: var TCompRes) = - var +proc genWhileStmt(p: PProc, n: PNode) = + var cond, stmt: TCompRes - length, labl: int - genLineDir(p, n, r) + internalAssert isEmptyType(n.typ) + genLineDir(p, n) inc(p.unique) - length = len(p.blocks) + var length = len(p.blocks) setlen(p.blocks, length + 1) p.blocks[length].id = - p.unique p.blocks[length].isLoop = true - labl = p.unique + let labl = p.unique.toRope + appf(p.body, "L$1: while (true) {$n" | "while true do$n", labl) gen(p, n.sons[0], cond) + appf(p.body, "if (!$1) break L$2;$n" | "if not $1 then goto ::L$2:: end;$n", + [cond.res, labl]) genStmt(p, n.sons[1], stmt) - if p.blocks[length].id > 0: - appf(r.com, "L$3: while ($1) {$n$2}$n", - [mergeExpr(cond), mergeStmt(stmt), toRope(labl)]) - else: - appf(r.com, "while ($1) {$n$2}$n", [mergeExpr(cond), mergeStmt(stmt)]) + internalAssert stmt.res.isNil + appf(p.body, "}$n" | "end$n", []) setlen(p.blocks, length) -proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) = +proc moveInto(p: PProc, src: var TCompRes, dest: TCompRes) = + if src.kind != resNone: + assert dest.kind != resNone + p.body.appf("$1 = $2;$n", dest.rdLoc, src.rdLoc) + src.kind = resNone + src.res = nil + +proc genTry(p: PProc, n: PNode, r: var TCompRes) = # code to generate: # # var sp = {prev: excHandler, exc: null}; # excHandler = sp; # try { # stmts; + # TMP = e # } catch (e) { # if (e.typ && e.typ == NTI433 || e.typ == NTI2321) { # stmts; @@ -522,116 +432,113 @@ proc genTryStmt(p: var TProc, n: PNode, r: var TCompRes) = # stmts; # excHandler = excHandler.prev; # } - # - var - i, length, blen: int - safePoint, orExpr, epart: PRope - a: TCompRes - genLineDir(p, n, r) + genLineDir(p, n) inc(p.unique) - safePoint = ropef("Tmp$1", [toRope(p.unique)]) - appf(r.com, + var safePoint = ropef("Tmp$1", [toRope(p.unique)]) + appf(p.body, "var $1 = {prev: excHandler, exc: null};$n" & "excHandler = $1;$n", [safePoint]) - if optStackTrace in p.Options: app(r.com, "framePtr = F;" & tnl) - app(r.com, "try {" & tnl) - length = sonsLen(n) + if optStackTrace in p.Options: app(p.body, "framePtr = F;" & tnl) + app(p.body, "try {" & tnl) + var length = sonsLen(n) + var a: TCompRes genStmt(p, n.sons[0], a) - app(r.com, mergeStmt(a)) - i = 1 - epart = nil - while (i < length) and (n.sons[i].kind == nkExceptBranch): - blen = sonsLen(n.sons[i]) + if not isEmptyType(n.typ): + r.kind = resVal + r.res = getTemp(p) + moveInto(p, a, r) + var i = 1 + if length > 1 and n.sons[i].kind == nkExceptBranch: + appf(p.body, "} catch (EXC) {$n") + while i < length and n.sons[i].kind == nkExceptBranch: + let blen = sonsLen(n.sons[i]) if blen == 1: # general except section: - if i > 1: app(epart, "else {" & tnl) + if i > 1: app(p.body, "else {" & tnl) genStmt(p, n.sons[i].sons[0], a) - app(epart, mergeStmt(a)) - if i > 1: app(epart, '}' & tnl) - else: - orExpr = nil + moveInto(p, a, r) + if i > 1: app(p.body, '}' & tnl) + else: + var orExpr: PRope = nil useMagic(p, "isObj") 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") if orExpr != nil: app(orExpr, "||") appf(orExpr, "isObj($1.exc.m_type, $2)", [safePoint, genTypeInfo(p, n.sons[i].sons[j].typ)]) - if i > 1: app(epart, "else ") - appf(epart, "if ($1.exc && $2) {$n", [safePoint, orExpr]) + if i > 1: app(p.body, "else ") + appf(p.body, "if ($1.exc && ($2)) {$n", [safePoint, orExpr]) genStmt(p, n.sons[i].sons[blen - 1], a) - appf(epart, "$1}$n", [mergeStmt(a)]) + moveInto(p, a, r) + appf(p.body, "}$n") inc(i) - if epart != nil: appf(r.com, "} catch (EXC) {$n$1", [epart]) - app(r.com, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl) - if (i < length) and (n.sons[i].kind == nkFinally): + app(p.body, "} finally {" & tnl & "excHandler = excHandler.prev;" & tnl) + if i < length and n.sons[i].kind == nkFinally: genStmt(p, n.sons[i].sons[0], a) - app(r.com, mergeStmt(a)) - app(r.com, '}' & tnl) + moveInto(p, a, r) + app(p.body, '}' & tnl) -proc genRaiseStmt(p: var TProc, n: PNode, r: var TCompRes) = - var - a: TCompRes - typ: PType - genLineDir(p, n, r) - if n.sons[0].kind != nkEmpty: +proc genRaiseStmt(p: PProc, n: PNode) = + genLineDir(p, n) + if n.sons[0].kind != nkEmpty: + var a: TCompRes gen(p, n.sons[0], a) - if a.com != nil: appf(r.com, "$1;$n", [a.com]) - typ = skipTypes(n.sons[0].typ, abstractPtrs) + let typ = skipTypes(n.sons[0].typ, abstractPtrs) useMagic(p, "raiseException") - appf(r.com, "raiseException($1, $2);$n", - [a.res, makeJSString(typ.sym.name.s)]) - else: + appf(p.body, "raiseException($1, $2);$n", + [a.rdLoc, makeJSString(typ.sym.name.s)]) + else: useMagic(p, "reraiseException") - app(r.com, "reraiseException();" & tnl) + app(p.body, "reraiseException();" & tnl) -proc genCaseStmt(p: var TProc, n: PNode, r: var TCompRes) = - var +proc genCase(p: PProc, n: PNode, r: var TCompRes) = + var cond, stmt: TCompRes - it, e, v: PNode - stringSwitch: bool - genLineDir(p, n, r) + genLineDir(p, n) gen(p, n.sons[0], cond) - if cond.com != nil: appf(r.com, "$1;$n", [cond.com]) - stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString + let stringSwitch = skipTypes(n.sons[0].typ, abstractVar).kind == tyString if stringSwitch: useMagic(p, "toJSStr") - appf(r.com, "switch (toJSStr($1)) {$n", [cond.res]) - else: - appf(r.com, "switch ($1) {$n", [cond.res]) + appf(p.body, "switch (toJSStr($1)) {$n", [cond.rdLoc]) + else: + appf(p.body, "switch ($1) {$n", [cond.rdLoc]) + if not isEmptyType(n.typ): + r.kind = resVal + r.res = getTemp(p) for i in countup(1, sonsLen(n) - 1): - it = n.sons[i] + let it = n.sons[i] case it.kind of nkOfBranch: for j in countup(0, sonsLen(it) - 2): - e = it.sons[j] + let e = it.sons[j] if e.kind == nkRange: - v = copyNode(e.sons[0]) - while (v.intVal <= e.sons[1].intVal): + var v = copyNode(e.sons[0]) + while v.intVal <= e.sons[1].intVal: gen(p, v, cond) - if cond.com != nil: internalError(v.info, "jsgen.genCaseStmt") - appf(r.com, "case $1: ", [cond.res]) + appf(p.body, "case $1: ", [cond.rdLoc]) Inc(v.intVal) - else: - gen(p, e, cond) - if cond.com != nil: internalError(e.info, "jsgen.genCaseStmt") + else: if stringSwitch: case e.kind - of nkStrLit..nkTripleStrLit: appf(r.com, "case $1: ", + of nkStrLit..nkTripleStrLit: appf(p.body, "case $1: ", [makeJSString(e.strVal)]) else: InternalError(e.info, "jsgen.genCaseStmt: 2") else: - appf(r.com, "case $1: ", [cond.res]) + gen(p, e, cond) + appf(p.body, "case $1: ", [cond.rdLoc]) genStmt(p, lastSon(it), stmt) - appf(r.com, "$n$1break;$n", [mergeStmt(stmt)]) - of nkElse: + moveInto(p, stmt, r) + appf(p.body, "$nbreak;$n") + of nkElse: + appf(p.body, "default: $n") genStmt(p, it.sons[0], stmt) - appf(r.com, "default: $n$1break;$n", [mergeStmt(stmt)]) + moveInto(p, stmt, r) + appf(p.body, "break;$n") else: internalError(it.info, "jsgen.genCaseStmt") - appf(r.com, "}$n", []) + appf(p.body, "}$n") -proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes) -proc genBlock(p: var TProc, n: PNode, r: var TCompRes) = +proc genBlock(p: PProc, n: PNode, r: var TCompRes) = var idx, labl: int sym: PSym @@ -646,22 +553,18 @@ proc genBlock(p: var TProc, n: PNode, r: var TCompRes) = setlen(p.blocks, idx + 1) p.blocks[idx].id = - p.unique # negative because it isn't used yet labl = p.unique - if n.kind == nkBlockExpr: genStmtListExpr(p, n.sons[1], r) - else: genStmt(p, n.sons[1], r) - if p.blocks[idx].id > 0: - # label has been used: - r.com = ropef("L$1: do {$n$2} while(false);$n", [toRope(labl), r.com]) + appf(p.body, "L$1: do {$n", toRope(labl)) + genStmt(p, n.sons[1], r) + appf(p.body, "} while(false);$n") setlen(p.blocks, idx) -proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) = - var - idx: int - sym: PSym - genLineDir(p, n, r) +proc genBreakStmt(p: PProc, n: PNode) = + var idx: int + genLineDir(p, n) if n.sons[0].kind != nkEmpty: # named break? assert(n.sons[0].kind == nkSym) - sym = n.sons[0].sym + let sym = n.sons[0].sym assert(sym.loc.k == locOther) idx = sym.loc.a else: @@ -671,73 +574,47 @@ proc genBreakStmt(p: var TProc, n: PNode, r: var TCompRes) = 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 - appf(r.com, "break L$1;$n", [toRope(p.blocks[idx].id)]) + appf(p.body, "break L$1;$n", [toRope(p.blocks[idx].id)]) -proc genAsmStmt(p: var TProc, n: PNode, r: var TCompRes) = - genLineDir(p, n, r) +proc genAsmStmt(p: PProc, n: PNode) = + genLineDir(p, n) assert(n.kind == nkAsmStmt) for i in countup(0, sonsLen(n) - 1): case n.sons[i].Kind - of nkStrLit..nkTripleStrLit: app(r.com, n.sons[i].strVal) - of nkSym: app(r.com, mangleName(n.sons[i].sym)) + of nkStrLit..nkTripleStrLit: app(p.body, n.sons[i].strVal) + of nkSym: app(p.body, mangleName(n.sons[i].sym)) else: InternalError(n.sons[i].info, "jsgen: genAsmStmt()") -proc genIfStmt(p: var TProc, n: PNode, r: var TCompRes) = - var - toClose: int - cond, stmt: TCompRes - it: PNode - toClose = 0 +proc genIf(p: PProc, n: PNode, r: var TCompRes) = + var cond, stmt: TCompRes + var toClose = 0 + if not isEmptyType(n.typ): + r.kind = resVal + r.res = getTemp(p) for i in countup(0, sonsLen(n) - 1): - it = n.sons[i] + let it = n.sons[i] if sonsLen(it) != 1: + if i > 0: + appf(p.body, "else {$n", []) + inc(toClose) gen(p, it.sons[0], cond) + appf(p.body, "if ($1) {$n", cond.rdLoc) genStmt(p, it.sons[1], stmt) - if i > 0: - appf(r.com, "else {$n", []) - inc(toClose) - if cond.com != nil: appf(r.com, "$1;$n", [cond.com]) - appf(r.com, "if ($1) {$n$2}", [cond.res, mergeStmt(stmt)]) - else: + else: # else part: + appf(p.body, "else {$n") genStmt(p, it.sons[0], stmt) - appf(r.com, "else {$n$1}$n", [mergeStmt(stmt)]) - app(r.com, repeatChar(toClose, '}') & tnl) - -proc genIfExpr(p: var TProc, n: PNode, r: var TCompRes) = - var - toClose: int - cond, stmt: TCompRes - it: PNode - toClose = 0 - for i in countup(0, sonsLen(n) - 1): - it = n.sons[i] - if sonsLen(it) != 1: - gen(p, it.sons[0], cond) - gen(p, it.sons[1], stmt) - if i > 0: - app(r.res, ": (") - inc(toClose) - r.com = mergeExpr(r.com, cond.com) - r.com = mergeExpr(r.com, stmt.com) - appf(r.res, "($1) ? ($2)", [cond.res, stmt.res]) - else: - # else part: - gen(p, it.sons[0], stmt) - r.com = mergeExpr(r.com, stmt.com) - appf(r.res, ": ($1)", [stmt.res]) - app(r.res, repeatChar(toClose, ')')) + moveInto(p, stmt, r) + appf(p.body, "}$n") + app(p.body, repeatChar(toClose, '}') & tnl) -proc generateHeader(p: var TProc, typ: PType): PRope = - var - param: PSym - name: PRope +proc generateHeader(p: PProc, typ: PType): PRope = result = nil for i in countup(1, sonsLen(typ.n) - 1): if result != nil: app(result, ", ") assert(typ.n.sons[i].kind == nkSym) - param = typ.n.sons[i].sym - name = mangleName(param) + var param = typ.n.sons[i].sym + var name = mangleName(param) app(result, name) if mapType(param.typ) == etyBaseIndex: app(result, ", ") @@ -754,56 +631,49 @@ proc needsNoCopy(y: PNode): bool = result = (y.kind in nodeKindsNeedNoCopy) or (skipTypes(y.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}) -proc genAsgnAux(p: var TProc, x, y: PNode, r: var TCompRes, - noCopyNeeded: bool) = +proc genAsgnAux(p: PProc, x, y: PNode, noCopyNeeded: bool) = var a, b: TCompRes gen(p, x, a) gen(p, y, b) case mapType(x.typ) - of etyObject: - if a.com != nil: appf(r.com, "$1;$n", [a.com]) - if b.com != nil: appf(r.com, "$1;$n", [b.com]) - if needsNoCopy(y) or noCopyNeeded: - appf(r.com, "$1 = $2;$n", [a.res, b.res]) - else: + of etyObject: + if needsNoCopy(y) or noCopyNeeded: + appf(p.body, "$1 = $2;$n", [a.rdLoc, b.rdLoc]) + else: useMagic(p, "NimCopy") - appf(r.com, "$1 = NimCopy($2, $3);$n", + appf(p.body, "$1 = NimCopy($2, $3);$n", [a.res, b.res, genTypeInfo(p, y.typ)]) of etyBaseIndex: - if (a.kind != etyBaseIndex) or (b.kind != etyBaseIndex): + if a.typ != etyBaseIndex or b.typ != etyBaseIndex: internalError(x.info, "genAsgn") - appf(r.com, "$1 = $2; $3 = $4;$n", [a.com, b.com, a.res, b.res]) - else: - if a.com != nil: appf(r.com, "$1;$n", [a.com]) - if b.com != nil: appf(r.com, "$1;$n", [b.com]) - appf(r.com, "$1 = $2;$n", [a.res, b.res]) + appf(p.body, "$1 = $2; $3 = $4;$n", [a.address, b.address, a.res, b.res]) + else: + appf(p.body, "$1 = $2;$n", [a.res, b.res]) -proc genAsgn(p: var TProc, n: PNode, r: var TCompRes) = - genLineDir(p, n, r) - genAsgnAux(p, n.sons[0], n.sons[1], r, false) +proc genAsgn(p: PProc, n: PNode) = + genLineDir(p, n) + genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=false) -proc genFastAsgn(p: var TProc, n: PNode, r: var TCompRes) = - genLineDir(p, n, r) - genAsgnAux(p, n.sons[0], n.sons[1], r, true) +proc genFastAsgn(p: PProc, n: PNode) = + genLineDir(p, n) + genAsgnAux(p, n.sons[0], n.sons[1], noCopyNeeded=true) -proc genSwap(p: var TProc, n: PNode, r: var TCompRes) = +proc genSwap(p: PProc, n: PNode) = var a, b: TCompRes gen(p, n.sons[1], a) gen(p, n.sons[2], b) inc(p.unique) - var tmp = ropef("Tmp$1", [toRope(p.unique)]) + let tmp = ropef("Tmp$1", [toRope(p.unique)]) case mapType(skipTypes(n.sons[1].typ, abstractVar)) of etyBaseIndex: inc(p.unique) - var tmp2 = ropef("Tmp$1", [toRope(p.unique)]) - if (a.kind != etyBaseIndex) or (b.kind != etyBaseIndex): + let tmp2 = ropef("Tmp$1", [toRope(p.unique)]) + if a.typ != etyBaseIndex or b.typ != etyBaseIndex: internalError(n.info, "genSwap") - appf(r.com, "var $1 = $2; $2 = $3; $3 = $1;$n", [tmp, a.com, b.com]) - appf(r.com, "var $1 = $2; $2 = $3; $3 = $1", [tmp2, a.res, b.res]) - else: - if a.com != nil: appf(r.com, "$1;$n", [a.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(p.body, "var $1 = $2; $2 = $3; $3 = $1;$n", [tmp, a.address, b.address]) + appf(p.body, "var $1 = $2; $2 = $3; $3 = $1", [tmp2, a.res, b.res]) + else: + appf(p.body, "var $1 = $2; $2 = $3; $3 = $1", [tmp, a.res, b.res]) proc getFieldPosition(f: PNode): int = case f.kind @@ -811,10 +681,10 @@ proc getFieldPosition(f: PNode): int = of nkSym: result = f.sym.position else: InternalError(f.info, "genFieldPosition") -proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = +proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes - r.kind = etyBaseIndex - var b = if n.kind == nkHiddenAddr: n.sons[0] else: n + r.typ = etyBaseIndex + let b = if n.kind == nkHiddenAddr: n.sons[0] else: n gen(p, b.sons[0], a) if skipTypes(b.sons[0].typ, abstractVarRange).kind == tyTuple: r.res = makeJSString("Field" & $getFieldPosition(b.sons[1])) @@ -823,10 +693,12 @@ proc genFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = var f = b.sons[1].sym if f.loc.r == nil: f.loc.r = mangleName(f) r.res = makeJSString(ropeToStr(f.loc.r)) - r.com = mergeExpr(a) + InternalAssert a.typ != etyBaseIndex + r.address = a.res + r.kind = resExpr -proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = - r.kind = etyNone +proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) = + r.typ = etyNone 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]) @@ -835,34 +707,37 @@ proc genFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = var f = n.sons[1].sym if f.loc.r == nil: f.loc.r = mangleName(f) r.res = ropef("$1.$2", [r.res, f.loc.r]) + r.kind = resExpr -proc genCheckedFieldAddr(p: var TProc, n: PNode, r: var TCompRes) = +proc genCheckedFieldAddr(p: PProc, n: PNode, r: var TCompRes) = genFieldAddr(p, n.sons[0], r) # XXX -proc genCheckedFieldAccess(p: var TProc, n: PNode, r: var TCompRes) = +proc genCheckedFieldAccess(p: PProc, n: PNode, r: var TCompRes) = genFieldAccess(p, n.sons[0], r) # XXX -proc genArrayAddr(p: var TProc, n: PNode, r: var TCompRes) = +proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = var a, b: TCompRes first: biggestInt - r.kind = etyBaseIndex + r.typ = etyBaseIndex gen(p, n.sons[0], a) gen(p, n.sons[1], b) - r.com = mergeExpr(a) + InternalAssert a.typ != etyBaseIndex and b.typ != etyBaseIndex + r.address = a.res var typ = skipTypes(n.sons[0].typ, abstractPtrs) if typ.kind in {tyArray, tyArrayConstr}: first = FirstOrd(typ.sons[0]) else: first = 0 if optBoundsCheck in p.options and not isConstExpr(n.sons[1]): useMagic(p, "chckIndx") - b.res = ropef("chckIndx($1, $2, $3.length)-$2", - [b.res, toRope(first), a.res]) - # XXX: BUG: a.res evaluated twice! - elif first != 0: - b.res = ropef("($1)-$2", [b.res, toRope(first)]) - r.res = mergeExpr(b) - -proc genArrayAccess(p: var TProc, n: PNode, r: var TCompRes) = + r.res = ropef("chckIndx($1, $2, $3.length)-$2", + [b.res, toRope(first), a.res]) + elif first != 0: + r.res = ropef("($1)-$2", [b.res, toRope(first)]) + else: + r.res = b.res + r.kind = resExpr + +proc genArrayAccess(p: PProc, n: PNode, r: var TCompRes) = var ty = skipTypes(n.sons[0].typ, abstractVarRange) if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange) case ty.kind @@ -872,38 +747,40 @@ proc genArrayAccess(p: var TProc, n: PNode, r: var TCompRes) = of tyTuple: genFieldAddr(p, n, r) else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') - r.kind = etyNone - r.res = ropef("$1[$2]", [r.com, r.res]) - r.com = nil + r.typ = etyNone + if r.res == nil: InternalError(n.info, "genArrayAccess") + r.res = ropef("$1[$2]", [r.address, r.res]) + r.address = nil + r.kind = resExpr -proc genAddr(p: var TProc, n: PNode, r: var TCompRes) = - var s: PSym +proc genAddr(p: PProc, n: PNode, r: var TCompRes) = case n.sons[0].kind - of nkSym: - s = n.sons[0].sym + of nkSym: + let s = n.sons[0].sym if s.loc.r == nil: InternalError(n.info, "genAddr: 3") case s.kind - of skVar, skLet, skResult: - if mapType(n.typ) == etyObject: + of skVar, skLet, skResult: + r.kind = resExpr + if mapType(n.typ) == etyObject: # make addr() a no-op: - r.kind = etyNone + r.typ = etyNone r.res = s.loc.r - r.com = nil - elif sfGlobal in s.flags: + r.address = nil + elif sfGlobal in s.flags: # globals are always indirect accessible - r.kind = etyBaseIndex - r.com = toRope("Globals") + r.typ = etyBaseIndex + r.address = toRope("Globals") r.res = makeJSString(ropeToStr(s.loc.r)) - elif sfAddrTaken in s.flags: - r.kind = etyBaseIndex - r.com = s.loc.r + elif sfAddrTaken in s.flags: + r.typ = etyBaseIndex + r.address = s.loc.r r.res = toRope("0") - else: + else: InternalError(n.info, "genAddr: 4") else: InternalError(n.info, "genAddr: 2") - of nkCheckedFieldExpr: + of nkCheckedFieldExpr: genCheckedFieldAddr(p, n, r) - of nkDotExpr: + of nkDotExpr: genFieldAddr(p, n, r) of nkBracketExpr: var ty = skipTypes(n.sons[0].typ, abstractVarRange) @@ -917,27 +794,27 @@ proc genAddr(p: var TProc, n: PNode, r: var TCompRes) = else: InternalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')') else: InternalError(n.info, "genAddr") -proc genSym(p: var TProc, n: PNode, r: var TCompRes) = +proc genSym(p: PProc, n: PNode, r: var TCompRes) = var s = n.sym case s.kind - of skVar, skLet, skParam, skTemp, skResult: - if s.loc.r == nil: + of skVar, skLet, skParam, skTemp, skResult: + if s.loc.r == nil: InternalError(n.info, "symbol has no generated name: " & s.name.s) var k = mapType(s.typ) - if k == etyBaseIndex: - r.kind = etyBaseIndex - if {sfAddrTaken, sfGlobal} * s.flags != {}: - r.com = ropef("$1[0]", [s.loc.r]) + if k == etyBaseIndex: + r.typ = etyBaseIndex + if {sfAddrTaken, sfGlobal} * s.flags != {}: + r.address = ropef("$1[0]", [s.loc.r]) r.res = ropef("$1[1]", [s.loc.r]) - else: - r.com = s.loc.r + else: + r.address = s.loc.r r.res = con(s.loc.r, "_Idx") - elif (k != etyObject) and (sfAddrTaken in s.flags): + elif k != etyObject and sfAddrTaken in s.flags: r.res = ropef("$1[0]", [s.loc.r]) - else: + else: r.res = s.loc.r of skConst: - genConstant(p, s, r) + genConstant(p, s) if s.loc.r == nil: InternalError(n.info, "symbol has no generated name: " & s.name.s) r.res = s.loc.r @@ -953,64 +830,70 @@ proc genSym(p: var TProc, n: PNode, r: var TCompRes) = elif sfForward in s.flags: p.g.forwarded.add(s) elif not p.g.generatedSyms.containsOrIncl(s.id): - var r2: TCompRes - genProc(p, s, r2) - app(p.locals, mergeStmt(r2)) - #app(r.com, mergeStmt(r2)) + let newp = genProc(p, s) + var owner = p + while owner != nil and owner.prc != s.owner: + owner = owner.up + if owner != nil: app(owner.locals, newp) + else: app(p.g.code, newp) else: if s.loc.r == nil: InternalError(n.info, "symbol has no generated name: " & s.name.s) r.res = s.loc.r + r.kind = resVal -proc genDeref(p: var TProc, n: PNode, r: var TCompRes) = - var a: TCompRes +proc genDeref(p: PProc, n: PNode, r: var TCompRes) = if mapType(n.sons[0].typ) == etyObject: gen(p, n.sons[0], r) - else: + else: + var a: TCompRes gen(p, n.sons[0], a) - if a.kind != etyBaseIndex: InternalError(n.info, "genDeref") - r.res = ropef("$1[$2]", [a.com, a.res]) + if a.typ != etyBaseIndex: InternalError(n.info, "genDeref") + r.res = ropef("$1[$2]", [a.address, a.res]) -proc genArg(p: var TProc, n: PNode, r: var TCompRes) = +proc genArg(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes gen(p, n, a) - if a.kind == etyBaseIndex: - app(r.res, a.com) + if a.typ == etyBaseIndex: + app(r.res, a.address) app(r.res, ", ") app(r.res, a.res) else: - app(r.res, mergeExpr(a)) + app(r.res, a.res) -proc genArgs(p: var TProc, n: PNode, r: var TCompRes) = +proc genArgs(p: PProc, n: PNode, r: var TCompRes) = app(r.res, "(") for i in countup(1, sonsLen(n) - 1): if i > 1: app(r.res, ", ") genArg(p, n.sons[i], r) app(r.res, ")") + r.kind = resExpr -proc genCall(p: var TProc, n: PNode, r: var TCompRes) = +proc genCall(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[0], r) genArgs(p, n, r) -proc genInfixCall(p: var TProc, n: PNode, r: var TCompRes) = +proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[1], r) - if r.kind == etyBaseIndex: - if r.com == nil: + if r.typ == etyBaseIndex: + if r.address == nil: GlobalError(n.info, "cannot invoke with infix syntax") - r.res = ropef("$1[0]", [r.res, r.com]) - r.com = nil + r.res = ropef("$1[$2]", [r.address, r.res]) + r.address = nil + r.typ = etyNone app(r.res, ".") var op: TCompRes gen(p, n.sons[0], op) - app(r.res, mergeExpr(op)) + app(r.res, op.res) app(r.res, "(") for i in countup(2, sonsLen(n) - 1): if i > 2: app(r.res, ", ") genArg(p, n.sons[i], r) app(r.res, ")") + r.kind = resExpr -proc genEcho(p: var TProc, n: PNode, r: var TCompRes) = +proc genEcho(p: PProc, n: PNode, r: var TCompRes) = useMagic(p, "rawEcho") app(r.res, "rawEcho") genArgs(p, n, r) @@ -1019,8 +902,8 @@ proc putToSeq(s: string, indirect: bool): PRope = result = toRope(s) if indirect: result = ropef("[$1]", [result]) -proc createVar(p: var TProc, typ: PType, indirect: bool): PRope -proc createRecordVarAux(p: var TProc, rec: PNode, c: var int): PRope = +proc createVar(p: PProc, typ: PType, indirect: bool): PRope +proc createRecordVarAux(p: PProc, rec: PNode, c: var int): PRope = result = nil case rec.kind of nkRecList: @@ -1038,7 +921,7 @@ proc createRecordVarAux(p: var TProc, rec: PNode, c: var int): PRope = inc(c) else: InternalError(rec.info, "createRecordVarAux") -proc createVar(p: var TProc, typ: PType, indirect: bool): PRope = +proc createVar(p: PProc, typ: PType, indirect: bool): PRope = var t = skipTypes(typ, abstractInst) case t.kind of tyInt..tyInt64, tyEnum, tyChar: @@ -1075,7 +958,7 @@ proc createVar(p: var TProc, typ: PType, indirect: bool): PRope = of tyObject: result = toRope("{") var c = 0 - if not (tfFinal in t.flags) or (t.sons[0] != nil): + if tfFinal notin t.flags or t.sons[0] != nil: inc(c) appf(result, "m_type: $1", [genTypeInfo(p, t)]) while t != nil: @@ -1095,38 +978,37 @@ proc isIndirect(v: PSym): bool = result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and v.kind notin {skProc, skConverter, skMethod, skIterator} -proc genVarInit(p: var TProc, v: PSym, n: PNode, r: var TCompRes) = +proc genVarInit(p: PProc, v: PSym, n: PNode) = var a: TCompRes s: PRope if n.kind == nkEmpty: - appf(r.com, "var $1 = $2;$n", + appf(p.body, "var $1 = $2;$n", [mangleName(v), createVar(p, v.typ, isIndirect(v))]) else: discard mangleName(v) gen(p, n, a) case mapType(v.typ) of etyObject: - if a.com != nil: appf(r.com, "$1;$n", [a.com]) if needsNoCopy(n): s = a.res else: useMagic(p, "NimCopy") s = ropef("NimCopy($1, $2)", [a.res, genTypeInfo(p, n.typ)]) of etyBaseIndex: - if (a.kind != etyBaseIndex): InternalError(n.info, "genVarInit") + if (a.typ != etyBaseIndex): InternalError(n.info, "genVarInit") if {sfAddrTaken, sfGlobal} * v.flags != {}: - appf(r.com, "var $1 = [$2, $3];$n", [v.loc.r, a.com, a.res]) + appf(p.body, "var $1 = [$2, $3];$n", [v.loc.r, a.address, a.res]) else: - appf(r.com, "var $1 = $2; var $1_Idx = $3;$n", [v.loc.r, a.com, a.res]) - return - else: - if a.com != nil: appf(r.com, "$1;$n", [a.com]) + appf(p.body, "var $1 = $2; var $1_Idx = $3;$n", [ + v.loc.r, a.address, a.res]) + return + else: s = a.res - if isIndirect(v): appf(r.com, "var $1 = [$2];$n", [v.loc.r, s]) - else: appf(r.com, "var $1 = $2;$n", [v.loc.r, s]) + if isIndirect(v): appf(p.body, "var $1 = [$2];$n", [v.loc.r, s]) + else: appf(p.body, "var $1 = $2;$n", [v.loc.r, s]) -proc genVarStmt(p: var TProc, n: PNode, r: var TCompRes) = +proc genVarStmt(p: PProc, n: PNode) = for i in countup(0, sonsLen(n) - 1): var a = n.sons[i] if a.kind == nkCommentStmt: continue @@ -1134,56 +1016,43 @@ proc genVarStmt(p: var TProc, n: PNode, r: var TCompRes) = assert(a.sons[0].kind == nkSym) var v = a.sons[0].sym if lfNoDecl in v.loc.flags: continue - genLineDir(p, a, r) - genVarInit(p, v, a.sons[2], r) + genLineDir(p, a) + genVarInit(p, v, a.sons[2]) -proc genConstant(p: var TProc, c: PSym, r: var TCompRes) = +proc genConstant(p: PProc, c: PSym) = if lfNoDecl notin c.loc.flags and not p.g.generatedSyms.containsOrIncl(c.id): - genLineDir(p, c.ast, r) - genVarInit(p, c, c.ast, r) - app(p.g.code, r.com) - r.com = nil - -when false: - proc genConstStmt(p: var TProc, n: PNode, r: var TCompRes) = - genLineDir(p, n, r) - for i in countup(0, sonsLen(n) - 1): - if n.sons[i].kind == nkCommentStmt: continue - assert(n.sons[i].kind == nkConstDef) - var c = n.sons[i].sons[0].sym - if c.ast != nil and c.typ.kind in ConstantDataTypes and - lfNoDecl notin c.loc.flags: - genLineDir(p, n.sons[i], r) - genVarInit(p, c, c.ast, r) - -proc genNew(p: var TProc, n: PNode, r: var TCompRes) = + let oldBody = p.body + p.body = nil + genLineDir(p, c.ast) + genVarInit(p, c, c.ast) + app(p.g.code, p.body) + p.body = oldBody + +proc genNew(p: PProc, n: PNode) = var a: TCompRes gen(p, n.sons[1], a) var t = skipTypes(n.sons[1].typ, abstractVar).sons[0] - if a.com != nil: appf(r.com, "$1;$n", [a.com]) - appf(r.com, "$1 = $2;$n", [a.res, createVar(p, t, true)]) + appf(p.body, "$1 = $2;$n", [a.res, createVar(p, t, true)]) -proc genNewSeq(p: var TProc, n: PNode, r: var TCompRes) = +proc genNewSeq(p: PProc, n: PNode) = 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)]) + let t = skipTypes(n.sons[1].typ, abstractVar).sons[0] + appf(p.body, "$1 = new Array($2); for (var i=0;i<$2;++i) {$1[i]=$3;}", [ + x.rdLoc, y.rdLoc, createVar(p, t, false)]) -proc genOrd(p: var TProc, n: PNode, r: var TCompRes) = +proc genOrd(p: PProc, n: PNode, r: var TCompRes) = case skipTypes(n.sons[1].typ, abstractVar).kind of tyEnum, tyInt..tyInt64, tyChar: gen(p, n.sons[1], r) of tyBool: unaryExpr(p, n, r, "", "($1 ? 1:0)") else: InternalError(n.info, "genOrd") -proc genConStrStr(p: var TProc, n: PNode, r: var TCompRes) = +proc genConStrStr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes gen(p, n.sons[1], a) - r.com = mergeExpr(r.com, a.com) + r.kind = resExpr if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyChar: r.res.app(ropef("[$1].concat(", [a.res])) else: @@ -1191,21 +1060,18 @@ proc genConStrStr(p: var TProc, n: PNode, r: var TCompRes) = for i in countup(2, sonsLen(n) - 2): gen(p, n.sons[i], a) - r.com = mergeExpr(r.com, a.com) - if skipTypes(n.sons[i].typ, abstractVarRange).kind == tyChar: r.res.app(ropef("[$1],", [a.res])) else: r.res.app(ropef("$1.slice(0,-1),", [a.res])) gen(p, n.sons[sonsLen(n) - 1], a) - r.com = mergeExpr(r.com, a.com) if skipTypes(n.sons[sonsLen(n) - 1].typ, abstractVarRange).kind == tyChar: r.res.app(ropef("[$1, 0])", [a.res])) else: r.res.app(ropef("$1)", [a.res])) -proc genRepr(p: var TProc, n: PNode, r: var TCompRes) = +proc genRepr(p: PProc, n: PNode, r: var TCompRes) = var t = skipTypes(n.sons[1].typ, abstractVarRange) case t.kind of tyInt..tyUInt64: @@ -1213,13 +1079,14 @@ proc genRepr(p: var TProc, n: PNode, r: var TCompRes) = of tyEnum, tyOrdinal: gen(p, n.sons[1], r) useMagic(p, "cstrToNimstr") + r.kind = resExpr r.res = ropef("cstrToNimstr($1.node.sons[$2].name)", [genTypeInfo(p, t), r.res]) else: # XXX: internalError(n.info, "genRepr: Not implemented") -proc genOf(p: var TProc, n: PNode, r: var TCompRes) = +proc genOf(p: PProc, n: PNode, r: var TCompRes) = var x: TCompRes let t = skipTypes(n.sons[2].typ, abstractVarRange+{tyRef, tyPtr, tyTypeDesc}) gen(p, n.sons[1], x) @@ -1228,17 +1095,16 @@ proc genOf(p: var TProc, n: PNode, r: var TCompRes) = else: useMagic(p, "isObj") r.res = ropef("isObj($1.m_type, $2)", [x.res, genTypeInfo(p, t)]) - r.com = mergeExpr(r.com, x.com) + r.kind = resExpr -proc genReset(p: var TProc, n: PNode, r: var TCompRes) = +proc genReset(p: PProc, n: PNode) = var x: TCompRes useMagic(p, "genericReset") gen(p, n.sons[1], x) - r.res = ropef("$1 = genericReset($1, $2)", [x.res, + appf(p.body, "$1 = genericReset($1, $2);$n", [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: PProc, n: PNode, r: var TCompRes) = var a: TCompRes line, filen: PRope @@ -1248,7 +1114,7 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = of mAnd: genAnd(p, n.sons[1], n.sons[2], r) of mAddi..mStrToStr: arith(p, n, r, op) of mRepr: genRepr(p, n, r) - of mSwap: genSwap(p, n, r) + of mSwap: genSwap(p, n) of mUnaryLt: # XXX: range checking? if not (optOverflowCheck in p.Options): unaryExpr(p, n, r, "", "$1 - 1") @@ -1261,21 +1127,21 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = # XXX: range checking? if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 - $2") else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)") - of mAppendStrCh: binaryStmt(p, n, r, "addChar", "$1 = addChar($1, $2)") + of mAppendStrCh: binaryExpr(p, n, r, "addChar", "$1 = addChar($1, $2)") of mAppendStrStr: if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString: - binaryStmt(p, n, r, "", "$1 += $2") + binaryExpr(p, n, r, "", "$1 += $2") else: - binaryStmt(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)") + binaryExpr(p, n, r, "", "$1 = ($1.slice(0,-1)).concat($2)") # XXX: make a copy of $2, because of Javascript's sucking semantics - of mAppendSeqElem: binaryStmt(p, n, r, "", "$1.push($2)") + of mAppendSeqElem: binaryExpr(p, n, r, "", "$1.push($2)") of mConStrStr: genConStrStr(p, n, r) of mEqStr: binaryExpr(p, n, r, "eqStrings", "eqStrings($1, $2)") of mLeStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) <= 0)") of mLtStr: binaryExpr(p, n, r, "cmpStrings", "(cmpStrings($1, $2) < 0)") of mIsNil: unaryExpr(p, n, r, "", "$1 == null") of mEnumToStr: genRepr(p, n, r) - of mNew, mNewFinalize: genNew(p, n, r) + of mNew, mNewFinalize: genNew(p, n) of mSizeOf: r.res = toRope(getSize(n.sons[1].typ)) of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do of mOrd: genOrd(p, n, r) @@ -1288,13 +1154,13 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = else: unaryExpr(p, n, r, "", "($1.length-1)") of mInc: - if not (optOverflowCheck in p.Options): binaryStmt(p, n, r, "", "$1 += $2") - else: binaryStmt(p, n, r, "addInt", "$1 = addInt($1, $2)") + if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 += $2") + else: binaryExpr(p, n, r, "addInt", "$1 = addInt($1, $2)") of ast.mDec: - if not (optOverflowCheck in p.Options): binaryStmt(p, n, r, "", "$1 -= $2") - else: binaryStmt(p, n, r, "subInt", "$1 = subInt($1, $2)") - of mSetLengthStr: binaryStmt(p, n, r, "", "$1.length = ($2)-1") - of mSetLengthSeq: binaryStmt(p, n, r, "", "$1.length = $2") + if not (optOverflowCheck in p.Options): binaryExpr(p, n, r, "", "$1 -= $2") + else: binaryExpr(p, n, r, "subInt", "$1 = subInt($1, $2)") + of mSetLengthStr: binaryExpr(p, n, r, "", "$1.length = ($2)-1") + of mSetLengthSeq: binaryExpr(p, n, r, "", "$1.length = $2") of mCard: unaryExpr(p, n, r, "SetCard", "SetCard($1)") of mLtSet: binaryExpr(p, n, r, "SetLt", "SetLt($1, $2)") of mLeSet: binaryExpr(p, n, r, "SetLe", "SetLe($1, $2)") @@ -1302,14 +1168,14 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = of mMulSet: binaryExpr(p, n, r, "SetMul", "SetMul($1, $2)") of mPlusSet: binaryExpr(p, n, r, "SetPlus", "SetPlus($1, $2)") of mMinusSet: binaryExpr(p, n, r, "SetMinus", "SetMinus($1, $2)") - of mIncl: binaryStmt(p, n, r, "", "$1[$2] = true") - of mExcl: binaryStmt(p, n, r, "", "delete $1[$2]") + of mIncl: binaryExpr(p, n, r, "", "$1[$2] = true") + of mExcl: binaryExpr(p, n, r, "", "delete $1[$2]") of mInSet: binaryExpr(p, n, r, "", "($1[$2] != undefined)") of mNLen..mNError: localError(n.info, errCannotGenerateCodeForX, n.sons[0].sym.name.s) - of mNewSeq: genNewSeq(p, n, r) + of mNewSeq: genNewSeq(p, n) of mOf: genOf(p, n, r) - of mReset: genReset(p, n, r) + of mReset: genReset(p, n) of mEcho: genEcho(p, n, r) of mSlurp, mStaticExec: localError(n.info, errXMustBeCompileTime, n.sons[0].sym.name.s) @@ -1317,94 +1183,95 @@ proc genMagic(p: var TProc, n: PNode, r: var TCompRes) = genCall(p, n, r) #else internalError(e.info, 'genMagic: ' + magicToStr[op]); -proc genSetConstr(p: var TProc, n: PNode, r: var TCompRes) = - var +proc genSetConstr(p: PProc, n: PNode, r: var TCompRes) = + var a, b: TCompRes useMagic(p, "SetConstr") r.res = toRope("SetConstr(") + r.kind = resExpr for i in countup(0, sonsLen(n) - 1): if i > 0: app(r.res, ", ") var it = n.sons[i] if it.kind == nkRange: gen(p, it.sons[0], a) gen(p, it.sons[1], b) - r.com = mergeExpr(r.com, mergeExpr(a.com, b.com)) appf(r.res, "[$1, $2]", [a.res, b.res]) else: gen(p, it, a) - r.com = mergeExpr(r.com, a.com) app(r.res, a.res) app(r.res, ")") -proc genArrayConstr(p: var TProc, n: PNode, r: var TCompRes) = +proc genArrayConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes r.res = toRope("[") + r.kind = resExpr for i in countup(0, sonsLen(n) - 1): if i > 0: app(r.res, ", ") gen(p, n.sons[i], a) - r.com = mergeExpr(r.com, a.com) app(r.res, a.res) app(r.res, "]") -proc genTupleConstr(p: var TProc, n: PNode, r: var TCompRes) = +proc genTupleConstr(p: PProc, n: PNode, r: var TCompRes) = var a: TCompRes r.res = toRope("{") + r.kind = resExpr for i in countup(0, sonsLen(n) - 1): if i > 0: app(r.res, ", ") var it = n.sons[i] if it.kind == nkExprColonExpr: it = it.sons[1] gen(p, it, a) - r.com = mergeExpr(r.com, a.com) appf(r.res, "Field$1: $2", [i.toRope, a.res]) r.res.app("}") -proc genObjConstr(p: var TProc, n: PNode, r: var TCompRes) = +proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) = # XXX inheritance? var a: TCompRes r.res = toRope("{") + r.kind = resExpr for i in countup(0, sonsLen(n) - 1): if i > 0: app(r.res, ", ") var it = n.sons[i] InternalAssert it.kind == nkExprColonExpr gen(p, it.sons[1], a) - r.com = mergeExpr(r.com, a.com) var f = it.sons[0].sym if f.loc.r == nil: f.loc.r = mangleName(f) appf(r.res, "$1: $2", [f.loc.r, a.res]) r.res.app("}") -proc genConv(p: var TProc, n: PNode, r: var TCompRes) = +proc genConv(p: PProc, n: PNode, r: var TCompRes) = var dest = skipTypes(n.typ, abstractVarRange) var src = skipTypes(n.sons[1].typ, abstractVarRange) gen(p, n.sons[1], r) if (dest.kind != src.kind) and (src.kind == tyBool): r.res = ropef("(($1)? 1:0)", [r.res]) + r.kind = resExpr -proc upConv(p: var TProc, n: PNode, r: var TCompRes) = +proc upConv(p: PProc, n: PNode, r: var TCompRes) = gen(p, n.sons[0], r) # XXX -proc genRangeChck(p: var TProc, n: PNode, r: var TCompRes, magic: string) = +proc genRangeChck(p: PProc, n: PNode, r: var TCompRes, magic: string) = var a, b: TCompRes gen(p, n.sons[0], r) if optRangeCheck in p.options: gen(p, n.sons[1], a) gen(p, n.sons[2], b) - r.com = mergeExpr(r.com, mergeExpr(a.com, b.com)) useMagic(p, "chckRange") r.res = ropef("chckRange($1, $2, $3)", [r.res, a.res, b.res]) + r.kind = resExpr -proc convStrToCStr(p: var TProc, n: PNode, r: var TCompRes) = +proc convStrToCStr(p: PProc, n: PNode, r: var TCompRes) = # we do an optimization here as this is likely to slow down # much of the code otherwise: if n.sons[0].kind == nkCStringToString: gen(p, n.sons[0].sons[0], r) - else: + else: gen(p, n.sons[0], r) if r.res == nil: InternalError(n.info, "convStrToCStr") useMagic(p, "toJSStr") r.res = ropef("toJSStr($1)", [r.res]) + r.kind = resExpr -proc convCStrToStr(p: var TProc, n: PNode, r: var TCompRes) = +proc convCStrToStr(p: PProc, n: PNode, r: var TCompRes) = # we do an optimization here as this is likely to slow down # much of the code otherwise: if n.sons[0].kind == nkStringToCString: @@ -1414,44 +1281,45 @@ proc convCStrToStr(p: var TProc, n: PNode, r: var TCompRes) = if r.res == nil: InternalError(n.info, "convCStrToStr") useMagic(p, "cstrToNimstr") r.res = ropef("cstrToNimstr($1)", [r.res]) + r.kind = resExpr -proc genReturnStmt(p: var TProc, n: PNode, r: var TCompRes) = +proc genReturnStmt(p: PProc, n: PNode) = var a: TCompRes if p.procDef == nil: InternalError(n.info, "genReturnStmt") p.BeforeRetNeeded = true if (n.sons[0].kind != nkEmpty): genStmt(p, n.sons[0], a) - if a.com != nil: appf(r.com, "$1;$n", mergeStmt(a)) else: - genLineDir(p, n, r) - app(r.com, "break BeforeRet;" & tnl) + genLineDir(p, n) + app(p.body, "break BeforeRet;" & tnl) -proc genProcBody(p: var TProc, prc: PSym, r: TCompRes): PRope = - if optStackTrace in prc.options: +proc genProcBody(p: PProc, prc: PSym): PRope = + if optStackTrace in prc.options: result = ropef("var F={procname:$1,prev:framePtr,filename:$2,line:0};$n" & "framePtr = F;$n", [makeJSString(prc.owner.name.s & '.' & prc.name.s), makeJSString(toFilename(prc.info))]) - else: + else: result = nil - if p.beforeRetNeeded: - appf(result, "BeforeRet: do {$n$1} while (false); $n", [mergeStmt(r)]) + if p.beforeRetNeeded: + appf(result, "BeforeRet: do {$n$1} while (false); $n", [p.body]) else: - app(result, mergeStmt(r)) + app(result, p.body) if prc.typ.callConv == ccSysCall: result = ropef("try {$n$1} catch (e) {$n" & " alert(\"Unhandled exception:\\n\" + e.message + \"\\n\"$n}", [result]) if optStackTrace in prc.options: app(result, "framePtr = framePtr.prev;" & tnl) -proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) = - var - p: TProc +proc genProc(oldProc: PProc, prc: PSym): PRope = + var resultSym: PSym name, returnStmt, resultAsgn, header: PRope - a: TCompRes + a, r: TCompRes #if gVerbosity >= 3: # echo "BEGIN generating code for: " & prc.name.s - initProc(p, oldProc.g, oldProc.module, prc.ast, prc.options) + var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options) + p.target = oldProc.target + p.up = oldProc returnStmt = nil resultAsgn = nil name = mangleName(prc) @@ -1461,112 +1329,57 @@ proc genProc(oldProc: var TProc, prc: PSym, r: var TCompRes) = resultAsgn = ropef("var $# = $#;$n", [mangleName(resultSym), createVar(p, resultSym.typ, isIndirect(resultSym))]) gen(p, prc.ast.sons[resultPos], a) - if a.com != nil: appf(returnStmt, "$1;$n", [a.com]) returnStmt = ropef("return $#;$n", [a.res]) genStmt(p, prc.getBody, r) - r.com = ropef("function $#($#) {$n$#$#$#$#}$n", + if r.res != nil: app(p.body, r.res) + result = ropef("function $#($#) {$n$#$#$#$#}$n", [name, header, p.locals, resultAsgn, - genProcBody(p, prc, r), returnStmt]) - r.res = nil + genProcBody(p, prc), returnStmt]) #if gVerbosity >= 3: # echo "END generated code for: " & prc.name.s -proc genStmtListExpr(p: var TProc, n: PNode, r: var TCompRes) = - var a: TCompRes - # watch out this trick: ``function () { stmtList; return expr; }()`` - r.res = toRope("function () {") - for i in countup(0, sonsLen(n) - 2): - genStmt(p, n.sons[i], a) - app(r.res, mergeStmt(a)) - gen(p, lastSon(n), a) - if a.com != nil: appf(r.res, "$1;$n", [a.com]) - appf(r.res, "return $1; }()", [a.res]) - -proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = - var a: TCompRes - r.kind = etyNone - r.com = nil - r.res = nil - case n.kind - of nkNilLit, nkEmpty: nil - of nkStmtList: - for i in countup(0, sonsLen(n) - 1): - genStmt(p, n.sons[i], a) - app(r.com, mergeStmt(a)) - of nkBlockStmt: genBlock(p, n, r) - of nkIfStmt: genIfStmt(p, n, r) - of nkWhileStmt: genWhileStmt(p, n, r) - of nkVarSection, nkLetSection: genVarStmt(p, n, r) - of nkConstSection: nil - of nkForStmt, nkParForStmt: - internalError(n.info, "for statement not eliminated") - of nkCaseStmt: genCaseStmt(p, n, r) - of nkReturnStmt: genReturnStmt(p, n, r) - of nkBreakStmt: genBreakStmt(p, n, r) - of nkAsgn: genAsgn(p, n, r) - of nkFastAsgn: genFastAsgn(p, n, r) - of nkDiscardStmt: - if n.sons[0].kind != nkEmpty: - genLineDir(p, n, r) - gen(p, n.sons[0], r) - app(r.res, ';' & tnl) - of nkAsmStmt: genAsmStmt(p, n, r) - of nkTryStmt: genTryStmt(p, n, r) - of nkRaiseStmt: genRaiseStmt(p, n, r) - of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, - nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, - nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil - of nkProcDef, nkMethodDef, nkConverterDef: - var s = n.sons[namePos].sym - if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: - #var r2: TCompRes - genSym(p, n.sons[namePos], r) - r.res = nil - of nkGotoState, nkState: - internalError(n.info, "first class iterators not implemented") - else: - genLineDir(p, n, r) - gen(p, n, r) - app(r.res, ';' & tnl) - -proc gen(p: var TProc, n: PNode, r: var TCompRes) = - var f: BiggestFloat - r.kind = etyNone - r.com = nil +proc genStmt(p: PProc, n: PNode, r: var TCompRes) = + gen(p, n, r) + +proc gen(p: PProc, n: PNode, r: var TCompRes) = + r.typ = etyNone + r.kind = resNone + #r.address = nil r.res = nil case n.kind - of nkSym: + of nkSym: genSym(p, n, r) - of nkCharLit..nkInt64Lit: + of nkCharLit..nkInt64Lit: r.res = toRope(n.intVal) - of nkNilLit: - if mapType(n.typ) == etyBaseIndex: - r.kind = etyBaseIndex - r.com = toRope"null" + of nkNilLit: + if isEmptyType(n.typ): + nil + elif mapType(n.typ) == etyBaseIndex: + r.typ = etyBaseIndex + r.address = toRope"null" r.res = toRope"0" - else: + else: r.res = toRope"null" - of nkStrLit..nkTripleStrLit: + of nkStrLit..nkTripleStrLit: if skipTypes(n.typ, abstractVarRange).kind == tyString: useMagic(p, "cstrToNimstr") r.res = ropef("cstrToNimstr($1)", [makeJSString(n.strVal)]) else: r.res = makeJSString(n.strVal) + r.kind = resExpr of nkFloatLit..nkFloat64Lit: - f = n.floatVal + let f = n.floatVal if f != f: r.res = toRope"NaN" elif f == 0.0: r.res = toRope"0.0" elif f == 0.5 * f: if f > 0.0: r.res = toRope"Infinity" else: r.res = toRope"-Infinity" else: r.res = toRope(f.ToStrMaxPrecision) - of nkBlockExpr: genBlock(p, n, r) - of nkIfExpr: genIfExpr(p, n, r) of nkCallKinds: if (n.sons[0].kind == nkSym) and (n.sons[0].sym.magic != mNone): genMagic(p, n, r) elif n.sons[0].kind == nkSym and sfInfixCall in n.sons[0].sym.flags and - n.len >= 2: + n.len >= 2: genInfixCall(p, n, r) else: genCall(p, n, r) @@ -1588,7 +1401,6 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) = of nkChckRange: genRangeChck(p, n, r, "chckRange") of nkStringToCString: convStrToCStr(p, n, r) of nkCStringToString: convCStrToStr(p, n, r) - of nkStmtListExpr: genStmtListExpr(p, n, r) of nkEmpty: nil of nkLambdaKinds: let s = n.sons[namePos].sym @@ -1596,11 +1408,51 @@ proc gen(p: var TProc, n: PNode, r: var TCompRes) = 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)) + app(p.locals, genProc(p, s)) of nkMetaNode: gen(p, n.sons[0], r) of nkType: r.res = genTypeInfo(p, n.typ) + of nkStmtList, nkStmtListExpr: + # this shows the distinction is nice for backends and should be kept + # in the frontend + let isExpr = not isEmptyType(n.typ) + var a: TCompRes + for i in countup(0, sonsLen(n) - 1 - isExpr.ord): + a.res = nil + genStmt(p, n.sons[i], a) + if a.res != nil: + app(p.body, a.res) + app(p.body, ";" & tnl) + if isExpr: + genStmt(p, lastSon(n), r) + of nkBlockStmt, nkBlockExpr: genBlock(p, n, r) + of nkIfStmt, nkIfExpr: genIf(p, n, r) + of nkWhileStmt: genWhileStmt(p, n) + of nkVarSection, nkLetSection: genVarStmt(p, n) + of nkConstSection: nil + of nkForStmt, nkParForStmt: + internalError(n.info, "for statement not eliminated") + of nkCaseStmt: genCase(p, n, r) + of nkReturnStmt: genReturnStmt(p, n) + of nkBreakStmt: genBreakStmt(p, n) + of nkAsgn: genAsgn(p, n) + of nkFastAsgn: genFastAsgn(p, n) + of nkDiscardStmt: + if n.sons[0].kind != nkEmpty: + genLineDir(p, n) + gen(p, n.sons[0], r) + of nkAsmStmt: genAsmStmt(p, n) + of nkTryStmt: genTry(p, n, r) + of nkRaiseStmt: genRaiseStmt(p, n) + of nkTypeSection, nkCommentStmt, nkIteratorDef, nkIncludeStmt, + nkImportStmt, nkImportExceptStmt, nkExportStmt, nkExportExceptStmt, + nkFromStmt, nkTemplateDef, nkMacroDef, nkPragma: nil + of nkProcDef, nkMethodDef, nkConverterDef: + var s = n.sons[namePos].sym + if {sfExportc, sfCompilerProc} * s.flags == {sfExportc}: + genSym(p, n.sons[namePos], r) + r.res = nil + of nkGotoState, nkState: + internalError(n.info, "first class iterators not implemented") else: InternalError(n.info, "gen: unknown node type: " & $n.kind) var globals: PGlobals @@ -1616,26 +1468,28 @@ proc genHeader(): PRope = "var framePtr = null;$n" & "var excHandler = null;$n", [toRope(versionAsString)]) -proc genModule(p: var TProc, n: PNode, r: var TCompRes) = - genStmt(p, n, r) - if optStackTrace in p.options: - r.com = ropef("var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" & - "framePtr = F;$n" & "$3" & "framePtr = framePtr.prev;$n", [ +proc genModule(p: PProc, n: PNode) = + if optStackTrace in p.options: + appf(p.body, "var F = {procname:$1,prev:framePtr,filename:$2,line:0};$n" & + "framePtr = F;$n", [ makeJSString("module " & p.module.module.name.s), - makeJSString(toFilename(p.module.module.info)), r.com]) + makeJSString(toFilename(p.module.module.info))]) + var r: TCompRes + genStmt(p, n, r) + if r.res != nil: + appf(p.body, "$#;$n", r.res) + if optStackTrace in p.options: + appf(p.body, "framePtr = framePtr.prev;$n") proc myProcess(b: PPassContext, n: PNode): PNode = if passes.skipCodegen(n): return n - var - p: TProc - r: TCompRes result = n var m = BModule(b) if m.module == nil: InternalError(n.info, "myProcess") - initProc(p, globals, m, nil, m.module.options) - genModule(p, n, r) + var p = newProc(globals, m, nil, m.module.options) + genModule(p, n) app(p.g.code, p.locals) - app(p.g.code, mergeStmt(r)) + app(p.g.code, p.body) proc myClose(b: PPassContext, n: PNode): PNode = if passes.skipCodegen(n): return n @@ -1644,23 +1498,15 @@ proc myClose(b: PPassContext, n: PNode): PNode = if sfMainModule in m.module.flags: for prc in globals.forwarded: if not globals.generatedSyms.containsOrIncl(prc.id): - var - p: TProc - r: TCompRes - initProc(p, globals, m, nil, m.module.options) - genProc(p, prc, r) - app(p.g.code, mergeStmt(r)) + var p = newProc(globals, m, nil, m.module.options) + app(p.g.code, genProc(p, prc)) var disp = generateMethodDispatchers() for i in 0..sonsLen(disp)-1: let prc = disp.sons[i].sym if not globals.generatedSyms.containsOrIncl(prc.id): - var - p: TProc - r: TCompRes - initProc(p, globals, m, nil, m.module.options) - genProc(p, prc, r) - app(p.g.code, mergeStmt(r)) + var p = newProc(globals, m, nil, m.module.options) + app(p.g.code, genProc(p, prc)) # write the file: var code = con(globals.typeInfo, globals.code) diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim new file mode 100644 index 000000000..0be1e99dc --- /dev/null +++ b/compiler/jstypes.nim @@ -0,0 +1,148 @@ +# +# +# The Nimrod Compiler +# (c) Copyright 2013 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Type info generation for the JS backend. + +proc genTypeInfo(p: PProc, typ: PType): PRope +proc genObjectFields(p: PProc, typ: PType, n: PNode): PRope = + var + s, u: PRope + length: int + field: PSym + b: PNode + result = nil + case n.kind + of nkRecList: + length = sonsLen(n) + if length == 1: + result = genObjectFields(p, typ, n.sons[0]) + else: + s = nil + for i in countup(0, length - 1): + if i > 0: app(s, ", " & tnl) + app(s, genObjectFields(p, typ, n.sons[i])) + result = ropef("{kind: 2, len: $1, offset: 0, " & + "typ: null, name: null, sons: [$2]}", [toRope(length), s]) + of nkSym: + field = n.sym + s = genTypeInfo(p, field.typ) + result = ropef("{kind: 1, offset: \"$1\", len: 0, " & + "typ: $2, name: $3, sons: null}", + [mangleName(field), s, makeJSString(field.name.s)]) + of nkRecCase: + length = sonsLen(n) + if (n.sons[0].kind != nkSym): InternalError(n.info, "genObjectFields") + field = n.sons[0].sym + s = genTypeInfo(p, field.typ) + for i in countup(1, length - 1): + b = n.sons[i] # branch + u = nil + case b.kind + of nkOfBranch: + if sonsLen(b) < 2: + internalError(b.info, "genObjectFields; nkOfBranch broken") + for j in countup(0, sonsLen(b) - 2): + if u != nil: app(u, ", ") + if b.sons[j].kind == nkRange: + appf(u, "[$1, $2]", [toRope(getOrdValue(b.sons[j].sons[0])), + toRope(getOrdValue(b.sons[j].sons[1]))]) + else: + app(u, toRope(getOrdValue(b.sons[j]))) + of nkElse: + u = toRope(lengthOrd(field.typ)) + else: internalError(n.info, "genObjectFields(nkRecCase)") + if result != nil: app(result, ", " & tnl) + appf(result, "[SetConstr($1), $2]", + [u, genObjectFields(p, typ, lastSon(b))]) + result = ropef("{kind: 3, offset: \"$1\", len: $3, " & + "typ: $2, name: $4, sons: [$5]}", [mangleName(field), s, + toRope(lengthOrd(field.typ)), makeJSString(field.name.s), result]) + else: internalError(n.info, "genObjectFields") + +proc genObjectInfo(p: PProc, typ: PType, name: PRope) = + var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & + "finalizer: null};$n", [name, toRope(ord(typ.kind))]) + prepend(p.g.typeInfo, s) + appf(p.g.typeInfo, "var NNI$1 = $2;$n", + [toRope(typ.id), genObjectFields(p, typ, typ.n)]) + appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) + if (typ.kind == tyObject) and (typ.sons[0] != nil): + appf(p.g.typeInfo, "$1.base = $2;$n", + [name, genTypeInfo(p, typ.sons[0])]) + +proc genTupleFields(p: PProc, typ: PType): PRope = + var s: PRope = nil + for i in 0 .. <typ.len: + if i > 0: app(s, ", " & tnl) + s.appf("{kind: 1, offset: \"Field$1\", len: 0, " & + "typ: $2, name: \"Field$1\", sons: null}", + [i.toRope, genTypeInfo(p, typ.sons[i])]) + result = ropef("{kind: 2, len: $1, offset: 0, " & + "typ: null, name: null, sons: [$2]}", [toRope(typ.len), s]) + +proc genTupleInfo(p: PProc, typ: PType, name: PRope) = + var s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & + "finalizer: null};$n", [name, toRope(ord(typ.kind))]) + prepend(p.g.typeInfo, s) + appf(p.g.typeInfo, "var NNI$1 = $2;$n", + [toRope(typ.id), genTupleFields(p, typ)]) + appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) + +proc genEnumInfo(p: PProc, typ: PType, name: PRope) = + let length = sonsLen(typ.n) + var s: PRope = nil + for i in countup(0, length - 1): + if (typ.n.sons[i].kind != nkSym): InternalError(typ.n.info, "genEnumInfo") + let field = typ.n.sons[i].sym + if i > 0: app(s, ", " & tnl) + let extName = if field.ast == nil: field.name.s else: field.ast.strVal + appf(s, "{kind: 1, offset: $1, typ: $2, name: $3, len: 0, sons: null}", + [toRope(field.position), name, makeJSString(extName)]) + var n = ropef("var NNI$1 = {kind: 2, offset: 0, typ: null, " & + "name: null, len: $2, sons: [$3]};$n", [toRope(typ.id), toRope(length), s]) + s = ropef("var $1 = {size: 0, kind: $2, base: null, node: null, " & + "finalizer: null};$n", [name, toRope(ord(typ.kind))]) + prepend(p.g.typeInfo, s) + app(p.g.typeInfo, n) + appf(p.g.typeInfo, "$1.node = NNI$2;$n", [name, toRope(typ.id)]) + if typ.sons[0] != nil: + appf(p.g.typeInfo, "$1.base = $2;$n", + [name, genTypeInfo(p, typ.sons[0])]) + +proc genTypeInfo(p: PProc, typ: PType): PRope = + var t = typ + if t.kind == tyGenericInst: t = lastSon(t) + result = ropef("NTI$1", [toRope(t.id)]) + if ContainsOrIncl(p.g.TypeInfoGenerated, t.id): return + case t.kind + of tyDistinct: + result = genTypeInfo(p, typ.sons[0]) + of tyPointer, tyProc, tyBool, tyChar, tyCString, tyString, tyInt..tyFloat128: + var s = ropef( + "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", + [result, toRope(ord(t.kind))]) + prepend(p.g.typeInfo, s) + of tyVar, tyRef, tyPtr, tySequence, tyRange, tySet: + var s = ropef( + "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", + [result, toRope(ord(t.kind))]) + prepend(p.g.typeInfo, s) + appf(p.g.typeInfo, "$1.base = $2;$n", + [result, genTypeInfo(p, typ.sons[0])]) + of tyArrayConstr, tyArray: + var s = ropef( + "var $1 = {size: 0,kind: $2,base: null,node: null,finalizer: null};$n", + [result, toRope(ord(t.kind))]) + prepend(p.g.typeInfo, s) + appf(p.g.typeInfo, "$1.base = $2;$n", + [result, genTypeInfo(p, typ.sons[1])]) + of tyEnum: genEnumInfo(p, t, result) + of tyObject: genObjectInfo(p, t, result) + of tyTuple: genTupleInfo(p, t, result) + else: InternalError("genTypeInfo(" & $t.kind & ')') |