+/* ast.c
+
+ Extension module for the rfxswf library.
+ Part of the swftools package.
+
+ Copyright (c) 2009 Matthias Kramm <kramm@quiss.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "expr.h"
+#include "common.h"
+#include "tokenizer.h"
+
+#define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
+#define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
+
+#define READ_HEADER_LEFTRIGHT \
+ typedcode_t left = n->child[0]->type->read(n->child[0]);\
+ typedcode_t right = n->child[1]->type->read(n->child[1]);\
+ code_t*c=0;\
+ classinfo_t*t=0;
+
+#define READ_HEADER_ONE \
+ typedcode_t x = n->child[0]->type->read(n->child[0]);\
+ code_t*c=0;\
+ classinfo_t*t=0;
+
+#define EXEC_HEADER_ONE \
+ code_t* x = n->child[0]->type->exec(n->child[0]);\
+ code_t*c=0;\
+ classinfo_t*t=0;
+
+#define EXEC_HEADER_LEFTRIGHT \
+ code_t* left = n->child[0]->type->exec(n->child[0]);\
+ code_t* right = n->child[1]->type->exec(n->child[1]);\
+ code_t*c=0;\
+ classinfo_t*t=0;
+
+#define RET \
+ typedcode_t r; \
+ r.c = c; \
+ r.t = t; \
+ return r;
+
+static classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, nodetype_t*t)
+{
+ if(!type1 || !type2)
+ return registry_getanytype();
+ if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
+ return registry_getanytype();
+ if(type1 == type2)
+ return type1;
+ return registry_getanytype();
+}
+static char is_getlocal(code_t*c)
+{
+ if(!c || c->prev || c->next)
+ return 0;
+ return(c->opcode == OPCODE_GETLOCAL
+ || c->opcode == OPCODE_GETLOCAL_0
+ || c->opcode == OPCODE_GETLOCAL_1
+ || c->opcode == OPCODE_GETLOCAL_2
+ || c->opcode == OPCODE_GETLOCAL_3);
+}
+static int getlocalnr(code_t*c)
+{
+ if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
+ else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
+ else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
+ else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
+ else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
+ else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
+ return 0;
+}
+
+
+int gettempvar(); /* FIXME: we should use a function pointer here */
+
+
+static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore, char pushvalue)
+{
+ /* converts this:
+
+ [prefix code] [read instruction]
+
+ to this:
+
+ [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
+ */
+ if(in && in->opcode == OPCODE_COERCE_A) {
+ in = code_cutlast(in);
+ }
+ if(in->next)
+ syntaxerror("internal error");
+
+ /* chop off read instruction */
+ code_t*prefix = in;
+ code_t*r = in;
+ if(r->prev) {
+ prefix = r->prev;r->prev = 0;
+ prefix->next=0;
+ } else {
+ prefix = 0;
+ }
+
+ char use_temp_var = readbefore;
+
+ /* generate the write instruction, and maybe append a dup to the prefix code */
+ code_t* write = abc_nop(0);
+ if(r->opcode == OPCODE_GETPROPERTY) {
+ write->opcode = OPCODE_SETPROPERTY;
+ multiname_t*m = (multiname_t*)r->data[0];
+ write->data[0] = multiname_clone(m);
+ if(m->type == QNAME || m->type == MULTINAME) {
+ if(!justassign) {
+ prefix = abc_dup(prefix); // we need the object, too
+ }
+ use_temp_var = 1;
+ } else if(m->type == MULTINAMEL) {
+ if(!justassign) {
+ /* dupping two values on the stack requires 5 operations and one register-
+ couldn't adobe just have given us a dup2? */
+ int temp = gettempvar();
+ prefix = abc_setlocal(prefix, temp);
+ prefix = abc_dup(prefix);
+ prefix = abc_getlocal(prefix, temp);
+ prefix = abc_swap(prefix);
+ prefix = abc_getlocal(prefix, temp);
+ if(!use_temp_var);
+ prefix = abc_kill(prefix, temp);
+ }
+ use_temp_var = 1;
+ } else {
+ syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
+ }
+ } else if(r->opcode == OPCODE_GETSLOT) {
+ write->opcode = OPCODE_SETSLOT;
+ write->data[0] = r->data[0];
+ if(!justassign) {
+ prefix = abc_dup(prefix); // we need the object, too
+ }
+ use_temp_var = 1;
+ } else if(r->opcode == OPCODE_GETLOCAL) {
+ write->opcode = OPCODE_SETLOCAL;
+ write->data[0] = r->data[0];
+ } else if(r->opcode == OPCODE_GETLOCAL_0) {
+ write->opcode = OPCODE_SETLOCAL_0;
+ } else if(r->opcode == OPCODE_GETLOCAL_1) {
+ write->opcode = OPCODE_SETLOCAL_1;
+ } else if(r->opcode == OPCODE_GETLOCAL_2) {
+ write->opcode = OPCODE_SETLOCAL_2;
+ } else if(r->opcode == OPCODE_GETLOCAL_3) {
+ write->opcode = OPCODE_SETLOCAL_3;
+ } else if(r->opcode == OPCODE_GETSUPER) {
+ write->opcode = OPCODE_SETSUPER;
+ multiname_t*m = (multiname_t*)r->data[0];
+ write->data[0] = multiname_clone(m);
+ } else {
+ code_dump(r);
+ syntaxerror("illegal lvalue: can't assign a value to this expression");
+ }
+ code_t* c = 0;
+
+ int temp = -1;
+ if(!justassign) {
+ if(use_temp_var) {
+ /* with getproperty/getslot, we have to be extra careful not
+ to execute the read code twice, as it might have side-effects
+ (e.g. if the property is in fact a setter/getter combination)
+
+ So read the value, modify it, and write it again,
+ using prefix only once and making sure (by using a temporary
+ register) that the return value is what we just wrote */
+ temp = gettempvar();
+ c = code_append(c, prefix);
+ c = code_append(c, r);
+ if(pushvalue && readbefore) {
+ c = abc_dup(c);
+ c = abc_setlocal(c, temp);
+ }
+ c = code_append(c, middlepart);
+ if(pushvalue && !readbefore) {
+ c = abc_dup(c);
+ c = abc_setlocal(c, temp);
+ }
+ c = code_append(c, write);
+ if(pushvalue) {
+ c = abc_getlocal(c, temp);
+ c = abc_kill(c, temp);
+ }
+ } else {
+ /* if we're allowed to execute the read code twice *and*
+ the middlepart doesn't modify the code, things are easier.
+ */
+ //c = code_append(c, prefix);
+ if(prefix) syntaxerror("internal error (prefix)");
+ code_t* r2 = 0;
+ if(pushvalue) {
+ r2 = code_dup(r);
+ }
+ c = code_append(c, r);
+ c = code_append(c, middlepart);
+ c = code_append(c, write);
+ if(pushvalue) {
+ c = code_append(c, r2);
+ }
+ }
+ } else {
+ /* even smaller version: overwrite the value without reading
+ it out first */
+ if(!use_temp_var) {
+ if(prefix) {
+ c = code_append(c, prefix);
+ c = abc_dup(c);
+ }
+ c = code_append(c, middlepart);
+ c = code_append(c, write);
+ if(pushvalue) {
+ c = code_append(c, r);
+ }
+ } else {
+ code_free(r);r=0;
+ temp = gettempvar();
+ if(prefix) {
+ c = code_append(c, prefix);
+ }
+ c = code_append(c, middlepart);
+ if(pushvalue) {
+ c = abc_dup(c);
+ c = abc_setlocal(c, temp);
+ }
+ c = code_append(c, write);
+ if(pushvalue) {
+ c = abc_getlocal(c, temp);
+ c = abc_kill(c, temp);
+ }
+ }
+ }
+ return c;
+}
+
+code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to);
+
+// -------------------------- x + y -----------------------------------
+
+typedcode_t node_plus_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_plus_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+ if(BOTH_INT(left.t, right.t)) {
+ c = abc_add_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_add(c);
+ t = join_types(left.t,right.t,n->type);
+ }
+ RET;
+}
+code_t* node_plus_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_plus =
+{
+name:"plus",
+flags:NODE_HAS_CHILDREN,
+write:node_plus_write,
+read:node_plus_read,
+exec:node_plus_exec,
+};
+
+// -------------------------- x - y -----------------------------------
+
+typedcode_t node_minus_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_minus_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+ if(BOTH_INT(left.t,right.t)) {
+ c = abc_subtract_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_subtract(c);
+ t = TYPE_NUMBER;
+ }
+ RET;
+}
+code_t* node_minus_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_minus =
+{
+name:"minus",
+flags:NODE_HAS_CHILDREN,
+write: node_minus_write,
+read: node_minus_read,
+exec: node_minus_exec
+};
+
+// ---------------------------- ++x -----------------------------------
+
+typedcode_t node_lplusplus_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_lplusplus_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ t = x.t;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_inclocal_i(c, nr);
+ c = abc_getlocal(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_inclocal(c, nr);
+ c = abc_getlocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_increment_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_increment(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t);
+ c = toreadwrite(x.c, c, 0, 0, 1);
+ t = x.t;
+ }
+ RET
+}
+code_t* node_lplusplus_exec(node_t*n)
+{
+ typedcode_t x = n->child[0]->type->read(n->child[0]);
+ code_t*c=0;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_inclocal_i(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_inclocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ classinfo_t*t;
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_increment_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_increment(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t); //convert back to original type
+ c = toreadwrite(x.c, c, 0, 0, 0);
+ t = x.t;
+ }
+ return c;
+}
+nodetype_t node_lplusplus =
+{
+name: "lplusplus",
+flags:NODE_HAS_CHILDREN,
+write: node_lplusplus_write,
+read: node_lplusplus_read,
+exec: node_lplusplus_exec
+};
+
+
+// ---------------------------- --x -----------------------------------
+
+typedcode_t node_lminusminus_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_lminusminus_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ t = x.t;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_declocal_i(c, nr);
+ c = abc_getlocal(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_declocal(c, nr);
+ c = abc_getlocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_decrement_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_decrement(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t);
+ c = toreadwrite(x.c, c, 0, 0, 1);
+ t = x.t;
+ }
+ RET
+}
+code_t* node_lminusminus_exec(node_t*n)
+{
+ typedcode_t x = n->child[0]->type->read(n->child[0]);
+ code_t*c=0;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_declocal_i(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_declocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ classinfo_t*t;
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_decrement_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_decrement(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t); //convert back to original type
+ c = toreadwrite(x.c, c, 0, 0, 0);
+ t = x.t;
+ }
+ return c;
+}
+nodetype_t node_lminusminus =
+{
+name: "lminusminus",
+flags:NODE_HAS_CHILDREN,
+write: node_lminusminus_write,
+read: node_lminusminus_read,
+exec: node_lminusminus_exec
+};
+
+
+
+// ---------------------------- x++ -----------------------------------
+
+typedcode_t node_rplusplus_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_rplusplus_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ t = x.t;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_getlocal(0, nr);
+ c = abc_inclocal_i(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_getlocal(0, nr);
+ c = abc_inclocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_increment_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_increment(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t);
+ c = toreadwrite(x.c, c, 0, 1, 1);
+ t = x.t;
+ }
+ RET
+}
+code_t* node_rplusplus_exec(node_t*n)
+{
+ typedcode_t x = n->child[0]->type->read(n->child[0]);
+ code_t*c=0;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_inclocal_i(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_inclocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ classinfo_t*t;
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_increment_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_increment(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t); //convert back to original type
+ c = toreadwrite(x.c, c, 0, 1, 0);
+ t = x.t;
+ }
+ return c;
+}
+nodetype_t node_rplusplus =
+{
+name: "rplusplus",
+flags:NODE_HAS_CHILDREN,
+write: node_rplusplus_write,
+read: node_rplusplus_read,
+exec: node_rplusplus_exec
+};
+
+// ---------------------------- x-- -----------------------------------
+
+typedcode_t node_rminusminus_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_rminusminus_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ t = x.t;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_getlocal(0, nr);
+ c = abc_declocal_i(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_getlocal(0, nr);
+ c = abc_declocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_decrement_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_decrement(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t);
+ c = toreadwrite(x.c, c, 0, 1, 1);
+ t = x.t;
+ }
+ RET
+}
+code_t* node_rminusminus_exec(node_t*n)
+{
+ typedcode_t x = n->child[0]->type->read(n->child[0]);
+ code_t*c=0;
+ if(is_getlocal(x.c) && (TYPE_IS_INT(x.t) || TYPE_IS_NUMBER(x.t))) {
+ int nr = getlocalnr(x.c);
+ code_free(x.c);x.c=0;
+ if(TYPE_IS_INT(x.t)) {
+ c = abc_declocal_i(c, nr);
+ } else if(TYPE_IS_NUMBER(x.t)) {
+ c = abc_declocal(c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ classinfo_t*t;
+ if(TYPE_IS_INT(x.t) || TYPE_IS_UINT(x.t)) {
+ c = abc_decrement_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_decrement(c);
+ t = TYPE_NUMBER;
+ }
+ c = converttype(c, t, x.t); //convert back to original type
+ c = toreadwrite(x.c, c, 0, 1, 0);
+ t = x.t;
+ }
+ return c;
+}
+nodetype_t node_rminusminus =
+{
+name: "rminusminus",
+flags:NODE_HAS_CHILDREN,
+write: node_rminusminus_write,
+read: node_rminusminus_read,
+exec: node_rminusminus_exec
+};
+
+// ---------------------------- x*y -----------------------------------
+
+typedcode_t node_multiply_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_multiply_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ if(BOTH_INT(left.t,right.t)) {
+ c = abc_multiply_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_multiply(c);
+ t = TYPE_NUMBER;
+ }
+ RET
+}
+code_t* node_multiply_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_multiply =
+{
+name: "multiply",
+flags:NODE_HAS_CHILDREN,
+write: node_multiply_write,
+read: node_multiply_read,
+exec: node_multiply_exec
+};
+
+// ---------------------------- x/y -----------------------------------
+
+typedcode_t node_div_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_div_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+ c = abc_divide(c);
+ t = TYPE_NUMBER;
+ RET
+}
+code_t* node_div_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_div =
+{
+name: "div",
+flags:NODE_HAS_CHILDREN,
+write: node_div_write,
+read: node_div_read,
+exec: node_div_exec
+};
+
+// ---------------------------- x%y -----------------------------------
+
+typedcode_t node_mod_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_mod_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+ c = abc_modulo(c);
+ t = TYPE_NUMBER;
+ RET
+}
+code_t* node_mod_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_mod =
+{
+name: "mod",
+flags:NODE_HAS_CHILDREN,
+write: node_mod_write,
+read: node_mod_read,
+exec: node_mod_exec
+};
+
+// ---------------------------- x<y -----------------------------------
+
+typedcode_t node_lt_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_lt_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_lessthan(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_lt_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_lt =
+{
+name: "lt",
+flags:NODE_HAS_CHILDREN,
+write: node_lt_write,
+read: node_lt_read,
+exec: node_lt_exec
+};
+
+// ---------------------------- x>y -----------------------------------
+
+typedcode_t node_gt_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_gt_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_greaterthan(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_gt_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_gt =
+{
+name: "gt",
+flags:NODE_HAS_CHILDREN,
+write: node_gt_write,
+read: node_gt_read,
+exec: node_gt_exec
+};
+
+// ---------------------------- x<=y ----------------------------------
+
+typedcode_t node_le_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_le_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_lessequals(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_le_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_le = //<=
+{
+name: "le",
+flags:NODE_HAS_CHILDREN,
+write: node_le_write,
+read: node_le_read,
+exec: node_le_exec
+};
+
+// ---------------------------- x>=y ----------------------------------
+
+typedcode_t node_ge_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_ge_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_greaterequals(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_ge_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_ge = //>=
+{
+name: "ge",
+flags:NODE_HAS_CHILDREN,
+write: node_ge_write,
+read: node_ge_read,
+exec: node_ge_exec
+};
+
+// ---------------------------- x==y ----------------------------------
+
+typedcode_t node_eqeq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_eqeq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_equals(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_eqeq_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_eqeq = //==
+{
+name: "eqeq",
+flags:NODE_HAS_CHILDREN,
+write: node_eqeq_write,
+read: node_eqeq_read,
+exec: node_eqeq_exec
+};
+
+// --------------------------- x===y ----------------------------------
+
+typedcode_t node_eqeqeq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_eqeqeq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_strictequals(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_eqeqeq_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_eqeqeq = //===
+{
+name: "eqeqeq",
+flags:NODE_HAS_CHILDREN,
+write: node_eqeqeq_write,
+read: node_eqeqeq_read,
+exec: node_eqeqeq_exec
+};
+
+// --------------------------- x!==y ----------------------------------
+
+typedcode_t node_noteqeq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_noteqeq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_strictequals(c);
+ c = abc_not(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_noteqeq_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_noteqeq = //!==
+{
+name: "noteqeq",
+flags:NODE_HAS_CHILDREN,
+write: node_noteqeq_write,
+read: node_noteqeq_read,
+exec: node_noteqeq_exec
+};
+
+// --------------------------- x!=y ----------------------------------
+
+typedcode_t node_noteq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_noteq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_equals(c);
+ c = abc_not(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_noteq_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_noteq = //!=
+{
+name: "noteq",
+flags:NODE_HAS_CHILDREN,
+write: node_noteq_write,
+read: node_noteq_read,
+exec: node_noteq_exec
+};
+
+// --------------------------- x||y ----------------------------------
+
+typedcode_t node_oror_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_oror_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ t = join_types(left.t, right.t, n->type);
+ c = left.c;
+ c = converttype(c, left.t, t);
+ c = abc_dup(c);
+ code_t*jmp = c = abc_iftrue(c, 0);
+ c = cut_last_push(c);
+ c = code_append(c, right.c);
+ c = converttype(c, right.t, t);
+ code_t*label = c = abc_label(c);
+ jmp->branch = label;
+ RET;
+}
+code_t* node_oror_exec(node_t*n)
+{
+ typedcode_t left = n->child[0]->type->read(n->child[0]);
+ code_t* right = n->child[1]->type->exec(n->child[1]);
+ code_t*c = left.c;
+ code_t*jmp = c = abc_iftrue(c, 0);
+ c = code_append(c, right);
+ code_t*label = c = abc_label(c);
+ jmp->branch = label;
+ return c;
+}
+nodetype_t node_oror = //||
+{
+name: "oror",
+flags:NODE_HAS_CHILDREN,
+write: node_oror_write,
+read: node_oror_read,
+exec: node_oror_exec
+};
+
+// --------------------------- x&&y ----------------------------------
+
+typedcode_t node_andand_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_andand_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ t = join_types(left.t, right.t, &node_andand);
+ c = left.c;
+ c = converttype(c, left.t, t);
+ c = abc_dup(c);
+ code_t*jmp = c = abc_iffalse(c, 0);
+ c = cut_last_push(c);
+ c = code_append(c,right.c);
+ c = converttype(c, right.t, t);
+ code_t*label = c = abc_label(c);
+ jmp->branch = label;
+ RET;
+}
+code_t* node_andand_exec(node_t*n)
+{
+ typedcode_t left = n->child[0]->type->read(n->child[0]);\
+ code_t* right = n->child[1]->type->exec(n->child[1]);\
+ code_t*c = left.c;
+ code_t*jmp = c = abc_iffalse(c, 0);
+ c = code_append(c, right);
+ code_t*label = c = abc_label(c);
+ jmp->branch = label;
+ return c;
+}
+nodetype_t node_andand = //&&
+{
+name: "andand",
+flags:NODE_HAS_CHILDREN,
+write: node_andand_write,
+read: node_andand_read,
+exec: node_andand_exec
+};
+
+// ----------------------------- !x -----------------------------------
+
+typedcode_t node_not_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_not_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ c = x.c;
+ c = abc_not(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_not_exec(node_t*n)
+{
+ EXEC_HEADER_ONE;
+ return x;
+}
+nodetype_t node_not =
+{
+name: "not",
+flags:NODE_HAS_CHILDREN,
+write: node_not_write,
+read: node_not_read,
+exec: node_not_exec
+};
+
+// ----------------------------- ~x -----------------------------------
+
+typedcode_t node_bitnot_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_bitnot_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ c = x.c;
+ c = abc_bitnot(c);
+ t = TYPE_INT;
+ RET;
+}
+code_t* node_bitnot_exec(node_t*n)
+{
+ EXEC_HEADER_ONE;
+ return x;
+}
+nodetype_t node_bitnot =
+{
+name: "bitnot",
+flags:NODE_HAS_CHILDREN,
+write: node_bitnot_write,
+read: node_bitnot_read,
+exec: node_bitnot_exec
+};
+
+// ----------------------------- x&y -----------------------------------
+
+typedcode_t node_bitand_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_bitand_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_bitand(c);
+ t = TYPE_INT;
+ RET;
+}
+code_t* node_bitand_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_bitand =
+{
+name: "bitand",
+flags:NODE_HAS_CHILDREN,
+write: node_bitand_write,
+read: node_bitand_read,
+exec: node_bitand_exec
+};
+
+// ----------------------------- x^y -----------------------------------
+
+typedcode_t node_bitxor_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_bitxor_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_bitxor(c);
+ t = TYPE_INT;
+ RET;
+}
+code_t* node_bitxor_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_bitxor =
+{
+name: "bitxor",
+flags:NODE_HAS_CHILDREN,
+write: node_bitxor_write,
+read: node_bitxor_read,
+exec: node_bitxor_exec
+};
+
+// ----------------------------- x|y -----------------------------------
+
+typedcode_t node_bitor_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_bitor_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_bitor(c);
+ t = TYPE_INT;
+ RET;
+}
+code_t* node_bitor_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_bitor =
+{
+name: "bitor",
+flags:NODE_HAS_CHILDREN,
+write: node_bitor_write,
+read: node_bitor_read,
+exec: node_bitor_exec
+};
+
+// ---------------------------- x>>y -----------------------------------
+
+typedcode_t node_shr_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_shr_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_rshift(c);
+ t = TYPE_INT;
+ RET;
+}
+code_t* node_shr_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_shr = //>>
+{
+name: "shr",
+flags:NODE_HAS_CHILDREN,
+write: node_shr_write,
+read: node_shr_read,
+exec: node_shr_exec
+};
+
+// ---------------------------- x<<y -----------------------------------
+
+typedcode_t node_shl_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_shl_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_lshift(c);
+ t = TYPE_INT;
+ RET;
+}
+code_t* node_shl_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_shl = //<<
+{
+name: "shl",
+flags:NODE_HAS_CHILDREN,
+write: node_shl_write,
+read: node_shl_read,
+exec: node_shl_exec
+};
+
+// ---------------------------- x>>>y -----------------------------------
+
+typedcode_t node_ushr_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_ushr_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_urshift(c);
+ t = TYPE_INT;
+ RET;
+}
+code_t* node_ushr_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_ushr = //>>>
+{
+name: "ushr",
+flags:NODE_HAS_CHILDREN,
+write: node_ushr_write,
+read: node_ushr_read,
+exec: node_ushr_exec
+};
+
+// ---------------------------- x in y ----------------------------------
+
+typedcode_t node_in_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_in_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c,right.c);
+ c = abc_in(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_in_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_in = //in
+{
+name: "in",
+flags:NODE_HAS_CHILDREN,
+write: node_in_write,
+read: node_in_read,
+exec: node_in_exec
+};
+
+// ---------------------------- x as y ----------------------------------
+
+typedcode_t node_as_write(node_t*n)
+{
+ /* ? */
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_as_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+ c = abc_astypelate(c);
+ t = TYPE_ANY;
+ RET;
+}
+code_t* node_as_exec(node_t*n)
+{
+ /* we assume here that "as" doesn't have side-effects (like
+ early run time type checking) */
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_as = //as
+{
+name: "as",
+flags:NODE_HAS_CHILDREN,
+write: node_as_write,
+read: node_as_read,
+exec: node_as_exec
+};
+
+// ------------------------- x instanceof y -----------------------------
+
+typedcode_t node_instanceof_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_instanceof_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+ c = abc_instanceof(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_instanceof_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_instanceof = //instanceof
+{
+name: "instanceof",
+flags:NODE_HAS_CHILDREN,
+write: node_instanceof_write,
+read: node_instanceof_read,
+exec: node_instanceof_exec
+};
+
+// ------------------------- x is y --------------------------------------
+
+typedcode_t node_is_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_is_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+ c = abc_istypelate(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_is_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_is = //is
+{
+name: "is",
+flags:NODE_HAS_CHILDREN,
+write: node_is_write,
+read: node_is_read,
+exec: node_is_exec
+};
+
+// ------------------------- x[y] --------------------------------------
+
+typedcode_t node_arraylookup_write(node_t*n)
+{
+ syntaxerror("not implemented yet");
+}
+typedcode_t node_arraylookup_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = code_append(left.c, right.c);
+
+ /* XXX not sure whether this access logic is correct */
+ namespace_t ns = {left.t?left.t->access:ACCESS_PACKAGE, ""};
+ namespace_set_t nsset;
+ namespace_list_t l;l.next = 0;
+ nsset.namespaces = &l;
+ l.namespace = &ns;
+ multiname_t m = {MULTINAMEL, 0, &nsset, 0};
+
+ c = abc_getproperty2(c, &m);
+ t = 0; // array elements have unknown type
+ RET;
+}
+code_t* node_arraylookup_exec(node_t*n)
+{
+ EXEC_HEADER_LEFTRIGHT;
+ return code_append(left, right);
+}
+nodetype_t node_arraylookup =
+{
+name: "arraylookup",
+flags:NODE_HAS_CHILDREN,
+write: node_arraylookup_write,
+read: node_arraylookup_read,
+exec: node_arraylookup_exec
+};
+
+// ------------------------- typeof(x) ------------------------------------
+
+typedcode_t node_typeof_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_typeof_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ c = x.c;
+ c = abc_typeof(c);
+ t = TYPE_BOOLEAN;
+ RET;
+}
+code_t* node_typeof_exec(node_t*n)
+{
+ EXEC_HEADER_ONE;
+ return x;
+}
+nodetype_t node_typeof = //typeof
+{
+name: "typeof",
+flags:NODE_HAS_CHILDREN,
+write: node_typeof_write,
+read: node_typeof_read,
+exec: node_typeof_exec
+};
+
+// ------------------------- (void)(x) ------------------------------------
+
+typedcode_t node_void_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_void_read(node_t*n)
+{
+ code_t*c = n->type->exec(n);
+ c = abc_pushundefined(c);
+ classinfo_t*t = TYPE_ANY;
+ RET;
+}
+code_t* node_void_exec(node_t*n)
+{
+ EXEC_HEADER_ONE;
+ return x;
+}
+nodetype_t node_void = //void
+{
+name: "void",
+flags:NODE_HAS_CHILDREN,
+write: node_void_write,
+read: node_void_read,
+exec: node_void_exec
+};
+
+// ---------------------------- -x ----------------------------------------
+
+typedcode_t node_neg_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_neg_read(node_t*n)
+{
+ READ_HEADER_ONE;
+ c = x.c;
+ if(IS_INT(x.t)) {
+ c = abc_negate_i(c);
+ t = TYPE_INT;
+ } else {
+ c = abc_negate(c);
+ t = TYPE_NUMBER;
+ }
+ RET;
+}
+code_t* node_neg_exec(node_t*n)
+{
+ EXEC_HEADER_ONE;
+ return x;
+}
+nodetype_t node_neg = //-
+{
+name: "neg",
+flags:NODE_HAS_CHILDREN,
+write: node_neg_write,
+read: node_neg_read,
+exec: node_neg_exec
+};
+
+// ---------------------------- x*=y ----------------------------------------
+
+typedcode_t node_muleq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_muleq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ classinfo_t*f = 0;
+ if(BOTH_INT(left.t,right.t)) {
+ c=abc_multiply_i(c);
+ f = TYPE_INT;
+ } else {
+ c=abc_multiply(c);
+ f = TYPE_NUMBER;
+ }
+ c=converttype(c, f, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_muleq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ classinfo_t*f = 0;
+ if(BOTH_INT(left.t,right.t)) {
+ c=abc_multiply_i(c);
+ f = TYPE_INT;
+ } else {
+ c=abc_multiply(c);
+ f = TYPE_NUMBER;
+ }
+ c = converttype(c, f, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_muleq =
+{
+name: "muleq",
+flags:NODE_HAS_CHILDREN,
+write: node_muleq_write,
+read: node_muleq_read,
+exec: node_muleq_exec
+};
+
+// ---------------------------- x%=y ----------------------------------------
+
+typedcode_t node_modeq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_modeq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_modulo(right.c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_modeq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_modulo(right.c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_modeq = //%=
+{
+name: "modeq",
+flags:NODE_HAS_CHILDREN,
+write: node_modeq_write,
+read: node_modeq_read,
+exec: node_modeq_exec
+};
+
+// ---------------------------- x<<=y ----------------------------------------
+
+typedcode_t node_shleq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_shleq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_lshift(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_shleq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_lshift(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_shleq = //<<=
+{
+name: "shleq",
+flags:NODE_HAS_CHILDREN,
+write: node_shleq_write,
+read: node_shleq_read,
+exec: node_shleq_exec
+};
+
+// ---------------------------- x>>=y ----------------------------------------
+
+typedcode_t node_shreq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_shreq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_rshift(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_shreq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_rshift(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_shreq = //>>=
+{
+name: "shreq",
+flags:NODE_HAS_CHILDREN,
+write: node_shreq_write,
+read: node_shreq_read,
+exec: node_shreq_exec
+};
+
+// --------------------------- x>>>=y ----------------------------------------
+
+typedcode_t node_ushreq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_ushreq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_urshift(right.c);
+ c = converttype(c, TYPE_UINT, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_ushreq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_urshift(right.c);
+ c = converttype(c, TYPE_UINT, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_ushreq = //>>>=
+{
+name: "ushreq",
+flags:NODE_HAS_CHILDREN,
+write: node_ushreq_write,
+read: node_ushreq_read,
+exec: node_ushreq_exec
+};
+
+// --------------------------- x/=y ----------------------------------------
+
+typedcode_t node_diveq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_diveq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_divide(right.c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_diveq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_divide(right.c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_diveq =
+{
+name: "diveq",
+flags:NODE_HAS_CHILDREN,
+write: node_diveq_write,
+read: node_diveq_read,
+exec: node_diveq_exec
+};
+
+// --------------------------- x|=y ----------------------------------------
+
+typedcode_t node_bitoreq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_bitoreq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_bitor(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_bitoreq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_bitor(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_bitoreq = //|=
+{
+name: "bitoreq",
+flags:NODE_HAS_CHILDREN,
+write: node_bitoreq_write,
+read: node_bitoreq_read,
+exec: node_bitoreq_exec
+};
+
+// --------------------------- x^=y ----------------------------------------
+
+typedcode_t node_bitxoreq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_bitxoreq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_bitxor(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_bitxoreq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_bitxor(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_bitxoreq = //^=
+{
+name: "bitxoreq",
+flags:NODE_HAS_CHILDREN,
+write: node_bitxoreq_write,
+read: node_bitxoreq_read,
+exec: node_bitxoreq_exec
+};
+
+// --------------------------- x&=y ----------------------------------------
+
+typedcode_t node_bitandeq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_bitandeq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_bitand(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_bitandeq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = abc_bitand(right.c);
+ c = converttype(c, TYPE_INT, left.t);
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_bitandeq = //^=
+{
+name: "bitandeq",
+flags:NODE_HAS_CHILDREN,
+write: node_bitandeq_write,
+read: node_bitandeq_read,
+exec: node_bitandeq_exec
+};
+
+// --------------------------- x+=y ----------------------------------------
+
+typedcode_t node_pluseq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_pluseq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ if(TYPE_IS_INT(left.t)) {
+ c = abc_add_i(c);
+ } else {
+ c = abc_add(c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ }
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_pluseq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ if(TYPE_IS_INT(left.t)) {
+ c = abc_add_i(c);
+ } else {
+ c = abc_add(c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ }
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_pluseq = //+=
+{
+name: "pluseq",
+flags:NODE_HAS_CHILDREN,
+write: node_pluseq_write,
+read: node_pluseq_read,
+exec: node_pluseq_exec
+};
+
+// --------------------------- x-=y ----------------------------------------
+
+typedcode_t node_minuseq_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_minuseq_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ if(TYPE_IS_INT(left.t)) {
+ c = abc_subtract_i(c);
+ } else {
+ c = abc_subtract(c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ }
+ c = toreadwrite(left.c, c, 0, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_minuseq_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ if(TYPE_IS_INT(left.t)) {
+ c = abc_subtract_i(c);
+ } else {
+ c = abc_subtract(c);
+ c = converttype(c, TYPE_NUMBER, left.t);
+ }
+ return toreadwrite(left.c, c, 0, 0, 0);
+}
+nodetype_t node_minuseq = //-=
+{
+name: "minuseq",
+flags:NODE_HAS_CHILDREN,
+write: node_minuseq_write,
+read: node_minuseq_read,
+exec: node_minuseq_exec
+};
+
+// --------------------------- x=y -----------------------------------------
+
+typedcode_t node_assign_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_assign_read(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ c = converttype(c, right.t, left.t);
+ c = toreadwrite(left.c, c, 1, 0, 1);
+ t = left.t;
+ RET;
+}
+code_t* node_assign_exec(node_t*n)
+{
+ READ_HEADER_LEFTRIGHT;
+ c = right.c;
+ c = converttype(c, right.t, left.t);
+ return toreadwrite(left.c, c, 1, 0, 0);
+}
+nodetype_t node_assign =
+{
+name: "assign",
+flags:NODE_HAS_CHILDREN,
+write: node_assign_write,
+read: node_assign_read,
+exec: node_assign_exec
+};
+
+// --------------------------- x?y1:y2 --------------------------------------
+
+typedcode_t node_tenary_write(node_t*n)
+{
+ /* TODO: this might actually be kinda useful.
+ (global?global.x:this.x) = 3;
+ */
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_tenary_read(node_t*n)
+{
+ typedcode_t cond = n->child[0]->type->read(n->child[0]);
+ typedcode_t left = n->child[1]->type->read(n->child[1]);
+ typedcode_t right = n->child[2]->type->read(n->child[2]);
+ classinfo_t*t = join_types(left.t,right.t,&node_tenary);
+ code_t* c = cond.c;
+ code_t*j1 = c = abc_iffalse(c, 0);
+ c = code_append(c, left.c);
+ c = converttype(c, left.t, t);
+ code_t*j2 = c = abc_jump(c, 0);
+ c = j1->branch = abc_label(c);
+ c = code_append(c, right.c);
+ c = converttype(c, right.t, t);
+ c = j2->branch = abc_label(c);
+ RET;
+}
+code_t* node_tenary_exec(node_t*n)
+{
+ typedcode_t cond = n->child[0]->type->read(n->child[0]);
+ code_t* left = n->child[1]->type->exec(n->child[1]);
+ code_t* right = n->child[2]->type->exec(n->child[2]);
+ code_t* c = cond.c;
+ code_t*j1 = c = abc_iffalse(c, 0);
+ c = code_append(c, left);
+ code_t*j2 = c = abc_jump(c, 0);
+ c = j1->branch = abc_label(c);
+ c = code_append(c, right);
+ c = j2->branch = abc_label(c);
+ return c;
+}
+nodetype_t node_tenary =
+{
+name: "tenary",
+flags:NODE_HAS_CHILDREN,
+write: node_tenary_write,
+read: node_tenary_read,
+exec: node_tenary_exec
+};
+
+// ---------------------------- comma ----------------------------------------
+
+typedcode_t node_comma_write(node_t*n)
+{
+ syntaxerror("can't assign to this expression");
+}
+typedcode_t node_comma_read(node_t*n)
+{
+ code_t*c = 0;
+ classinfo_t*t = 0;
+ int i;
+ for(i=0;i<n->num_children-1;i++) {
+ c = code_append(c, n->child[i]->type->exec(n->child[i]));
+ }
+ typedcode_t o = n->child[i]->type->read(n->child[i]);
+ c = code_append(c, o.c);
+ t = o.t;
+ RET;
+}
+code_t* node_comma_exec(node_t*n)
+{
+ int t;
+ code_t*c = 0;
+ for(t=0;t<n->num_children;t++) {
+ c = code_append(c, n->child[t]->type->exec(n->child[t]));
+ }
+ return c;
+}
+nodetype_t node_comma =
+{
+name: "expr",
+flags: NODE_HAS_CHILDREN,
+write: node_comma_write,
+read: node_comma_read,
+exec: node_comma_exec
+};
+
+
+#if 0
+// -------------------------- new x -----------------------------------
+
+typedcode_t node_new_write(node_t*n)
+{
+}
+typedcode_t node_new_read(node_t*n)
+{
+}
+code_t* node_new_exec(node_t*n)
+{
+}
+nodetype_t node_new = //new
+{
+write: node_new_write,
+read: node_new_read,
+exec: node_new_exec
+};
+
+// ------------------------ delete x ----------------------------------
+
+typedcode_t node_delete_write(node_t*n)
+{
+}
+typedcode_t node_delete_read(node_t*n)
+{
+}
+code_t* node_delete_exec(node_t*n)
+{
+}
+nodetype_t node_delete = //delete
+{
+write: node_delete_write,
+read: node_delete_read,
+exec: node_delete_exec
+};
+
+// ---------------------------- x.y -----------------------------------
+
+typedcode_t node_dot_write(node_t*n)
+{
+}
+typedcode_t node_dot_read(node_t*n)
+{
+}
+code_t* node_dot_exec(node_t*n)
+{
+}
+nodetype_t node_dot =
+{
+write: node_dot_write,
+read: node_dot_read,
+exec: node_dot_exec
+};
+
+// --------------------------- x..y -----------------------------------
+
+typedcode_t node_dotdot_write(node_t*n)
+{
+}
+typedcode_t node_dotdot_read(node_t*n)
+{
+}
+code_t* node_dotdot_exec(node_t*n)
+{
+
+}
+nodetype_t node_dotdot = //..
+{
+write: node_dotdot_write,
+read: node_dotdot_read,
+exec: node_dotdot_exec
+};
+
+// --------------------------- x.@y -----------------------------------
+
+typedcode_t node_dotat_write(node_t*n)
+{
+}
+typedcode_t node_dotat_read(node_t*n)
+{
+}
+code_t* node_dotat_exec(node_t*n)
+{
+}
+nodetype_t node_dotat = //.@
+{
+write: node_dotat_write,
+read: node_dotat_read,
+exec: node_dotat_exec
+};
+
+// --------------------------- x.*y -----------------------------------
+
+typedcode_t node_dotstar_write(node_t*n)
+{
+}
+typedcode_t node_dotstar_read(node_t*n)
+{
+}
+code_t* node_dotstar_exec(node_t*n)
+{
+}
+nodetype_t node_dotstar = //.*
+{
+write: node_dotstar_write,
+read: node_dotstar_read,
+exec: node_dotstar_exec
+};
+
+// -------------------------- x.(y) -----------------------------------
+
+typedcode_t node_filter_write(node_t*n)
+{
+}
+typedcode_t node_filter_read(node_t*n)
+{
+}
+code_t* node_filter_exec(node_t*n)
+{
+}
+nodetype_t node_filter = //.(
+{
+write: node_filter_write,
+read: node_filter_read,
+exec: node_filter_exec
+};
+
+// ------------------------ x(y1,...,yn) ------------------------------
+
+typedcode_t node_call_write(node_t*n)
+{
+}
+typedcode_t node_call_read(node_t*n)
+{
+}
+code_t* node_call_exec(node_t*n)
+{
+}
+nodetype_t node_call = //functioncall
+{
+write: node_call_write,
+read: node_call_read,
+exec: node_call_exec
+};
+
+// ------------------------------ @x ----------------------------------------
+
+typedcode_t node_at_write(node_t*n)
+{
+}
+typedcode_t node_at_read(node_t*n)
+{
+}
+code_t* node_at_exec(node_t*n)
+{
+}
+nodetype_t node_at = //@
+{
+write: node_at_write,
+read: node_at_read,
+exec: node_at_exec
+};
+
+// ---------------------------- x.ns::y ----------------------------------------
+
+typedcode_t node_dotns_write(node_t*n)
+{
+}
+typedcode_t node_dotns_read(node_t*n)
+{
+}
+code_t* node_dotns_exec(node_t*n)
+{
+}
+nodetype_t node_dotns = //.::
+{
+write: node_dotns_write,
+read: node_dotns_read,
+exec: node_dotns_exec
+};
+#endif
+
+// ------------------------ constant ------------------------------
+
+typedcode_t node_const_write(node_t*n)
+{
+ syntaxerror("can't assign a value to a constant");
+}
+typedcode_t node_const_read(node_t*n)
+{
+ constant_t*v = n->value;
+ code_t*c=0;
+ classinfo_t*t=0;
+ switch(v->type) {
+ case CONSTANT_INT:
+ if(v->i>-128 && v->i<128) {
+ c = abc_pushbyte(0,v->i);
+ } else if(v->i>=-32768 && v->i<32768) {
+ c = abc_pushshort(0,v->i);
+ } else {
+ c = abc_pushint(0,v->i);
+ }
+ t = TYPE_INT;
+ break;
+ case CONSTANT_UINT:
+ c = abc_pushuint(0,v->u);
+ if(v->u<128) {
+ c = abc_pushbyte(0,v->u);
+ } else if(v->u<32768) {
+ c = abc_pushshort(0,v->u);
+ } else {
+ c = abc_pushint(0,v->u);
+ }
+ t = TYPE_UINT;
+ break;
+ case CONSTANT_FLOAT:
+ c = abc_pushdouble(0,v->f);
+ t = TYPE_FLOAT;
+ break;
+ case CONSTANT_TRUE:
+ c = abc_pushtrue(0);
+ t = TYPE_BOOLEAN;
+ break;
+ case CONSTANT_FALSE:
+ c = abc_pushfalse(0);
+ t = TYPE_BOOLEAN;
+ break;
+ case CONSTANT_NULL:
+ c = abc_pushnull(0);
+ t = TYPE_NULL;
+ break;
+ case CONSTANT_STRING:
+ c = abc_pushstring2(0,v->s);
+ t = TYPE_STRING;
+ break;
+ case CONSTANT_UNDEFINED:
+ c = abc_pushundefined(0);
+ t = 0;
+ break;
+ case CONSTANT_NAMESPACE:
+ case CONSTANT_NAMESPACE_PACKAGE:
+ case CONSTANT_NAMESPACE_PACKAGEINTERNAL:
+ case CONSTANT_NAMESPACE_PROTECTED:
+ case CONSTANT_NAMESPACE_EXPLICIT:
+ case CONSTANT_NAMESPACE_STATICPROTECTED:
+ case CONSTANT_NAMESPACE_PRIVATE:
+ c = abc_pushnamespace(0, v->ns);
+ break;
+ default: syntaxerror("invalid constant");
+ }
+ RET;
+}
+
+code_t* node_const_exec(node_t*n)
+{
+ return 0;
+}
+nodetype_t node_const =
+{
+name: "const",
+flags:0,
+write: node_const_write,
+read: node_const_read,
+exec: node_const_exec
+};
+
+// ------------------------ code node ------------------------------
+
+typedcode_t node_code_write(node_t*n)
+{
+ syntaxerror("not implemented yet");
+}
+typedcode_t node_code_read(node_t*n)
+{
+ /* TODO: this dup might be unnecessary- n->code.c is only read out once */
+ typedcode_t t;
+ t.c = code_dup(n->code.c);
+ t.t = n->code.t;
+ return t;
+}
+code_t* node_code_exec(node_t*n)
+{
+ code_t*c = code_dup(n->code.c);
+ c = cut_last_push(c);
+ return c;
+}
+nodetype_t node_code =
+{
+name: "code",
+flags:0,
+write: node_code_write,
+read: node_code_read,
+exec: node_code_exec
+};
+
+// ------------------------ code node ------------------------------
+
+typedcode_t node_dummy_write(node_t*n)
+{
+ syntaxerror("not implemented yet");
+}
+typedcode_t node_dummy_read(node_t*n)
+{
+ typedcode_t t;
+ t.c = abc_pushundefined(0);
+ t.t = 0;
+ return t;
+}
+code_t* node_dummy_exec(node_t*n)
+{
+ return 0;
+}
+nodetype_t node_dummy =
+{
+name: "dummy",
+flags:0,
+write: node_dummy_write,
+read: node_dummy_read,
+exec: node_dummy_exec
+};
+
+// ======================== node handling ==============================
+
+node_t* mkdummynode()
+{
+ node_t*n = (node_t*)rfx_calloc(sizeof(node_t));
+ n->type = &node_dummy;
+ return n;
+}
+
+node_t* mkconstnode(constant_t*c)
+{
+ node_t*n = (node_t*)malloc(sizeof(node_t));
+ n->type = &node_const;
+ n->parent = 0;
+ n->value = c;
+ return n;
+}
+
+node_t* mkcodenode(typedcode_t c)
+{
+ node_t*n = (node_t*)malloc(sizeof(node_t));
+ n->type = &node_code;
+ n->parent = 0;
+ n->code = c;
+ return n;
+}
+
+node_t* mkmultinode(nodetype_t*t, node_t*one)
+{
+ node_t*n = (node_t*)malloc(sizeof(node_t));
+ n->type = t;
+ n->parent = 0;
+ n->child = (node_t**)malloc(sizeof(node_t*)*1);
+ n->child[0] = one;
+ n->num_children = 1;
+ return n;
+}
+
+node_t* multinode_extend(node_t*n, node_t*add)
+{
+ n->child = realloc(n->child, (n->num_children+1)*sizeof(node_t*));
+ n->child[n->num_children] = add;
+ n->num_children++;
+ return n;
+}
+
+node_t* mknode1(nodetype_t*t, node_t*node)
+{
+ node_t*n = (node_t*)malloc(sizeof(node_t)+sizeof(node_t*)*2);
+ node_t**x = (node_t**)&n[1];
+ n->type = t;
+ n->parent = 0;
+ n->child = x;
+ n->num_children = 1;
+ x[0] = node;
+ x[1] = 0;
+ return n;
+};
+
+node_t* mknode2(nodetype_t*t, node_t*left, node_t*right)
+{
+ node_t*n = (node_t*)malloc(sizeof(node_t)+sizeof(node_t*)*3);
+ node_t**x = (node_t**)&n[1];
+ n->type = t;
+ n->parent = 0;
+ n->child = x;
+ n->num_children = 2;
+ x[0] = left;
+ x[1] = right;
+ x[2] = 0;
+ return n;
+}
+node_t* mknode3(nodetype_t*t, node_t*one, node_t*two, node_t*three)
+{
+ node_t*n = (node_t*)malloc(sizeof(node_t)+sizeof(node_t*)*4);
+ node_t**x = (node_t**)&n[1];
+ n->type = t;
+ n->parent = 0;
+ n->child = x;
+ n->num_children = 3;
+ x[0] = one;
+ x[1] = two;
+ x[2] = three;
+ x[3] = 0;
+ return n;
+}
+
+void node_free(node_t*n)
+{
+ int t;
+ if(n->type == &node_const) {
+ constant_free(n->value);n->value = 0;
+ }
+ else if(n->type == &node_code) {
+ code_free(n->code.c);n->code.c = 0;
+ }
+ else for(t=0;t<n->num_children;t++) {
+ node_free(n->child[t]);n->child[t] = 0;
+ }
+ free(n);
+}
+
+typedcode_t node_read(node_t*n)
+{
+ typedcode_t t = n->type->read(n);
+ node_free(n);
+ return t;
+}
+code_t* node_exec(node_t*n)
+{
+ code_t*c = n->type->exec(n);
+ node_free(n);
+ return c;
+}
+
+/*
+ |
+ +-add
+ | |
+ | +-code
+ | |
+ | +-code
+ | |
+ | +
+ |
+ +-div
+
+*/
+void node_dump2(node_t*n, const char*p1, const char*p2, FILE*fi)
+{
+ if(n->type->flags&NODE_HAS_CHILDREN) {
+ fprintf(fi, "%s%s\n", p1, n->type->name);
+ int t;
+ char*o2 = malloc(strlen(p2)+3);
+ strcpy(o2, p2);strcat(o2, "| ");
+ char*o3 = malloc(strlen(p2)+3);
+ strcpy(o3, p2);strcat(o3, "+-");
+ char*o4 = malloc(strlen(p2)+3);
+ strcpy(o4, p2);strcat(o4, " ");
+
+ for(t=0;t<n->num_children;t++) {
+ fprintf(fi, "%s\n", o2);
+ node_dump2(n->child[t], o3, t<n->num_children-1?o2:o4, fi);
+ }
+ free(o2);
+ free(o3);
+ free(o4);
+ } else if(n->type == &node_const) {
+ char*s = constant_tostring(n->value);
+ fprintf(fi, "%s%s (%s)\n", p1, n->type->name, s);
+ free(s);
+ } else if(n->type == &node_code) {
+ fprintf(fi, "%s%s\n", p1, n->type->name);
+ code_dump2(n->code.c, 0, 0, (char*)p2, fi);
+ } else {
+ fprintf(fi, "%s%s\n", p1, n->type->name);
+ }
+}
+
+void node_dump(node_t*n)
+{
+ printf("---------------------------VVVV\n");
+ node_dump2(n,"","",stdout);
+ printf("---------------------------^^^^\n");
+}
+