mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
PHP codegen can generate PHP classes
This commit is contained in:
@@ -74,6 +74,7 @@ type
|
||||
forwarded: seq[PSym]
|
||||
generatedSyms: IntSet
|
||||
typeInfoGenerated: IntSet
|
||||
classes: seq[(PType, Rope)]
|
||||
|
||||
PGlobals = ref TGlobals
|
||||
PProc = ref TProc
|
||||
@@ -99,6 +100,7 @@ proc newGlobals(): PGlobals =
|
||||
result.forwarded = @[]
|
||||
result.generatedSyms = initIntSet()
|
||||
result.typeInfoGenerated = initIntSet()
|
||||
result.classes = @[]
|
||||
|
||||
proc initCompRes(r: var TCompRes) =
|
||||
r.address = nil
|
||||
@@ -127,6 +129,10 @@ proc newProc(globals: PGlobals, module: BModule, procDef: PNode,
|
||||
if result.target == targetPHP:
|
||||
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
|
||||
MappedToObject = {tyObject, tyArray, tyArrayConstr, tyTuple, tyOpenArray,
|
||||
tySet, tyBigNum, tyVarargs}
|
||||
@@ -164,10 +170,24 @@ proc mapType(p: PProc; typ: PType): TJSTypeKind =
|
||||
if p.target == targetPHP: result = etyObject
|
||||
else: result = mapType(typ)
|
||||
|
||||
proc mangleName(s: PSym): Rope =
|
||||
proc mangleName(s: PSym; target: TTarget): Rope =
|
||||
result = s.loc.r
|
||||
if result == nil:
|
||||
result = rope(mangle(s.name.s))
|
||||
if target == targetJS or s.kind == skTemp:
|
||||
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, rope(s.id))
|
||||
s.loc.r = result
|
||||
@@ -211,7 +231,8 @@ proc useMagic(p: PProc, name: string) =
|
||||
if s != nil:
|
||||
internalAssert s.kind in {skProc, skMethod, skConverter}
|
||||
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:
|
||||
# we used to exclude the system module from this check, but for DLL
|
||||
# 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)
|
||||
let trimmer = unsignedTrimmer(n[1].typ.skipTypes(abstractRange).size)
|
||||
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:
|
||||
arithAux(p, n, r, op, jsOps)
|
||||
r.kind = resExpr
|
||||
@@ -449,7 +481,7 @@ proc genLineDir(p: PProc, n: PNode) =
|
||||
elif ({optLineTrace, optStackTrace} * p.options ==
|
||||
{optLineTrace, optStackTrace}) and
|
||||
((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) =
|
||||
var
|
||||
@@ -666,7 +698,7 @@ proc genAsmOrEmitStmt(p: PProc, n: PNode) =
|
||||
let v = n.sons[i].sym
|
||||
if p.target == targetPHP and v.kind in {skVar, skLet, skTemp, skConst, skResult, skParam, skForVar}:
|
||||
add(p.body, "$")
|
||||
add(p.body, mangleName(v))
|
||||
add(p.body, mangleName(v, p.target))
|
||||
else: internalError(n.sons[i].info, "jsgen: genAsmOrEmitStmt()")
|
||||
|
||||
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
|
||||
if isCompileTimeOnly(param.typ): continue
|
||||
if result != nil: add(result, ", ")
|
||||
var name = mangleName(param)
|
||||
var name = mangleName(param, p.target)
|
||||
if p.target == targetJS:
|
||||
add(result, name)
|
||||
if mapType(param.typ) == etyBaseIndex:
|
||||
add(result, ", ")
|
||||
add(result, name)
|
||||
add(result, "_Idx")
|
||||
else:
|
||||
elif not (i == 1 and param.name.s == "this"):
|
||||
if param.typ.skipTypes({tyGenericInst}).kind == tyVar:
|
||||
add(result, "&")
|
||||
add(result, "$")
|
||||
@@ -807,7 +839,7 @@ proc genFieldAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
else:
|
||||
if b.sons[1].kind != nkSym: internalError(b.sons[1].info, "genFieldAddr")
|
||||
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)
|
||||
internalAssert a.typ != etyBaseIndex
|
||||
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) =
|
||||
r.typ = etyNone
|
||||
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, getFieldPosition(n.sons[1]).rope]
|
||||
else:
|
||||
if n.sons[1].kind != nkSym: internalError(n.sons[1].info, "genFieldAccess")
|
||||
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.kind = resExpr
|
||||
|
||||
@@ -937,6 +970,32 @@ proc genAddr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n.sons[0], r)
|
||||
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) =
|
||||
if not p.g.generatedSyms.containsOrIncl(s.id):
|
||||
let newp = genProc(p, s)
|
||||
@@ -944,7 +1003,7 @@ proc genProcForSymIfNeeded(p: PProc, s: PSym) =
|
||||
while owner != nil and owner.prc != s.owner:
|
||||
owner = owner.up
|
||||
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) =
|
||||
var s = n.sym
|
||||
@@ -968,9 +1027,8 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = s.loc.r
|
||||
else:
|
||||
r.res = "$" & s.loc.r
|
||||
if sfGlobal in s.flags and p.prc != nil and
|
||||
not p.declaredGlobals.containsOrIncl(s.id):
|
||||
p.locals.addf("global $1;$n", [r.res])
|
||||
if sfGlobal in s.flags:
|
||||
p.declareGlobal(s.id, r.res)
|
||||
of skConst:
|
||||
genConstant(p, s)
|
||||
if s.loc.r == nil:
|
||||
@@ -979,8 +1037,9 @@ proc genSym(p: PProc, n: PNode, r: var TCompRes) =
|
||||
r.res = s.loc.r
|
||||
else:
|
||||
r.res = "$" & s.loc.r
|
||||
p.declareGlobal(s.id, r.res)
|
||||
of skProc, skConverter, skMethod:
|
||||
discard mangleName(s)
|
||||
discard mangleName(s, p.target)
|
||||
r.res = s.loc.r
|
||||
if lfNoDecl in s.loc.flags or s.magic != mNone or
|
||||
{sfImportc, sfInfixCall} * s.flags != {}:
|
||||
@@ -1035,8 +1094,7 @@ proc genArg(p: PProc, n: PNode, param: PSym, r: var TCompRes) =
|
||||
else:
|
||||
add(r.res, a.res)
|
||||
|
||||
|
||||
proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
|
||||
proc genArgs(p: PProc, n: PNode, r: var TCompRes; start=1) =
|
||||
add(r.res, "(")
|
||||
var hasArgs = false
|
||||
|
||||
@@ -1044,7 +1102,7 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
|
||||
assert(typ.kind == tyProc)
|
||||
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]
|
||||
var paramType: PNode = nil
|
||||
if i < sonsLen(typ):
|
||||
@@ -1061,11 +1119,53 @@ proc genArgs(p: PProc, n: PNode, r: var TCompRes) =
|
||||
add(r.res, ")")
|
||||
r.kind = resExpr
|
||||
|
||||
proc genCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
gen(p, n.sons[0], r)
|
||||
genArgs(p, n, r)
|
||||
proc genOtherArg(p: PProc; n: PNode; i: int; typ: PType;
|
||||
generated: var int; r: var TCompRes) =
|
||||
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) =
|
||||
# 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)
|
||||
if r.typ == etyBaseIndex:
|
||||
if r.address == nil:
|
||||
@@ -1077,13 +1177,14 @@ proc genInfixCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
var op: TCompRes
|
||||
gen(p, n.sons[0], op)
|
||||
add(r.res, op.res)
|
||||
genArgs(p, n, r, 2)
|
||||
|
||||
add(r.res, "(")
|
||||
for i in countup(2, sonsLen(n) - 1):
|
||||
if i > 2: add(r.res, ", ")
|
||||
genArgNoParam(p, n.sons[i], r)
|
||||
add(r.res, ")")
|
||||
r.kind = resExpr
|
||||
proc genCall(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if thisParam(p, n.sons[0].typ) != nil:
|
||||
genInfixCall(p, n, r)
|
||||
return
|
||||
gen(p, n.sons[0], r)
|
||||
genArgs(p, n, r)
|
||||
|
||||
proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||
let n = n[1].skipConv
|
||||
@@ -1093,15 +1194,15 @@ proc genEcho(p: PProc, n: PNode, r: var TCompRes) =
|
||||
useMagic(p, "rawEcho")
|
||||
elif n.len == 0:
|
||||
r.kind = resExpr
|
||||
add(r.res, """echo "\n"""")
|
||||
add(r.res, """print("\n")""")
|
||||
return
|
||||
add(r.res, "rawEcho(" | "echo ")
|
||||
add(r.res, "rawEcho(" | "print(")
|
||||
for i in countup(0, sonsLen(n) - 1):
|
||||
let it = n.sons[i]
|
||||
if it.typ.isCompileTimeOnly: continue
|
||||
if i > 0: add(r.res, ", ")
|
||||
if i > 0: add(r.res, ", " | ".")
|
||||
genArgNoParam(p, it, r)
|
||||
add(r.res, ")" | ""","\n"""")
|
||||
add(r.res, ")" | """."\n")""")
|
||||
r.kind = resExpr
|
||||
|
||||
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 output.len > 0: output.add(", ")
|
||||
if p.target == targetJS:
|
||||
output.add(mangleName(rec.sym))
|
||||
output.add(mangleName(rec.sym, p.target))
|
||||
output.add(": ")
|
||||
else:
|
||||
output.addf("'$#' => ", [mangleName(rec.sym)])
|
||||
output.addf("'$#' => ", [mangleName(rec.sym, p.target)])
|
||||
output.add(createVar(p, rec.sym.typ, false))
|
||||
else: internalError(rec.info, "createRecordVarAux")
|
||||
|
||||
@@ -1221,9 +1322,9 @@ proc genVarInit(p: PProc, v: PSym, n: PNode) =
|
||||
s: Rope
|
||||
if n.kind == nkEmpty:
|
||||
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:
|
||||
discard mangleName(v)
|
||||
discard mangleName(v, p.target)
|
||||
gen(p, n, a)
|
||||
case mapType(p, v.typ)
|
||||
of etyObject:
|
||||
@@ -1336,9 +1437,29 @@ proc genConStrStrPHP(p: PProc, n: PNode, r: var TCompRes) =
|
||||
|
||||
proc genRepr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
if p.target == targetPHP:
|
||||
localError(n.info, "'repr' not available for PHP backend")
|
||||
if n.sons[0].sym.name.s == "repr":
|
||||
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
|
||||
var t = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
let t = skipTypes(n.sons[1].typ, abstractVarRange)
|
||||
case t.kind
|
||||
of tyInt..tyUInt64:
|
||||
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]; }")
|
||||
else:
|
||||
binaryExpr(p, n, r, "",
|
||||
"if ($1 != null) { $1 .= chr($2); } else { $1 = chr($2); }")
|
||||
"$1 .= chr($2)")
|
||||
of mAppendStrStr:
|
||||
if p.target == targetJS:
|
||||
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
|
||||
else:
|
||||
binaryExpr(p, n, r, "",
|
||||
"if ($1 != null) { $1 .= $2; } else { $1 = $2; }")
|
||||
"$1 .= $2;")
|
||||
of mAppendSeqElem:
|
||||
if p.target == targetJS:
|
||||
binaryExpr(p, n, r, "",
|
||||
"if ($1 != null) { $1.push($2); } else { $1 = [$2]; }")
|
||||
else:
|
||||
binaryExpr(p, n, r, "",
|
||||
"if ($1 != null) { $1[] = $2; } else { $1 = array($2); }")
|
||||
"$1[] = $2")
|
||||
of mConStrStr:
|
||||
if p.target == targetJS:
|
||||
genConStrStr(p, n, r)
|
||||
@@ -1555,7 +1676,7 @@ proc genObjConstr(p: PProc, n: PNode, r: var TCompRes) =
|
||||
internalAssert it.kind == nkExprColonExpr
|
||||
gen(p, it.sons[1], a)
|
||||
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)
|
||||
addf(initList, "$#: $#" | "'$#' => $#" , [f.loc.r, a.res])
|
||||
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 =
|
||||
var
|
||||
resultSym: PSym
|
||||
name, returnStmt, resultAsgn, header: Rope
|
||||
a: TCompRes
|
||||
#if gVerbosity >= 3:
|
||||
# echo "BEGIN generating code for: " & prc.name.s
|
||||
var p = newProc(oldProc.g, oldProc.module, prc.ast, prc.options)
|
||||
p.up = oldProc
|
||||
returnStmt = nil
|
||||
resultAsgn = nil
|
||||
name = mangleName(prc)
|
||||
header = generateHeader(p, prc.typ)
|
||||
var returnStmt: Rope = nil
|
||||
var resultAsgn: Rope = nil
|
||||
let name = mangleName(prc, p.target)
|
||||
let header = generateHeader(p, prc.typ)
|
||||
if prc.typ.sons[0] != nil and sfPure notin prc.flags:
|
||||
resultSym = prc.ast.sons[resultPos].sym
|
||||
resultAsgn = ("var $# = $#;$n" | "$$$# = $#;$n") % [
|
||||
mangleName(resultSym),
|
||||
mangleName(resultSym, p.target),
|
||||
createVar(p, resultSym.typ, isIndirect(resultSym))]
|
||||
gen(p, prc.ast.sons[resultPos], a)
|
||||
if mapType(p, resultSym.typ) == etyBaseIndex:
|
||||
@@ -1799,7 +1919,7 @@ proc gen(p: PProc, n: PNode, r: var TCompRes) =
|
||||
of nkEmpty: discard
|
||||
of nkLambdaKinds:
|
||||
let s = n.sons[namePos].sym
|
||||
discard mangleName(s)
|
||||
discard mangleName(s, p.target)
|
||||
r.res = s.loc.r
|
||||
if lfNoDecl in s.loc.flags or s.magic != mNone: discard
|
||||
elif not p.g.generatedSyms.containsOrIncl(s.id):
|
||||
@@ -1854,7 +1974,8 @@ var globals: PGlobals
|
||||
proc newModule(module: PSym): BModule =
|
||||
new(result)
|
||||
result.module = module
|
||||
if globals == nil: globals = newGlobals()
|
||||
if globals == nil:
|
||||
globals = newGlobals()
|
||||
|
||||
proc genHeader(target: TTarget): Rope =
|
||||
if target == targetJS:
|
||||
@@ -1905,31 +2026,56 @@ proc wholeCode*(m: BModule): Rope =
|
||||
for prc in globals.forwarded:
|
||||
if not globals.generatedSyms.containsOrIncl(prc.id):
|
||||
var p = newProc(globals, m, nil, m.module.options)
|
||||
add(p.g.code, genProc(p, prc))
|
||||
attachProc(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 = newProc(globals, m, nil, m.module.options)
|
||||
add(p.g.code, genProc(p, prc))
|
||||
attachProc(p, prc)
|
||||
|
||||
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 =
|
||||
if passes.skipCodegen(n): return n
|
||||
result = myProcess(b, n)
|
||||
var m = BModule(b)
|
||||
if sfMainModule in m.module.flags:
|
||||
let ext = if m.target == targetJS: "js" else: "php"
|
||||
let code = wholeCode(m)
|
||||
let outfile =
|
||||
if options.outFile.len > 0:
|
||||
if options.outFile.isAbsolute: options.outFile
|
||||
else: getCurrentDir() / options.outFile
|
||||
else:
|
||||
changeFileExt(completeCFilePath(m.module.filename),
|
||||
if m.target == targetJS: "js" else: "php")
|
||||
changeFileExt(completeCFilePath(m.module.filename), ext)
|
||||
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 =
|
||||
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)
|
||||
result = ("{kind: 1, offset: \"$1\", len: 0, " &
|
||||
"typ: $2, name: $3, sons: null}") %
|
||||
[mangleName(field), s, makeJSString(field.name.s)]
|
||||
[mangleName(field, p.target), s,
|
||||
makeJSString(field.name.s)]
|
||||
of nkRecCase:
|
||||
length = sonsLen(n)
|
||||
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]",
|
||||
[u, genObjectFields(p, typ, lastSon(b))])
|
||||
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]
|
||||
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",
|
||||
[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 =
|
||||
if p.target == targetPHP:
|
||||
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 """
|
||||
$args = func_get_args();
|
||||
$result = array();
|
||||
foreach ($args as $key=>$x) {
|
||||
if (is_array(($val)) {
|
||||
foreach ($args as $x) {
|
||||
if (is_array($x)) {
|
||||
for ($j = $x[0]; $j <= $x[1]; $j++) {
|
||||
result[$j] = true;
|
||||
$result[$j] = true;
|
||||
}
|
||||
} else {
|
||||
result[$x] = true;
|
||||
$result[$x] = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return $result;
|
||||
"""
|
||||
else:
|
||||
asm """
|
||||
|
||||
Reference in New Issue
Block a user