constant_t*constant;
for_start_t for_start;
abc_exception_t *exception;
- abc_exception_list_t *exception_list;
regexp_t regexp;
+ struct {
+ abc_exception_list_t *l;
+ code_t*finally;
+ } catch_list;
}
%token<token> KW_NEW "new"
%token<token> KW_NATIVE "native"
%token<token> KW_FUNCTION "function"
+%token<token> KW_FINALLY "finally"
%token<token> KW_UNDEFINED "undefined"
%token<token> KW_CONTINUE "continue"
%token<token> KW_CLASS "class"
%token<token> T_SHR ">>"
%type <for_start> FOR_START
-%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
+%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
%type <token> VARCONST
%type <code> CODE
%type <code> CODEPIECE CODE_STATEMENT
%type <code> PACKAGE_DECLARATION SLOT_DECLARATION
%type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
-%type <exception> CATCH
-%type <exception_list> CATCH_LIST
+%type <exception> CATCH FINALLY
+%type <catch_list> CATCH_LIST CATCH_FINALLY_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 TRY
+%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
+%type <value> INNERFUNCTION
%type <token> USE_NAMESPACE
%type <code> FOR_INIT
%type <code> IMPORT
// needed for "return" precedence:
%nonassoc T_STRING T_REGEXP
%nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
-%nonassoc "false" "true" "null" "undefined" "super"
+%nonassoc "false" "true" "null" "undefined" "super" "function"
+%nonassoc above_function
static int yyerror(char*s)
{
syntaxerror("%s", s);
+ return 0; //make gcc happy
}
static char* concat2(const char* t1, const char* t2)
state = state->old;
state_destroy(leaving);
}
-void initialize_state()
+
+void initialize_parser()
{
global = rfx_calloc(sizeof(global_t));
- new_state();
-
- state->package = current_filename;
-
global->file = abc_file_new();
global->file->flags &= ~ABCFILE_LAZY;
global->variable_count = 1;
-
- global->init = abc_initscript(global->file, 0);
+ global->init = abc_initscript(global->file);
code_t*c = global->init->method->body->code;
-
c = abc_getlocal_0(c);
c = abc_pushscope(c);
-
+ /*c = abc_findpropstrict(c, "[package]::trace");
+ c = abc_pushstring(c, "[entering global init function]");
+ c = abc_callpropvoid(c, "[package]::trace", 1);*/
+ global->init->method->body->code = c;
+}
+
+void initialize_file(char*filename)
+{
+ new_state();
+ state->package = filename;
+ // needed for state->method->late_binding:
+ state->method = rfx_calloc(sizeof(methodstate_t));
+}
+void finish_file()
+{
+ if(!state || state->level!=1) {
+ syntaxerror("unexpected end of file");
+ }
+ state_destroy(state);state=0;
+}
+
+void* finish_parser()
+{
+ code_t*c = global->init->method->body->code;
+ /*c = abc_findpropstrict(c, "[package]::trace");
+ c = abc_pushstring(c, "[leaving global init function]");
+ c = abc_callpropvoid(c, "[package]::trace", 1);*/
+ c = abc_returnvoid(c);
+ global->init->method->body->code = c;
+ return global->file;
+}
+
+
+static void xx_scopetest()
+{
/* findpropstrict doesn't just return a scope object- it
also makes it "active" somehow. Push local_0 on the
scope stack and read it back with findpropstrict, it'll
c = abc_getlocal_3(c);
c = abc_kill(c, 3);
c = abc_iftrue(c,xx);*/
-
- c = abc_findpropstrict(c, "[package]::trace");
- c = abc_pushstring(c, "[entering global init function]");
- c = abc_callpropvoid(c, "[package]::trace", 1);
-
- global->init->method->body->code = c;
-}
-void* finalize_state()
-{
- if(state->level!=1) {
- syntaxerror("unexpected end of file");
- }
- abc_method_body_t*m = global->init->method->body;
- //__ popscope(m);
-
- __ findpropstrict(m, "[package]::trace");
- __ pushstring(m, "[leaving global init function]");
- __ callpropvoid(m, "[package]::trace", 1);
- __ returnvoid(m);
-
- state_destroy(state);state=0;
-
- return global->file;
}
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) {
+ if(!c || (c->opcode != OPCODE_RETURNVOID &&
+ c->opcode != OPCODE_RETURNVALUE)) {
c = abc_returnvoid(c);
}
return c;
old_state();
}
-char*globalclass=0;
+char*as3_globalclass=0;
static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
{
if(state->cls) {
new_state();
global->variable_count = 1;
state->cls = rfx_calloc(sizeof(classstate_t));
+ state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
token_list_t*t=0;
classinfo_list_t*mlist=0;
- /*printf("entering class %s\n", name);
- printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
- if(extends)
- printf(" extends: %s.%s\n", extends->package, extends->name);
- printf(" implements (%d): ", list_length(implements));
- for(mlist=implements;mlist;mlist=mlist->next) {
- printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
- }
- printf("\n");
- */
if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
syntaxerror("invalid modifier(s)");
__ setslot(m, slotindex);
/* flash.display.MovieClip handling */
- if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
+ if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
if(state->package && state->package[0]) {
- globalclass = concat3(state->package, ".", classname);
+ as3_globalclass = concat3(state->package, ".", classname);
} else {
- globalclass = strdup(classname);
+ as3_globalclass = strdup(classname);
}
}
multiname_destroy(extends2);
c = abc_constructsuper(c, 0);
state->cls->init = code_append(state->cls->init, c);
}
+ if(!state->method->late_binding) {
+ // class initialization code uses late binding
+ code_t*c = 0;
+ c = abc_getlocal_0(c);
+ c = abc_pushscope(c);
+ state->cls->static_init = code_append(c, state->cls->static_init);
+ }
if(state->cls->init) {
abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
if(state->cls->static_init) {
abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
- } else {
- // handy for scope testing
- /*code_t*c = 0;
- c = abc_pop(c);
- c = abc_pop(c);
- abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
}
free(state->cls);state->cls=0;
+ free(state->method);state->method=0;
old_state();
}
static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
params_t*params, classinfo_t*return_type)
{
- if(state->method) {
+ if(state->method && state->method->info) {
syntaxerror("not able to start another method scope");
}
new_state();
if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
return c;
syntaxerror("can't convert type %s to %s", from->name, to->name);
+ return 0; // make gcc happy
}
code_t*defaultvalue(code_t*c, classinfo_t*type)
return 0;
}
+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;
+}
+
static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
{
/* converts this:
} else if(r->opcode == OPCODE_GETLOCAL_3) {
write->opcode = OPCODE_SETLOCAL_3;
} else {
- code_dump(r, 0, 0, "", stdout);
+ code_dump(r);
syntaxerror("illegal lvalue: can't assign a value to this expression");
}
code_t* c = 0;
c = abc_kill(c, temp);
}
}
+ return c;
+}
+
+char is_break_or_jump(code_t*c)
+{
+ if(!c)
+ return 0;
+ if(c->opcode == OPCODE_JUMP ||
+ c->opcode == OPCODE___BREAK__ ||
+ c->opcode == OPCODE___CONTINUE__ ||
+ c->opcode == OPCODE_THROW ||
+ c->opcode == OPCODE_RETURNVOID ||
+ c->opcode == OPCODE_RETURNVALUE) {
+ return 1;
+ }
+ return 0;
+}
+
+
+#define IS_FINALLY_TARGET(op) \
+ ((op) == OPCODE___CONTINUE__ || \
+ (op) == OPCODE___BREAK__ || \
+ (op) == OPCODE_RETURNVOID || \
+ (op) == OPCODE_RETURNVALUE || \
+ (op) == OPCODE___RETHROW__)
+
+static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
+{
+#define NEED_EXTRA_STACK_ARG
+ code_t*finally_label = abc_nop(0);
+ NEW(lookupswitch_t, l);
+ //_lookupswitch
+
+ code_t*i = c;
+ int count=0;
+ while(i) {
+ code_t*prev = i->prev;
+ if(IS_FINALLY_TARGET(i->opcode)) {
+ code_t*p = prev;
+ char needvalue=0;
+ if(i->opcode == OPCODE___RETHROW__ ||
+ i->opcode == OPCODE_RETURNVALUE) {
+ if(i->opcode == OPCODE___RETHROW__)
+ i->opcode = OPCODE_THROW;
+ needvalue=1;
+ p = abc_coerce_a(p);
+ p = abc_setlocal(p, tempvar);
+ }
+ p = abc_pushbyte(p, count++);
+ p = abc_jump(p, finally_label);
+ code_t*target = p = abc_label(p);
+#ifdef NEED_EXTRA_STACK_ARG
+ p = abc_pop(p);
+#endif
+ if(needvalue) {
+ p = abc_getlocal(p, tempvar);
+ }
+
+ p->next = i;i->prev = p;
+ list_append(l->targets, target);
+ }
+ i = prev;
+ }
+
+ code_t*j,*f;
+ c = abc_pushbyte(c, -1);
+ c = code_append(c, finally_label);
+ c = code_append(c, finally);
+
+#ifdef NEED_EXTRA_STACK_ARG
+ c = abc_dup(c);
+#endif
+ c = abc_lookupswitch(c, l);
+ c = l->def = abc_label(c);
+#ifdef NEED_EXTRA_STACK_ARG
+ c = abc_pop(c);
+#endif
return c;
}
+static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
+{
+ code_t*i = c;
+ while(i) {
+ code_t*prev = i->prev;
+ if(IS_FINALLY_TARGET(i->opcode)) {
+ if(i->opcode == OPCODE___RETHROW__)
+ i->opcode = OPCODE_THROW;
+ code_t*end = code_dup(finally);
+ code_t*start = code_start(end);
+ if(prev) prev->next = start;
+ start->prev = prev;
+ i->prev = end;
+ end->next = i;
+ }
+ i = prev;
+ }
+ return code_append(c, finally);
+}
+
+code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
+{
+ if(!finally)
+ return c;
+ code_t*i = c;
+ char cantdup=0;
+ int num_insertion_points=0;
+ while(i) {
+ if(IS_FINALLY_TARGET(i->opcode))
+ num_insertion_points++;
+ i = i->prev;
+ }
+ i = finally;
+ int code_size=0;
+ while(i) {
+ code_size++;
+ if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
+ cantdup=1;
+ }
+ i = i->prev;
+ }
+ int simple_version_cost = (1+num_insertion_points)*code_size;
+ int lookup_version_cost = 4*num_insertion_points + 5;
+
+ if(cantdup || simple_version_cost > lookup_version_cost) {
+ printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
+ return insert_finally_lookup(c, finally, tempvar);
+ } else {
+ printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
+ return insert_finally_simple(c, finally, tempvar);
+ }
+}
%}
// code which also may appear outside a method
CODE_STATEMENT: IMPORT
-CODE_STATEMENT: VOIDEXPRESSION
CODE_STATEMENT: FOR
CODE_STATEMENT: FOR_IN
CODE_STATEMENT: WHILE
CODE_STATEMENT: IF
CODE_STATEMENT: WITH
CODE_STATEMENT: TRY
+CODE_STATEMENT: VOIDEXPRESSION
// code which may appear anywhere
CODEPIECE: ';' {$$=0;}
-CODEPIECE: VARIABLE_DECLARATION
CODEPIECE: CODE_STATEMENT
+CODEPIECE: VARIABLE_DECLARATION
CODEPIECE: BREAK
CODEPIECE: CONTINUE
CODEPIECE: RETURN
/* ------------ package init code ------------------- */
PACKAGE_INITCODE: CODE_STATEMENT {
- if($1) warning("code ignored");
+ code_t**cc = &global->init->method->body->code;
+ *cc = code_append(*cc, $1);
}
/* ------------ variables --------------------------- */
FOR_INIT : {$$=code_new();}
FOR_INIT : VARIABLE_DECLARATION
FOR_INIT : VOIDEXPRESSION
+
+// TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
$$=$2;new_variable($2,$3,1);
}
/* ------------ 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 '}' {
+ '{' MAYBECODE '}' {
namespace_t name_ns = {ACCESS_PACKAGE, ""};
multiname_t name = {QNAME, &name_ns, 0, $3};
code_t*c = 0;
int i = find_variable_safe($3)->index;
- e->target = c = abc_setlocal(0, i);
+ e->target = c = abc_nop(0);
+ c = abc_setlocal(c, i);
c = code_append(c, $8);
c = abc_kill(c, i);
c = var_block(c);
old_state();
-
+}
+FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
+ $4 = var_block($4);
+ if(!$4) {
+ $$=0;
+ old_state();
+ } else {
+ NEW(abc_exception_t, e)
+ e->exc_type = 0; //all exceptions
+ e->var_name = 0; //no name
+ e->target = 0;
+ e->to = abc_nop(0);
+ e->to = code_append(e->to, $4);
+ old_state();
+ $$ = e;
+ }
}
-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;
+CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
+CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
+CATCH_FINALLY_LIST: CATCH_LIST {$$=$1};
+CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
+ $$ = $1;
+ $$.finally = 0;
+ if($2) {
+ list_append($$.l,$2);
+ $$.finally = $2->to;$2->to=0;
+ }
+}
+CATCH_FINALLY_LIST: FINALLY {
+ $$.l=list_new();
+ $$.finally = 0;
+ if($1) {
+ list_append($$.l,$1);
+ $$.finally = $1->to;$1->to=0;
+ }
+}
+TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
code_t*out = abc_nop(0);
- code_t*jmp = $$ = abc_jump($$, out);
- abc_exception_list_t*l = $6;
+ code_t*start = abc_nop(0);
+ $$ = code_append(start, $4);
+ if(!is_break_or_jump($4)) {
+ $$ = abc_jump($$, out);
+ }
+ code_t*end = $$ = abc_nop($$);
+
+ int tmp;
+ if($6.finally)
+ tmp = new_variable("__finally__", 0, 0);
+
+ abc_exception_list_t*l = $6.l;
+ int count=0;
while(l) {
abc_exception_t*e = l->abc_exception;
+ if(e->var_name) {
+ $$ = code_append($$, e->target);
+ $$ = abc_jump($$, out);
+ } else {
+ parserassert((ptroff_t)$6.finally);
+ // finally block
+ e->target = $$ = abc_nop($$);
+ $$ = abc___rethrow__($$);
+ }
+
e->from = start;
- e->to = jmp;
- $$ = code_append($$, e->target);
- $$ = abc_jump($$, out);
+ e->to = end;
+
l = l->next;
}
$$ = code_append($$, out);
- jmp->branch = out;
+
+ $$ = insert_finally($$, $6.finally, tmp);
- list_concat(state->method->exceptions, $6);
+ list_concat(state->method->exceptions, $6.l);
$$ = var_block($$);
old_state();
/* ------------ classes and interfaces (header) -------------- */
-MAYBE_MODIFIERS : {$$=0;}
+MAYBE_MODIFIERS : %prec above_function {$$=0;}
MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
MODIFIER_LIST : MODIFIER {$$=$1;}
MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
$$=0;
}
+MAYBE_IDENTIFIER: T_IDENTIFIER
+MAYBE_IDENTIFIER: {$$=0;}
+INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
+{
+ syntaxerror("nested functions not supported yet");
+}
+
+
/* ------------- package + class ids --------------- */
CLASS: T_IDENTIFIER {
// ----------------------- expression evaluation -------------------------------------
+E : INNERFUNCTION %prec prec_none {$$ = $1;}
//V : CONSTANT {$$ = 0;}
E : CONSTANT
//V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
$$.t = TYPE_INT;
}
-E : E '-' E {$$.c = code_append($1.c,$3.c);
- if(BOTH_INT($1.t,$3.t)) {
- $$.c = abc_subtract_i($$.c);
- $$.t = TYPE_INT;
- } else {
- $$.c = abc_subtract($$.c);
- $$.t = TYPE_NUMBER;
- }
- }
E : E ">>" E {$$.c = code_append($1.c,$3.c);
$$.c = abc_rshift($$.c);
$$.t = TYPE_INT;
$$.t = join_types($1.t,$3.t,'+');
}
}
+E : E '-' E {$$.c = code_append($1.c,$3.c);
+ if(BOTH_INT($1.t,$3.t)) {
+ $$.c = abc_subtract_i($$.c);
+ $$.t = TYPE_INT;
+ } else {
+ $$.c = abc_subtract($$.c);
+ $$.t = TYPE_NUMBER;
+ }
+ }
E : E '*' E {$$.c = code_append($1.c,$3.c);
if(BOTH_INT($1.t,$3.t)) {
$$.c = abc_multiply_i($$.c);
}
E : E "+=" E {
code_t*c = $3.c;
- if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
+
+ if(TYPE_IS_INT($1.t)) {
c=abc_add_i(c);
} else {
c=abc_add(c);
+ c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
}
- c=converttype(c, join_types($1.t, $3.t, '+'), $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(TYPE_IS_INT($1.t)) {
c=abc_subtract_i(c);
} else {
c=abc_subtract(c);
+ c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
}
- c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
$$.c = toreadwrite($1.c, c, 0, 0);
$$.t = $1.t;
}
E : E '?' E ':' E %prec below_assignment {
+ $$.t = join_types($3.t,$5.t,'?');
$$.c = $1.c;
code_t*j1 = $$.c = abc_iffalse($$.c, 0);
$$.c = code_append($$.c, $3.c);
+ $$.c = converttype($$.c, $3.t, $$.t);
code_t*j2 = $$.c = abc_jump($$.c, 0);
$$.c = j1->branch = abc_label($$.c);
$$.c = code_append($$.c, $5.c);
+ $$.c = converttype($$.c, $3.t, $$.t);
$$.c = j2->branch = abc_label($$.c);
- $$.t = join_types($3.t,$5.t,'?');
}
-// TODO: use inclocal where appropriate
E : E "++" { code_t*c = 0;
classinfo_t*type = $1.t;
- if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
- c=abc_increment_i(c);
- type = TYPE_INT;
+ if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
+ int nr = getlocalnr($1.c);
+ code_free($1.c);$1.c=0;
+ if(TYPE_IS_INT($1.t)) {
+ $$.c = abc_getlocal(0, nr);
+ $$.c = abc_inclocal_i($$.c, nr);
+ } else if(TYPE_IS_NUMBER($1.t)) {
+ $$.c = abc_getlocal(0, nr);
+ $$.c = abc_inclocal($$.c, nr);
+ } else syntaxerror("internal error");
} else {
- c=abc_increment(c);
- type = TYPE_NUMBER;
+ if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
+ c=abc_increment_i(c);
+ type = TYPE_INT;
+ } else {
+ c=abc_increment(c);
+ type = TYPE_NUMBER;
+ }
+ c=converttype(c, type, $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 1);
+ $$.t = $1.t;
}
- c=converttype(c, type, $1.t);
- $$.c = toreadwrite($1.c, c, 0, 1);
- $$.t = $1.t;
}
+
+// TODO: use inclocal, like with ++
E : E "--" { code_t*c = 0;
classinfo_t*type = $1.t;
if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
// $1 is a local variable
$$.c = abc_getlocal($$.c, v->index);
$$.t = v->type;
+ break;
+ }
+
+ int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
/* look at current class' members */
- } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
+ if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
+ (f->flags&FLAG_STATIC) >= i_am_static) {
// $1 is a function in this class
int var_is_static = (f->flags&FLAG_STATIC);
- int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
- if(var_is_static != i_am_static) {
- /* there doesn't seem to be any "static" way to access
- static properties of a class */
+
+ if(f->kind == MEMBER_METHOD) {
+ $$.t = TYPE_FUNCTION(f);
+ } else {
+ $$.t = f->type;
+ }
+ if(var_is_static && !i_am_static) {
+ /* access to a static member from a non-static location.
+ do this via findpropstrict:
+ there doesn't seem to be any non-lookup way to access
+ static properties of a class */
state->method->late_binding = 1;
$$.t = f->type;
namespace_t ns = {flags2access(f->flags), ""};
multiname_t m = {QNAME, &ns, 0, $1};
$$.c = abc_findpropstrict2($$.c, &m);
$$.c = abc_getproperty2($$.c, &m);
+ break;
+ } else if(f->slot>0) {
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = abc_getslot($$.c, f->slot);
+ break;
} else {
- if(f->slot>0) {
- $$.c = abc_getlocal_0($$.c);
- $$.c = abc_getslot($$.c, f->slot);
- } else {
- namespace_t ns = {flags2access(f->flags), ""};
- multiname_t m = {QNAME, &ns, 0, $1};
- $$.c = abc_getlocal_0($$.c);
- $$.c = abc_getproperty2($$.c, &m);
- }
- }
- if(f->kind == MEMBER_METHOD) {
- $$.t = TYPE_FUNCTION(f);
- } else {
- $$.t = f->type;
+ namespace_t ns = {flags2access(f->flags), ""};
+ multiname_t m = {QNAME, &ns, 0, $1};
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = abc_getproperty2($$.c, &m);
+ break;
}
+ }
/* look at actual classes, in the current package and imported */
- } else if((a = find_class($1))) {
+ if((a = find_class($1))) {
if(a->flags & FLAG_METHOD) {
MULTINAME(m, a);
$$.c = abc_findpropstrict2($$.c, &m);
$$.c = abc_getproperty2($$.c, &m);
- $$.t = TYPE_FUNCTION(a->function);
+ if(a->function->kind == MEMBER_METHOD) {
+ $$.t = TYPE_FUNCTION(a->function);
+ } else {
+ $$.t = a->function->type;
+ }
} else {
if(a->slot) {
$$.c = abc_getglobalscope($$.c);
}
$$.t = TYPE_CLASS(a);
}
+ break;
+ }
/* unknown object, let the avm2 resolve it */
- } else {
+ if(1) {
if(strcmp($1,"trace"))
- warning("Couldn't resolve '%s', doing late binding", $1);
+ as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
state->method->late_binding = 1;
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};