X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=ffc9960aa71818e45ce776ca31f94ec4e246b9c1;hb=154c4e0a4ab32a753a43e8f1d573c3802c4dac7b;hp=847386d18256faf3ca6fe3f14520d056aa3e15d1;hpb=af10e7690da33fe79627b0bf1946ac8969486841;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index 847386d..ffc9960 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -253,6 +253,7 @@ static int yyerror(char*s) { syntaxerror("%s", s); + return 0; //make gcc happy } static char* concat2(const char* t1, const char* t2) @@ -426,6 +427,16 @@ static void old_state() state_t*leaving = state; state = state->old; + + if(leaving->method && leaving->method != state->method) { + free(leaving->method); + leaving->method=0; + } + if(leaving->cls && leaving->cls != state->cls) { + free(leaving->cls); + leaving->cls=0; + } + state_destroy(leaving); } @@ -449,6 +460,8 @@ 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() { @@ -601,8 +614,8 @@ 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) { + if(!c || (c->opcode != OPCODE_RETURNVOID && + c->opcode != OPCODE_RETURNVALUE)) { c = abc_returnvoid(c); } return c; @@ -626,6 +639,12 @@ static void endpackage() old_state(); } +void parserassert(int b) +{ + if(!b) syntaxerror("internal error: assertion failed"); +} + + char*as3_globalclass=0; static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface) { @@ -660,131 +679,135 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo syntaxerror("public classes only allowed inside a package"); } - if(registry_findclass(package, classname)) { - syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname); - } - - - /* build info struct */ - int num_interfaces = (list_length(implements)); - state->cls->info = classinfo_register(access, package, classname, num_interfaces); - state->cls->info->superclass = extends?extends:TYPE_OBJECT; - int pos = 0; - classinfo_list_t*l = implements; - for(l=implements;l;l=l->next) { - state->cls->info->interfaces[pos++] = l->classinfo; + if(as3_pass==1) { + if(registry_findclass(package, classname)) { + syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname); + } + /* build info struct */ + int num_interfaces = (list_length(implements)); + state->cls->info = classinfo_register(access, package, classname, num_interfaces); } - multiname_t*extends2 = sig2mname(extends); - - MULTINAME(classname2,state->cls->info); + if(as3_pass == 2) { + state->cls->info = registry_findclass(package, classname); + parserassert((int)state->cls->info); + + /* fill out interfaces and extends (we couldn't resolve those during the first pass) */ + state->cls->info->superclass = extends?extends:TYPE_OBJECT; + int pos = 0; + classinfo_list_t*l = implements; + for(l=implements;l;l=l->next) { + state->cls->info->interfaces[pos++] = l->classinfo; + } - /*if(extends) { - state->cls_init = abc_getlocal_0(state->cls_init); - state->cls_init = abc_constructsuper(state->cls_init, 0); - }*/ + /* generate the abc code for this class */ + MULTINAME(classname2,state->cls->info); + multiname_t*extends2 = sig2mname(extends); - state->cls->abc = abc_class_new(global->file, &classname2, extends2); - if(flags&FLAG_FINAL) abc_class_final(state->cls->abc); - if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc); - if(interface) { - state->cls->info->flags |= CLASS_INTERFACE; - abc_class_interface(state->cls->abc); - } + state->cls->abc = abc_class_new(global->file, &classname2, extends2); + if(flags&FLAG_FINAL) abc_class_final(state->cls->abc); + if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc); + if(interface) { + state->cls->info->flags |= CLASS_INTERFACE; + abc_class_interface(state->cls->abc); + } - abc_class_protectedNS(state->cls->abc, classname); + abc_class_protectedNS(state->cls->abc, classname); - for(mlist=implements;mlist;mlist=mlist->next) { - MULTINAME(m, mlist->classinfo); - abc_class_add_interface(state->cls->abc, &m); - } + for(mlist=implements;mlist;mlist=mlist->next) { + MULTINAME(m, mlist->classinfo); + abc_class_add_interface(state->cls->abc, &m); + } - /* now write the construction code for this class */ - int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc); + /* write the construction code for this class to the global init + function */ + int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc); - abc_method_body_t*m = global->init->method->body; - __ getglobalscope(m); - classinfo_t*s = extends; + abc_method_body_t*m = global->init->method->body; + __ getglobalscope(m); + classinfo_t*s = extends; - int count=0; - - while(s) { - //TODO: take a look at the current scope stack, maybe - // we can re-use something - s = s->superclass; - if(!s) - break; - - multiname_t*s2 = sig2mname(s); - __ getlex2(m, s2); - multiname_destroy(s2); - - __ pushscope(m); count++; - m->code = m->code->prev->prev; // invert - } - /* continue appending after last op end */ - while(m->code && m->code->next) m->code = m->code->next; - - /* TODO: if this is one of *our* classes, we can also - do a getglobalscope/getslot (which references - the init function's slots) */ - if(extends2) { - __ getlex2(m, extends2); - __ dup(m); - /* notice: we get a Verify Error #1107 if the top elemnt on the scope - stack is not the superclass */ - __ pushscope(m);count++; - } else { - __ pushnull(m); - /* notice: we get a verify error #1107 if the top element on the scope - stack is not the global object */ - __ getlocal_0(m); - __ pushscope(m);count++; - } - __ newclass(m,state->cls->abc); - while(count--) { - __ popscope(m); - } - __ setslot(m, slotindex); - - /* flash.display.MovieClip handling */ - if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) { - if(state->package && state->package[0]) { - as3_globalclass = concat3(state->package, ".", classname); + int count=0; + + while(s) { + //TODO: take a look at the current scope stack, maybe + // we can re-use something + s = s->superclass; + if(!s) + break; + + multiname_t*s2 = sig2mname(s); + __ getlex2(m, s2); + multiname_destroy(s2); + + __ pushscope(m); count++; + m->code = m->code->prev->prev; // invert + } + /* continue appending after last op end */ + while(m->code && m->code->next) m->code = m->code->next; + + /* TODO: if this is one of *our* classes, we can also + do a getglobalscope/getslot (which references + the init function's slots) */ + if(extends2) { + __ getlex2(m, extends2); + __ dup(m); + /* notice: we get a Verify Error #1107 if the top elemnt on the scope + stack is not the superclass */ + __ pushscope(m);count++; } else { - as3_globalclass = strdup(classname); + __ pushnull(m); + /* notice: we get a verify error #1107 if the top element on the scope + stack is not the global object */ + __ getlocal_0(m); + __ pushscope(m);count++; + } + __ newclass(m,state->cls->abc); + while(count--) { + __ popscope(m); + } + __ setslot(m, slotindex); + multiname_destroy(extends2); + + /* flash.display.MovieClip handling */ + + if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) { + if(state->package && state->package[0]) { + as3_globalclass = concat3(state->package, ".", classname); + } else { + as3_globalclass = strdup(classname); + } } } - multiname_destroy(extends2); } static void endclass() { - if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) { - code_t*c = 0; - c = abc_getlocal_0(c); - 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(as3_pass == 2) { + if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) { + code_t*c = 0; + c = abc_getlocal_0(c); + 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); - m->body->code = wrap_function(0, state->cls->init, m->body->code); - } - 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); + if(state->cls->init) { + abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0); + m->body->code = wrap_function(0, state->cls->init, m->body->code); + } + 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); + } } - free(state->cls);state->cls=0; - free(state->method);state->method=0; old_state(); } @@ -913,36 +936,52 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n syntaxerror("not able to start another method scope"); } new_state(); - global->variable_count = 0; state->method = rfx_calloc(sizeof(methodstate_t)); 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; - - new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0); } else { state->method->is_global = 1; state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack + } + if(state->method->is_constructor) + name = "__as3_constructor__"; - new_variable("globalscope", 0, 0); + if(as3_pass == 1) { + return_type = 0; + state->method->info = registerfunction(getset, flags, name, params, return_type, 0); } - /* state->vars is initialized by state_new */ + if(as3_pass == 2) { + /* retrieve the member info that we stored in the first pass. + TODO: better getter/setter support? */ + if(!state->cls) state->method->info = registry_findclass(state->package, name)->function; + else state->method->info = registry_findmember(state->cls->info, name, 0); + state->method->info->return_type = return_type; - param_list_t*p=0; - for(p=params->list;p;p=p->next) { - new_variable(p->param->name, p->param->type, 0); - } - if(state->method->is_constructor) - name = "__as3_constructor__"; - state->method->info = registerfunction(getset, flags, name, params, return_type, 0); + global->variable_count = 0; + /* state->vars is initialized by state_new */ + if(!state->method->is_global) + new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0); + else + new_variable("globalscope", 0, 0); + param_list_t*p=0; + for(p=params->list;p;p=p->next) { + new_variable(p->param->name, p->param->type, 0); + } + } } static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name, params_t*params, classinfo_t*return_type, code_t*body) { + if(as3_pass==1) { + old_state(); + return; + } + abc_method_t*f = 0; multiname_t*type2 = sig2mname(return_type); @@ -999,7 +1038,6 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam syntaxerror("interface methods can't have a method body"); } - free(state->method);state->method=0; old_state(); } @@ -1103,6 +1141,7 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to) 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) @@ -1130,11 +1169,6 @@ char is_pushundefined(code_t*c) return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED); } -void parserassert(int b) -{ - if(!b) syntaxerror("internal error: assertion failed"); -} - static classinfo_t* find_class(char*name) { classinfo_t*c=0; @@ -1167,7 +1201,7 @@ static classinfo_t* find_class(char*name) if(c) return c; /* try local "filename" package */ - c = registry_findclass(current_filename, name); + c = registry_findclass(current_filename_short, name); if(c) return c; return 0; @@ -1191,6 +1225,7 @@ static int getlocalnr(code_t*c) 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) @@ -1353,9 +1388,17 @@ char is_break_or_jump(code_t*c) return 0; } -#define NEED_EXTRA_STACK_ARG -static code_t* insert_finally(code_t*c, code_t*finally) + +#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 @@ -1364,21 +1407,27 @@ static code_t* insert_finally(code_t*c, code_t*finally) int count=0; while(i) { code_t*prev = i->prev; - if(i->opcode == OPCODE___CONTINUE__ || - i->opcode == OPCODE___BREAK__ || - i->opcode == OPCODE_RETURNVOID || - i->opcode == OPCODE_RETURNVALUE || - i->opcode == OPCODE___RETHROW__) - { - if(i->opcode == OPCODE___RETHROW__) - i->opcode = OPCODE_NOP; + 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); } @@ -1402,8 +1451,66 @@ static code_t* insert_finally(code_t*c, code_t*finally) 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); + } +} + +#define PASS1 }} if(as3_pass == 1) {{ +#define PASS1END }} if(as3_pass == 2) {{ +#define PASS2 }} if(as3_pass == 2) {{ +#define PASS12 }} {{ +#define PASS12END }} if(as3_pass == 2) {{ + +%} %% @@ -1472,7 +1579,8 @@ CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;} /* ------------ package init code ------------------- */ PACKAGE_INITCODE: CODE_STATEMENT { - if($1) as3_warning("code ignored"); + code_t**cc = &global->init->method->body->code; + *cc = code_append(*cc, $1); } /* ------------ variables --------------------------- */ @@ -1681,7 +1789,7 @@ MAYBE_CASE_LIST : {$$=0;} MAYBE_CASE_LIST : CASE_LIST {$$=$1;} MAYBE_CASE_LIST : DEFAULT {$$=$1;} MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);} -CASE_LIST: CASE {$$=$1} +CASE_LIST: CASE {$$=$1;} CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);} CASE: "case" E ':' MAYBECODE { @@ -1739,7 +1847,8 @@ CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name 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); @@ -1747,35 +1856,55 @@ CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name old_state(); } FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' { - NEW(abc_exception_t, e) - e->exc_type = 0; //all exceptions - e->var_name = 0; //no name - e->target = 0; - $$ = e; - e->to = var_block($4); - old_state(); + $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 {$$.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 {$$=$1;} CATCH_FINALLY_LIST: CATCH_LIST FINALLY { - $$ = $1;list_append($$.l,$2); - $$.finally = $2->to;$2->to=0; + $$ = $1; + $$.finally = 0; + if($2) { + list_append($$.l,$2); + $$.finally = $2->to;$2->to=0; + } } CATCH_FINALLY_LIST: FINALLY { - $$.l=list_new();list_append($$.l,$1); - $$.finally = $1->to;$1->to=0; + $$.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*start = abc_nop(0); - code_t*end = $$ = code_append(start, $4); code_t*out = abc_nop(0); - + + code_t*start = abc_nop(0); + $$ = code_append(start, $4); if(!is_break_or_jump($4)) { - end = $$ = abc_jump($$, out); + $$ = 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; @@ -1785,24 +1914,20 @@ TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST { $$ = code_append($$, e->target); $$ = abc_jump($$, out); } else { + parserassert((ptroff_t)$6.finally); // finally block - int tmp = new_variable("__finally__", 0, 0); - e->target = - $$ = abc_coerce_a($$); - $$ = abc_setlocal($$, tmp); + e->target = $$ = abc_nop($$); $$ = abc___rethrow__($$); - $$ = abc_getlocal($$, tmp); - $$ = abc_throw($$); } e->from = start; - e->to = end->next; + e->to = end; l = l->next; } $$ = code_append($$, out); - $$ = insert_finally($$, $6.finally); + $$ = insert_finally($$, $6.finally, tmp); list_concat(state->method->exceptions, $6.l); @@ -1837,13 +1962,15 @@ WITH : "with" '(' EXPRESSION ')' CODEBLOCK { /* ------------ packages and imports ---------------- */ X_IDENTIFIER: T_IDENTIFIER - | "package" {$$="package";} + | "package" {PASS12 $$="package";} -PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;} -PACKAGE: X_IDENTIFIER {$$=strdup($1);} +PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;} +PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);} -PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;} -PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;} +PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;} + MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;} +PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} + MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;} IMPORT : "import" QNAME { classinfo_t*c = $2; @@ -1863,20 +1990,20 @@ IMPORT : "import" PACKAGE '.' '*' { /* ------------ classes and interfaces (header) -------------- */ -MAYBE_MODIFIERS : %prec above_function {$$=0;} -MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1} -MODIFIER_LIST : MODIFIER {$$=$1;} -MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;} - -MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;} - | KW_PRIVATE {$$=FLAG_PRIVATE;} - | KW_PROTECTED {$$=FLAG_PROTECTED;} - | KW_STATIC {$$=FLAG_STATIC;} - | KW_DYNAMIC {$$=FLAG_DYNAMIC;} - | KW_FINAL {$$=FLAG_FINAL;} - | KW_OVERRIDE {$$=FLAG_OVERRIDE;} - | KW_NATIVE {$$=FLAG_NATIVE;} - | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;} +MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;} +MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;} +MODIFIER_LIST : MODIFIER {PASS12 $$=$1;} +MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;} + +MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;} + | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;} + | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;} + | KW_STATIC {PASS12 $$=FLAG_STATIC;} + | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;} + | KW_FINAL {PASS12 $$=FLAG_FINAL;} + | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;} + | KW_NATIVE {PASS12 $$=FLAG_NATIVE;} + | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;} EXTENDS : {$$=registry_getobjectclass();} EXTENDS : KW_EXTENDS QNAME {$$=$2;} @@ -1884,20 +2011,20 @@ EXTENDS : KW_EXTENDS QNAME {$$=$2;} EXTENDS_LIST : {$$=list_new();} EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;} -IMPLEMENTS_LIST : {$$=list_new();} -IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;} +IMPLEMENTS_LIST : {PASS12 $$=list_new();} +IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {PASS12 $$=$2;} CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST - '{' {startclass($1,$3,$4,$5, 0);} + '{' {PASS12 startclass($1,$3,$4,$5, 0);} MAYBE_CLASS_BODY - '}' {endclass();$$=0;} + '}' {PASS12 endclass();$$=0;} INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST - '{' {startclass($1,$3,0,$4,1);} + '{' {PASS12 startclass($1,$3,0,$4,1);} MAYBE_INTERFACE_BODY - '}' {endclass();$$=0;} + '}' {PASS12 endclass();$$=0;} /* ------------ classes and interfaces (body) -------------- */ @@ -1924,6 +2051,7 @@ IDECLARATION : "var" T_IDENTIFIER { syntaxerror("variable declarations not allowed in interfaces"); } IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE { + PASS12 $1 |= FLAG_PUBLIC; if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) { syntaxerror("invalid method modifiers: interface methods always need to be public"); @@ -1953,6 +2081,7 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSIO code_t**code; if(!state->cls) { // global variable + mname_ns.name = state->package; traits = &global->init->traits; code = &global->init->method->body->code; } else if(flags&FLAG_STATIC) { @@ -2056,8 +2185,10 @@ GETSET : "get" {$$=$1;} | {$$=0;} FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' - MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' + MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}' { + PASS1 old_state(); + PASS2 code_t*c = 0; if(state->method->late_binding) { c = abc_getlocal_0(c); @@ -2069,6 +2200,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P c = abc_constructsuper(c, 0); } c = wrap_function(c, 0, $11); + endfunction(0,$1,$3,$4,&$6,$8,c); $$=0; } @@ -2084,13 +2216,16 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{ /* ------------- package + class ids --------------- */ CLASS: T_IDENTIFIER { - + PASS1 $$=0; + PASS2 /* try current package */ $$ = find_class($1); if(!$$) syntaxerror("Could not find class %s\n", $1); } PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER { + PASS1 $$=0; + PASS2 $$ = registry_findclass($1, $3); if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3); free($1);$1=0; @@ -2099,8 +2234,8 @@ PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER { QNAME: PACKAGEANDCLASS | CLASS -QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);} -QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);} +QNAME_LIST : QNAME {PASS12 $$=list_new();list_append($$, $1);} +QNAME_LIST : QNAME_LIST ',' QNAME {PASS12 $$=$1;list_append($$,$3);} TYPE : QNAME {$$=$1;} | '*' {$$=registry_getanytype();} @@ -2119,7 +2254,7 @@ MAYBETYPE: {$$=0;} /* ----------function calls, delete, constructor calls ------ */ MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;} -MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2} +MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;} MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;} MAYBE_EXPRESSION_LIST : EXPRESSION_LIST @@ -2517,7 +2652,7 @@ E : '-' E { E : E '[' E ']' { $$.c = $1.c; $$.c = code_append($$.c, $3.c); - + MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, ""); $$.c = abc_getproperty2($$.c, &m); $$.t = 0; // array elements have unknown type @@ -2531,7 +2666,7 @@ E : '[' MAYBE_EXPRESSION_LIST ']' { } MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;} -MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1}; +MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;} EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION { $$.cc = 0; @@ -2649,7 +2784,7 @@ E : E '?' E ':' E %prec below_assignment { E : E "++" { code_t*c = 0; classinfo_t*type = $1.t; - if(is_getlocal($1.c) && TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t)) { + 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)) { @@ -2777,40 +2912,49 @@ VAR_READ : T_IDENTIFIER { // $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); @@ -2830,9 +2974,11 @@ VAR_READ : T_IDENTIFIER { } $$.t = TYPE_CLASS(a); } + break; + } /* unknown object, let the avm2 resolve it */ - } else { + if(1) { if(strcmp($1,"trace")) as3_softwarning("Couldn't resolve '%s', doing late binding", $1); state->method->late_binding = 1;