X-Git-Url: http://git.asbjorn.biz/?a=blobdiff_plain;f=lib%2Fas3%2Fparser.y;h=e678826c05f13602fd266b2754ffd9a4c9ad0cee;hb=7af2d06662c689c9b0e1e736e4299c030f080a8f;hp=093b1eb525420eb206d1a64b3d60bdac780675b6;hpb=c9d83d91b9eae931ea0f884d854d5eee2384d29b;p=swftools.git diff --git a/lib/as3/parser.y b/lib/as3/parser.y index 093b1eb..e678826 100644 --- a/lib/as3/parser.y +++ b/lib/as3/parser.y @@ -211,7 +211,7 @@ %nonassoc '^' %nonassoc '&' %nonassoc "==" "!=" "===" "!==" -%nonassoc "is" "as" +%nonassoc "is" "as" "in" %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax? %left "<<" ">>" ">>>" %left below_minus @@ -222,6 +222,7 @@ %nonassoc below_curly %left '[' ']' '{' "new" '.' ".." "::" %nonassoc T_IDENTIFIER +%left above_identifier %left below_else %nonassoc "else" %left '(' @@ -287,6 +288,7 @@ typedef struct _methodstate { code_t*initcode; char is_constructor; char has_super; + char is_global; } methodstate_t; typedef struct _state { @@ -793,10 +795,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); @@ -813,6 +844,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) @@ -848,24 +880,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) { @@ -873,17 +887,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); @@ -896,21 +917,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; @@ -1146,6 +1174,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 { @@ -1233,6 +1263,7 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r c = abc_setlocal(c, temp); c = code_append(c, write); c = abc_getlocal(c, temp); + c = abc_kill(c, temp); } } @@ -2103,6 +2134,11 @@ E : E '*' E {$$.c = code_append($1.c,$3.c); } } +E : E "in" E {$$.c = code_append($1.c,$3.c); + $$.c = abc_in($$.c); + $$.t = TYPE_BOOLEAN; + } + E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate if(use_astype && TYPE_IS_CLASS($3.t)) { MULTINAME(m,$3.t->cls); @@ -2398,7 +2434,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);