X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=0c8c6354db0e5d979b9af71e3079e026cf9bda92;hb=b16e095437f2a9c6adcfadbe8116f413927a4ed5;hp=e678826c05f13602fd266b2754ffd9a4c9ad0cee;hpb=7af2d06662c689c9b0e1e736e4299c030f080a8f;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index e678826..0c8c635 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -58,6 +58,8 @@ char*id; constant_t*constant; for_start_t for_start; + abc_exception_t *exception; + abc_exception_list_t *exception_list; } @@ -95,6 +97,7 @@ %token KW_CASE "case" %token KW_SET "set" %token KW_VOID "void" +%token KW_THROW "throw" %token KW_STATIC %token KW_INSTANCEOF "instanceof" %token KW_IMPORT "import" @@ -156,23 +159,25 @@ %type X_IDENTIFIER PACKAGE FOR_IN_INIT %type VARCONST %type CODE -%type CODEPIECE +%type CODEPIECE CODE_STATEMENT %type CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH -%type PACKAGE_DECLARATION -%type FUNCTION_DECLARATION -%type VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST -%type CLASS_DECLARATION -%type NAMESPACE_DECLARATION -%type INTERFACE_DECLARATION +%type PACKAGE_DECLARATION SLOT_DECLARATION +%type FUNCTION_DECLARATION PACKAGE_INITCODE +%type VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW +%type CATCH +%type CATCH_LIST +%type CLASS_DECLARATION +%type NAMESPACE_DECLARATION +%type INTERFACE_DECLARATION %type VOIDEXPRESSION %type EXPRESSION NONCOMMAEXPRESSION %type MAYBEEXPRESSION %type E DELETE %type CONSTANT -%type FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE +%type FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY %type USE_NAMESPACE %type FOR_INIT -%type IMPORT +%type IMPORT %type MAYBETYPE %type GETSET %type PARAM @@ -289,6 +294,7 @@ typedef struct _methodstate { char is_constructor; char has_super; char is_global; + abc_exception_list_t*exceptions; } methodstate_t; typedef struct _state { @@ -302,6 +308,8 @@ typedef struct _state { classstate_t*cls; methodstate_t*method; + + char*exception_name; dict_t*vars; } state_t; @@ -360,11 +368,6 @@ static namespace_list_t nl2 = {&ns2,&nl3}; static namespace_list_t nl1 = {&ns1,&nl2}; static namespace_set_t nopackage_namespace_set = {&nl1}; -static void init_globals() -{ - global = rfx_calloc(sizeof(global_t)); -} - static void new_state() { NEW(state_t, s); @@ -377,7 +380,7 @@ static void new_state() state = s; state->level++; state->has_own_imports = 0; - state->vars = dict_new(); + state->vars = dict_new(); state->old = oldstate; } static void state_has_imports() @@ -425,11 +428,14 @@ static void old_state() } void initialize_state() { - init_globals(); + 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); code_t*c = global->init->method->body->code; @@ -490,12 +496,10 @@ void* finalize_state() static void startpackage(char*name) { - if(state->package) { - syntaxerror("Packages can not be nested."); - } new_state(); /*printf("entering package \"%s\"\n", name);*/ state->package = strdup(name); + global->variable_count = 1; } static void endpackage() { @@ -514,6 +518,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo syntaxerror("inner classes now allowed"); } new_state(); + global->variable_count = 1; state->cls = rfx_calloc(sizeof(classstate_t)); token_list_t*t=0; @@ -723,6 +728,7 @@ static int new_variable(char*name, classinfo_t*type, char init) NEW(variable_t, v); v->index = global->variable_count; v->type = type; + dict_put(state->vars, name, v); if(init && state->method && type) { @@ -818,13 +824,7 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na memberinfo_t*minfo = 0; if(!state->cls) { //package method - minfo = rfx_calloc(sizeof(memberinfo_t)); - classinfo_t*c = classinfo_register(flags2access(flags), state->package, name, 0); - c->flags |= FLAG_METHOD; - c->function = minfo; - minfo->kind = MEMBER_METHOD; - minfo->name = name; - minfo->flags = FLAG_STATIC; + minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD); minfo->return_type = return_type; } else if(getset != KW_GET && getset != KW_SET) { //class method @@ -965,11 +965,13 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam } check_code_for_break(body); - if(f->body) + if(f->body) { f->body->code = body; - else //interface + f->body->exceptions = state->method->exceptions; + } else { //interface if(body) syntaxerror("interface methods can't have a method body"); + } free(state->method);state->method=0; old_state(); @@ -1095,14 +1097,15 @@ static classinfo_t* find_class(char*name) classinfo_t*c=0; c = registry_findclass(state->package, name); + if(c) return c; /* try explicit imports */ dictentry_t* e = dict_get_slot(state->imports, name); + if(c) return c; while(e) { - if(c) - break; if(!strcmp(e->key, name)) { c = (classinfo_t*)e->data; + if(c) return c; } e = e->next; } @@ -1110,18 +1113,21 @@ static classinfo_t* find_class(char*name) /* try package.* imports */ import_list_t*l = state->wildcard_imports; while(l) { - if(c) - break; //printf("does package %s contain a class %s?\n", l->import->package, name); c = registry_findclass(l->import->package, name); + if(c) return c; l = l->next; } /* try global package */ - if(!c) { - c = registry_findclass("", name); - } - return c; + c = registry_findclass("", name); + if(c) return c; + + /* try local "filename" package */ + c = registry_findclass(current_filename, name); + if(c) return c; + + return 0; } static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore) @@ -1280,47 +1286,71 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r /* ------------ code blocks / statements ---------------- */ -PROGRAM: MAYBECODE { - /* todo: do something with this code if we're outside a function */ - if($1) - warning("ignored code"); -} +PROGRAM: MAYBE_PROGRAM_CODE_LIST + +MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST +PROGRAM_CODE_LIST: PROGRAM_CODE + | PROGRAM_CODE_LIST PROGRAM_CODE + +PROGRAM_CODE: PACKAGE_DECLARATION + | INTERFACE_DECLARATION + | CLASS_DECLARATION + | FUNCTION_DECLARATION + | SLOT_DECLARATION + | PACKAGE_INITCODE + | ';' + +MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST +INPACKAGE_CODE_LIST: INPACKAGE_CODE + | INPACKAGE_CODE_LIST INPACKAGE_CODE + +INPACKAGE_CODE: INTERFACE_DECLARATION + | CLASS_DECLARATION + | FUNCTION_DECLARATION + | SLOT_DECLARATION + | PACKAGE_INITCODE + | ';' MAYBECODE: CODE {$$=$1;} MAYBECODE: {$$=code_new();} -CODE: CODE CODEPIECE { - $$=code_append($1,$2); -} -CODE: CODEPIECE { - $$=$1; -} - -CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/} -CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/} -CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/} -CODEPIECE: INTERFACE_DECLARATION {$$=code_new();} -CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/} -CODEPIECE: ';' {$$=code_new();} -CODEPIECE: VARIABLE_DECLARATION {$$=$1} -CODEPIECE: VOIDEXPRESSION {$$=$1} -CODEPIECE: FOR {$$=$1} -CODEPIECE: FOR_IN {$$=$1} -CODEPIECE: WHILE {$$=$1} -CODEPIECE: DO_WHILE {$$=$1} -CODEPIECE: SWITCH {$$=$1} -CODEPIECE: BREAK {$$=$1} -CODEPIECE: CONTINUE {$$=$1} -CODEPIECE: RETURN {$$=$1} -CODEPIECE: IF {$$=$1} -CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();} -CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();} +CODE: CODE CODEPIECE {$$=code_append($1,$2);} +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 +CODE_STATEMENT: DO_WHILE +CODE_STATEMENT: SWITCH +CODE_STATEMENT: IF +CODE_STATEMENT: TRY + +// code which may appear anywhere +CODEPIECE: ';' {$$=0;} +CODEPIECE: VARIABLE_DECLARATION +CODEPIECE: CODE_STATEMENT +CODEPIECE: BREAK +CODEPIECE: CONTINUE +CODEPIECE: RETURN +CODEPIECE: THROW + +CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;} +CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;} CODEBLOCK : '{' CODE '}' {$$=$2;} CODEBLOCK : '{' '}' {$$=0;} CODEBLOCK : CODEPIECE ';' {$$=$1;} CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;} +/* ------------ package init code ------------------- */ + +PACKAGE_INITCODE: CODE_STATEMENT { + if($1) warning("code ignored"); +} + /* ------------ variables --------------------------- */ MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;} @@ -1563,6 +1593,70 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' { old_state(); } +/* ------------ 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 '}' { + code_t*c = 0; + int i = find_variable_safe($3)->index; + c = abc_setlocal(c, i); + c = code_append(c, $8); + c = abc_kill(c, i); + + namespace_t name_ns = {ACCESS_PACKAGE, ""}; + multiname_t name = {QNAME, &name_ns, 0, $3}; + + NEW(abc_exception_t, e) + e->exc_type = sig2mname($4); + e->var_name = multiname_clone(&name); + e->target = code_start(c); + $$ = e; + old_state(); +} + +CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);} +CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);} + +TRY : "try" '{' CODE '}' CATCH_LIST MAYBE_FINALLY { + code_t*start = code_start($3); + $$=$3; + + code_t*out = abc_nop(0); + code_t*jmp = $$ = abc_jump($$, out); + + abc_exception_list_t*l = $5; + while(l) { + abc_exception_t*e = l->abc_exception; + e->from = start; + e->to = jmp; + $$ = code_append($$, e->target); + $$ = abc_jump($$, out); + l = l->next; + } + $$ = code_append($$, out); + jmp->branch = out; + + list_concat(state->method->exceptions, $5); +} + +/* ------------ throw ------------------------------- */ + +THROW : "throw" EXPRESSION { + $$=$2.c; + $$=abc_throw($$); +} +THROW : "throw" %prec prec_none { + if(!state->exception_name) + syntaxerror("re-throw only possible within a catch block"); + variable_t*v = find_variable(state->exception_name); + $$=code_new(); + $$=abc_getlocal($$, v->index); + $$=abc_throw($$); +} + /* ------------ packages and imports ---------------- */ X_IDENTIFIER: T_IDENTIFIER @@ -1571,8 +1665,8 @@ X_IDENTIFIER: T_IDENTIFIER PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;} PACKAGE: X_IDENTIFIER {$$=strdup($1);} -PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()} -PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()} +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;} IMPORT : "import" QNAME { classinfo_t*c = $2; @@ -1619,29 +1713,35 @@ IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;} CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5, 0);} - MAYBE_DECLARATION_LIST - '}' {endclass();} + MAYBE_CLASS_BODY + '}' {endclass();$$=0;} INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' {startclass($1,$3,0,$4,1);} - MAYBE_IDECLARATION_LIST - '}' {endclass();} + MAYBE_INTERFACE_BODY + '}' {endclass();$$=0;} /* ------------ classes and interfaces (body) -------------- */ -MAYBE_DECLARATION_LIST : -MAYBE_DECLARATION_LIST : DECLARATION_LIST -DECLARATION_LIST : DECLARATION -DECLARATION_LIST : DECLARATION_LIST DECLARATION -DECLARATION : ';' -DECLARATION : SLOT_DECLARATION -DECLARATION : FUNCTION_DECLARATION - -MAYBE_IDECLARATION_LIST : -MAYBE_IDECLARATION_LIST : IDECLARATION_LIST -IDECLARATION_LIST : IDECLARATION -IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION +MAYBE_CLASS_BODY : +MAYBE_CLASS_BODY : CLASS_BODY +CLASS_BODY : CLASS_BODY_ITEM +CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM +CLASS_BODY_ITEM : ';' +CLASS_BODY_ITEM : SLOT_DECLARATION +CLASS_BODY_ITEM : FUNCTION_DECLARATION + +CLASS_BODY_ITEM : CODE_STATEMENT { + code_t*c = state->cls->static_init; + c = code_append(c, $1); + state->cls->static_init = c; +} + +MAYBE_INTERFACE_BODY : +MAYBE_INTERFACE_BODY : INTERFACE_BODY +INTERFACE_BODY : IDECLARATION +INTERFACE_BODY : INTERFACE_BODY IDECLARATION IDECLARATION : ';' IDECLARATION : "var" T_IDENTIFIER { syntaxerror("variable declarations not allowed in interfaces"); @@ -1661,45 +1761,58 @@ VARCONST: "var" | "const" SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION { int flags = $1; - memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT); + memberinfo_t* info = state->cls? + memberinfo_register(state->cls->info, $3, MEMBER_SLOT): + memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT); + info->type = $4; info->flags = flags; - trait_t*t=0; + /* slot name */ namespace_t mname_ns = {flags2access(flags), ""}; multiname_t mname = {QNAME, &mname_ns, 0, $3}; - - if(!(flags&FLAG_STATIC)) { - if($4) { - MULTINAME(m, $4); - t=abc_class_slot(state->cls->abc, &mname, &m); - } else { - t=abc_class_slot(state->cls->abc, &mname, 0); - } - info->slot = t->slot_id; + + trait_list_t**traits; + code_t**code; + if(!state->cls) { + // global variable + traits = &global->init->traits; + code = &global->init->method->body->code; + } else if(flags&FLAG_STATIC) { + // static variable + traits = &state->cls->abc->static_traits; + code = &state->cls->static_init; } else { - if($4) { - MULTINAME(m, $4); - t=abc_class_staticslot(state->cls->abc, &mname, &m); - } else { - t=abc_class_staticslot(state->cls->abc, &mname, 0); - } - info->slot = t->slot_id; + // instance variable + traits = &state->cls->abc->traits; + code = &state->cls->init; } + + trait_t*t=0; + if($4) { + MULTINAME(m, $4); + t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0); + } else { + t = trait_new_member(traits, 0, multiname_clone(&mname), 0); + } + info->slot = t->slot_id; + + /* initalization code (if needed) */ + code_t*c = 0; if($5.c && !is_pushundefined($5.c)) { - code_t*c = 0; c = abc_getlocal_0(c); c = code_append(c, $5.c); c = converttype(c, $5.t, $4); c = abc_setslot(c, t->slot_id); - if(!(flags&FLAG_STATIC)) - state->cls->init = code_append(state->cls->init, c); - else - state->cls->static_init = code_append(state->cls->static_init, c); } + + *code = code_append(*code, c); + if($2==KW_CONST) { t->kind= TRAIT_CONST; } + + $$=0; } /* ------------ constants -------------------------------------- */ @@ -1780,6 +1893,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P } c = wrap_function(c, state->method->initcode, $11); endfunction(0,$1,$3,$4,&$6,$8,c); + $$=0; } /* ------------- package + class ids --------------- */ @@ -2503,9 +2617,9 @@ VAR_READ : T_IDENTIFIER { // ----------------- namespaces ------------------------------------------------- -NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;} -NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;} -NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;} +NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;} +NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;} +NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;} -USE_NAMESPACE : "use" "namespace" T_IDENTIFIER +USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}