char*id;
constant_t*constant;
for_start_t for_start;
+ abc_exception_t *exception;
+ abc_exception_list_t *exception_list;
+ regexp_t regexp;
}
%token<id> T_IDENTIFIER
%token<str> T_STRING
-%token<token> T_REGEXP
+%token<regexp> T_REGEXP
%token<token> T_EMPTY
%token<number_int> T_INT
%token<number_uint> T_UINT
%token<id> T_DO "do"
%token<id> T_SWITCH "switch"
-%token<token> KW_IMPLEMENTS
+%token<token> KW_IMPLEMENTS "implements"
%token<token> KW_NAMESPACE "namespace"
%token<token> KW_PACKAGE "package"
-%token<token> KW_PROTECTED
-%token<token> KW_PUBLIC
-%token<token> KW_PRIVATE
+%token<token> KW_PROTECTED "protected"
+%token<token> KW_PUBLIC "public"
+%token<token> KW_PRIVATE "private"
%token<token> KW_USE "use"
-%token<token> KW_INTERNAL
+%token<token> KW_INTERNAL "internal"
%token<token> KW_NEW "new"
-%token<token> KW_NATIVE
+%token<token> KW_NATIVE "native"
%token<token> KW_FUNCTION "function"
%token<token> KW_UNDEFINED "undefined"
%token<token> KW_CONTINUE "continue"
%token<token> KW_CASE "case"
%token<token> KW_SET "set"
%token<token> KW_VOID "void"
-%token<token> KW_STATIC
+%token<token> KW_THROW "throw"
+%token<token> KW_STATIC "static"
+%token<token> KW_WITH "with"
%token<token> KW_INSTANCEOF "instanceof"
%token<token> KW_IMPORT "import"
%token<token> KW_RETURN "return"
%token<token> KW_NULL "null"
%token<token> KW_VAR "var"
%token<token> KW_DYNAMIC "dynamic"
-%token<token> KW_OVERRIDE
-%token<token> KW_FINAL
+%token<token> KW_OVERRIDE "override"
+%token<token> KW_FINAL "final"
%token<token> KW_EACH "each"
%token<token> KW_GET "get"
%token<token> KW_TRY "try"
%token<token> KW_SUPER "super"
-%token<token> KW_EXTENDS
+%token<token> KW_EXTENDS "extends"
%token<token> KW_FALSE "false"
%token<token> KW_TRUE "true"
%token<token> KW_BOOLEAN "Boolean"
%token<token> T_NEE "!=="
%token<token> T_LE "<="
%token<token> T_GE ">="
+%token<token> T_ORBY "|="
%token<token> T_DIVBY "/="
%token<token> T_MODBY "%="
%token<token> T_MULBY "*="
%type <token> VARCONST
%type <code> CODE
%type <code> CODEPIECE CODE_STATEMENT
-%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
+%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
%type <code> PACKAGE_DECLARATION SLOT_DECLARATION
%type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
-%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
+%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
+%type <exception> CATCH
+%type <exception_list> CATCH_LIST
%type <code> CLASS_DECLARATION
%type <code> NAMESPACE_DECLARATION
%type <code> INTERFACE_DECLARATION
%type <value> MAYBEEXPRESSION
%type <value> E DELETE
%type <value> CONSTANT
-%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
+%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
%type <token> USE_NAMESPACE
%type <code> FOR_INIT
%type <code> IMPORT
%right '?' ':'
%left "||"
%left "&&"
-%nonassoc '|'
-%nonassoc '^'
+%left '|'
+%left '^'
%nonassoc '&'
%nonassoc "==" "!=" "===" "!=="
%nonassoc "is" "as" "in"
/* method data */
memberinfo_t*info;
char late_binding;
- /* code that needs to be executed at the start of
- a method (like initializing local registers) */
- code_t*initcode;
char is_constructor;
char has_super;
char is_global;
+ abc_exception_list_t*exceptions;
} methodstate_t;
typedef struct _state {
struct _state*old;
int level;
-
+
char*package;
import_list_t*wildcard_imports;
dict_t*imports;
classstate_t*cls;
methodstate_t*method;
+
+ char*exception_name;
dict_t*vars;
} state_t;
multiname_t m;\
namespace_t m##_ns;\
if(f) { \
- m##_ns.access = flags2access(f->flags); \
- m##_ns.name = ""; \
+ m##_ns = flags2namespace(f->flags, ""); \
m.type = QNAME; \
m.ns = &m##_ns; \
m.namespace_set = 0; \
if(!state || !state->old)
syntaxerror("invalid nesting");
state_t*leaving = state;
+
state = state->old;
- /*if(state->method->initcode) {
- printf("residual initcode\n");
- code_dump(state->method->initcode, 0, 0, "", stdout);
- }*/
state_destroy(leaving);
}
void initialize_state()
__ callpropvoid(m, "[package]::trace", 1);
__ returnvoid(m);
- state_destroy(state);
+ state_destroy(state);state=0;
return global->file;
}
+typedef struct _variable {
+ int index;
+ classinfo_t*type;
+ char init;
+} variable_t;
+
+static variable_t* find_variable(char*name)
+{
+ state_t* s = state;
+ while(s) {
+ variable_t*v = 0;
+ if(s->method)
+ v = dict_lookup(s->vars, name);
+ if(v) {
+ return v;
+ }
+ s = s->old;
+ }
+ return 0;
+}
+static variable_t* find_variable_safe(char*name)
+{
+ variable_t* v = find_variable(name);
+ if(!v)
+ syntaxerror("undefined variable: %s", name);
+ return v;
+}
+static char variable_exists(char*name)
+{
+ return dict_lookup(state->vars, name)!=0;
+}
+code_t*defaultvalue(code_t*c, classinfo_t*type);
+static int new_variable(char*name, classinfo_t*type, char init)
+{
+ NEW(variable_t, v);
+ v->index = global->variable_count;
+ v->type = type;
+ v->init = init;
+
+ dict_put(state->vars, name, v);
+
+ return global->variable_count++;
+}
+#define TEMPVARNAME "__as3_temp__"
+static int gettempvar()
+{
+ variable_t*v = find_variable(TEMPVARNAME);
+ if(v)
+ return v->index;
+ return new_variable(TEMPVARNAME, 0, 0);
+}
+
+code_t* var_block(code_t*body)
+{
+ code_t*c = 0;
+ code_t*k = 0;
+ int t;
+ int num=0;
+ for(t=0;t<state->vars->hashsize;t++) {
+ dictentry_t*e = state->vars->slots[t];
+ while(e) {
+ variable_t*v = (variable_t*)e->data;
+ if(v->type && v->init) {
+ c = defaultvalue(c, v->type);
+ c = abc_setlocal(c, v->index);
+ k = abc_kill(k, v->index);
+ num++;
+ }
+ e = e->next;
+ }
+ }
+
+ if(k) {
+ code_t*x = body;
+ while(x) {
+ if(x->opcode== OPCODE___BREAK__ ||
+ x->opcode== OPCODE___CONTINUE__) {
+ /* link kill code before break/continue */
+ code_t*e = code_dup(k);
+ code_t*s = code_start(e);
+ s->prev = x->prev;
+ if(x->prev) {
+ x->prev->next = s;
+ }
+ e->next = x;
+ x->prev = e;
+ }
+ x = x->prev;
+ }
+ }
+
+ c = code_append(c, body);
+ c = code_append(c, k);
+ return c;
+}
+
+static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
+{
+ c = code_append(c, header);
+ c = code_append(c, var_block(body));
+ /* append return if necessary */
+ if(!c || c->opcode != OPCODE_RETURNVOID &&
+ c->opcode != OPCODE_RETURNVALUE) {
+ c = abc_returnvoid(c);
+ }
+ return c;
+}
+
+
static void startpackage(char*name)
{
new_state();
printf("\n");
*/
- if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
+ if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
syntaxerror("invalid modifier(s)");
- if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
+ if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
syntaxerror("public and internal not supported at the same time.");
/* create the class name, together with the proper attributes */
multiname_destroy(extends2);
}
-static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
-{
- c = code_append(c, initcode);
- c = code_append(c, body);
- /* append return if necessary */
- if(!c || c->opcode != OPCODE_RETURNVOID &&
- c->opcode != OPCODE_RETURNVALUE) {
- c = abc_returnvoid(c);
- }
- return c;
-}
-
static void endclass()
{
if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
old_state();
}
-typedef struct _variable {
- int index;
- classinfo_t*type;
-} variable_t;
-
-static variable_t* find_variable(char*name)
-{
- state_t* s = state;
- while(s) {
- variable_t*v = 0;
- if(s->method)
- v = dict_lookup(s->vars, name);
- if(v) {
- return v;
- }
- s = s->old;
- }
- return 0;
-}
-static variable_t* find_variable_safe(char*name)
-{
- variable_t* v = find_variable(name);
- if(!v)
- syntaxerror("undefined variable: %s", name);
- return v;
-}
-static char variable_exists(char*name)
-{
- return dict_lookup(state->vars, name)!=0;
-}
-code_t*defaultvalue(code_t*c, classinfo_t*type);
-static int new_variable(char*name, classinfo_t*type, char init)
-{
- NEW(variable_t, v);
- v->index = global->variable_count;
- v->type = type;
-
- dict_put(state->vars, name, v);
-
- if(init && state->method && type) {
- /* if this is a typed variable:
- push default value for type on stack at the very beginning of the
- method, so that it always has that type regardless of the control
- path */
- state->method->initcode = defaultvalue(state->method->initcode, type);
- state->method->initcode = abc_setlocal(state->method->initcode, v->index);
- }
- return global->variable_count++;
-}
-#define TEMPVARNAME "__as3_temp__"
-static int gettempvar()
-{
- variable_t*v = find_variable(TEMPVARNAME);
- if(v)
- return v->index;
- return new_variable(TEMPVARNAME, 0, 0);
-}
-
-code_t* killvars(code_t*c)
-{
- int t;
- for(t=0;t<state->vars->hashsize;t++) {
- dictentry_t*e =state->vars->slots[t];
- while(e) {
- variable_t*v = (variable_t*)e->data;
- //do this always, otherwise register types don't match
- //in the verifier when doing nested loops
- //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
- c = abc_kill(c, v->index);
- e = e->next;
- }
- }
- return c;
-}
-
void check_code_for_break(code_t*c)
{
while(c) {
}
}
+
static int flags2access(int flags)
{
int access = 0;
if(flags&FLAG_PUBLIC) {
- if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+ if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels");
access = ACCESS_PACKAGE;
} else if(flags&FLAG_PRIVATE) {
- if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+ if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels");
access = ACCESS_PRIVATE;
} else if(flags&FLAG_PROTECTED) {
- if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+ if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels");
access = ACCESS_PROTECTED;
} else {
access = ACCESS_PACKAGEINTERNAL;
return access;
}
+
static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
{
memberinfo_t*minfo = 0;
if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
- if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
+ if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
return minfo;
}
new_state();
global->variable_count = 0;
state->method = rfx_calloc(sizeof(methodstate_t));
- state->method->initcode = 0;
state->method->has_super = 0;
+
if(state->cls) {
state->method->is_constructor = !strcmp(state->cls->info->name,name);
state->cls->has_constructor |= state->method->is_constructor;
if(state->method->is_constructor) {
f = abc_class_getconstructor(state->cls->abc, type2);
} else if(!state->method->is_global) {
- namespace_t mname_ns = {flags2access(flags), ""};
+ namespace_t mname_ns = flags2namespace(flags, "");
multiname_t mname = {QNAME, &mname_ns, 0, name};
if(flags&FLAG_STATIC)
f = abc_class_method(state->cls->abc, type2, &mname);
slot = f->trait->slot_id;
} else {
- namespace_t mname_ns = {flags2access(flags), state->package};
+ namespace_t mname_ns = flags2namespace(flags, state->package);
multiname_t mname = {QNAME, &mname_ns, 0, name};
f = abc_method_new(global->file, type2, 1);
}
check_code_for_break(body);
- if(f->body)
+ if(f->body) {
f->body->code = body;
- else //interface
+ f->body->exceptions = state->method->exceptions;
+ } else { //interface
if(body)
syntaxerror("interface methods can't have a method body");
+ }
free(state->method);state->method=0;
old_state();
}
}
+#define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
+#define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
+#define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
+
classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
{
if(!type1 || !type2)
return registry_getanytype();
if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
return registry_getanytype();
+
+ if(op=='+') {
+ if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
+ return TYPE_NUMBER;
+ } else {
+ return TYPE_ANY;
+ }
+ }
+
if(type1 == type2)
return type1;
return registry_getanytype();
c = abc_pushnan(c);
} else if(TYPE_IS_BOOLEAN(type)) {
c = abc_pushfalse(c);
+ } else if(!type) {
+ //c = abc_pushundefined(c);
} else {
c = abc_pushnull(c);
+ MULTINAME(m, type);
+ c = abc_coerce2(c, &m);
}
return c;
}
return c;
}
-#define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
-#define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
%}
CODE_STATEMENT: DO_WHILE
CODE_STATEMENT: SWITCH
CODE_STATEMENT: IF
+CODE_STATEMENT: WITH
+CODE_STATEMENT: TRY
// code which may appear anywhere
-//CODEPIECE: PACKAGE_DECLARATION
-//CODEPIECE: CLASS_DECLARATION
-//CODEPIECE: FUNCTION_DECLARATION
-//CODEPIECE: INTERFACE_DECLARATION
CODEPIECE: ';' {$$=0;}
CODEPIECE: VARIABLE_DECLARATION
CODEPIECE: CODE_STATEMENT
CODEPIECE: BREAK
CODEPIECE: CONTINUE
CODEPIECE: RETURN
+CODEPIECE: THROW
CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
//MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
+
$$ = code_new();
$$ = code_append($$, $4.c);
code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
$$ = code_append($$, $7);
myjmp->branch = $$ = abc_nop($$);
}
-
- $$ = killvars($$);old_state();
+ $$ = var_block($$);
+ old_state();
}
FOR_INIT : {$$=code_new();}
continuejumpsto($$, $1.name, cont);
myif->branch = out;
- $$ = killvars($$);old_state();
+ $$ = var_block($$);
+ old_state();
}
FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
breakjumpsto($$, $1.name, out);
continuejumpsto($$, $1.name, loopstart);
- $$ = killvars($$);
-
myif->branch = out;
+ $$ = var_block($$);
old_state();
+
free(tmp1name);
free(tmp2name);
}
WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
+
$$ = code_new();
code_t*myjmp = $$ = abc_jump($$, 0);
breakjumpsto($$, $1, out);
continuejumpsto($$, $1, cont);
- $$ = killvars($$);
+ $$ = var_block($$);
old_state();
}
code_t*out = $$ = abc_nop($$);
breakjumpsto($$, $1, out);
continuejumpsto($$, $1, cont);
- $$ = killvars($$);
+
+ $$ = var_block($$);
old_state();
}
}
c=c->prev;
}
+
+ $$ = var_block($$);
+ old_state();
+}
+
+/* ------------ try / catch /finally ---------------- */
+
+FINALLY: "finally" '{' CODE '}'
+MAYBE_FINALLY: | FINALLY
+
+CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);}
+ '{' CODE '}' {
+ namespace_t name_ns = {ACCESS_PACKAGE, ""};
+ multiname_t name = {QNAME, &name_ns, 0, $3};
+
+ NEW(abc_exception_t, e)
+ e->exc_type = sig2mname($4);
+ e->var_name = multiname_clone(&name);
+ $$ = e;
+
+ code_t*c = 0;
+ int i = find_variable_safe($3)->index;
+ e->target = c = abc_setlocal(0, i);
+ c = code_append(c, $8);
+ c = abc_kill(c, i);
+
+ c = var_block(c);
old_state();
+
+}
+
+CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
+CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
+
+TRY : "try" '{' {new_state();} CODE '}' CATCH_LIST MAYBE_FINALLY {
+ code_t*start = code_start($4);
+ $$=$4;
+
+ code_t*out = abc_nop(0);
+ code_t*jmp = $$ = abc_jump($$, out);
+
+ abc_exception_list_t*l = $6;
+ while(l) {
+ abc_exception_t*e = l->abc_exception;
+ e->from = start;
+ e->to = jmp;
+ $$ = code_append($$, e->target);
+ $$ = abc_jump($$, out);
+ l = l->next;
+ }
+ $$ = code_append($$, out);
+ jmp->branch = out;
+
+ list_concat(state->method->exceptions, $6);
+
+ $$ = var_block($$);
+ old_state();
+}
+
+/* ------------ throw ------------------------------- */
+
+THROW : "throw" EXPRESSION {
+ $$=$2.c;
+ $$=abc_throw($$);
+}
+THROW : "throw" %prec prec_none {
+ if(!state->exception_name)
+ syntaxerror("re-throw only possible within a catch block");
+ variable_t*v = find_variable(state->exception_name);
+ $$=code_new();
+ $$=abc_getlocal($$, v->index);
+ $$=abc_throw($$);
+}
+
+/* ------------ with -------------------------------- */
+
+WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
+ $$ = $3.c;
+ $$ = abc_pushscope($$);
+ $$ = code_append($$, $5);
+ $$ = abc_popscope($$);
}
/* ------------ packages and imports ---------------- */
| KW_FINAL {$$=FLAG_FINAL;}
| KW_OVERRIDE {$$=FLAG_OVERRIDE;}
| KW_NATIVE {$$=FLAG_NATIVE;}
- | KW_INTERNAL {$$=FLAG_INTERNAL;}
+ | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
EXTENDS : {$$=registry_getobjectclass();}
EXTENDS : KW_EXTENDS QNAME {$$=$2;}
}
IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
$1 |= FLAG_PUBLIC;
- if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
+ if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
syntaxerror("invalid method modifiers: interface methods always need to be public");
}
startfunction(0,$1,$3,$4,&$6,$8);
c = abc_getlocal_0(c);
c = abc_constructsuper(c, 0);
}
- c = wrap_function(c, state->method->initcode, $11);
+ c = wrap_function(c, 0, $11);
endfunction(0,$1,$3,$4,&$6,$8,c);
$$=0;
}
// ----------------------- expression evaluation -------------------------------------
+//V : CONSTANT {$$ = 0;}
E : CONSTANT
+//V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
+//V : NEW {$$ = $1.c;}
E : NEW {$$ = $1;}
+//V : DELETE {$$ = $1.c;}
E : DELETE {$$ = $1;}
-E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
- $$.t = TYPE_ANY;
- }
+
+E : T_REGEXP {
+ $$.c = 0;
+ namespace_t ns = {ACCESS_PACKAGE, ""};
+ multiname_t m = {QNAME, &ns, 0, "RegExp"};
+ if(!$1.options) {
+ $$.c = abc_getlex2($$.c, &m);
+ $$.c = abc_pushstring($$.c, $1.pattern);
+ $$.c = abc_construct($$.c, 1);
+ } else {
+ $$.c = abc_getlex2($$.c, &m);
+ $$.c = abc_pushstring($$.c, $1.pattern);
+ $$.c = abc_pushstring($$.c, $1.options);
+ $$.c = abc_construct($$.c, 2);
+ }
+ $$.t = TYPE_REGEXP;
+}
CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
//MULTINAME(m, registry_getintclass());
}
E : E '-' E {$$.c = code_append($1.c,$3.c);
- if(BOTH_INT($1,$3)) {
+ if(BOTH_INT($1.t,$3.t)) {
$$.c = abc_subtract_i($$.c);
$$.t = TYPE_INT;
} else {
$$.c = abc_divide($$.c);
$$.t = TYPE_NUMBER;
}
-E : E '+' E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_add($$.c);
- $$.t = TYPE_NUMBER;
- }
E : E '%' E {$$.c = code_append($1.c,$3.c);
$$.c = abc_modulo($$.c);
$$.t = TYPE_NUMBER;
}
+E : E '+' E {$$.c = code_append($1.c,$3.c);
+ if(BOTH_INT($1.t, $3.t)) {
+ $$.c = abc_add_i($$.c);
+ $$.t = TYPE_INT;
+ } else {
+ $$.c = abc_add($$.c);
+ $$.t = join_types($1.t,$3.t,'+');
+ }
+ }
E : E '*' E {$$.c = code_append($1.c,$3.c);
- if(BOTH_INT($1,$3)) {
+ if(BOTH_INT($1.t,$3.t)) {
$$.c = abc_multiply_i($$.c);
$$.t = TYPE_INT;
} else {
E : '-' E {
$$=$2;
- if(IS_INT($2)) {
+ if(IS_INT($2.t)) {
$$.c=abc_negate_i($$.c);
$$.t = TYPE_INT;
} else {
E : E "*=" E {
code_t*c = $3.c;
- if(BOTH_INT($1,$3)) {
+ if(BOTH_INT($1.t,$3.t)) {
c=abc_multiply_i(c);
} else {
c=abc_multiply(c);
$$.c = toreadwrite($1.c, c, 0, 0);
$$.t = $1.t;
}
+E : E "|=" E {
+ code_t*c = abc_bitor($3.c);
+ c=converttype(c, TYPE_INT, $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
E : E "+=" E {
code_t*c = $3.c;
if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
if(!t) t = TYPE_OBJECT;
memberinfo_t*f = registry_findmember(t, $3, 1);
- namespace_t ns = {flags2access(f->flags), ""};
+ namespace_t ns = flags2namespace(f->flags, "");
MEMBER_MULTINAME(m, f, $3);
$$.c = 0;
$$.c = abc_getlocal_0($$.c);