Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
tree: a8a097aa35
Fetching contributors…

Cannot retrieve contributors at this time

2642 lines (2341 sloc) 66.884 kb
#! winxed
// winxedxx.winxed
// C++ backend for winxed
// (C) 2011-2012 Julián Albo "NotFound"
// This code uses and abuses winxed compiler internals.
// Not a good example on how to write winxed compiler extensions,
// but there is no better way right now.
//**************************************************************
// Declare used classes
namespace Winxed.Compiler
{
class Token;
class TokenString;
class TokenQuoted;
class TokenSingleQuoted;
class IntegerLiteral;
class FloatLiteral;
class StringLiteral;
class Builtin;
class ClassSpecifierStr;
class ClassSpecifierId;
class NullExpr;
class CastExpr;
class VarCastExpr;
class IdentifierExpr;
class LexicalVolatileExpr;
class MemberExpr;
class MemberRefExpr;
class IndexExpr;
class StringIndexExpr;
class OpExistsExpr;
class NewExpr;
class NewIndexedExpr;
class NewQualifiedExpr;
class ArrayExpr;
class HashExpr;
class FunctionExpr;
class FunctionId;
class FunctionRef;
class NullCheckerExpr;
class ConcatString;
class CallExpr;
class CallSubid;
class CallMemberExpr;
class CallBuiltinExpr;
class OpPreIncExpr;
class OpPreDecExpr;
class OpPostIncExpr;
class OpPostDecExpr;
class OpUnaryMinusExpr;
class OpAssignExpr;
class OpAssignToExpr;
class OpAddExpr;
class OpAddToExpr;
class OpSubToExpr;
class OpMulToExpr;
class OpSubExpr;
class RepeatString;
class OpMulExpr;
class OpDivExpr;
class OpModExpr;
class OpCModExpr;
class OpNotExpr;
class OpBinNotExpr;
class ZeroCheckerExpr;
class OpEqualExpr;
class OpSameExpr;
class OpLessEqualExpr;
class OpGreaterEqualExpr;
class OpLessExpr;
class OpGreaterExpr;
class OpBoolAndExpr;
class OpBoolOrExpr;
class OpBinOrExpr;
class OpBinAndExpr;
class OpBinXorExpr;
class OpShiftrightExpr;
class OpShiftleftExpr;
class OpInstanceOfExpr;
class OpConditionalExpr;
class OpNamespaceExpr;
class EmptyStatement;
class UsingNamespaceStatement;
class UsingStatement;
class StaticStatement;
class ExternStatement;
class ExprStatement;
class MultiStatement;
class CompoundStatement;
class VarStatement;
class IntStatement;
class FloatStatement;
class StringStatement;
class IntArrayStatement;
class FloatArrayStatement;
class StringArrayStatement;
class ConstStatement;
class MultiAssignStatement;
class ReturnStatement;
class LabelStatement;
class BreakStatement;
class ContinueStatement;
class IfStatement;
class GotoStatement;
class SwitchStatement;
class SwitchCaseStatement;
class ForStatement;
class ForeachStatement;
class DoStatement;
class WhileStatement;
class TryStatement;
class ThrowStatement;
class FunctionExtern;
class FunctionStatement;
class ClassStatement;
class NamespaceStatement;
class RootNamespace;
// Constants
const int
SEARCH_NAMESPACE = 1,
SEARCH_CLASS = 2,
VAR_is_lexical = 2;
} // namespace Winxed.Compiler
//**************************************************************
namespace WinxedXC.WinxedXX
{
using namespace Winxed.Compiler;
//**************************************************************
// Errors
function WxxError(string message)
{
return Error(message, 2, __WINXED_ERROR__);
}
function WxxUnsupported(thing, string msg[optional])
{
if (msg == null) {
if (thing instanceof "String")
msg = thing;
else
msg = typeof(thing);
}
string filename = "";
int line = 0;
string desc;
try {
var start;
if (thing instanceof Token)
start = thing;
else
start = thing.start;
filename = start.file;
line = start.line;
desc = start.viewable();
}
catch () { }
return WxxError(filename + ":" + string(line) + ": " +
msg + " unsupported near " + desc);
}
//**************************************************************
// Algorithms and binders
function for_each(params, func)
{
if (params != null) {
for (var param in params)
func(param);
}
}
function find_if(params, func)
{
for (var item in params)
if (func(item))
return item;
return null;
}
function bindfirst(func, argfirst[slurpy])
{
return function (arg2 [slurpy]) { func(argfirst:[flat], arg2:[flat]); };
}
function bindlast(func, arglast[slurpy])
{
return function (arg2 [slurpy]) { func(arg2:[flat], arglast:[flat]); };
}
function bindmethod(string name)
{
return function(var obj, var args[slurpy])
{
return obj.*name(args:[flat]);
};
}
// Types
const string DATA = "__data";
const string
// Parrot types
REGint = "I",
REGfloat = "N",
REGstring = "S",
REGvar = "P",
// Generated types, for own use and for NCI
Type_Void = "void",
Type_Short = "short",
Type_Int = "int",
Type_Long = "long",
Type_Num = "double",
Type_Float = "float",
Type_VoidPtr = "void*",
Type_String = "std::string",
Type_PMC = "WxxObjectPtr",
Type_Hash = "WxxHash",
Type_PMCArray = "WxxObjectArray",
Type_Instance = "WxxInstance";
function generatedType(string ptype)
{
switch (ptype) {
case REGint: return Type_Int;
case REGfloat: return Type_Num;
case REGstring: return Type_String;
case REGvar: return Type_PMC;
default:
throw "Internal error: wrong call: generatedType " + ptype;
}
}
// Helper C++ functions
const string ARGSEP = ", ";
const string
INTCAST = "wxx_int_cast",
NUMCAST = "wxx_num_cast",
STRINGCAST = "wxx_string_cast",
INDEXOF = "wxx_indexof",
ORD = "wxx_ord",
SUBSTR = "wxx_substr",
ERROR = "wxx_error",
OPEN = "wxx_open",
PRINT = "wxx_print",
EPRINT = "wxx_eprint";
//**************************************************************
function strtoxx(string str)
{
string result = "";
for (string c in str) {
switch (c) {
case "\"":
case "\\":
result += "\\" + c; break;
case "\t":
result += "\\t"; break;
case "\r":
result += "\\r"; break;
case "\n":
result += "\\n"; break;
default:
int code = ord(c);
if (code < 32)
result += "\\x" + substr(("0" + string(code.get_as_base(16))), -2);
else if (code > 65535)
result += "\\U" + substr(("0000000" + string(code.get_as_base(16))), -8);
else if (code > 127)
result += "\\u" + substr(("000" + string(code.get_as_base(16))), -4);
else
result += c;
}
}
return result;
}
function tokstringtoxx(strval)
{
__ASSERT__(strval instanceof TokenString);
return strtoxx(unescape(strval.getasquoted()));
}
function stringtoxx(literal)
{
if (!(literal instanceof StringLiteral)) die("UUU");
__ASSERT__(literal instanceof StringLiteral);
return tokstringtoxx(literal.strval);
}
function nciitemtoc(string item)
{
switch (item)
{
case "v":
return Type_Void;
case "i": // int
case "I": // INTVAL
return Type_Int;
case "s":
return Type_Short;
case "l":
return Type_Long;
case "d":
case "N":
return Type_Num;
case "f":
return Type_Float;
case "p":
return Type_VoidPtr;
default:
throw Error("signature unsupported: " + item);
}
}
function ncisigtoc(string sig)
{
string csig[];
for (string item in sig)
push(csig, nciitemtoc(item));
return csig;
}
//**********************************************************************
// Emit helpers
//**********************************************************************
function emit_namespacefromroot(var out, var path)
{
out.print("getRootNamespace()");
for (string item in path)
out.print(".childNamespace(\"", item, "\")");
}
function emit_plainfun1(var out, string name, var arg)
{
out.print(name, "(");
emit_expr(out, arg);
out.print(")");
}
function emit_plainfun1string(var out, string name, var arg)
{
out.print(name, "(");
if (arg.checkresult() != REGstring)
out.print(STRINGCAST);
emit_expr(out, arg);
out.print(")");
}
function emit_plainfun2(var out, string name, var arg1, var arg2)
{
out.print(name, "(");
emit_expr(out, arg1);
out.print(ARGSEP);
emit_expr(out, arg2);
out.print(")");
}
//**********************************************************************
// Builtins
//**********************************************************************
function emit_callbuiltin_void(out, string name)
{
out.print(name, "()");
}
function emit_builtin_print(out, args)
{
for (var arg in args) {
var argexp = arg.arg;
out.print(PRINT);
emit_expr(out, argexp);
out.print(ARGSEP);
}
out.print("0");
}
function emit_builtin_say(out, args)
{
for (var arg in args) {
var argexp = arg.arg;
out.print(PRINT);
emit_expr(out, argexp);
out.print(ARGSEP);
}
out.print(PRINT + "(\"\\n\"), 0");
}
function emit_builtin_cry(out, args)
{
for (var arg in args) {
var argexp = arg.arg;
out.print(EPRINT);
emit_expr(out, argexp);
out.print(ARGSEP);
}
out.print(EPRINT + "(\"\\n\"), 0");
}
function emit_builtin_open(out, args)
{
int nargs = elements(args);
out.print(OPEN, "(");
emit_stringexpr(out, args[0].arg);
if (nargs > 1) {
out.print(ARGSEP);
emit_stringexpr(out, args[1].arg);
}
out.print(")");
}
function emit_builtin_Error(out, args)
{
int nargs = elements(args);
out.print(ERROR, "(");
emit_stringexpr(out, args[0].arg);
if (nargs > 1) {
out.print(ARGSEP);
emit_intexpr(out, args[1].arg);
if (nargs > 2) {
out.print(ARGSEP);
emit_intexpr(out, args[2].arg);
}
}
out.print(")");
}
function emit_builtin_dlfunc(out, args)
{
var sig = args[2].arg;
if (! sig.isstringliteral())
throw WxxError("dlfunc siganture must be compile time constant");
var csig = ncisigtoc(sig.strval.rawstring());
int n = elements(csig);
if (n < 1)
throw WxxError("invalid signature");
out.print("wxx_dlfunc<");
out.print(csig[0]);
for (int i = 1; i < n; ++i) {
string item = csig[i];
if (item == Type_Void)
throw WxxError("invalid signature");
out.print(ARGSEP, item);
}
out.print(">(");
emit_expr(out, args[0].arg);
out.print(ARGSEP);
emit_stringexpr(out, args[1].arg);
out.print(")");
}
function emit_builtin_ord(out, args)
{
int nargs = elements(args);
out.print(ORD, "(");
emit_stringexpr(out, args[0].arg);
if (nargs > 1) {
out.print(ARGSEP);
emit_intexpr(out, args[1].arg);
}
out.print(")");
}
function emit_builtin_substr(out, args)
{
int nargs = elements(args);
out.print(SUBSTR, "(");
emit_stringexpr(out, args[0].arg);
out.print(ARGSEP);
emit_intexpr(out, args[1].arg);
if (nargs > 2) {
out.print(ARGSEP);
emit_intexpr(out, args[2].arg);
}
out.print(")");
}
function emit_builtin_indexof(out, args)
{
int nargs = elements(args);
out.print(INDEXOF, "(");
emit_stringexpr(out, args[0].arg);
out.print(ARGSEP);
emit_stringexpr(out, args[1].arg);
if (nargs > 2) {
out.print(ARGSEP);
emit_intexpr(out, args[2].arg);
}
out.print(")");
}
//**********************************************
function emitExpr(var out, :CallBuiltinExpr expr)
{
var builtin = expr.builtin;
string name = builtin.name;
var args = expr.args;
int nargs = elements(args);
var arg0 = nargs > 0 ? args[0].arg : null;
var arg1 = nargs > 1 ? args[1].arg : null;
string type0;
int i;
switch (name) {
case "__ASSERT__":
// No --debug option yet, emit something parseable as an expression
// that does nothing.
out.print("(void)0");
break;
case "string":
emit_plainfun1(out, STRINGCAST, arg0);
break;
case "int":
emit_plainfun1(out, INTCAST, arg0);
break;
case "float":
emit_plainfun1(out, NUMCAST, arg0);
break;
case "typeof":
out.print("wxx_typeof");
emit_expr(out, arg0);
break;
case "getstdin":
case "getstdout":
case "getstderr":
out.print("wxx_" + name + "()");
break;
case "print":
emit_builtin_print(out, args);
break;
case "say":
emit_builtin_say(out, args);
break;
case "cry":
emit_builtin_cry(out, args);
break;
case "elements":
emit_expr(out, arg0);
out.print(".elements()");
break;
case "length":
case "bytelength":
emit_plainfun1(out, "wxx_length", arg0);
break;
case "ord":
emit_builtin_ord(out, args);
break;
case "chr":
emit_plainfun1(out, "wxx_chr", arg0);
break;
case "indexof":
emit_builtin_indexof(out, args);
break;
case "substr":
emit_builtin_substr(out, args);
break;
case "chomp":
emit_plainfun1(out, "wxx_chomp", arg0);
break;
case "join":
emit_plainfun2(out, "wxx_join", arg0, arg1);
break;
case "downcase":
// Fake implementation, just cast to string the argument
emit_stringexpr(out, arg0);
break;
case "push":
emit_expr(out, arg0);
out.print(".push");
emit_expr(out, arg1);
break;
case "split":
emit_plainfun2(out, "wxx_split", arg0, arg1);
break;
case "die":
out.print("wxx_die(");
emit_expr(out, arg0);
out.print(")");
break;
case "Error":
emit_builtin_Error(out, args);
break;
case "open":
emit_builtin_open(out, args);
break;
case "loadlib":
emit_plainfun1(out, "wxx_loadlib", arg0);
break;
case "dlfunc":
emit_builtin_dlfunc(out, args);
break;
case "spawnw":
emit_plainfun1(out, "wxx_spawnw", arg0);
break;
case "exit":
emit_plainfun1(out, "exit", arg0);
break;
case "sin":
case "cos":
case "tan":
case "asin":
case "acos":
case "atan":
case "exp":
case "sqrt":
emit_plainfun1(out, name, arg0);
break;
case "ln":
emit_plainfun1(out, "log", arg0);
break;
case "time":
emit_callbuiltin_void(out, "wxx_time");
break;
case "floattime":
emit_callbuiltin_void(out, "wxx_floattime");
break;
case "sleep":
emit_plainfun1(out, "wxx_sleep", arg0);
break;
// Unsupported, always return null
case "load_bytecode":
case "load_language":
case "compreg":
case "getinterp":
out.print("winxedxxnull");
break;
// Unimplemented, just to allow some testing
case "clone":
emit_expr(out, arg0);
break;
// Unimplemented, just to allow some testing
case "get_class":
out.print("winxedxxnull");
break;
case "escape":
emit_plainfun1string(out, "wxx_escape", arg0);
break;
case "unescape":
emit_plainfun1string(out, "wxx_unescape", arg0);
break;
default:
throw WxxUnsupported(expr, "builtin " + name);
}
}
//**********************************************************************
function emitExpr(var out, :IntegerLiteral expr)
{
out.print(expr.getIntegerValue());
}
function emitExpr(var out, :FloatLiteral expr)
{
out.print(expr.numval);
}
function emitExpr(var out, :StringLiteral expr)
{
out.print(Type_String + "(\"");
out.print(stringtoxx(expr));
out.print("\")");
}
function emitExpr(var out, :IdentifierExpr expr)
{
string name = expr.name;
if (name == "null")
out.print("winxedxxnull");
else
out.print(name);
}
function emitExpr(var out, :LexicalVolatileExpr expr)
{
string name = expr.start.getidentifier();
out.print(name);
}
function emitExpr(var out, :NullExpr expr)
{
out.print("winxedxxnull");
}
function emitExpr(var out, :CastExpr expr)
{
var arg = expr.arg;
string type = expr.type;
switch (type) {
case REGint:
emit_intexpr(out, arg);
break;
case REGfloat:
emit_numexpr(out, arg);
break;
case REGstring:
emit_stringexpr(out, arg);
break;
default:
throw WxxError("unexpected cast");
}
}
function emitExpr(var out, :VarCastExpr expr)
{
var arg = expr.arg;
switch {
case arg instanceof MemberExpr:
string key[];
arg.buildkey(key);
string name = key.pop();
emit_namespacefromroot(out, key);
out.print(".get(\"", name, "\")");
break;
default:
throw WxxUnsupported(expr);
}
}
function emitExpr(var out, :OpPreIncExpr expr)
{
emit_plainfun1(out, "wxx_preinc", expr.subexpr);
}
function emitExpr(var out, :OpPreDecExpr expr)
{
emit_plainfun1(out, "wxx_predec", expr.subexpr);
}
function emitExpr(var out, :OpPostIncExpr expr)
{
emit_plainfun1(out, "wxx_postinc", expr.subexpr);
}
function emitExpr(var out, :OpPostDecExpr expr)
{
emit_plainfun1(out, "wxx_postdec", expr.subexpr);
}
//**********************************************************************
function emit_callargs(out, args)
{
out.print("WinxedXX::", Type_PMCArray, "()");
int nargs = args == null ? 0 : args.numargs();
for (int i = 0; i < nargs; ++i) {
out.print(".push(");
var arg = args.getfreearg(i);
emit_expr(out, arg);
out.print(")");
}
}
function emitExpr(var out, :CallSubid callexpr)
{
out.print(callexpr.subid, "(");
emit_callargs(out, callexpr.args);
out.print(")");
}
function emitExpr(var out, :CallMemberExpr callexpr)
{
var funref = callexpr.funref;
var args = callexpr.args;
int nargs = args == null ? 0 : args.numargs();
var left = funref.left;
int is_var = left.checkresult() == REGvar;
if (!is_var)
out.print(Type_PMC, "(");
emit_expr(out, funref.left);
if (!is_var)
out.print(")");
out.print(".call_method(\"", funref.right.getidentifier(), "\"");
if (nargs > 0) {
out.print(ARGSEP);
emit_callargs(out, args);
}
out.print(")");
}
function emitExpr(var out, :CallExpr callexpr)
{
var funref = callexpr.funref;
var args = callexpr.args;
switch {
case funref instanceof FunctionExpr:
out.print(Type_PMC);
emit_expr(out, funref);
break;
case funref instanceof FunctionId:
out.print(funref.subid);
break;
case funref instanceof FunctionRef:
var path = funref.sym.owner.getpath().path;
var name = funref.getstart();
emit_namespacefromroot(out, path);
out.print(".get(\"", name.getidentifier(), "\")");
break;
case funref.isidentifier():
if ((callexpr instanceof CallMemberExpr) && callexpr.subid != null)
out.print(callexpr.subid);
else {
string callname = funref.getName();
var sym = callexpr.owner.getvar(callname);
if (sym != null)
out.print(callname);
else
out.print("wxxGetCurrentNamespace().find_symbol(\"", callname, "\")");
}
break;
default:
emit_expr(out, funref);
}
out.print("(");
emit_callargs(out, args);
out.print(")");
}
function emitExpr(var out, :ArrayExpr expr)
{
var values = expr.values;
int nvalues = values == null ? 0 : elements(values);
out.print(Type_PMC, "(&((* new ", Type_PMCArray, "())");
int i;
for (i = 0; i < nvalues; ++i) {
out.print(".push");
emit_expr(out, values[i]);
}
out.print("))");
}
function emitExpr(var out, :HashExpr expr)
{
var keys = expr.keys;
var values = expr.values;
int n = elements(keys);
out.print(Type_PMC, "(&((* new ", Type_Hash, "())");
int i;
for (i = 0; i < n; ++i) {
out.print(".set(");
emit_expr(out, keys[i]);
out.print(ARGSEP);
emit_expr(out, values[i]);
out.print(")");
}
out.print("))");
}
function emitExpr(var out, :FunctionExpr expr)
{
var funst = expr.fn;
out.print("new ", funst.name, "(* ", DATA, ")");
}
function emitExpr(var out, :FunctionId funid)
{
out.print(funid.subid);
}
function emitExpr(var out, :NewExpr expr)
{
var initializer = expr.initializer;
int numinits = initializer == null ? -1 : initializer.numargs();
var value = expr.value;
if (value.isidentifier()) {
var id = expr.owner.getvar(value);
if (id != null) {
out.print("wxx_new(");
emit_expr("test");
}
else {
var cl = expr.owner.checkclass(value);
if (cl != null) {
var key = cl.getpath().path;
out.print("wxx_new_obj(getRootNamespace()");
int n = elements(key);
for (int i = 0; i < n - 1; ++i)
out.print(".childNamespace(\"", key[i], "\")");
string clname = "\"" + string(key[n - 1]) + "\"";
out.print(".get(", clname, ")");
if (numinits >= 0)
out.print(ARGSEP, clname);
}
else
out.print("wxx_new(\"", value, "\"");
}
if (numinits > 0) {
out.print(ARGSEP);
emit_callargs(out, initializer);
}
out.print(")");
}
else if (value.isstring()) {
out.print("wxx_new_string(\"", value.getasquoted(), "\")");
}
else {
if (__DEBUG__) cry("In new expression:");
throw WxxUnsupported(expr);
}
}
function emitExpr(var out, :NewIndexedExpr expr)
{
var key = expr.nskey.key;
if (elements(key) != 1)
throw WxxUnsupported(expr, "supported only with keys length == 1");
// TESTING
string name = key[0];
out.print("wxx_new_string(\"", name, "\"");
var initializer = expr.initializer;
int numinits = initializer == null ? -1 : initializer.numargs();
switch (numinits) {
case -1:
break;
case 1:
out.print(ARGSEP);
emit_expr(out, initializer.getfreearg(0));
break;
default:
throw WxxError("Invalid initializer");
}
out.print(")");
}
function emitExpr(var out, :NewQualifiedExpr expr)
{
var newkey = expr.nskey;
var nskey = newkey.checknskey(expr);
var initializer = expr.initializer;
int numinits = initializer == null ? -1 : initializer.numargs();
// TESTING
var key = newkey.key;
out.print("wxx_new_obj(getRootNamespace()");
int n = elements(key);
for (int i = 0; i < n - 1; ++i)
out.print(".childNamespace(\"", key[i], "\")");
string clname = "\"" + string(key[n - 1]) + "\"";
out.print(".get(", clname, ")");
if (numinits >= 0) {
out.print(ARGSEP, clname);
if (numinits > 0) {
out.print(ARGSEP);
emit_callargs(out, initializer);
}
}
out.print(")");
}
function emitExpr(var out, :OpAssignExpr assignexpr)
{
var lexpr = assignexpr.lexpr;
var rexpr = assignexpr.rexpr;
string ltype = lexpr.checkresult();
switch {
case lexpr instanceof IdentifierExpr:
out.print(lexpr.name, " = ");
emit_typedexpr(out, rexpr, ltype);
break;
case lexpr instanceof LexicalVolatileExpr:
out.print(lexpr.start.getidentifier(), " = ");
emit_typedexpr(out, rexpr, ltype);
break;
case lexpr instanceof MemberExpr:
emit_expr(out, lexpr.left);
string ident = lexpr.right.getidentifier();
out.print(".set_attr_str(\"" + ident + "\",");
emit_varexpr(out, rexpr);
out.print(")");
break;
case lexpr instanceof MemberRefExpr:
emit_expr(out, lexpr.left);
out.print(".set_attr_str(");
emit_stringexpr(out, lexpr.right);
out.print(ARGSEP);
emit_varexpr(out, rexpr);
out.print(")");
break;
case lexpr instanceof IndexExpr:
var left = lexpr.left;
emit_expr(out, left);
var arg = lexpr.args.getarg(0);
out.print(".set_pmc_keyed(");
emit_expr(out, arg);
out.print(ARGSEP);
emit_expr(out, rexpr);
out.print(")");
break;
default:
if (__DEBUG__) cry("In assignment:");
throw WxxUnsupported(lexpr);
}
}
function emitExpr(var out, :OpAssignToExpr expr)
{
var lexpr = expr.lexpr;
var rexpr = expr.rexpr;
if (lexpr instanceof IdentifierExpr) {
out.print(lexpr.name, ".set");
emit_expr(out, rexpr);
}
else if (lexpr instanceof MemberExpr) {
emit_expr(out, lexpr.left);
string ident = lexpr.right.getidentifier();
out.print(".get_attr_str(\"", ident, "\").set");
emit_expr(out, rexpr);
}
else if (lexpr instanceof MemberRefExpr) {
// Fake implementation to allow some testing.
out.print("winxedxxnull");
}
else {
if (__DEBUG__) cry("In assign to:");
throw WxxUnsupported(lexpr);
}
}
function emitExpr(var out, :OpInstanceOfExpr instanceofexpr)
{
var lexpr = instanceofexpr.lexpr;
var checked = instanceofexpr.checked;
out.print("wxx_instanceof(");
emit_expr(out, lexpr);
out.print(ARGSEP);
if (checked instanceof ClassSpecifierStr)
out.print("\"", checked.name.getasquoted(), "\"");
else if (checked instanceof ClassSpecifierId)
out.print("\"", checked.last(), "\"");
else
out.print("\"", tokstringtoxx(checked), "\"");
out.print(")");
}
function emitExpr(var out, :OpAddToExpr assignexpr)
{
var lexpr = assignexpr.lexpr;
if (lexpr instanceof IdentifierExpr) {
out.print(lexpr.name, " += ");
if (lexpr.checkresult() == REGstring)
out.print(Type_String);
emit_expr(out, assignexpr.rexpr);
}
else {
if (__DEBUG__) cry("In " + __FUNCTION__);
throw WxxUnsupported(lexpr);
}
}
function emit_OpSubToExpr(out, assignexpr)
{
var lexpr = assignexpr.lexpr;
if (lexpr instanceof IdentifierExpr) {
out.print(lexpr.name, " -= ");
if (lexpr.checkresult() == REGstring)
out.print(Type_String);
emit_expr(out, assignexpr.rexpr);
}
else {
if (__DEBUG__) cry("In " + __FUNCTION__);
throw WxxUnsupported(lexpr);
}
}
function emit_OpMulToExpr(out, assignexpr)
{
var lexpr = assignexpr.lexpr;
if (lexpr instanceof IdentifierExpr) {
out.print(lexpr.name, " *= ");
if (lexpr.checkresult() == REGstring)
out.print(Type_String);
emit_expr(out, assignexpr.rexpr);
}
else {
if (__DEBUG__) cry("In " + __FUNCTION__);
throw WxxUnsupported(lexpr);
}
}
function emitExpr(var out, :OpAddExpr expr)
{
emit_plainfun2(out, "wxx_add", expr.lexpr, expr.rexpr);
}
function emitExpr(var out, :OpSubExpr expr)
{
emit_plainfun2(out, "wxx_sub", expr.lexpr, expr.rexpr);
}
function emitExpr(var out, :RepeatString expr)
{
out.print("wxx_repeat_string(");
emit_expr(out, expr.lexpr);
out.print(ARGSEP);
emit_expr(out, expr.rexpr);
out.print(")");
}
function emitExpr(var out, :OpMulExpr expr)
{
emit_plainfun2(out, "wxx_mul", expr.lexpr, expr.rexpr);
}
function emitExpr(var out, :OpDivExpr expr)
{
emit_plainfun2(out, "wxx_div", expr.lexpr, expr.rexpr);
}
function emitExpr(var out, :ConcatString concatstr)
{
var values = concatstr.values;
emit_stringexpr(out, values[0]);
int n = elements(values);
for (int i = 1; i < n; ++i) {
out.print(" + ");
emit_stringexpr(out, values[i]);
}
}
function emitExpr(var out, :NullCheckerExpr expr)
{
if (! expr.positive)
out.print("!");
emit_plainfun1(out, "wxx_isnull", expr.expr);
}
function emit_OpNotExpr(out, expr)
{
out.print("!");
emit_expr(out, expr.subexpr);
}
function emitExpr(var out, :OpBinNotExpr expr)
{
out.print("~");
emit_expr(out, expr.subexpr);
}
function emitExpr(var out, :OpBinOrExpr expr)
{
emit_commonop(out, expr, "|");
}
function emitExpr(var out, :OpBinAndExpr expr)
{
emit_commonop(out, expr, "&");
}
function emitExpr(var out, :ZeroCheckerExpr expr)
{
out.print("(");
emit_expr(out, expr.expr);
out.print(expr.positive ? "=" : "!", "= 0)");
}
function emitExpr(var out, :OpEqualExpr expr)
{
var lexpr = expr.lexpr;
var rexpr = expr.rexpr;
if (lexpr.checkresult() == REGvar && rexpr.checkresult() == REGvar) {
if (! expr.positive)
out.print("!");
out.print("(");
emit_expr(out, lexpr);
out.print(".is_equal");
emit_expr(out, rexpr);
out.print(")");
}
else
emit_commonop(out, expr, expr.positive ? "==" : "!=");
}
function emitExpr(var out, :OpSameExpr expr)
{
var lexpr = expr.lexpr;
var rexpr = expr.rexpr;
if (lexpr.checkresult() != REGvar || rexpr.checkresult() != REGvar)
throw WxxUnsupported(expr, "unsupported usage of ===");
if (! expr.positive)
out.print("!");
out.print("(");
emit_expr(out, rexpr);
out.print(".is_same(");
emit_expr(out, lexpr);
out.print("))");
}
function emit_commonop(out, expr, string opstr)
{
emit_expr(out, expr.lexpr);
out.print(" ", opstr, " ");
emit_expr(out, expr.rexpr);
}
function emitExpr(var out, :OpBoolOrExpr lessexpr)
{
out.print("wxx_boolor(");
emit_expr(out, lessexpr.lexpr);
out.print(ARGSEP);
emit_expr(out, lessexpr.rexpr);
out.print(")");
}
function emitExpr(var out, :OpBoolAndExpr lessexpr)
{
out.print("wxx_booland(");
emit_expr(out, lessexpr.lexpr);
out.print(ARGSEP);
emit_expr(out, lessexpr.rexpr);
out.print(")");
}
function emitExpr(var out, :OpConditionalExpr expr)
{
emit_expr(out, expr.condition.condexpr);
out.print(" ? ");
string ttrue = expr.etrue.checkresult();
string tfalse = expr.efalse.checkresult();
emit_expr(out, expr.etrue);
out.print(" : (");
if (ttrue != tfalse)
out.print("(" + string(generatedType(ttrue)) + ")");
emit_expr(out, expr.efalse);
out.print(")");
}
function emitExpr(var out, :IndexExpr expr)
{
var left = expr.left;
emit_expr(out, left);
var arg = expr.args.getarg(0);
if (left.checkresult() == REGstring) {
out.print(".substr(");
emit_expr(out, arg);
out.print(", 1)");
}
else {
out.print(".get_pmc_keyed");
emit_expr(out, arg);
}
}
function emitExpr(var out, :StringIndexExpr expr)
{
var left = expr.left;
emit_expr(out, left);
var arg = expr.arg;
out.print(".substr(");
emit_expr(out, arg);
out.print(", 1)");
}
function emitExpr(var out, :OpExistsExpr expr)
{
var subexpr = expr.subexpr;
if (! (subexpr instanceof IndexExpr) || expr.checkresult() == REGstring)
throw WxxUnsupported(expr, "exits with invalid operator");
// Fake implementation to allow some testing
emit_expr(out, subexpr.left);
var arg = subexpr.args.getarg(0);
out.print(".exists");
emit_expr(out, arg);
}
function emitExpr(var out, :MemberExpr expr)
{
emit_expr(out, expr.left);
out.print(".get_attr_str(\"", expr.right.getidentifier(), "\")");
}
function emitExpr(var out, :MemberRefExpr expr)
{
emit_expr(out, expr.left);
out.print(".get_attr_str(");
emit_expr(out, expr.right);
out.print(")");
}
function emitExpr(var out, :OpNamespaceExpr expr)
{
var owner = expr.owner;
var sym = owner.scopesearch(expr.key, SEARCH_NAMESPACE);
if (sym == null)
WxxError("unknow namespace", expr);
var path = sym.getpath().path;
out.print("WxxObjectPtr(& (");
emit_namespacefromroot(out, path);
out.print("))");
}
function emitExpr(var out, var expr)
{
switch {
case expr instanceof OpSubToExpr:
emit_OpSubToExpr(out, expr);
break;
case expr instanceof OpMulToExpr:
emit_OpMulToExpr(out, expr);
break;
case expr instanceof OpNotExpr:
emit_OpNotExpr(out, expr);
break;
case expr instanceof OpUnaryMinusExpr:
out.print("-");
emit_expr(out, expr.subexpr);
break;
case expr instanceof OpLessEqualExpr:
emit_commonop(out, expr, "<=");
break;
case expr instanceof OpLessExpr:
emit_commonop(out, expr, "<");
break;
case expr instanceof OpGreaterExpr:
emit_commonop(out, expr, ">");
break;
case expr instanceof OpGreaterEqualExpr:
emit_commonop(out, expr, ">=");
break;
case expr instanceof OpBinXorExpr:
emit_commonop(out, expr, "^");
break;
case expr instanceof OpShiftrightExpr:
emit_commonop(out, expr, ">>");
break;
case expr instanceof OpShiftleftExpr:
emit_commonop(out, expr, "<<");
break;
case expr instanceof OpModExpr:
emit_commonop(out, expr, "%");
break;
case expr instanceof OpCModExpr:
emit_commonop(out, expr, "%");
break;
default:
if (__DEBUG__) cry("In " + __FUNCTION__);
throw WxxUnsupported(expr);
}
}
function emit_expr(out, expr)
{
out.print("(");
emitExpr(out, expr);
out.print(")");
}
function emit_intexpr(out, expr)
{
if (expr.isliteral())
out.print(expr.getIntegerValue());
else {
if (expr.checkresult() != REGint)
out.print("wxx_int_cast");
emit_expr(out, expr);
}
}
function emit_numexpr(out, expr)
{
if (expr.isliteral())
out.print(expr.getFloatValue());
else {
if (expr.checkresult() != REGfloat)
out.print("wxx_num_cast");
emit_expr(out, expr);
}
}
function emit_stringexpr(out, expr)
{
if (expr.isliteral())
out.print("std::string(\"", strtoxx(expr.getStringValue()), "\")");
else {
if (expr.checkresult() != REGstring)
out.print("wxx_string_cast");
emit_expr(out, expr);
}
}
function emit_varexpr(out, expr)
{
switch (expr.checkresult()) {
case REGint:
out.print("new WxxInteger");
break;
case REGfloat:
out.print("new WxxFloat");
break;
case REGstring:
out.print("new WxxString");
break;
}
emit_expr(out, expr);
}
function emit_typedexpr(out, expr, string type)
{
switch (type) {
case REGint:
emit_intexpr(out, expr);
break;
case REGstring:
emit_stringexpr(out, expr);
break;
case REGfloat:
emit_numexpr(out, expr);
break;
default:
emit_varexpr(out, expr);
}
}
//**********************************************************************
// Statements in functions
//**********************************************************************
function emitStatement(var out, :EmptyStatement st)
{
// Do nothing
}
function emitStatement(var out, :ExprStatement exprst)
{
for (var expr in exprst.expr)
emit_expr(out, expr);
}
function emitStatement(var out, :ConstStatement st)
{
}
function emit_nativetypestatement(out, st, string type, string nullinit)
{
string name = st.name;
var init = st.init;
int flags = 0;
string lexname = null;
var local = st.owner.getvar(name);
if (local != null) {
flags = local.getflags();
lexname = local.getlex();
}
int is_lex = (flags & VAR_is_lexical) || lexname != null;
// If lexical, declare a reference to the data struct
// Else, declare plain var
out.print(generatedType(type), " ");
if (is_lex)
out.print("&", name, " = ", DATA, "->", name);
else
out.print(name);
out.print(" = ");
if (init == null)
out.print(nullinit);
else
emit_typedexpr(out, init, type);
}
function emit_nativearraystatement(out, st, string arraytype)
{
string name = st.name;
var init = st.initarray;
var size = st.size;
out.print(Type_PMC, " ", name, "(&((*new Wxx");
if (size == null)
out.print("Resizable");
out.print(arraytype, "Array(");
if (size != null)
emit_intexpr(out, size);
else if (init != null) {
int ninit = elements(init);
out.print(ninit);
}
out.print("))");
if (init != null) {
int i = 0;
for (var item in init) {
out.print(".set_keyed(", i++, ARGSEP);
emit_expr(out, item);
out.print(")");
}
}
out.print("))");
}
function emitStatement(var out, :IntStatement st)
{
emit_nativetypestatement(out, st, REGint, "0");
}
function emitStatement(var out, :FloatStatement st)
{
emit_nativetypestatement(out, st, REGfloat, "0.0");
}
function emitStatement(var out, :StringStatement st)
{
emit_nativetypestatement(out, st, REGstring, "\"\"");
}
function emitStatement(var out, :IntArrayStatement st)
{
emit_nativearraystatement(out, st, "Integer");
}
function emitStatement(var out, :FloatArrayStatement st)
{
emit_nativearraystatement(out, st, "Float");
}
function emitStatement(var out, :StringArrayStatement st)
{
emit_nativearraystatement(out, st, "String");
}
function emitStatement(var out, :VarStatement st)
{
string name = st.name;
var init = st.init;
int flags = 0;
string lexname = null;
var local = st.owner.getvar(name);
if (local != null) {
flags = local.getflags();
lexname = local.getlex();
}
int is_lex = (flags & VAR_is_lexical) || lexname != null;
// If lexical, declare a reference to the data struct
// Else, declare plain var
out.print(Type_PMC, " ");
if (is_lex)
out.print("&", name, " = ", DATA, "->", name);
else
out.print(name);
if (init != null) {
out.print(" = ");
emit_expr(out, init);
}
}
function emitStatement(var out, :MultiAssignStatement st)
{
out.print("{\n WxxObjectPtr __m_1 = ");
emit_expr(out, st.expr);
out.print(";\n");
var params = st.params.params;
int i = 0;
for (var param in params) {
var data = param.getvar();
out.print(" ", param.name, " = __m_1.get_pmc_keyed(", i++, ");\n");
}
out.print("}\n");
}
function emitStatement(var out, :LabelStatement labelst)
{
out.print(labelst.name);
out.print(":\n");
}
function emitStatement(var out, :BreakStatement st)
{
out.print("break");
}
function emitStatement(var out, :ContinueStatement st)
{
out.print("continue");
}
function emitStatement(var out, :GotoStatement gotost)
{
out.print("goto ", gotost.label);
}
function emitStatement(var out, :IfStatement ifst)
{
var truebranch = ifst.truebranch;
var falsebranch = ifst.falsebranch;
out.print("if ");
emit_expr(out, ifst.condexpr);
out.print("\n{\n");
if (! truebranch.isempty())
emit_statement(out, truebranch);
if (! falsebranch.isempty()) {
out.print("} else {\n");
emit_statement(out, falsebranch);
}
out.print("}\n");
}
function emitStatement(var out, :SwitchStatement switchst)
{
var case_value = switchst.case_value;
var case_st = switchst.case_st;
out.print("do {\n", Type_PMC, " wxxswvar = ");
emit_expr(out, switchst.condition);
out.print(";\n");
int n = elements(case_st);
for (int i = 0; i < n; ++i) {
var caseval = case_value[i];
out.print ("if (wxxswvar == ");
emit_expr(out, caseval);
out.print(") {\n");
int nst = elements(case_st[i]);
int j;
for (j = 0; j < nst; ++j)
emit_statement(out, case_st[i][j]);
out.print("}\n");
}
var default_st = switchst.default_st;
int nst = elements(default_st);
int j;
for (j = 0; j < nst; ++j)
emit_statement(out, default_st[j]);
out.print("} while (false)\n");
}
function emitStatement(var out, :SwitchCaseStatement switchst)
{
var case_value = switchst.case_value;
var case_st = switchst.case_st;
int n = elements(case_st);
out.print("do {\n");
for (int i = 0; i < n; ++i) {
var caseval = case_value[i];
out.print ("if ");
emit_expr(out, caseval);
out.print(" {\n");
int nst = elements(case_st[i]);
int j;
for (j = 0; j < nst; ++j)
emit_statement(out, case_st[i][j]);
out.print("}\n");
}
var default_st = switchst.default_st;
int nst = elements(default_st);
int j;
for (j = 0; j < nst; ++j)
emit_statement(out, default_st[j]);
out.print("} while (false)\n");
}
function emitStatement(var out, :WhileStatement whilest)
{
out.print("while ");
emit_expr(out, whilest.condexpr);
out.print("\n{\n");
emit_statement(out, whilest.body);
out.print("}\n");
}
function emitStatement(var out, :DoStatement dost)
{
out.print("do {\n");
emit_statement(out, dost.body);
out.print("} while ");
emit_expr(out, dost.condexpr);
}
function emitStatement(var out, :TryStatement tryst)
{
out.print("try\n{\n");
emit_statement(out, tryst.stry);
out.print("}\ncatch (");
if (tryst.exname == null)
out.print("...");
else {
out.print(Type_PMC, " &", tryst.exname);
}
out.print(")\n{\n");
emit_statement(out, tryst.scatch);
out.print("}\n");
}
function emitStatement(var out, :ThrowStatement throwst)
{
var excep = throwst.excep;
out.print("throw ");
if (excep.checkresult() == REGstring) {
out.print("wxx_error(");
emit_expr(out, excep);
out.print(")");
}
else
emit_expr(out, excep);
}
function emitStatement(var out, :ForStatement forst)
{
var initializer = forst.initializer;
var condexpr = forst.condexpr;
var iteration = forst.iteration;
out.print("for (");
if (initializer != null)
emit_statement(out, initializer);
else
out.print(";");
if (condexpr != null)
emit_expr(out, condexpr);
out.print(";");
if (iteration != null) {
for (var expr in iteration)
emit_expr(out, expr);
}
out.print(") {\n");
emit_statement(out, forst.body);
out.print("}\n");
}
function emitStatement(var out, :ForeachStatement forst)
{
var varname = forst.varname;
var container = forst.container;
out.print("{\n", Type_PMC, " wxx_it = ");
string ctype = container.checkresult();
if (ctype == REGstring)
out.print(Type_PMC, "(");
emit_expr(out, container);
if (ctype == REGstring)
out.print(")");
out.print(".get_iter();\nwhile (bool(wxx_it)) {\n");
string type = forst.deftype == null ? "" : string(forst.deftype);
if (indexof("INSP", type) >= 0)
out.print(string(generatedType(type)) + " ");
out.print(varname);
out.print(" = wxx_it.shift_pmc();\n");
emit_statement(out, forst.body);
out.print("}\n}\n");
}
function emitStatement(var out, :ReturnStatement returnst)
{
var values = returnst.values;
int nargs = values == null ? 0 : int(values.numargs());
out.print("return ");
switch (nargs) {
case 0:
out.print(Type_PMC, "()");
break;
case 1:
var expr = values.getfreearg(0);
emit_expr(out, expr);
break;
default:
out.print(Type_PMC, "(&((new ", Type_PMCArray, "())->");
for (int i = 0; i < nargs; ++i) {
if (i)
out.print(".");
out.print("push(");
emit_expr(out, values.getfreearg(i));
out.print(")");
}
out.print("))");
}
}
function emitStatement(var out, :CompoundStatement compound)
{
out.print("{\n");
for_each(compound.statements, bindfirst(emit_statement, out));
out.print("}\n");
}
function emitStatement(var out, :MultiStatement mst)
{
for_each(mst.statements, bindfirst(emit_statement, out));
}
function emitStatement(var out, :UsingStatement st)
{
if (st.subid != null) {
var path = st.path;
string name = path[-1];
out.print("static ", Type_PMC, " (*const ", name,
")(const ", Type_PMCArray, " &wxx_fun_args) = ", st.subid);
}
}
function emitStatement(var out, var st)
{
switch {
case st instanceof ExternStatement:
case st instanceof StaticStatement:
case st instanceof UsingNamespaceStatement:
// Do nothing
break;
default:
if (__DEBUG__) cry("In " + __FUNCTION__);
throw WxxUnsupported(st);
}
}
function emit_statement(out, st)
{
emitStatement(out, st);
if (! (st instanceof CompoundStatement))
out.print(";\n");
}
//**********************************************************************
function emit_declare_function(out, funst)
{
string name = funst.name;
out.print(Type_PMC, " ", name,
"(const ", Type_PMCArray, " &wxx_fun_args);\n");
}
function emit_declare_method(out, funst)
{
string name = funst.name;
out.print("static ", Type_PMC, " ");
int isconstructor = false;
var cl = funst.owner;
string clname = cl.name;
if (clname == name)
isconstructor = true;
if (! isconstructor)
out.print(name);
else
out.print("__Winxedxx_constructor");
out.print("(", Type_PMC, " &, const ",
Type_PMCArray, " &wxx_fun_args);\n");
}
function emit_declare_function_subid(out, funst, key)
{
__ASSERT__(funst instanceof FunctionStatement);
string name = funst.name;
string subid = funst.makesubid();
// TODO: skip anonymous.
{
out.print("static ", Type_PMC,
" (*const ", subid, ")(const ",
Type_PMCArray, " &wxx_fun_args) = &");
if (elements(key) > 0)
out.print(join("::", key) + "::");
out.print(name, ";\n");
}
}
//**********************************************************************
function declareFunctionData(string name)
{
return "struct " + name + " : public WinxedXX::WxxFunctionVars";
}
function declareDataInstance(string name)
{
return name + " *" + DATA + " = new " + name + ";\n";
}
function declareDataVar(out, string varname, string vartype)
{
out.print(generatedType(vartype), " ", varname);
//out.print(";\n");
}
function getArgValue(out, string type, int i)
{
out.print(" = wxx_fun_args.get_pmc_keyed(", i, ")");
switch (type) {
case REGint:
out.print(".get_integer()");
break;
case REGfloat:
out.print(".get_number()");
break;
case REGstring:
out.print(".get_string()");
break;
}
out.print(";\n");
}
function setDataVarFromArg(out, string name, string type, int i)
{
out.print(DATA + "->", name);
getArgValue(out, type, i);
}
function declareReferenceToData(out, string name, string type)
{
out.print(generatedType(type), " &", name,
" = " + DATA + "->", name, ";\n");
}
function declareReferenceToOuter(out, string name, string type)
{
out.print(generatedType(type)," &", name,
" = " + DATA + ".", name, ";\n");
}
function foreachparam(params, funst, func)
{
for_each(params,
function(param)
{
string name = param.name;
string type = funst.getvar(name).gettype();
func(name, type);
}
);
}
function emit_declare_local(out, funst, string dataname)
{
string name = funst.name;
out.print("\n\n// declare local " + name + "\n\n");
out.print("\nclass " + name + " : public WxxInnerFunction\n{\n");
out.print(dataname + "& " + DATA + ";\n");
out.print("public:\n");
out.print(name + "(" + dataname + " & outer) : "+ DATA + "(outer)\n" );
out.print("{\n");
out.print("}\n");
out.print("\n", Type_PMC, " operator() (const ", Type_PMCArray, " &);\n" );
out.print("\n};\n");
}
function emit_define_local(out, funst, string dataname)
{
string name = funst.name;
out.print("\n", Type_PMC, " " + name +
"::operator() (const ", Type_PMCArray, " & wxx_fun_args)\n");
out.print("{\n" );
:EmitFunction emitlocal(funst);
emitlocal.emit_params(out);
var usedlexicals = funst.usedlexicals;
var locals = funst.locals;
for (string varname in locals) {
var local = locals[varname];
string reg = local.getreg();
if (exists usedlexicals[reg])
declareReferenceToOuter(out, varname, local.gettype());
}
emitlocal.emit_body(out);
out.print("\nreturn winxedxxnull;\n\n}\n");
}
class EmitFunction
{
var funst;
var name;
var dataname;
var isconstructor;
var localfuncs;
var body;
function EmitFunction(funst)
{
self.funst = funst;
string name = funst.name;
self.name = name;
int isconstructor = false;
if (funst.ismethod()) {
var cl = funst.owner;
string clname = cl.name;
if (clname == name)
isconstructor = true;
}
self.isconstructor = isconstructor;
self.localfuncs = funst.localfun;
self.body = funst.body;
string newname = isconstructor ? "__Winxedxx_constructor" : name;
string dataname = newname + DATA;
self.dataname = dataname;
}
function emit_params(out)
{
var funst = self.funst;
var params = funst.params;
if (params != null)
params = params.paramlist;
int nparams = params == null ? 0 : elements(params);
if (nparams != 0)
out.print("if (", nparams, " != wxx_fun_args.elements()) throw wxx_error(\"Wrong number of params\");\n");
if (self.localfuncs != null) {
string dataname = self.dataname;
out.print(declareDataInstance(dataname));
out.print("WxxDataHolder __holder(" + dataname + ")\n;");
for (int i = 0; i < nparams; ++i) {
var param = params[i];
string name = param.name;
setDataVarFromArg(out, name, funst.getvar(name).gettype(), i);
}
foreachparam(params, funst,
function(string name, string type)
{
declareReferenceToData(out, name, type);
}
);
}
else
{
for (int i = 0; i < nparams; ++i) {
var param = params[i];
string name = param.name;
string type = funst.getvar(name).gettype();
declareDataVar(out, name, type);
getArgValue(out, type, i);
}
}
}
function emit_body(out)
{
emit_statement(out, self.body);
}
}
function emit_FunctionStatement(out, funst, string prefix[optional])
{
:EmitFunction emitfun(funst);
string name = funst.name;
int ismethod = funst.ismethod();
int haslocals = funst.localfun != null;
//haslocals = true; // Testing
out.print("\n// function " + name + "\n\n");
int isconstructor = false;
if (ismethod) {
var cl = funst.owner;
string clname = cl.name;
if (clname == name)
isconstructor = true;
}
string newname = isconstructor ? "__Winxedxx_constructor" : name;
string dataname = newname + DATA;
var params = funst.params;
if (params != null)
params = params.paramlist;
int nparams = params == null ? 0 : elements(params);
if (haslocals) {
out.print(declareFunctionData(dataname));
out.print(" \n{\n");
foreachparam(params, funst,
function(string name, string type)
{
declareDataVar(out, name, type);
out.print(";\n");
}
);
var locals = funst.body.locals;
for_each(locals,
function(string name)
{
var local = locals[name];
if (local.isconst())
return;
declareDataVar(out, name, local.type);
out.print(";\n");
}
);
out.print("};\n\n");
for_each(funst.localfun,
bindlast(bindfirst(emit_declare_local, out), dataname));
}
out.print(Type_PMC, " ");
if (prefix != null)
out.print(prefix);
out.print(newname);
out.print("(");
if (ismethod)
out.print(Type_PMC, " &self, ");
out.print("const ", Type_PMCArray, " &wxx_fun_args");
out.print(")\n{\n");
emitfun.emit_params(out);
emitfun.emit_body(out);
out.print("\nreturn winxedxxnull;\n\n} // function " + name + "\n\n");
for_each(funst.localfun,
bindlast(bindfirst(emit_define_local, out), dataname));
}
//**************************************************************
function emit_classst(out, clst)
{
string name = clst.name;
var functions [];
for_each(clst.items, function(item)
{
if ((item instanceof FunctionStatement) ||
(item instanceof FunctionExtern))
push(functions, item);
});
out.print("\n// class " + name + "\n\n");
out.print("class ");
out.print(name);
out.print("\n{\n");
for_each(functions, bindfirst(emit_declare_method, out));
// Arguments for sprintf
var argname = [ name ];
out.print(sprintf(<<:CLINIT
static WxxClass * init_class()
{
WxxClass *cl = new WxxClass("%s");
cl->incref();
CLINIT:>>
, argname ));
var bases = clst.bases;
if (bases != null) {
for (var base in bases) {
out.print(" cl->addbase(");
out.print("wxxGetCurrentNamespace()");
var key = base.key;
int n = elements(key) - 1;
for (int i = 0; i < n; ++i)
out.print(".childNamespace(\"", key[i], "\")");
out.print(".getClass(\"", key[n], "\")");
out.print(");\n");
}
}
for_each(clst.members, function(string member)
{
out.print(" cl->addattribute(\"" + member + "\");\n");
}
);
for_each(functions, function(fun)
{
string fname = fun.name;
string cxxname = fname == name ? "__Winxedxx_constructor" : fname;
out.print(" cl->addfunction(\"" + fname +
"\", &" + name + "::" + cxxname + ");\n");
}
);
out.print(sprintf(<<:CLINITEND
wxxGetCurrentNamespace().setClass("%s", cl);
return cl;
}
CLINITEND:>>
, argname));
out.print("static WxxClass *clreg;\n};\n");
out.print("WxxClass * " + name + "::clreg = " + name + "::init_class();");
var prefix = name + "::";
for_each(functions, function(f)
{
emit_FunctionStatement(out, f, prefix);
}
);
}
function emit_namespacest(out, ns)
{
var emitit = [];
var functions = ns.items;
for (var item in functions) {
if (item instanceof FunctionStatement)
emitit.push(bindlast(emit_FunctionStatement, item));
else if (item instanceof FunctionExtern)
emitit.push(bindlast(emit_FunctionStatement, item));
else if (item instanceof NamespaceStatement)
emitit.push(bindlast(emit_namespacest, item));
else if (item instanceof ClassStatement)
emitit.push(bindlast(emit_classst, item));
else if (item instanceof MultiStatement)
emitit.push(bindlast(emit_statement, item));
else if (item instanceof ConstStatement)
/* ignored */;
else
throw WxxUnsupported(item);
}
if (elements(emitit)) {
int is_root = ns instanceof RootNamespace;
if (! is_root) {
out.print("namespace ", ns.name, "\n{\n");
out.print("static WxxNamespace &wxxGetCurrentNamespace();\n");
}
for (var doit in emitit)
doit(out);
if (! is_root)
out.print("\n} // ", ns.name, "\n");
}
}
function get_main(ns)
{
var functions = ns.funcont.functions;
var result = find_if(functions, function(string name) {
var fun = functions[name];
if (fun instanceof FunctionExtern)
return false;
var modifiers = fun.modifiers;
return (modifiers != null && modifiers.pick("main") != null) ||
name == "main";
});
return result != null ? string(result) : "";
}
//**********************************************************************
class NamespaceGen
{
var st;
var childs;
var functions;
var classes;
var items;
function NamespaceGen(var namespacest)
{
self.st = namespacest;
var functions [];
var genitems [];
var genchilds [];
for_each(namespacest.items,
function(item)
{
if (item instanceof FunctionStatement) {
push(functions, item);
push(genitems, item);
}
else if (item instanceof NamespaceStatement) {
:ChildNamespaceGen child(item);
push(genchilds, child);
push(genitems, child);
}
else
push(genitems, item);
});
self.functions = functions;
var childs [];
for (var childst in namespacest.namespaces) {
var child;
for (var ch in genchilds) {
if (ch.st === childst) {
child = ch;
break;
}
}
if (child == null)
child = new ChildNamespaceGen(childst);
push(childs, child);
}
self.childs = childs;
self.items = genitems;
}
function emit_declare(var out)
{
var ns = self.st;
var functions = self.functions;
var childs = self.childs;
var classes = self.st.classes;
if (elements(functions) || elements(childs) || elements(classes)) {
self.emit_nsopen(out);
for (var fun in functions)
emit_declare_function(out, fun);
// Declare child namespaces
for_each(childs, bindlast(bindmethod("emit_declare"), out));
self.emit_nsclose(out);
}
}
function emit_declare_funsubid(var out, var key)
{
for (var fun in self.functions)
emit_declare_function_subid(out, fun, key);
}
function emit_declare_childsubid(var out, var key)
{
for (var child in self.items) {
if (child instanceof NamespaceGen)
child.emit_declare_subid(out, key);
}
}
function emit_initialize(var out, string nsvarname)
{
for (var f in self.st.items) {
if (f instanceof FunctionStatement) {
string name = f.name;
if (f.subid != null) {
out.print(" ", nsvarname, ".set(\"", name, "\", ",
"WxxObjectPtr(new WxxSub(", f.subid, ", \"", name, "\"))",
");\n");
}
}
}
int counter = 0;
for (var child in self.childs) {
string name = child.name;
// Special case
if (name == "Winxed_Builtins")
continue;
string childvarname = nsvarname + "_child_" + string(counter++);
out.print(" WxxNamespace &", childvarname,
" = ", nsvarname, ".childNamespace(\"", name, "\");\n");
child.emit_initialize(out, childvarname);
}
}
function emit_namespace_initializers(var out)
{
var childs = {};
for (var child in self.childs) {
string name = child.name;
if (name == "Winxed_Builtins")
continue;
if (! exists childs[name])
childs[name] = child;
}
string nspath[];
for (var curns = self.st;
! (curns instanceof RootNamespace);
curns = curns.parent)
unshift(nspath, curns.name);
out.print("// Initializing ");
if (elements(nspath))
out.print("namespace ", join(".", nspath));
else
out.print("root namespace");
out.print("\n");
self.emit_nsopen(out);
out.print("static WxxNamespace &wxxGetCurrentNamespace()\n");
out.print("{\n");
out.print(" return getRootNamespace()");
for (string nsname in nspath)
out.print(".childNamespace(\"" + nsname + "\")");
out.print(";\n}\n");
for (string childname in childs) {
var child = childs[childname];
child.emit_namespace_initializers(out);
}
self.emit_nsclose(out);
}
}
class ChildNamespaceGen : NamespaceGen
{
var name;
function ChildNamespaceGen(var namespacest)
{
self.NamespaceGen(namespacest);
self.name = namespacest.name;
}
function emit_nsopen(var out)
{
out.print("namespace ", self.name, "\n{\n");
}
function emit_nsclose(var out)
{
out.print("\n} // ", self.name, "\n");
}
function emit_declare_subid(var out, var key)
{
key = clone(key);
push(key, self.name);
self.emit_declare_funsubid(out, key);
self.emit_declare_childsubid(out, key);
}
}
class RootNamespaceGen : NamespaceGen
{
function RootNamespaceGen(var namespacest)
{
self.NamespaceGen(namespacest);
}
function emit_nsopen(var out)
{
// Do nothing
}
function emit_nsclose(var out)
{
// Do nothing
}
function emit_declare_subid(var out)
{
string key[];
self.emit_declare_funsubid(out, key);
self.emit_declare_childsubid(out, key);
}
}
//**********************************************************************
// C++ code chunks for header, footer and main
//----------------------------------------------
const string HEADER = <<:HEADER
// Generated by winxedxx
#include "winxedxx.h"
#include "winxedxx_namespace.h"
#include "winxedxx_builtin_test_more.h"
namespace WinxedXX
{
static WxxNamespace &wxxGetCurrentNamespace();
HEADER:>>
;
//----------------------------------------------
const string FOOTER1 = <<:FOOTER1
static const int initializer = initialize();
} // namespace WinxedXX
FOOTER1:>>
;
//----------------------------------------------
const string CXXMAIN = <<:CXXMAIN
int main(int argc, char **argv)
{
try {
WinxedXX::WxxObjectPtr mainarg(new WinxedXX::WxxResizableStringArray(argc, argv));
WinxedXX::WxxObjectPtr objresult =
WinxedXX::%s(WinxedXX::WxxObjectArray().push(mainarg));
int result = objresult.is_null() ? 0 : int(objresult);
return result;
}
catch (WinxedXX::WxxObjectPtr &e) {
std::cerr << "Exception caught:\n\t";
std::cerr.flush();
std::cerr << e.get_string() << '\n';
return 1;
}
catch (const std::exception &e) {
std::cerr << "Error: " << e.what() << '\n';
return 1;
}
catch (const std::string &s) {
std::cerr << "Error(string): " << s << '\n';
return 1;
}
catch (const char *s) {
std::cerr << "Error(cstring): " << s << '\n';
return 1;
}
}
CXXMAIN:>>
;
//----------------------------------------------
//**********************************************************************
class Output
{
var handle;
var nsgen;
function Output(handle)
{
self.handle = handle;
}
function emit_initializer(var rootns)
{
self.print(<<:INITIALIZER
static int initialize()
{
WxxNamespace &rootns = getRootNamespace();
INITIALIZER:>>
);
self.nsgen.emit_initialize(self, "rootns");
self.emit_initialize_modules(rootns);
self.print(<<:INITIALIZEREND
return 1;
}
INITIALIZEREND:>>
);
}
function emit(parsed)
{
var ns = parsed.rootns;
string mainfunc = get_main(ns);
self.print(HEADER);
:RootNamespaceGen nsgen(ns);
self.nsgen = nsgen;
nsgen.emit_declare(self);
nsgen.emit_declare_subid(self);
emit_namespacest(self, ns);
nsgen.emit_namespace_initializers(self);
self.emit_initializer(parsed.rootns);
self.print(FOOTER1);
if (mainfunc != "")
self.print(sprintf(CXXMAIN, [ mainfunc ] ));
self.print("// End\n");
}
function emit_initialize_modules(var ns)
{
var loads = ns.loads;
for (string module in loads)
self.emit_load_module(module);
}
function emit_load_module(string modulename)
{
// Harcoded for a now, don't even check functions to import
if (modulename == "\"Test/More.pbc\"") {
self.print(" // Initialize builtin module ", modulename, "\n");
self.print(" WinxedXX::BuiltinModule::Test::More::initialize();\n");
self.print(" WxxNamespace &modTestMode = rootns.childNamespace(\"Test\").childNamespace(\"More\");\n");
self.print(" WxxObjectPtr fun;\n");
for (string objname in [ "diag", "plan", "done_testing", "ok", "nok", "is", "isnt", "is_null", "throws_type" ] ) {
objname = "\"" + objname + "\"";
self.print(" fun = modTestMode.get(",
objname, ");\n");
self.print(" if (fun.is_null()) fun = new WxxInteger(42);\n");
self.print(" rootns.set(", objname, ", fun);\n");
}
return;
}
cry("LOAD NON BUILTIN MODULE UNIMPLEMENTED: ", modulename);
}
function print(args[slurpy])
{
var handle = self.handle;
for (var arg in args)
handle.print(arg);
}
}
} // namespace WinxedXC.WinxedXX
//**********************************************************************
// End
Jump to Line
Something went wrong with that request. Please try again.