X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=847386d18256faf3ca6fe3f14520d056aa3e15d1;hb=af10e7690da33fe79627b0bf1946ac8969486841;hp=ea4da6b0c4050ceeeb582116db645746733b2f19;hpb=49e07c7d7adac5b5b9d5fa012e75de3a0e2ec51e;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index ea4da6b..847386d 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -59,8 +59,11 @@ 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; } @@ -90,6 +93,7 @@ %token KW_NEW "new" %token KW_NATIVE "native" %token KW_FUNCTION "function" +%token KW_FINALLY "finally" %token KW_UNDEFINED "undefined" %token KW_CONTINUE "continue" %token KW_CLASS "class" @@ -159,7 +163,7 @@ %token T_SHR ">>" %type FOR_START -%type X_IDENTIFIER PACKAGE FOR_IN_INIT +%type X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER %type VARCONST %type CODE %type CODEPIECE CODE_STATEMENT @@ -167,8 +171,8 @@ %type PACKAGE_DECLARATION SLOT_DECLARATION %type FUNCTION_DECLARATION PACKAGE_INITCODE %type VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW -%type CATCH -%type CATCH_LIST +%type CATCH FINALLY +%type CATCH_LIST CATCH_FINALLY_LIST %type CLASS_DECLARATION %type NAMESPACE_DECLARATION %type INTERFACE_DECLARATION @@ -177,7 +181,8 @@ %type MAYBEEXPRESSION %type E DELETE %type CONSTANT -%type FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY +%type FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY +%type INNERFUNCTION %type USE_NAMESPACE %type FOR_INIT %type IMPORT @@ -238,7 +243,8 @@ // 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 @@ -422,23 +428,50 @@ static void old_state() 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; +} +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 @@ -464,29 +497,6 @@ void initialize_state() 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; } @@ -616,7 +626,7 @@ static void endpackage() 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) { @@ -738,11 +748,11 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo __ 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); @@ -1259,7 +1269,7 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r } 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; @@ -1325,10 +1335,72 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r 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 NEED_EXTRA_STACK_ARG +static code_t* insert_finally(code_t*c, code_t*finally) +{ + 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(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; + code_t*p = prev; + 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 + 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; +} %} @@ -1370,7 +1442,6 @@ CODE: CODEPIECE {$$=$1;} // code which also may appear outside a method CODE_STATEMENT: IMPORT -CODE_STATEMENT: VOIDEXPRESSION CODE_STATEMENT: FOR CODE_STATEMENT: FOR_IN CODE_STATEMENT: WHILE @@ -1379,11 +1450,12 @@ CODE_STATEMENT: SWITCH 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 @@ -1400,7 +1472,7 @@ CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;} /* ------------ package init code ------------------- */ PACKAGE_INITCODE: CODE_STATEMENT { - if($1) warning("code ignored"); + if($1) as3_warning("code ignored"); } /* ------------ variables --------------------------- */ @@ -1483,6 +1555,8 @@ IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE { 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); } @@ -1653,11 +1727,8 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' { /* ------------ 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}; @@ -1674,32 +1745,66 @@ CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name c = var_block(c); 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(); } -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;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; +} +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*jmp = $$ = abc_jump($$, out); - - abc_exception_list_t*l = $6; + + if(!is_break_or_jump($4)) { + end = $$ = abc_jump($$, out); + } + + 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 { + // finally block + int tmp = new_variable("__finally__", 0, 0); + e->target = + $$ = abc_coerce_a($$); + $$ = abc_setlocal($$, tmp); + $$ = abc___rethrow__($$); + $$ = abc_getlocal($$, tmp); + $$ = abc_throw($$); + } + e->from = start; - e->to = jmp; - $$ = code_append($$, e->target); - $$ = abc_jump($$, out); + e->to = end->next; + l = l->next; } $$ = code_append($$, out); - jmp->branch = out; + + $$ = insert_finally($$, $6.finally); - list_concat(state->method->exceptions, $6); + list_concat(state->method->exceptions, $6.l); $$ = var_block($$); old_state(); @@ -1758,7 +1863,7 @@ IMPORT : "import" PACKAGE '.' '*' { /* ------------ 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;} @@ -1968,6 +2073,14 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P $$=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 { @@ -2155,6 +2268,7 @@ VOIDEXPRESSION : EXPRESSION %prec below_minus { // ----------------------- expression evaluation ------------------------------------- +E : INNERFUNCTION %prec prec_none {$$ = $1;} //V : CONSTANT {$$ = 0;} E : CONSTANT //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;} @@ -2701,7 +2815,11 @@ VAR_READ : T_IDENTIFIER { 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); @@ -2716,7 +2834,7 @@ VAR_READ : T_IDENTIFIER { /* unknown object, let the avm2 resolve it */ } else { 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};