first version of an PHP codegen

This commit is contained in:
Andreas Rumpf 2016-02-04 03:40:39 +01:00
commit 35567a1eb9
8 changed files with 665 additions and 411 deletions

File diff suppressed because it is too large Load diff

View file

@ -116,6 +116,8 @@ proc genEnumInfo(p: PProc, typ: PType, name: Rope) =
[name, genTypeInfo(p, typ.sons[0])]) [name, genTypeInfo(p, typ.sons[0])])
proc genTypeInfo(p: PProc, typ: PType): Rope = proc genTypeInfo(p: PProc, typ: PType): Rope =
if p.target == targetPHP:
return makeJSString(typeToString(typ, preferModuleInfo))
let t = typ.skipTypes({tyGenericInst, tyDistinct}) let t = typ.skipTypes({tyGenericInst, tyDistinct})
result = "NTI$1" % [rope(t.id)] result = "NTI$1" % [rope(t.id)]
if containsOrIncl(p.g.typeInfoGenerated, t.id): return if containsOrIncl(p.g.typeInfoGenerated, t.id): return

View file

@ -108,6 +108,7 @@ proc commandCompileToJS =
defineSymbol("nimrod") # 'nimrod' is always defined defineSymbol("nimrod") # 'nimrod' is always defined
defineSymbol("ecmascript") # For backward compatibility defineSymbol("ecmascript") # For backward compatibility
defineSymbol("js") defineSymbol("js")
if gCmd == cmdCompileToPHP: defineSymbol("nimphp")
semanticPasses() semanticPasses()
registerPass(JSgenPass) registerPass(JSgenPass)
compileProject() compileProject()
@ -267,6 +268,9 @@ proc mainCommand* =
of "js", "compiletojs": of "js", "compiletojs":
gCmd = cmdCompileToJS gCmd = cmdCompileToJS
commandCompileToJS() commandCompileToJS()
of "php":
gCmd = cmdCompileToPHP
commandCompileToJS()
of "doc": of "doc":
wantMainModule() wantMainModule()
gCmd = cmdDoc gCmd = cmdDoc

View file

@ -84,6 +84,14 @@ proc handleCmdLine() =
ex = quoteShell( ex = quoteShell(
completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir)) completeCFilePath(changeFileExt(gProjectFull, "js").prependCurDir))
execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments) execExternalProgram(findNodeJs() & " " & ex & ' ' & commands.arguments)
elif gCmd == cmdCompileToPHP:
var ex: string
if options.outFile.len > 0:
ex = options.outFile.prependCurDir.quoteShell
else:
ex = quoteShell(
completeCFilePath(changeFileExt(gProjectFull, "php").prependCurDir))
execExternalProgram("php " & ex & ' ' & commands.arguments)
else: else:
var binPath: string var binPath: string
if options.outFile.len > 0: if options.outFile.len > 0:

View file

@ -70,7 +70,9 @@ type # please make sure we have under 32 options
TCommands* = enum # Nim's commands TCommands* = enum # Nim's commands
# **keep binary compatible** # **keep binary compatible**
cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, cmdNone, cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToJS, cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc, cmdCompileToJS,
cmdCompileToPHP,
cmdCompileToLLVM, cmdInterpret, cmdPretty, cmdDoc,
cmdGenDepend, cmdDump, cmdGenDepend, cmdDump,
cmdCheck, # semantic checking for whole project cmdCheck, # semantic checking for whole project
cmdParse, # parse a single file (for debugging) cmdParse, # parse a single file (for debugging)

View file

@ -527,7 +527,7 @@ proc cmdChangeTriggersRecompilation(old, new: TCommands): bool =
# new command forces us to consider it here :-) # new command forces us to consider it here :-)
case old case old
of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC, of cmdCompileToC, cmdCompileToCpp, cmdCompileToOC,
cmdCompileToJS, cmdCompileToLLVM: cmdCompileToJS, cmdCompileToPHP, cmdCompileToLLVM:
if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef, if new in {cmdDoc, cmdCheck, cmdIdeTools, cmdPretty, cmdDef,
cmdInteractive}: cmdInteractive}:
return false return false

View file

@ -2452,14 +2452,17 @@ type
when defined(JS): when defined(JS):
proc add*(x: var string, y: cstring) {.asmNoStackFrame.} = proc add*(x: var string, y: cstring) {.asmNoStackFrame.} =
asm """ when defined(nimphp):
var len = `x`[0].length-1; asm """`x` .= `y`;"""
for (var i = 0; i < `y`.length; ++i) { else:
`x`[0][len] = `y`.charCodeAt(i); asm """
++len; var len = `x`[0].length-1;
} for (var i = 0; i < `y`.length; ++i) {
`x`[0][len] = 0 `x`[0][len] = `y`.charCodeAt(i);
""" ++len;
}
`x`[0][len] = 0
"""
proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".} proc add*(x: var cstring, y: cstring) {.magic: "AppendStrStr".}
elif hasAlloc: elif hasAlloc:

View file

@ -1,7 +1,7 @@
# #
# #
# Nim's Runtime Library # Nim's Runtime Library
# (c) Copyright 2012 Andreas Rumpf # (c) Copyright 2015 Andreas Rumpf
# #
# See the file "copying.txt", included in this # See the file "copying.txt", included in this
# distribution, for details about the copyright. # distribution, for details about the copyright.
@ -61,7 +61,6 @@ proc getCurrentExceptionMsg*(): string =
proc auxWriteStackTrace(f: PCallFrame): string = proc auxWriteStackTrace(f: PCallFrame): string =
type type
TempFrame = tuple[procname: cstring, line: int] TempFrame = tuple[procname: cstring, line: int]
{.deprecated: [TTempFrame: TempFrame].}
var var
it = f it = f
i = 0 i = 0
@ -128,8 +127,11 @@ proc reraiseException() {.compilerproc, asmNoStackFrame.} =
else: else:
when not defined(noUnhandledHandler): when not defined(noUnhandledHandler):
if excHandler == 0: if excHandler == 0:
var isNimException : bool var isNimException: bool
asm "`isNimException` = lastJSError.m_type;" when defined(nimphp):
asm "`isNimException` = isset(`lastJSError`['m_type']);"
else:
asm "`isNimException` = lastJSError.m_type;"
if isNimException: if isNimException:
unhandledException(cast[ref Exception](lastJSError)) unhandledException(cast[ref Exception](lastJSError))
asm "throw lastJSError;" asm "throw lastJSError;"
@ -150,35 +152,57 @@ proc raiseFieldError(f: string) {.compilerproc, noreturn.} =
raise newException(FieldError, f & " is not accessible") raise newException(FieldError, f & " is not accessible")
proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} = proc SetConstr() {.varargs, asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = {}; asm """
for (var i = 0; i < arguments.length; ++i) { $args = func_get_args();
var x = arguments[i]; $result = array();
if (typeof(x) == "object") { foreach ($args as $key=>$x) {
for (var j = x[0]; j <= x[1]; ++j) { if (is_array(($val)) {
result[j] = true; for ($j = $x[0]; $j <= $x[1]; $j++) {
result[$j] = true;
}
} else {
result[$x] = true;
} }
} else {
result[x] = true;
} }
} return result;
return result; """
""" else:
asm """
var result = {};
for (var i = 0; i < arguments.length; ++i) {
var x = arguments[i];
if (typeof(x) == "object") {
for (var j = x[0]; j <= x[1]; ++j) {
result[j] = true;
}
} else {
result[x] = true;
}
}
return result;
"""
proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} = proc makeNimstrLit(c: cstring): string {.asmNoStackFrame, compilerproc.} =
{.emit: """ when defined(nimphp):
var ln = `c`.length; {.emit: """return `c`;""".}
var result = new Array(ln + 1); else:
var i = 0; {.emit: """
for (; i < ln; ++i) { var ln = `c`.length;
result[i] = `c`.charCodeAt(i); var result = new Array(ln + 1);
} var i = 0;
result[i] = 0; // terminating zero for (; i < ln; ++i) {
return result; result[i] = `c`.charCodeAt(i);
""".} }
result[i] = 0; // terminating zero
return result;
""".}
proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} = proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
{.emit: """ when defined(nimphp):
{.emit: """return `c`;""".}
else:
{.emit: """
var ln = `c`.length; var ln = `c`.length;
var result = new Array(ln); var result = new Array(ln);
var r = 0; var r = 0;
@ -207,7 +231,10 @@ proc cstrToNimstr(c: cstring): string {.asmNoStackFrame, compilerproc.} =
""".} """.}
proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} = proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
{.emit: """return `s`;""".}
else:
asm """
var len = `s`.length-1; var len = `s`.length-1;
var asciiPart = new Array(len); var asciiPart = new Array(len);
var fcc = String.fromCharCode; var fcc = String.fromCharCode;
@ -234,62 +261,113 @@ proc toJSStr(s: string): cstring {.asmNoStackFrame, compilerproc.} =
""" """
proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} = proc mnewString(len: int): string {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = new Array(`len`+1); asm """
result[0] = 0; $result = array();
result[`len`] = 0; for($i = 0; $i < `len`; $i++) $result[] = chr(0);
return result; return $result;
""" """
else:
asm """
var result = new Array(`len`+1);
result[0] = 0;
result[`len`] = 0;
return result;
"""
proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} = proc SetCard(a: int): int {.compilerproc, asmNoStackFrame.} =
# argument type is a fake # argument type is a fake
asm """ when defined(nimphp):
var result = 0; asm """
for (var elem in `a`) { ++result; } return count(`a`);
return result; """
""" else:
asm """
var result = 0;
for (var elem in `a`) { ++result; }
return result;
"""
proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} = proc SetEq(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
asm """ when defined(nimphp):
for (var elem in `a`) { if (!`b`[elem]) return false; } asm """
for (var elem in `b`) { if (!`a`[elem]) return false; } foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; }
return true; foreach (`b` as $elem=>$_) { if (!isset(`a`[$elem])) return false; }
""" return true;
"""
else:
asm """
for (var elem in `a`) { if (!`b`[elem]) return false; }
for (var elem in `b`) { if (!`a`[elem]) return false; }
return true;
"""
proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} = proc SetLe(a, b: int): bool {.compilerproc, asmNoStackFrame.} =
asm """ when defined(nimphp):
for (var elem in `a`) { if (!`b`[elem]) return false; } asm """
return true; foreach (`a` as $elem=>$_) { if (!isset(`b`[$elem])) return false; }
""" return true;
"""
else:
asm """
for (var elem in `a`) { if (!`b`[elem]) return false; }
return true;
"""
proc SetLt(a, b: int): bool {.compilerproc.} = proc SetLt(a, b: int): bool {.compilerproc.} =
result = SetLe(a, b) and not SetEq(a, b) result = SetLe(a, b) and not SetEq(a, b)
proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} = proc SetMul(a, b: int): int {.compilerproc, asmNoStackFrame.} =
asm """ when defined(nimphp):
var result = {}; asm """
for (var elem in `a`) { var $result = array();
if (`b`[elem]) { result[elem] = true; } foreach (`a` as $elem=>$_) {
} if (isset(`b`[$elem])) { $result[$elem] = true; }
return result; }
""" return $result;
"""
else:
asm """
var result = {};
for (var elem in `a`) {
if (`b`[elem]) { result[elem] = true; }
}
return result;
"""
proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} = proc SetPlus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
asm """ when defined(nimphp):
var result = {}; asm """
for (var elem in `a`) { result[elem] = true; } var $result = array();
for (var elem in `b`) { result[elem] = true; } foreach (`a` as $elem=>$_) { $result[$elem] = true; }
return result; foreach (`b` as $elem=>$_) { $result[$elem] = true; }
""" return $result;
"""
else:
asm """
var result = {};
for (var elem in `a`) { result[elem] = true; }
for (var elem in `b`) { result[elem] = true; }
return result;
"""
proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} = proc SetMinus(a, b: int): int {.compilerproc, asmNoStackFrame.} =
asm """ when defined(nimphp):
var result = {}; asm """
for (var elem in `a`) { $result = array();
if (!`b`[elem]) { result[elem] = true; } foreach (`a` as $elem=>$_) {
} if (!isset(`b`[$elem])) { $result[$elem] = true; }
return result; }
""" return $result;
"""
else:
asm """
var result = {};
for (var elem in `a`) {
if (!`b`[elem]) { result[elem] = true; }
}
return result;
"""
proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} = proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
asm """ asm """
@ -303,7 +381,15 @@ proc cmpStrings(a, b: string): int {.asmNoStackFrame, compilerProc.} =
return 0; return 0;
""" """
proc cmp(x, y: string): int = return cmpStrings(x, y) proc cmp(x, y: string): int =
when defined(nimphp):
asm """
if(`x` < `y`) `result` = -1;
elseif (`x` > `y`) `result` = 1;
else `result` = 0;
"""
else:
return cmpStrings(x, y)
proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} = proc eqStrings(a, b: string): bool {.asmNoStackFrame, compilerProc.} =
asm """ asm """
@ -338,7 +424,7 @@ elif defined(nodejs):
console.log(buf); console.log(buf);
""" """
else: elif not defined(nimphp):
proc ewriteln(x: cstring) = proc ewriteln(x: cstring) =
var node : JSRef var node : JSRef
{.emit: "`node` = document.getElementsByTagName('body')[0];".} {.emit: "`node` = document.getElementsByTagName('body')[0];".}
@ -364,77 +450,127 @@ else:
# Arithmetic: # Arithmetic:
proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc addInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = `a` + `b`; asm """
if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); return `a` + `b`;
return result; """
""" else:
asm """
var result = `a` + `b`;
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
return result;
"""
proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc subInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = `a` - `b`; asm """
if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); return `a` - `b`;
return result; """
""" else:
asm """
var result = `a` - `b`;
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
return result;
"""
proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc mulInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = `a` * `b`; asm """
if (result > 2147483647 || result < -2147483648) `raiseOverflow`(); return `a` * `b`;
return result; """
""" else:
asm """
var result = `a` * `b`;
if (result > 2147483647 || result < -2147483648) `raiseOverflow`();
return result;
"""
proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc divInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
if (`b` == 0) `raiseDivByZero`(); asm """
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); return floor(`a` / `b`);
return Math.floor(`a` / `b`); """
""" else:
asm """
if (`b` == 0) `raiseDivByZero`();
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
return Math.floor(`a` / `b`);
"""
proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc modInt(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
if (`b` == 0) `raiseDivByZero`(); asm """
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`(); return `a` % `b`;
return Math.floor(`a` % `b`); """
""" else:
asm """
if (`b` == 0) `raiseDivByZero`();
if (`b` == -1 && `a` == 2147483647) `raiseOverflow`();
return Math.floor(`a` % `b`);
"""
proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc addInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = `a` + `b`; asm """
if (result > 9223372036854775807 return `a` + `b`;
|| result < -9223372036854775808) `raiseOverflow`(); """
return result; else:
""" asm """
var result = `a` + `b`;
if (result > 9223372036854775807
|| result < -9223372036854775808) `raiseOverflow`();
return result;
"""
proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc subInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = `a` - `b`; asm """
if (result > 9223372036854775807 return `a` - `b`;
|| result < -9223372036854775808) `raiseOverflow`(); """
return result; else:
""" asm """
var result = `a` - `b`;
if (result > 9223372036854775807
|| result < -9223372036854775808) `raiseOverflow`();
return result;
"""
proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc mulInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
var result = `a` * `b`; asm """
if (result > 9223372036854775807 return `a` * `b`;
|| result < -9223372036854775808) `raiseOverflow`(); """
return result; else:
""" asm """
var result = `a` * `b`;
if (result > 9223372036854775807
|| result < -9223372036854775808) `raiseOverflow`();
return result;
"""
proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc divInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
if (`b` == 0) `raiseDivByZero`(); asm """
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); return floor(`a` / `b`);
return Math.floor(`a` / `b`); """
""" else:
asm """
if (`b` == 0) `raiseDivByZero`();
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
return Math.floor(`a` / `b`);
"""
proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} = proc modInt64(a, b: int): int {.asmNoStackFrame, compilerproc.} =
asm """ when defined(nimphp):
if (`b` == 0) `raiseDivByZero`(); asm """
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`(); return `a` % `b`;
return Math.floor(`a` % `b`); """
""" else:
asm """
if (`b` == 0) `raiseDivByZero`();
if (`b` == -1 && `a` == 9223372036854775807) `raiseOverflow`();
return Math.floor(`a` % `b`);
"""
proc negInt(a: int): int {.compilerproc.} = proc negInt(a: int): int {.compilerproc.} =
result = a*(-1) result = a*(-1)
@ -587,11 +723,18 @@ proc genericReset(x: JSRef, ti: PNimType): JSRef {.compilerproc.} =
proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {. proc arrayConstr(len: int, value: JSRef, typ: PNimType): JSRef {.
asmNoStackFrame, compilerproc.} = asmNoStackFrame, compilerproc.} =
# types are fake # types are fake
asm """ when defined(nimphp):
var result = new Array(`len`); asm """
for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`); $result = array();
return result; for ($i = 0; $i < `len`; $i++) $result[] = `value`;
""" return $result;
"""
else:
asm """
var result = new Array(`len`);
for (var i = 0; i < `len`; ++i) result[i] = nimCopy(null, `value`, `typ`);
return result;
"""
proc chckIndx(i, a, b: int): int {.compilerproc.} = proc chckIndx(i, a, b: int): int {.compilerproc.} =
if i >= a and i <= b: return i if i >= a and i <= b: return i