X-Git-Url: http://git.asbjorn.it/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=32007bc3798d5f35190a02a0764a775263022aa1;hb=f5192a905ac6fe6406519f8b78c128fda3d4fd21;hp=3cdf1fe4870755e265ae91c7eefdd7fd23b58ccc;hpb=16901658118e16e75f0ec606fcf54cc09774fe87;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index 3cdf1fe..32007bc 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -156,14 +156,14 @@ %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 PACKAGE_DECLARATION SLOT_DECLARATION +%type FUNCTION_DECLARATION PACKAGE_INITCODE %type VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST -%type CLASS_DECLARATION -%type NAMESPACE_DECLARATION -%type INTERFACE_DECLARATION +%type CLASS_DECLARATION +%type NAMESPACE_DECLARATION +%type INTERFACE_DECLARATION %type VOIDEXPRESSION %type EXPRESSION NONCOMMAEXPRESSION %type MAYBEEXPRESSION @@ -172,7 +172,7 @@ %type FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE %type USE_NAMESPACE %type FOR_INIT -%type IMPORT +%type IMPORT %type MAYBETYPE %type GETSET %type PARAM @@ -288,6 +288,7 @@ typedef struct _methodstate { code_t*initcode; char is_constructor; char has_super; + char is_global; } methodstate_t; typedef struct _state { @@ -376,7 +377,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() @@ -429,6 +430,7 @@ void initialize_state() 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; @@ -495,6 +497,7 @@ static void startpackage(char*name) new_state(); /*printf("entering package \"%s\"\n", name);*/ state->package = strdup(name); + global->variable_count = 1; } static void endpackage() { @@ -513,6 +516,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; @@ -722,6 +726,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) { @@ -794,10 +799,39 @@ static void check_constant_against_type(classinfo_t*t, constant_t*c) } } +static int flags2access(int flags) +{ + int access = 0; + if(flags&FLAG_PUBLIC) { + if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels"); + access = ACCESS_PACKAGE; + } else if(flags&FLAG_PRIVATE) { + if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels"); + access = ACCESS_PRIVATE; + } else if(flags&FLAG_PROTECTED) { + if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels"); + access = ACCESS_PROTECTED; + } else { + access = ACCESS_PACKAGEINTERNAL; + } + return access; +} + static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot) { memberinfo_t*minfo = 0; - if(getset != KW_GET && getset != KW_SET) { + 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->return_type = return_type; + } else if(getset != KW_GET && getset != KW_SET) { + //class method if((minfo = registry_findmember(state->cls->info, name, 0))) { if(minfo->parent == state->cls->info) { syntaxerror("class already contains a member/method called '%s'", name); @@ -814,6 +848,7 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na // to actually store these //state->minfo->slot = state->method->abc->method->trait->slot_id; } else { + //class getter/setter int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET; classinfo_t*type=0; if(getset == KW_GET) @@ -849,24 +884,6 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na return minfo; } -static int flags2access(int flags) -{ - int access = 0; - if(flags&FLAG_PUBLIC) { - if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels"); - access = ACCESS_PACKAGE; - } else if(flags&FLAG_PRIVATE) { - if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels"); - access = ACCESS_PRIVATE; - } else if(flags&FLAG_PROTECTED) { - if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels"); - access = ACCESS_PROTECTED; - } else { - access = ACCESS_PACKAGEINTERNAL; - } - return access; -} - static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name, params_t*params, classinfo_t*return_type) { @@ -874,17 +891,24 @@ 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->initcode = 0; - state->method->is_constructor = !strcmp(state->cls->info->name,name); state->method->has_super = 0; - - state->cls->has_constructor |= state->method->is_constructor; + 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 - global->variable_count = 0; + new_variable("globalscope", 0, 0); + } /* state->vars is initialized by state_new */ - if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0)!=0) syntaxerror("Internal error"); + param_list_t*p=0; for(p=params->list;p;p=p->next) { new_variable(p->param->name, p->param->type, 0); @@ -897,21 +921,28 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name, params_t*params, classinfo_t*return_type, code_t*body) { - namespace_t mname_ns = {flags2access(flags), ""}; - multiname_t mname = {QNAME, &mname_ns, 0, name}; - abc_method_t*f = 0; multiname_t*type2 = sig2mname(return_type); int slot = 0; if(state->method->is_constructor) { f = abc_class_getconstructor(state->cls->abc, type2); - } else { + } else if(!state->method->is_global) { + namespace_t mname_ns = {flags2access(flags), ""}; + multiname_t mname = {QNAME, &mname_ns, 0, name}; + if(flags&FLAG_STATIC) f = abc_class_staticmethod(state->cls->abc, type2, &mname); else f = abc_class_method(state->cls->abc, type2, &mname); slot = f->trait->slot_id; + } else { + namespace_t mname_ns = {flags2access(flags), state->package}; + multiname_t mname = {QNAME, &mname_ns, 0, name}; + + f = abc_method_new(global->file, type2, 1); + trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f); + //abc_code_t*c = global->init->method->body->code; } //flash doesn't seem to allow us to access function slots //state->method->info->slot = slot; @@ -1147,6 +1178,8 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r prefix = abc_getlocal(prefix, temp); prefix = abc_swap(prefix); prefix = abc_getlocal(prefix, temp); + if(!use_temp_var); + prefix = abc_kill(prefix, temp); } use_temp_var = 1; } else { @@ -1251,47 +1284,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 which may appear anywhere +CODEPIECE: ';' {$$=0;} +//CODEPIECE: PACKAGE_DECLARATION +//CODEPIECE: CLASS_DECLARATION +//CODEPIECE: FUNCTION_DECLARATION +//CODEPIECE: INTERFACE_DECLARATION +CODEPIECE: VARIABLE_DECLARATION +CODEPIECE: CODE_STATEMENT +CODEPIECE: BREAK +CODEPIECE: CONTINUE +CODEPIECE: RETURN + +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;} @@ -1542,8 +1599,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; @@ -1590,29 +1647,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"); @@ -1671,6 +1734,8 @@ SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSIO if($2==KW_CONST) { t->kind= TRAIT_CONST; } + + $$=0; } /* ------------ constants -------------------------------------- */ @@ -1751,6 +1816,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 --------------- */ @@ -2405,7 +2471,7 @@ VAR_READ : T_IDENTIFIER { $$.t = v->type; /* look at current class' members */ - } else if((f = registry_findmember(state->cls->info, $1, 1))) { + } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) { // $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); @@ -2474,9 +2540,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;}