X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=a8cb4a74098c249ba394db4718cc344e42b311e1;hb=6eea5a0549bb22c1bd081fd9249bef19d25ec099;hp=b6ffafafc9d3f0147fa7b37d1b735fcb5f9aebb2;hpb=0be76c34f97fccb5150a45c7ee879d56bad664e8;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index b6ffafa..a8cb4a7 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -301,6 +301,7 @@ typedef struct _methodstate { char is_constructor; char has_super; char is_global; + char inner; abc_exception_list_t*exceptions; } methodstate_t; @@ -427,6 +428,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); } @@ -629,6 +640,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) { @@ -663,131 +680,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(); } @@ -909,6 +930,32 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na return minfo; } +static void innerfunction(char*name, params_t*params, classinfo_t*return_type) +{ + parserassert(state->method && state->method->info); + memberinfo_t*parent_method = state->method->info; + + if(as3_pass==1) { + // not valid yet + params = 0; + return_type = 0; + } + + new_state(); + state->method = rfx_calloc(sizeof(methodstate_t)); + state->method->inner = 1; + + NEW(memberinfo_t,minfo); + minfo->return_type = return_type; + minfo->name = name; + + if(!parent_method->subfunctions) + parent_method->subfunctions = dict_new(); + + dict_put(parent_method->subfunctions, name, minfo); + state->method->info = minfo; +} + static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name, params_t*params, classinfo_t*return_type) { @@ -916,41 +963,59 @@ 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, +static abc_method_t* 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 0; + } + abc_method_t*f = 0; multiname_t*type2 = sig2mname(return_type); int slot = 0; - if(state->method->is_constructor) { + if(state->method->inner) { + f = abc_method_new(global->file, type2, 1); + } else if(state->method->is_constructor) { f = abc_class_getconstructor(state->cls->abc, type2); } else if(!state->method->is_global) { namespace_t mname_ns = flags2namespace(flags, ""); @@ -1002,12 +1067,10 @@ 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(); + return f; } - - char is_subtype_of(classinfo_t*type, classinfo_t*supertype) { return 1; // FIXME @@ -1134,11 +1197,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; @@ -1171,7 +1229,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; @@ -1474,8 +1532,13 @@ code_t* insert_finally(code_t*c, code_t*finally, int 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) {{ +%} %% @@ -1544,7 +1607,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 --------------------------- */ @@ -1753,7 +1817,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 { @@ -1838,7 +1902,7 @@ FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' { 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; $$.finally = 0; @@ -1926,13 +1990,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; @@ -1952,41 +2018,41 @@ 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;} -EXTENDS_LIST : {$$=list_new();} -EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;} +EXTENDS_LIST : {PASS12 $$=list_new();} +EXTENDS_LIST : KW_EXTENDS QNAME_LIST {PASS12 $$=$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) -------------- */ @@ -2013,6 +2079,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"); @@ -2042,6 +2109,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) { @@ -2145,8 +2213,11 @@ 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 + if(!state->method->info) syntaxerror("internal error"); code_t*c = 0; if(state->method->late_binding) { c = abc_getlocal_0(c); @@ -2158,28 +2229,44 @@ 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; } MAYBE_IDENTIFIER: T_IDENTIFIER MAYBE_IDENTIFIER: {$$=0;} -INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}' +INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE + '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}' { - syntaxerror("nested functions not supported yet"); + PASS1 old_state(); + PASS2 + memberinfo_t*f = state->method->info; + if(!f) syntaxerror("internal error"); + + code_t*c = 0; + c = wrap_function(c, 0, $9); + + abc_method_t*abc = endfunction(0,0,0,$2,&$4,$6,c); + + $$.c = abc_newfunction(0, abc); + $$.t = TYPE_FUNCTION(f); } /* ------------- 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; @@ -2188,8 +2275,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();} @@ -2208,7 +2295,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 @@ -2606,7 +2693,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 @@ -2620,7 +2707,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; @@ -2866,40 +2953,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); @@ -2919,9 +3015,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;