PHP codegen can generate PHP classes
This commit is contained in:
parent
35567a1eb9
commit
9b44ca17c2
4 changed files with 275 additions and 60 deletions
|
|
@ -74,6 +74,7 @@ type
|
||||||
forwarded: seq[PSym]
|
forwarded: seq[PSym]
|
||||||
generatedSyms: IntSet
|
generatedSyms: IntSet
|
||||||
typeInfoGenerated: IntSet
|
typeInfoGenerated: IntSet
|
||||||
|
classes: seq[(PType, Rope)]
|
||||||
|
|
||||||
PGlobals = ref TGlobals
|
PGlobals = ref TGlobals
|
||||||
PProc = ref TProc
|
PProc = ref TProc
|
||||||
|
|
@ -99,6 +100,7 @@ proc newGlobals(): PGlobals =
|
||||||
result.forwarded = @[]
|
result.forwarded = @[]
|
||||||
result.generatedSyms = initIntSet()
|
result.generatedSyms = initIntSet()
|
||||||
result.typeInfoGenerated = initIntSet()
|
result.typeInfoGenerated = initIntSet()
|
||||||
|
result.classes = @[]
|
||||||
|
|
||||||
proc initCompRes(r: var TCompRes) =
|
proc initCompRes(r: var TCompRes) =
|
||||||
r.address = nil
|
r.address = nil
|
||||||
|
|
@ -127,6 +129,10 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||||
if result.target == targetPHP:
|
if result.target == targetPHP:
|
||||||
result.declaredGlobals = initIntSet()
|
result.declaredGlobals = initIntSet()
|
||||||
|
|
||||||
|
proc declareGlobal(p: PProc; id: int; r: Rope) =
|
||||||
|
if p.prc != nil and not p.declaredGlobals.containsOrIncl(id):
|
||||||
|
p.locals.addf("global $1;$n", [r])
|
||||||
|
|
||||||
const
|
const
|
||||||
MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
|
MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
|
||||||
tySet, tyBigNum, tyVarargs}
|
tySet, tyBigNum, tyVarargs}
|
||||||
|
|
@ -164,10 +170,24 @@ proc mapType(p: PProc; typ: PType): TJSTypeKind =
|
||||||
if p.target == targetPHP: result = etyObject
|
if p.target == targetPHP: result = etyObject
|
||||||
else: result = mapType(typ)
|
else: result = mapType(typ)
|
||||||
|
|
||||||
proc mangleName(s: PSym): Rope =
|
proc mangleName(s: PSym; target: TTarget): Rope =
|
||||||
result = s.loc.r
|
result = s.loc.r
|
||||||
if result == nil:
|
if result == nil:
|
||||||
|
if target == targetJS or s.kind == skTemp:
|
||||||
result = rope(mangle(s.name.s))
|
result = rope(mangle(s.name.s))
|
||||||
|
else:
|
||||||
|
var x = newStringOfCap(s.name.s.len)
|
||||||
|
var i = 0
|
||||||
|
while i < s.name.s.len:
|
||||||
|
let c = s.name.s[i]
|
||||||
|
if c in {'A'..'Z'}:
|
||||||
|
if i > 0 and s.name.s[i-1] in {'a'..'z'}:
|
||||||
|
x.add '_'
|
||||||
|
x.add(chr(c.ord - 'A'.ord + 'a'.ord))
|
||||||
|
else:
|
||||||
|
x.add c
|
||||||
|
inc i
|
||||||
|
result = rope(x)
|
||||||
add(result, "_")
|
add(result, "_")
|
||||||
add(result, rope(s.id))
|
add(result, rope(s.id))
|
||||||
s.loc.r = result
|
s.loc.r = result
|
||||||
|
|
@ -211,7 +231,8 @@ proc useMagic(p: PProc, name: string) =
|
||||||
if s != nil:
|
if s != nil:
|
||||||
internalAssert s.kind in {skProc, skMethod, skConverter}
|
internalAssert s.kind in {skProc, skMethod, skConverter}
|
||||||
if not p.g.generatedSyms.containsOrIncl(s.id):
|
if not p.g.generatedSyms.containsOrIncl(s.id):
|
||||||
add(p.g.code, genProc(p, s))
|
let code = genProc(p, s)
|
||||||
|
add(p.g.code, code)
|
||||||
else:
|
else:
|
||||||
# we used to exclude the system module from this check, but for DLL
|
# we used to exclude the system module from this check, but for DLL
|
||||||
# generation support this sloppyness leads to hard to detect bugs, so
|
# generation support this sloppyness leads to hard to detect bugs, so
|
||||||
|
|
@ -433,6 +454,17 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
|
||||||
gen(p, n.sons[2], y)
|
gen(p, n.sons[2], y)
|
||||||
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
|
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
|
||||||
r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
|
r.res = "(($1 $2) >>> $3)" % [x.rdLoc, trimmer, y.rdLoc]
|
||||||
|
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
|
||||||
|
mCStrToStr, mStrToStr, mEnumToStr:
|
||||||
|
if p.target == targetPHP:
|
||||||
|
if op == mEnumToStr:
|
||||||
|
var x: TCompRes
|
||||||
|
gen(p, n.sons[1], x)
|
||||||
|
r.res = "$#[$#]" % [genEnumInfoPHP(p, n.sons[1].typ), x.rdLoc]
|
||||||
|
else:
|
||||||
|
gen(p, n.sons[1], r)
|
||||||
|
else:
|
||||||
|
arithAux(p, n, r, op, jsOps)
|
||||||
else:
|
else:
|
||||||
arithAux(p, n, r, op, jsOps)
|
arithAux(p, n, r, op, jsOps)
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
@ -449,7 +481,7 @@ proc genLineDir(p: PProc, n: PNode) =
|
||||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||||
{optLineTrace, optStackTrace}) and
|
{optLineTrace, optStackTrace}) and
|
||||||
((p.prc == nil) or not (sfPure in p.prc.flags)):
|
((p.prc == nil) or not (sfPure in p.prc.flags)):
|
||||||
addf(p.body, "F.line = $1;$n", [rope(line)])
|
addf(p.body, "F.line = $1;$n" | "$$F['line'] = $1;$n", [rope(line)])
|
||||||
|
|
||||||
proc genWhileStmt(p: PProc, n: PNode) =
|
proc genWhileStmt(p: PProc, n: PNode) =
|
||||||
var
|
var
|
||||||
|
|
@ -666,7 +698,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||||
let v = n.sons[i].sym
|
let v = n.sons[i].sym
|
||||||
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||||
add(p.body, "$")
|
add(p.body, "$")
|
||||||
add(p.body, mangleName(v))
|
add(p.body, mangleName(v, p.target))
|
||||||
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
||||||
|
|
||||||
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
proc genIf(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
|
@ -699,14 +731,14 @@ proc generateHeader(p: PProc, typ: PType): Rope =
|
||||||
var param = typ.n.sons[i].sym
|
var param = typ.n.sons[i].sym
|
||||||
if isCompileTimeOnly(param.typ): continue
|
if isCompileTimeOnly(param.typ): continue
|
||||||
if result != nil: add(result, ", ")
|
if result != nil: add(result, ", ")
|
||||||
var name = mangleName(param)
|
var name = mangleName(param, p.target)
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
add(result, name)
|
add(result, name)
|
||||||
if mapType(param.typ) == etyBaseIndex:
|
if mapType(param.typ) == etyBaseIndex:
|
||||||
add(result, ", ")
|
add(result, ", ")
|
||||||
add(result, name)
|
add(result, name)
|
||||||
add(result, "_Idx")
|
add(result, "_Idx")
|
||||||
else:
|
elif not (i == 1 and param.name.s == "this"):
|
||||||
if param.typ.skipTypes({tyGenericInst}).kind == tyVar:
|
if param.typ.skipTypes({tyGenericInst}).kind == tyVar:
|
||||||
add(result, "&")
|
add(result, "&")
|
||||||
add(result, "$")
|
add(result, "$")
|
||||||
|
|
@ -807,7 +839,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
else:
|
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, p.target)
|
||||||
r.res = makeJSString($f.loc.r)
|
r.res = makeJSString($f.loc.r)
|
||||||
internalAssert a.typ != etyBaseIndex
|
internalAssert a.typ != etyBaseIndex
|
||||||
r.address = a.res
|
r.address = a.res
|
||||||
|
|
@ -816,13 +848,14 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
|
proc genFieldAccess(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.typ = etyNone
|
r.typ = etyNone
|
||||||
gen(p, n.sons[0], r)
|
gen(p, n.sons[0], r)
|
||||||
if skipTypes(n.sons[0].typ, abstractVarRange).kind == tyTuple:
|
let otyp = skipTypes(n.sons[0].typ, abstractVarRange)
|
||||||
|
if otyp.kind == tyTuple:
|
||||||
r.res = ("$1.Field$2" | "$1[$2]") %
|
r.res = ("$1.Field$2" | "$1[$2]") %
|
||||||
[r.res, getFieldPosition(n.sons[1]).rope]
|
[r.res, getFieldPosition(n.sons[1]).rope]
|
||||||
else:
|
else:
|
||||||
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
|
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
|
||||||
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, p.target)
|
||||||
r.res = ("$1.$2" | "$1['$2']") % [r.res, f.loc.r]
|
r.res = ("$1.$2" | "$1['$2']") % [r.res, f.loc.r]
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
|
|
@ -937,6 +970,32 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
gen(p, n.sons[0], r)
|
gen(p, n.sons[0], r)
|
||||||
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
|
else: internalError(n.sons[0].info, "genAddr: " & $n.sons[0].kind)
|
||||||
|
|
||||||
|
proc thisParam(p: PProc; typ: PType): PType =
|
||||||
|
if p.target == targetPHP:
|
||||||
|
# XXX Might be very useful for the JS backend too?
|
||||||
|
let typ = skipTypes(typ, abstractInst)
|
||||||
|
assert(typ.kind == tyProc)
|
||||||
|
if 1 < sonsLen(typ.n):
|
||||||
|
assert(typ.n.sons[1].kind == nkSym)
|
||||||
|
let param = typ.n.sons[1].sym
|
||||||
|
if param.name.s == "this":
|
||||||
|
result = param.typ.skipTypes(abstractVar)
|
||||||
|
|
||||||
|
proc attachProc(p: PProc; content: Rope; s: PSym) =
|
||||||
|
let otyp = thisParam(p, s.typ)
|
||||||
|
if otyp != nil:
|
||||||
|
for i, cls in p.g.classes:
|
||||||
|
if sameType(cls[0], otyp):
|
||||||
|
add(p.g.classes[i][1], content)
|
||||||
|
return
|
||||||
|
p.g.classes.add((otyp, content))
|
||||||
|
else:
|
||||||
|
add(p.g.code, content)
|
||||||
|
|
||||||
|
proc attachProc(p: PProc; s: PSym) =
|
||||||
|
let newp = genProc(p, s)
|
||||||
|
attachProc(p, newp, s)
|
||||||
|
|
||||||
proc genProcForSymIfNeeded(p: PProc, s: PSym) =
|
proc genProcForSymIfNeeded(p: PProc, s: PSym) =
|
||||||
if not p.g.generatedSyms.containsOrIncl(s.id):
|
if not p.g.generatedSyms.containsOrIncl(s.id):
|
||||||
let newp = genProc(p, s)
|
let newp = genProc(p, s)
|
||||||
|
|
@ -944,7 +1003,7 @@ proc genProcForSymIfNeeded(p: PProc, s: PSym) =
|
||||||
while owner != nil and owner.prc != s.owner:
|
while owner != nil and owner.prc != s.owner:
|
||||||
owner = owner.up
|
owner = owner.up
|
||||||
if owner != nil: add(owner.locals, newp)
|
if owner != nil: add(owner.locals, newp)
|
||||||
else: add(p.g.code, newp)
|
else: attachProc(p, newp, s)
|
||||||
|
|
||||||
proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var s = n.sym
|
var s = n.sym
|
||||||
|
|
@ -968,9 +1027,8 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
else:
|
else:
|
||||||
r.res = "$" & s.loc.r
|
r.res = "$" & s.loc.r
|
||||||
if sfGlobal in s.flags and p.prc != nil and
|
if sfGlobal in s.flags:
|
||||||
not p.declaredGlobals.containsOrIncl(s.id):
|
p.declareGlobal(s.id, r.res)
|
||||||
p.locals.addf("global $1;$n", [r.res])
|
|
||||||
of skConst:
|
of skConst:
|
||||||
genConstant(p, s)
|
genConstant(p, s)
|
||||||
if s.loc.r == nil:
|
if s.loc.r == nil:
|
||||||
|
|
@ -979,8 +1037,9 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
else:
|
else:
|
||||||
r.res = "$" & s.loc.r
|
r.res = "$" & s.loc.r
|
||||||
|
p.declareGlobal(s.id, r.res)
|
||||||
of skProc, skConverter, skMethod:
|
of skProc, skConverter, skMethod:
|
||||||
discard mangleName(s)
|
discard mangleName(s, p.target)
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
if lfNoDecl in s.loc.flags or s.magic != mNone or
|
if lfNoDecl in s.loc.flags or s.magic != mNone or
|
||||||
{sfImportc, sfInfixCall} * s.flags != {}:
|
{sfImportc, sfInfixCall} * s.flags != {}:
|
||||||
|
|
@ -1035,8 +1094,7 @@ proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes) =
|
||||||
else:
|
else:
|
||||||
add(r.res, a.res)
|
add(r.res, a.res)
|
||||||
|
|
||||||
|
proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
|
||||||
proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
|
|
||||||
add(r.res, "(")
|
add(r.res, "(")
|
||||||
var hasArgs = false
|
var hasArgs = false
|
||||||
|
|
||||||
|
|
@ -1044,7 +1102,7 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
assert(typ.kind == tyProc)
|
assert(typ.kind == tyProc)
|
||||||
assert(sonsLen(typ) == sonsLen(typ.n))
|
assert(sonsLen(typ) == sonsLen(typ.n))
|
||||||
|
|
||||||
for i in countup(1, sonsLen(n) - 1):
|
for i in countup(start, sonsLen(n) - 1):
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
var paramType: PNode = nil
|
var paramType: PNode = nil
|
||||||
if i < sonsLen(typ):
|
if i < sonsLen(typ):
|
||||||
|
|
@ -1061,11 +1119,53 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
add(r.res, ")")
|
add(r.res, ")")
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc genCall(p: PProc, n: PNode, r: var TCompRes) =
|
proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
|
||||||
gen(p, n.sons[0], r)
|
generated: var int; r: var TCompRes) =
|
||||||
genArgs(p, n, r)
|
let it = n[i]
|
||||||
|
var paramType: PNode = nil
|
||||||
|
if i < sonsLen(typ):
|
||||||
|
assert(typ.n.sons[i].kind == nkSym)
|
||||||
|
paramType = typ.n.sons[i]
|
||||||
|
if paramType.typ.isCompileTimeOnly: return
|
||||||
|
if paramType.isNil:
|
||||||
|
genArgNoParam(p, it, r)
|
||||||
|
else:
|
||||||
|
genArg(p, it, paramType.sym, r)
|
||||||
|
|
||||||
|
proc genPatternCall(p: PProc; n: PNode; pat: string; typ: PType;
|
||||||
|
r: var TCompRes) =
|
||||||
|
var i = 0
|
||||||
|
var j = 1
|
||||||
|
while i < pat.len:
|
||||||
|
case pat[i]
|
||||||
|
of '@':
|
||||||
|
var generated = 0
|
||||||
|
for k in j .. < n.len:
|
||||||
|
if generated > 0: add(r.res, ", ")
|
||||||
|
genOtherArg(p, n, k, typ, generated, r)
|
||||||
|
inc i
|
||||||
|
of '#':
|
||||||
|
var generated = 0
|
||||||
|
genOtherArg(p, n, j, typ, generated, r)
|
||||||
|
inc j
|
||||||
|
inc i
|
||||||
|
else:
|
||||||
|
let start = i
|
||||||
|
while i < pat.len:
|
||||||
|
if pat[i] notin {'@', '#'}: inc(i)
|
||||||
|
else: break
|
||||||
|
if i - 1 >= start:
|
||||||
|
add(r.res, substr(pat, start, i - 1))
|
||||||
|
|
||||||
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
# don't call '$' here for efficiency:
|
||||||
|
let pat = n.sons[0].sym.loc.r.data
|
||||||
|
internalAssert pat != nil
|
||||||
|
if pat.contains({'#', '(', '@'}):
|
||||||
|
var typ = skipTypes(n.sons[0].typ, abstractInst)
|
||||||
|
assert(typ.kind == tyProc)
|
||||||
|
genPatternCall(p, n, pat, typ, r)
|
||||||
|
return
|
||||||
gen(p, n.sons[1], r)
|
gen(p, n.sons[1], r)
|
||||||
if r.typ == etyBaseIndex:
|
if r.typ == etyBaseIndex:
|
||||||
if r.address == nil:
|
if r.address == nil:
|
||||||
|
|
@ -1077,13 +1177,14 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
var op: TCompRes
|
var op: TCompRes
|
||||||
gen(p, n.sons[0], op)
|
gen(p, n.sons[0], op)
|
||||||
add(r.res, op.res)
|
add(r.res, op.res)
|
||||||
|
genArgs(p, n, r, 2)
|
||||||
|
|
||||||
add(r.res, "(")
|
proc genCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
for i in countup(2, sonsLen(n) - 1):
|
if thisParam(p, n.sons[0].typ) != nil:
|
||||||
if i > 2: add(r.res, ", ")
|
genInfixCall(p, n, r)
|
||||||
genArgNoParam(p, n.sons[i], r)
|
return
|
||||||
add(r.res, ")")
|
gen(p, n.sons[0], r)
|
||||||
r.kind = resExpr
|
genArgs(p, n, r)
|
||||||
|
|
||||||
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
let n = n[1].skipConv
|
let n = n[1].skipConv
|
||||||
|
|
@ -1093,15 +1194,15 @@ proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
useMagic(p, "rawEcho")
|
useMagic(p, "rawEcho")
|
||||||
elif n.len == 0:
|
elif n.len == 0:
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
add(r.res, """echo "\n"""")
|
add(r.res, """print("\n")""")
|
||||||
return
|
return
|
||||||
add(r.res, "rawEcho(" | "echo ")
|
add(r.res, "rawEcho(" | "print(")
|
||||||
for i in countup(0, sonsLen(n) - 1):
|
for i in countup(0, sonsLen(n) - 1):
|
||||||
let it = n.sons[i]
|
let it = n.sons[i]
|
||||||
if it.typ.isCompileTimeOnly: continue
|
if it.typ.isCompileTimeOnly: continue
|
||||||
if i > 0: add(r.res, ", ")
|
if i > 0: add(r.res, ", " | ".")
|
||||||
genArgNoParam(p, it, r)
|
genArgNoParam(p, it, r)
|
||||||
add(r.res, ")" | ""","\n"""")
|
add(r.res, ")" | """."\n")""")
|
||||||
r.kind = resExpr
|
r.kind = resExpr
|
||||||
|
|
||||||
proc putToSeq(s: string, indirect: bool): Rope =
|
proc putToSeq(s: string, indirect: bool): Rope =
|
||||||
|
|
@ -1122,10 +1223,10 @@ proc createRecordVarAux(p: PProc, rec: PNode, excludedFieldIDs: IntSet, output:
|
||||||
if rec.sym.id notin excludedFieldIDs:
|
if rec.sym.id notin excludedFieldIDs:
|
||||||
if output.len > 0: output.add(", ")
|
if output.len > 0: output.add(", ")
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
output.add(mangleName(rec.sym))
|
output.add(mangleName(rec.sym, p.target))
|
||||||
output.add(": ")
|
output.add(": ")
|
||||||
else:
|
else:
|
||||||
output.addf("'$#' => ", [mangleName(rec.sym)])
|
output.addf("'$#' => ", [mangleName(rec.sym, p.target)])
|
||||||
output.add(createVar(p, rec.sym.typ, false))
|
output.add(createVar(p, rec.sym.typ, false))
|
||||||
else: internalError(rec.info, "createRecordVarAux")
|
else: internalError(rec.info, "createRecordVarAux")
|
||||||
|
|
||||||
|
|
@ -1221,9 +1322,9 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||||
s: Rope
|
s: Rope
|
||||||
if n.kind == nkEmpty:
|
if n.kind == nkEmpty:
|
||||||
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
addf(p.body, "var $1 = $2;$n" | "$$$1 = $2;$n",
|
||||||
[mangleName(v), createVar(p, v.typ, isIndirect(v))])
|
[mangleName(v, p.target), createVar(p, v.typ, isIndirect(v))])
|
||||||
else:
|
else:
|
||||||
discard mangleName(v)
|
discard mangleName(v, p.target)
|
||||||
gen(p, n, a)
|
gen(p, n, a)
|
||||||
case mapType(p, v.typ)
|
case mapType(p, v.typ)
|
||||||
of etyObject:
|
of etyObject:
|
||||||
|
|
@ -1336,9 +1437,29 @@ proc genConStrStrPHP(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
|
|
||||||
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
|
if n.sons[0].sym.name.s == "repr":
|
||||||
localError(n.info, "'repr' not available for PHP backend")
|
localError(n.info, "'repr' not available for PHP backend")
|
||||||
|
else:
|
||||||
|
# we map mRepr to PHP's array constructor, a mild hack:
|
||||||
|
var a, b: TCompRes
|
||||||
|
r.kind = resExpr
|
||||||
|
r.res = rope("array(")
|
||||||
|
let x = skipConv(n[1])
|
||||||
|
if x.kind == nkBracket:
|
||||||
|
for i in countup(0, x.len - 1):
|
||||||
|
let it = x[i]
|
||||||
|
if it.kind == nkPar and it.len == 2:
|
||||||
|
if i > 0: r.res.add(", ")
|
||||||
|
gen(p, it[0], a)
|
||||||
|
gen(p, it[1], b)
|
||||||
|
r.res.add("$# => $#" % [a.rdLoc, b.rdLoc])
|
||||||
|
else:
|
||||||
|
localError(it.info, "'toArray' needs tuple constructors")
|
||||||
|
else:
|
||||||
|
localError(x.info, "'toArray' needs an array literal")
|
||||||
|
r.res.add(")")
|
||||||
return
|
return
|
||||||
var t = skipTypes(n.sons[1].typ, abstractVarRange)
|
let t = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||||
case t.kind
|
case t.kind
|
||||||
of tyInt..tyUInt64:
|
of tyInt..tyUInt64:
|
||||||
unaryExpr(p, n, r, "", "(\"\"+ ($1))")
|
unaryExpr(p, n, r, "", "(\"\"+ ($1))")
|
||||||
|
|
@ -1390,7 +1511,7 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
"if ($1 != null) { addChar($1, $2); } else { $1 = [$2, 0]; }")
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "",
|
||||||
"if ($1 != null) { $1 .= chr($2); } else { $1 = chr($2); }")
|
"$1 .= chr($2)")
|
||||||
of mAppendStrStr:
|
of mAppendStrStr:
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:
|
||||||
|
|
@ -1401,14 +1522,14 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
# XXX: make a copy of $2, because of Javascript's sucking semantics
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "",
|
||||||
"if ($1 != null) { $1 .= $2; } else { $1 = $2; }")
|
"$1 .= $2;")
|
||||||
of mAppendSeqElem:
|
of mAppendSeqElem:
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "",
|
||||||
"if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
|
"if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
|
||||||
else:
|
else:
|
||||||
binaryExpr(p, n, r, "",
|
binaryExpr(p, n, r, "",
|
||||||
"if ($1 != null) { $1[] = $2; } else { $1 = array($2); }")
|
"$1[] = $2")
|
||||||
of mConStrStr:
|
of mConStrStr:
|
||||||
if p.target == targetJS:
|
if p.target == targetJS:
|
||||||
genConStrStr(p, n, r)
|
genConStrStr(p, n, r)
|
||||||
|
|
@ -1555,7 +1676,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
internalAssert it.kind == nkExprColonExpr
|
internalAssert it.kind == nkExprColonExpr
|
||||||
gen(p, it.sons[1], a)
|
gen(p, it.sons[1], a)
|
||||||
var f = it.sons[0].sym
|
var f = it.sons[0].sym
|
||||||
if f.loc.r == nil: f.loc.r = mangleName(f)
|
if f.loc.r == nil: f.loc.r = mangleName(f, p.target)
|
||||||
fieldIDs.incl(f.id)
|
fieldIDs.incl(f.id)
|
||||||
addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res])
|
addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res])
|
||||||
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
let t = skipTypes(n.typ, abstractInst + skipPtrs)
|
||||||
|
|
@ -1655,20 +1776,19 @@ proc genProcBody(p: PProc, prc: PSym): Rope =
|
||||||
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||||
var
|
var
|
||||||
resultSym: PSym
|
resultSym: PSym
|
||||||
name, returnStmt, resultAsgn, header: Rope
|
|
||||||
a: TCompRes
|
a: TCompRes
|
||||||
#if gVerbosity >= 3:
|
#if gVerbosity >= 3:
|
||||||
# echo "BEGIN generating code for: " & prc.name.s
|
# echo "BEGIN generating code for: " & prc.name.s
|
||||||
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
|
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
|
||||||
p.up = oldProc
|
p.up = oldProc
|
||||||
returnStmt = nil
|
var returnStmt: Rope = nil
|
||||||
resultAsgn = nil
|
var resultAsgn: Rope = nil
|
||||||
name = mangleName(prc)
|
let name = mangleName(prc, p.target)
|
||||||
header = generateHeader(p, prc.typ)
|
let header = generateHeader(p, prc.typ)
|
||||||
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
||||||
resultSym = prc.ast.sons[resultPos].sym
|
resultSym = prc.ast.sons[resultPos].sym
|
||||||
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
||||||
mangleName(resultSym),
|
mangleName(resultSym, p.target),
|
||||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
||||||
gen(p, prc.ast.sons[resultPos], a)
|
gen(p, prc.ast.sons[resultPos], a)
|
||||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||||
|
|
@ -1799,7 +1919,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||||
of nkEmpty: discard
|
of nkEmpty: discard
|
||||||
of nkLambdaKinds:
|
of nkLambdaKinds:
|
||||||
let s = n.sons[namePos].sym
|
let s = n.sons[namePos].sym
|
||||||
discard mangleName(s)
|
discard mangleName(s, p.target)
|
||||||
r.res = s.loc.r
|
r.res = s.loc.r
|
||||||
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
|
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
|
||||||
elif not p.g.generatedSyms.containsOrIncl(s.id):
|
elif not p.g.generatedSyms.containsOrIncl(s.id):
|
||||||
|
|
@ -1854,7 +1974,8 @@ var globals: PGlobals
|
||||||
proc newModule(module: PSym): BModule =
|
proc newModule(module: PSym): BModule =
|
||||||
new(result)
|
new(result)
|
||||||
result.module = module
|
result.module = module
|
||||||
if globals == nil: globals = newGlobals()
|
if globals == nil:
|
||||||
|
globals = newGlobals()
|
||||||
|
|
||||||
proc genHeader(target: TTarget): Rope =
|
proc genHeader(target: TTarget): Rope =
|
||||||
if target == targetJS:
|
if target == targetJS:
|
||||||
|
|
@ -1905,31 +2026,56 @@ proc wholeCode*(m: BModule): Rope =
|
||||||
for prc in globals.forwarded:
|
for prc in globals.forwarded:
|
||||||
if not globals.generatedSyms.containsOrIncl(prc.id):
|
if not globals.generatedSyms.containsOrIncl(prc.id):
|
||||||
var p = newProc(globals, m, nil, m.module.options)
|
var p = newProc(globals, m, nil, m.module.options)
|
||||||
add(p.g.code, genProc(p, prc))
|
attachProc(p, prc)
|
||||||
|
|
||||||
var disp = generateMethodDispatchers()
|
var disp = generateMethodDispatchers()
|
||||||
for i in 0..sonsLen(disp)-1:
|
for i in 0..sonsLen(disp)-1:
|
||||||
let prc = disp.sons[i].sym
|
let prc = disp.sons[i].sym
|
||||||
if not globals.generatedSyms.containsOrIncl(prc.id):
|
if not globals.generatedSyms.containsOrIncl(prc.id):
|
||||||
var p = newProc(globals, m, nil, m.module.options)
|
var p = newProc(globals, m, nil, m.module.options)
|
||||||
add(p.g.code, genProc(p, prc))
|
attachProc(p, prc)
|
||||||
|
|
||||||
result = globals.typeInfo & globals.code
|
result = globals.typeInfo & globals.code
|
||||||
|
|
||||||
|
proc getClassName(t: PType): Rope =
|
||||||
|
var s = t.sym
|
||||||
|
if s.isNil or sfAnon in s.flags:
|
||||||
|
s = skipTypes(t, abstractPtrs).sym
|
||||||
|
if s.isNil or sfAnon in s.flags:
|
||||||
|
internalError("cannot retrieve class name")
|
||||||
|
result = mangleName(s, targetPHP)
|
||||||
|
|
||||||
|
proc genClass(obj: PType; content: Rope; ext: string) =
|
||||||
|
let cls = getClassName(obj)
|
||||||
|
let t = skipTypes(obj, abstractPtrs)
|
||||||
|
let extends = if t.kind == tyObject and t.sons[0] != nil:
|
||||||
|
" extends " & getClassName(t.sons[0])
|
||||||
|
else: nil
|
||||||
|
let result = ("<?php$n" &
|
||||||
|
"/* Generated by the Nim Compiler v$# */$n" &
|
||||||
|
"/* (c) 2016 Andreas Rumpf */$n$n" &
|
||||||
|
"class $#$# {$n$#$n}$n") %
|
||||||
|
[rope(VersionAsString), cls, extends, content]
|
||||||
|
|
||||||
|
let outfile = changeFileExt(completeCFilePath($cls), ext)
|
||||||
|
discard writeRopeIfNotEqual(result, outfile)
|
||||||
|
|
||||||
proc myClose(b: PPassContext, n: PNode): PNode =
|
proc myClose(b: PPassContext, n: PNode): PNode =
|
||||||
if passes.skipCodegen(n): return n
|
if passes.skipCodegen(n): return n
|
||||||
result = myProcess(b, n)
|
result = myProcess(b, n)
|
||||||
var m = BModule(b)
|
var m = BModule(b)
|
||||||
if sfMainModule in m.module.flags:
|
if sfMainModule in m.module.flags:
|
||||||
|
let ext = if m.target == targetJS: "js" else: "php"
|
||||||
let code = wholeCode(m)
|
let code = wholeCode(m)
|
||||||
let outfile =
|
let outfile =
|
||||||
if options.outFile.len > 0:
|
if options.outFile.len > 0:
|
||||||
if options.outFile.isAbsolute: options.outFile
|
if options.outFile.isAbsolute: options.outFile
|
||||||
else: getCurrentDir() / options.outFile
|
else: getCurrentDir() / options.outFile
|
||||||
else:
|
else:
|
||||||
changeFileExt(completeCFilePath(m.module.filename),
|
changeFileExt(completeCFilePath(m.module.filename), ext)
|
||||||
if m.target == targetJS: "js" else: "php")
|
|
||||||
discard writeRopeIfNotEqual(genHeader(m.target) & code, outfile)
|
discard writeRopeIfNotEqual(genHeader(m.target) & code, outfile)
|
||||||
|
for obj, content in items(globals.classes):
|
||||||
|
genClass(obj, content, ext)
|
||||||
|
|
||||||
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
|
proc myOpenCached(s: PSym, rd: PRodReader): PPassContext =
|
||||||
internalError("symbol files are not possible with the JS code generator")
|
internalError("symbol files are not possible with the JS code generator")
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,8 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||||
s = genTypeInfo(p, field.typ)
|
s = genTypeInfo(p, field.typ)
|
||||||
result = ("{kind: 1, offset: \"$1\", len: 0, " &
|
result = ("{kind: 1, offset: \"$1\", len: 0, " &
|
||||||
"typ: $2, name: $3, sons: null}") %
|
"typ: $2, name: $3, sons: null}") %
|
||||||
[mangleName(field), s, makeJSString(field.name.s)]
|
[mangleName(field, p.target), s,
|
||||||
|
makeJSString(field.name.s)]
|
||||||
of nkRecCase:
|
of nkRecCase:
|
||||||
length = sonsLen(n)
|
length = sonsLen(n)
|
||||||
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
|
if (n.sons[0].kind != nkSym): internalError(n.info, "genObjectFields")
|
||||||
|
|
@ -61,7 +62,8 @@ proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
|
||||||
addf(result, "[SetConstr($1), $2]",
|
addf(result, "[SetConstr($1), $2]",
|
||||||
[u, genObjectFields(p, typ, lastSon(b))])
|
[u, genObjectFields(p, typ, lastSon(b))])
|
||||||
result = ("{kind: 3, offset: \"$1\", len: $3, " &
|
result = ("{kind: 3, offset: \"$1\", len: $3, " &
|
||||||
"typ: $2, name: $4, sons: [$5]}") % [mangleName(field), s,
|
"typ: $2, name: $4, sons: [$5]}") % [
|
||||||
|
mangleName(field, p.target), s,
|
||||||
rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
|
rope(lengthOrd(field.typ)), makeJSString(field.name.s), result]
|
||||||
else: internalError(n.info, "genObjectFields")
|
else: internalError(n.info, "genObjectFields")
|
||||||
|
|
||||||
|
|
@ -115,6 +117,23 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
|
||||||
addf(p.g.typeInfo, "$1.base = $2;$n",
|
addf(p.g.typeInfo, "$1.base = $2;$n",
|
||||||
[name, genTypeInfo(p, typ.sons[0])])
|
[name, genTypeInfo(p, typ.sons[0])])
|
||||||
|
|
||||||
|
proc genEnumInfoPHP(p: PProc; t: PType): Rope =
|
||||||
|
let t = t.skipTypes({tyGenericInst, tyDistinct})
|
||||||
|
result = "$$NTI$1" % [rope(t.id)]
|
||||||
|
p.declareGlobal(t.id, result)
|
||||||
|
if containsOrIncl(p.g.typeInfoGenerated, t.id): return
|
||||||
|
|
||||||
|
let length = sonsLen(t.n)
|
||||||
|
var s: Rope = nil
|
||||||
|
for i in countup(0, length - 1):
|
||||||
|
if (t.n.sons[i].kind != nkSym): internalError(t.n.info, "genEnumInfo")
|
||||||
|
let field = t.n.sons[i].sym
|
||||||
|
if i > 0: add(s, ", " & tnl)
|
||||||
|
let extName = if field.ast == nil: field.name.s else: field.ast.strVal
|
||||||
|
addf(s, "$# => $#$n",
|
||||||
|
[rope(field.position), makeJSString(extName)])
|
||||||
|
prepend(p.g.typeInfo, "$$$# = $#;$n" % [result, s])
|
||||||
|
|
||||||
proc genTypeInfo(p: PProc, typ: PType): Rope =
|
proc genTypeInfo(p: PProc, typ: PType): Rope =
|
||||||
if p.target == targetPHP:
|
if p.target == targetPHP:
|
||||||
return makeJSString(typeToString(typ, preferModuleInfo))
|
return makeJSString(typeToString(typ, preferModuleInfo))
|
||||||
|
|
|
||||||
50
lib/phpcl.nim
Normal file
50
lib/phpcl.nim
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nim's Runtime Library
|
||||||
|
# (c) Copyright 2015 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## PHP compatibility layer.
|
||||||
|
|
||||||
|
type
|
||||||
|
PhpArray*[Key, Val] = ref object
|
||||||
|
|
||||||
|
PhpObj* = ref object ## can be a string, an int etc.
|
||||||
|
|
||||||
|
proc explode*(sep, x: string): seq[string] {.importc: "explode".}
|
||||||
|
template split*(x, sep: string): seq[string] = explode(sep, x)
|
||||||
|
|
||||||
|
proc `$`*(x: PhpObj): string {.importcpp: "(#)".}
|
||||||
|
proc `++`*(x: PhpObj) {.importcpp: "++(#)".}
|
||||||
|
|
||||||
|
proc `==`*(x, y: PhpObj): string {.importcpp: "((#) == (#))".}
|
||||||
|
proc `<=`*(x, y: PhpObj): string {.importcpp: "((#) <= (#))".}
|
||||||
|
proc `<`*(x, y: PhpObj): string {.importcpp: "((#) < (#))".}
|
||||||
|
|
||||||
|
proc toUpper*(x: string): string {.importc: "strtoupper".}
|
||||||
|
proc toLower*(x: string): string {.importc: "strtolower".}
|
||||||
|
|
||||||
|
proc strtr*(s: string, replacePairs: PhpArray[string, string]): string {.importc.}
|
||||||
|
proc strtr*(s, fromm, to: string): string {.importc.}
|
||||||
|
|
||||||
|
proc toArray*[K,V](pairs: openarray[(K,V)]): PhpArray[K,V] {.magic:
|
||||||
|
"Repr".}
|
||||||
|
template strtr*(s: string, replacePairs: openarray[(string, string)]): string =
|
||||||
|
strtr(toArray(replacePairs))
|
||||||
|
|
||||||
|
iterator pairs*[K,V](d: PhpArray[K,V]): (K,V) =
|
||||||
|
var k: K
|
||||||
|
var v: V
|
||||||
|
{.emit: "foreach (`d` as `k`=>`v`) {".}
|
||||||
|
yield (k, v)
|
||||||
|
{.emit: "}".}
|
||||||
|
|
||||||
|
proc `[]`*[K,V](d: PhpArray[K,V]; k: K): V {.importcpp: "#[#]".}
|
||||||
|
proc `[]=`*[K,V](d: PhpArray[K,V]; k: K; v: V) {.importcpp: "#[#] = #".}
|
||||||
|
|
||||||
|
proc ksort*[K,V](d: PhpArray[K,V]) {.importc.}
|
||||||
|
proc krsort*[K,V](d: PhpArray[K,V]) {.importc.}
|
||||||
|
proc keys*[K,V](d: PhpArray[K,V]): seq[K] {.importc.}
|
||||||
|
|
@ -156,16 +156,16 @@ proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} =
|
||||||
asm """
|
asm """
|
||||||
$args = func_get_args();
|
$args = func_get_args();
|
||||||
$result = array();
|
$result = array();
|
||||||
foreach ($args as $key=>$x) {
|
foreach ($args as $x) {
|
||||||
if (is_array(($val)) {
|
if (is_array($x)) {
|
||||||
for ($j = $x[0]; $j <= $x[1]; $j++) {
|
for ($j = $x[0]; $j <= $x[1]; $j++) {
|
||||||
result[$j] = true;
|
$result[$j] = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result[$x] = true;
|
$result[$x] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return $result;
|
||||||
"""
|
"""
|
||||||
else:
|
else:
|
||||||
asm """
|
asm """
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue