X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=6aa84e44cea07c2c6802b5db3fa2fb4854f095a7;hb=1adc9bdd04d6c40fadf2211a4af8c281b46ca5ec;hp=f26a444befd9da6eb2d896173a9957c2bdfb4602;hpb=2eef2111d088a6fe4a3cddbe0db05d2f77d8453d;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index f26a444..6aa84e4 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -427,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); } @@ -629,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) { @@ -663,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); + 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; + } - MULTINAME(classname2,state->cls->info); + /* generate the abc code for this class */ + MULTINAME(classname2,state->cls->info); + multiname_t*extends2 = sig2mname(extends); - /*if(extends) { - state->cls_init = abc_getlocal_0(state->cls_init); - state->cls_init = abc_constructsuper(state->cls_init, 0); - }*/ + 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); - } + /* write the construction code for this class to the global init + function */ + int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc); - /* now write the construction code for this class */ - 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); - 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); + __ 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(); } @@ -916,36 +936,50 @@ 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) { + 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); - 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); @@ -1002,7 +1036,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(); } @@ -1134,11 +1167,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 +1199,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 +1502,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) {{ +%} %% @@ -1754,7 +1787,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 { @@ -1839,7 +1872,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; @@ -1927,13 +1960,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; @@ -1953,20 +1988,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;} @@ -1974,20 +2009,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) -------------- */ @@ -2014,6 +2049,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"); @@ -2146,8 +2182,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); @@ -2159,6 +2197,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; } @@ -2174,13 +2213,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; @@ -2189,8 +2231,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();} @@ -2209,7 +2251,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 @@ -2621,7 +2663,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;