%token<token> KW_NAMESPACE "namespace"
%token<token> KW_PACKAGE "package"
%token<token> KW_PROTECTED "protected"
+%token<token> KW_ARGUMENTS "arguments"
%token<token> KW_PUBLIC "public"
%token<token> KW_PRIVATE "private"
%token<token> KW_USE "use"
%token<token> KW_NUMBER "Number"
%token<token> KW_STRING "String"
%token<token> KW_DEFAULT "default"
+%token<token> KW_DEFAULT_XML "default xml"
%token<token> KW_DELETE "delete"
%token<token> KW_IF "if"
%token<token> KW_ELSE "else"
%type <node> VAR_READ
%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
%type <value> INNERFUNCTION
-%type <code> USE_NAMESPACE
+%type <code> USE_NAMESPACE DEFAULT_NAMESPACE
%type <code> FOR_INIT
%type <code> IMPORT
%type <classinfo> MAYBETYPE
%type <classinfo_list> EXTENDS_LIST
%type <classinfo> CLASS PACKAGEANDCLASS
%type <classinfo_list> CLASS_SPEC_LIST
-%type <id> XML XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT
+%type <id> XML XML2 XMLNODE XMLATTRIBUTE XMLATTRIBUTES MAYBE_XMLATTRIBUTES XMLTEXT XML_ID_OR_EXPR XMLEXPR1 XMLEXPR2
%type <classinfo> TYPE
//%type <token> VARIABLE
%type <value> MEMBER
%left new2
%left '[' ']' "new" '{' "{ (dictionary)" '.' ".." "::" '@'
-%left T_IDENTIFIER
+%left T_IDENTIFIER "arguments"
%left above_identifier
%left below_else
%nonassoc "else"
/* class data */
classinfo_t*info;
abc_class_t*abc;
-
+
methodstate_t*init;
methodstate_t*static_init;
//code_t*init;
//code_t*static_init;
+ parsedclass_t*dependencies;
char has_constructor;
} classstate_t;
char is_constructor;
char has_super;
char is_global;
+ char is_static;
int variable_count;
dict_t*unresolved_variables;
dict_t*slots;
int activation_var;
+ int need_arguments;
+
abc_method_t*abc;
int var_index; // for inner methods
int slot_index; // for inner methods
char has_own_imports;
char new_vars; // e.g. transition between two functions
+ char xmlfilter; // are we inside a xmlobj..() filter?
classstate_t*cls;
methodstate_t*method;
DECLARE_LIST(state);
+/* protected handling here is a big hack: we just assume the protectedns
+ is package:class. the correct approach would be to add the proper
+ namespace to all protected members in the registry, even though that
+ would slow down searching */
#define MEMBER_MULTINAME(m,f,n) \
multiname_t m;\
namespace_t m##_ns;\
if(f) { \
- if((m##_ns.access = ((slotinfo_t*)(f))->access)==ACCESS_NAMESPACE) \
+ m##_ns.access = ((slotinfo_t*)(f))->access; \
+ if(m##_ns.access == ACCESS_NAMESPACE) \
m##_ns.name = ((slotinfo_t*)(f))->package; \
+ else if(m##_ns.access == ACCESS_PROTECTED && (f)->parent) \
+ m##_ns.name = concat3((f)->parent->package,":",(f)->parent->name); \
else \
m##_ns.name = ""; \
m.type = QNAME; \
static namespace_t ns1 = {ACCESS_PRIVATE, ""};
static namespace_t ns2 = {ACCESS_PROTECTED, ""};
static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
-static namespace_t ns4 = {ACCESS_PACKAGE, ""};
-static namespace_list_t nl4 = {&ns4,0};
+static namespace_t stdns = {ACCESS_PACKAGE, ""};
+static namespace_list_t nl4 = {&stdns,0};
static namespace_list_t nl3 = {&ns3,&nl4};
static namespace_list_t nl2 = {&ns2,&nl3};
static namespace_list_t nl1 = {&ns1,&nl2};
static code_t* method_header(methodstate_t*m);
static code_t* wrap_function(code_t*c,code_t*header, code_t*body);
-static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0);
+static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0);
static char* internal_filename_package = 0;
state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
if(!state->method)
syntaxerror("internal error: skewed tokencount");
- function_initvars(state->method, 0, 0, 1);
+ function_initvars(state->method, 0, 0, 0, 1);
global->init = abc_initscript(global->file);
}
}
{
if(maybeslot) {
variable_t*v = find_slot(state, name);
- if(v)
+ if(v) {
+ alloc_local();
return v;
+ }
}
NEW(variable_t, v);
code_t*k = 0;
int t;
int num=0;
- for(t=0;t<state->vars->hashsize;t++) {
- dictentry_t*e = state->vars->slots[t];
- while(e) {
- variable_t*v = (variable_t*)e->data;
- if(v->type && v->init) {
- c = defaultvalue(c, v->type);
- c = abc_setlocal(c, v->index);
- k = abc_kill(k, v->index);
- num++;
- }
- e = e->next;
+ DICT_ITERATE_DATA(state->vars, variable_t*, v) {
+ if(v->type && v->init) {
+ c = defaultvalue(c, v->type);
+ c = abc_setlocal(c, v->index);
+ k = abc_kill(k, v->index);
+ num++;
}
}
if(m->uses_slots) {
/* FIXME: this alloc_local() causes variable indexes to be
different in pass2 than in pass1 */
- if(!m->activation_var)
+ if(!m->activation_var) {
m->activation_var = alloc_local();
+ }
if(init) {
c = abc_newactivation(c);
c = abc_dup(c);
return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
}
-static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
+static void innerfunctions2vars(methodstate_t*m)
+{
+ methodstate_list_t*l = m->innerfunctions;
+ while(l) {
+ methodstate_t*m = l->methodstate;
+
+ variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 0);
+ m->var_index = v->index;
+ if(m->is_a_slot)
+ m->slot_index = m->is_a_slot;
+ v->is_inner_method = m;
+ l = l->next;
+ }
+}
+
+static void function_initvars(methodstate_t*m, char has_params, params_t*params, int flags, char var0)
{
if(var0) {
int index = -1;
parserassert(!index);
}
- if(m->uses_slots) {
- /* as variables and slots share the same number, make sure
- that those variable indices are reserved. It's up to the
- optimizer to later shuffle the variables down to lower
- indices */
- m->variable_count = m->uses_slots;
- }
-
- if(params) {
+ if(has_params) {
param_list_t*p=0;
for(p=params->list;p;p=p->next) {
variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
v->is_parameter = 1;
}
+ if(as3_pass==2 && m->need_arguments) {
+ /* arguments can never be used by an innerfunction (the inner functions
+ have their own arguments var), so it's ok to not initialize this until
+ pass 2. (We don't know whether we need it before, anyway) */
+ variable_t*v = new_variable2("arguments", TYPE_ARRAY, 0, 0);
+ m->need_arguments = v->index;
+ }
}
-
- methodstate_list_t*l = m->innerfunctions;
- while(l) {
- methodstate_t*m = l->methodstate;
-
- variable_t* v = new_variable2(m->info->name, TYPE_FUNCTION(m->info), 0, 1);
- m->var_index = v->index;
- m->slot_index = v->index;
- v->is_inner_method = m;
-
- l = l->next;
- }
+
+ innerfunctions2vars(m);
if(as3_pass==2) {
m->scope_code = add_scope_code(m->scope_code, m, 0);
- }
-
- if(as3_pass==2 && m->slots) {
- /* exchange unresolved identifiers with the actual objects */
- DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
- if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
- classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
- if(!type || type->kind != INFOTYPE_CLASS) {
- syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
+ if(m->slots) {
+ /* exchange unresolved identifiers with the actual objects */
+ DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v) {
+ if(v->type && v->type->kind == INFOTYPE_UNRESOLVED) {
+ classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v->type);
+ if(!type || type->kind != INFOTYPE_CLASS) {
+ syntaxerror("Couldn't find class %s::%s (%s)", v->type->package, v->type->name, name);
+ }
+ v->type = type;
}
- v->type = type;
}
}
}
if((mod->flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
syntaxerror("public and internal not supported at the same time.");
+ if((mod->flags&(FLAG_PROTECTED|FLAG_STATIC)) == (FLAG_PROTECTED|FLAG_STATIC))
+ syntaxerror("protected and static not supported at the same time.");
+
//if(!(mod->flags&FLAG_INTERFACE) && !extends) {
if(!(mod->flags&FLAG_INTERFACE) && !extends) {
// all classes extend object
state->cls = rfx_calloc(sizeof(classstate_t));
state->cls->init = rfx_calloc(sizeof(methodstate_t));
state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
+ state->cls->static_init->is_static=FLAG_STATIC;
state->cls->static_init->variable_count=1;
/* notice: we make no effort to initialize the top variable (local0) here,
- even though it has special meaning. We just rely on the facat
+ even though it has special meaning. We just rely on the fact
that pass 1 won't do anything with variables */
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->cls);
if(as3_pass == 2) {
state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
-
+
state->method = state->cls->init;
parserassert(state->cls && state->cls->info);
- function_initvars(state->cls->init, 0, 0, 1);
- function_initvars(state->cls->static_init, 0, 0, 0);
+ function_initvars(state->cls->init, 0, 0, 0, 1);
+ function_initvars(state->cls->static_init, 0, 0, 0, 0);
if(extends && (extends->flags & FLAG_FINAL))
syntaxerror("Can't extend final class '%s'", extends->name);
abc_class_interface(state->cls->abc);
}
- 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);
}
- NEW(parsedclass_t,p);
- p->cls = state->cls->info;
- p->abc = state->cls->abc;
- list_append(global->classes, p);
+ state->cls->dependencies = parsedclass_new(state->cls->info, state->cls->abc);
+ list_append(global->classes, state->cls->dependencies);
/* flash.display.MovieClip handling */
if(!as3_globalclass && (mod->flags&FLAG_PUBLIC) && slotinfo_equals((slotinfo_t*)registry_getMovieClip(),(slotinfo_t*)extends)) {
code_t*c = method_header(state->cls->static_init);
m->body->code = wrap_function(c, 0, m->body->code);
}
+
+ trait_list_t*trait = state->cls->abc->traits;
+ /* switch all protected members to the protected ns of this class */
+ while(trait) {
+ trait_t*t = trait->trait;
+ if(t->name->ns->access == ACCESS_PROTECTED) {
+ if(!state->cls->abc->protectedNS) {
+ char*n = concat3(state->cls->info->package, ":", state->cls->info->name);
+ state->cls->abc->protectedNS = namespace_new_protected(n);
+ state->cls->abc->flags |= CLASS_PROTECTED_NS;
+ }
+ t->name->ns->name = strdup(state->cls->abc->protectedNS->name);
+ }
+ trait = trait->next;
+ }
}
old_state();
if(as3_pass == 1) {
state->method = rfx_calloc(sizeof(methodstate_t));
state->method->inner = 1;
+ state->method->is_static = parent_method->is_static;
state->method->variable_count = 0;
state->method->abc = rfx_calloc(sizeof(abc_method_t));
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
- function_initvars(state->method, params, 0, 1);
+ function_initvars(state->method, 1, params, 0, 1);
}
if(as3_pass == 2) {
parserassert(state->method);
state->method->info->return_type = return_type;
- function_initvars(state->method, params, 0, 1);
+ function_initvars(state->method, 1, params, 0, 1);
}
}
if(as3_pass == 1) {
state->method = rfx_calloc(sizeof(methodstate_t));
state->method->has_super = 0;
+ state->method->is_static = mod->flags&FLAG_STATIC;
if(state->cls) {
state->method->is_constructor = !strcmp(state->cls->info->name,name);
state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
- function_initvars(state->method, params, mod->flags, 1);
+ function_initvars(state->method, 1, params, mod->flags, 1);
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
}
state->cls->has_constructor |= state->method->is_constructor;
}
- function_initvars(state->method, params, mod->flags, 1);
+ function_initvars(state->method, 1, params, mod->flags, 1);
}
}
params_t*params, classinfo_t*return_type, code_t*body)
{
if(as3_pass==1) {
- // store inner methods in variables
- function_initvars(state->method, 0, 0, 0);
+ innerfunctions2vars(state->method);
methodstate_list_t*ml = state->method->innerfunctions;
if(m->unresolved_variables) {
dict_t*d = m->unresolved_variables;
int t;
- for(t=0;t<d->hashsize;t++) {
- dictentry_t*l = d->slots[t];
- while(l) {
- /* check parent method's variables */
- variable_t*v;
- if((v=find_variable(state, l->key))) {
- m->uses_parent_function = 1;
- state->method->uses_slots = 1;
- dict_put(xvars, l->key, 0);
- }
- l = l->next;
+ DICT_ITERATE_KEY(d, char*, id) {
+ /* check parent method's variables */
+ variable_t*v;
+ if((v=find_variable(state, id))) {
+ m->uses_parent_function = 1;
+ state->method->uses_slots = 1;
+ dict_put(xvars, id, 0);
}
- if(l) break;
}
-
- dict_destroy(m->unresolved_variables);
- m->unresolved_variables = 0;
+ dict_destroy(m->unresolved_variables);m->unresolved_variables = 0;
}
ml = ml->next;
}
if(!name) syntaxerror("internal error");
if(v->index && dict_contains(xvars, name)) {
v->init = 0;
- v->index = i++;
+ v->index = i;
if(v->is_inner_method) {
- v->is_inner_method->is_a_slot = 1;
+ v->is_inner_method->is_a_slot = i;
}
- //v->type = 0;
+ i++;
dict_put(state->method->slots, name, v);
}
}
f = abc_class_getconstructor(state->cls->abc, type2);
} else if(!state->method->is_global) {
namespace_t ns = modifiers2access(mod);
-
- /* deal with protected */
- if(ns.access == ACCESS_PROTECTED && state->cls)
- ns.name = state->cls->info->name;
-
multiname_t mname = {QNAME, &ns, 0, name};
-
if(mod->flags&FLAG_STATIC)
f = abc_class_staticmethod(state->cls->abc, type2, &mname);
else
if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
if(params->varargs) f->flags |= METHOD_NEED_REST;
+ if(state->method->need_arguments) f->flags |= METHOD_NEED_ARGUMENTS;
char opt=0;
param_list_t*p=0;
check_constant_against_type(p->param->type, p->param->value);
opt=1;list_append(f->optional_parameters, p->param->value);
} else if(opt) {
- syntaxerror("non-optional parameter not allowed after optional parameters");
+ syntaxerror("function %s: non-optional parameter not allowed after optional parameters", name);
}
}
if(state->method->slots) {
}
}
-#define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
-
code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
{
if(from==to)
return abc_coerce2(c, &m);
}
+ if(TYPE_IS_XMLLIST(to) && TYPE_IS_XML(from))
+ return c;
+
if(TYPE_IS_BOOLEAN(to))
return abc_convert_b(c);
if(TYPE_IS_STRING(to))
infotypename(a), a->name, a->package, state->package);
}
+
if(a->kind != INFOTYPE_CLASS) {
MULTINAME(m, a);
x.c = abc_findpropstrict2(x.c, &m);
varinfo_t*v = (varinfo_t*)a;
x.t = v->type;
}
+ return x;
} else {
+ if(state->cls && state->method == state->cls->static_init) {
+ /* we're in the static initializer.
+ record the fact that we're using this class here */
+ parsedclass_add_dependency(state->cls->dependencies, (classinfo_t*)a);
+ }
classinfo_t*c = (classinfo_t*)a;
- if(c->slot) {
+ //if(c->slot) {
+ if(0) { //Error #1026: Slot 1 exceeds slotCount=0 of global
x.c = abc_getglobalscope(x.c);
x.c = abc_getslot(x.c, c->slot);
} else {
CODE: CODEPIECE {$$=$1;}
// code which may appear outside of methods
+CODE_STATEMENT: DEFAULT_NAMESPACE
CODE_STATEMENT: IMPORT
CODE_STATEMENT: FOR
CODE_STATEMENT: FOR_IN
CODE_STATEMENT: '{' CODE '}' {$$=$2;}
CODE_STATEMENT: '{' '}' {$$=0;}
-// code which may appear in methods
+// code which may appear in methods (includes the above)
CODEPIECE: ';' {$$=0;}
CODEPIECE: CODE_STATEMENT
CODEPIECE: VARIABLE_DECLARATION
X_IDENTIFIER: T_IDENTIFIER
| "package" {PASS12 $$="package";}
+ | "namespace" {PASS12 $$="namespace";}
| T_NAMESPACE {PASS12 $$=$1;}
PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
slotstate_varconst = varconst;
slotstate_flags = flags;
if(state->cls) {
- if(flags && flags->flags&FLAG_STATIC) {
- state->method = state->cls->static_init;
+ if(flags) {
+ if(flags->flags&FLAG_STATIC) {
+ state->method = state->cls->static_init;
+ } else {
+ state->method = state->cls->init;
+ }
} else {
- state->method = state->cls->init;
+ // reset to "default" state (all in class code is static by default) */
+ state->method = state->cls->static_init;
}
} else {
parserassert(state->method);
{
int flags = modifiers->flags;
namespace_t ns = modifiers2access(modifiers);
- /* deal with protected */
- if(ns.access == ACCESS_PROTECTED && state->cls)
- ns.name = state->cls->info->name;
/* slot name */
multiname_t mname = {QNAME, &ns, 0, name};
// instance variable
traits = &state->cls->abc->traits;
code = &state->cls->init->header;
+
+ if(ns.access == ACCESS_PROTECTED) {
+ ns.name = concat3(state->cls->info->package,":",state->cls->info->name);
+ }
}
if(c)
*c = code;
if(m)
- memcpy(m, &mname, sizeof(multiname_t));
+ *m = *multiname_clone(&mname);
return trait_new_member(traits, 0, multiname_clone(&mname), 0);
}
c = code_append(c, v.c);
c = converttype(c, v.t, $2);
if(!t->slot_id) {
- c = abc_setproperty2(c, &mname);
+ c = abc_initproperty2(c, &mname);
} else {
c = abc_setslot(c, t->slot_id);
}
XML: XMLNODE
-OPEN : '<' {PASS_ALWAYS tokenizer_begin_xml();xml_level++;}
+OPEN : '<' {PASS_ALWAYS if(!xml_level++) tokenizer_begin_xml();}
CLOSE : '>' {PASS_ALWAYS tokenizer_begin_xmltext();}
CLOSE2 : {PASS_ALWAYS if(!--xml_level) tokenizer_end_xml(); else tokenizer_begin_xmltext();}
+XMLEXPR1 : '{' E {PASS_ALWAYS tokenizer_begin_xmltext();} '}' {
+ $$=strdup("{...}");
+ as3_warning("xml string substitution not yet supported");
+}
+XMLEXPR2 : '{' E {PASS_ALWAYS tokenizer_begin_xml();} '}' {
+ $$=strdup("{...}");
+ as3_warning("xml string substitution not yet supported");
+}
XMLTEXT : {$$="";}
+XMLTEXT : XMLTEXT XMLEXPR1 {
+ $$ = concat2($1, "{...}");
+}
XMLTEXT : XMLTEXT T_STRING {$$=concat2($1, string_cstr(&$2));}
XMLTEXT : XMLTEXT '>' {$$=concat2($1, ">");}
XML2 : XMLNODE XMLTEXT {$$=concat2($1,$2);}
XML2 : XML2 XMLNODE XMLTEXT {$$=concat3($1,$2,$3);free($1);free($2);free($3);}
-XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' T_IDENTIFIER CLOSE2 '>' {
+XML_ID_OR_EXPR: T_IDENTIFIER {$$=$1;}
+XML_ID_OR_EXPR: XMLEXPR2 {$$=$1;}
+
+XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
$$ = allocprintf("<%s%s>%s</%s>", $2, $3, $5, $8);
free($2);free($3);free($5);free($8);
}
-XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
+XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES '/' CLOSE2 '>' {
$$ = allocprintf("<%s%s/>", $2, $3);
}
-XMLNODE : OPEN T_IDENTIFIER MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' T_IDENTIFIER CLOSE2 '>' {
+XMLNODE : OPEN XML_ID_OR_EXPR MAYBE_XMLATTRIBUTES CLOSE XMLTEXT XML2 '<' '/' XML_ID_OR_EXPR CLOSE2 '>' {
$$ = allocprintf("<%s%s>%s%s</%s>", $2, $3, $5, $6, $9);
- free($2);free($3);free($5);free($6);free($6);free($9);
+ free($2);free($3);free($5);free($6);free($9);
}
MAYBE_XMLATTRIBUTES: {$$=strdup("");}
MAYBE_XMLATTRIBUTES: XMLATTRIBUTES {$$=concat2(" ",$1);}
XMLATTRIBUTES: XMLATTRIBUTE {$$=$1;}
XMLATTRIBUTES: XMLATTRIBUTES XMLATTRIBUTE {$$=concat3($1," ",$2);free($1);free($2);}
+
+XMLATTRIBUTE: XMLEXPR2 {
+ $$ = strdup("{...}");
+}
+XMLATTRIBUTE: XMLEXPR2 '=' T_STRING {
+ char* str = string_cstr(&$3);
+ $$ = concat2("{...}=",str);
+}
+XMLATTRIBUTE: XMLEXPR2 '=' XMLEXPR2 {
+ $$ = strdup("{...}={...}");
+}
+XMLATTRIBUTE: T_IDENTIFIER '=' XMLEXPR2 {
+ $$ = concat2($1,"={...}");
+}
XMLATTRIBUTE: T_IDENTIFIER '=' T_STRING {
char* str = string_cstr(&$3);
- $$=allocprintf("%s=\"%s\"", $1,str);
+ $$=allocprintf("%s=%s", $1,str);
free(str);
free($1);free((char*)$3.str);
}
$$.c = code_append($$.c, paramcode);
$$.c = abc_constructprop2($$.c, name, $4.number);
multiname_destroy(name);
- } else if($$.c->opcode == OPCODE_GETSLOT) {
+ } else if(TYPE_IS_CLASS(v.t) && v.t->data) {
+ code_free($$.c);
+ classinfo_t*c = v.t->data;
+ MULTINAME(m, c);
+ $$.c = abc_findpropstrict2(0, &m);
+ $$.c = code_append($$.c, paramcode);
+ $$.c = abc_constructprop2($$.c, &m, $4.number);
+ /*} else if($$.c->opcode == OPCODE_GETSLOT) {
int slot = (int)(ptroff_t)$$.c->data[0];
trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);//FIXME
multiname_t*name = t->name;
$$.c = code_cutlast($$.c);
$$.c = code_append($$.c, paramcode);
- $$.c = abc_constructprop2($$.c, name, $4.number);
+ $$.c = abc_constructprop2($$.c, name, $4.number);*/
} else {
$$.c = code_append($$.c, paramcode);
$$.c = abc_construct($$.c, $4.number);
$$.c = code_append($$.c, paramcode);
$$.c = abc_callproperty2($$.c, name, $3.number);
multiname_destroy(name);
- } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
+/* } else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
int slot = (int)(ptroff_t)$$.c->data[0];
trait_t*t = traits_find_slotid(state->cls->abc->traits,slot);
if(t->kind!=TRAIT_METHOD) {
$$.c = code_cutlast($$.c);
$$.c = code_append($$.c, paramcode);
//$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
- $$.c = abc_callproperty2($$.c, name, $3.number);
+ $$.c = abc_callproperty2($$.c, name, $3.number);*/
} else if($$.c->opcode == OPCODE_GETSUPER) {
multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
$$.c = code_cutlast($$.c);
DICTLH: T_IDENTIFIER {$$=abc_pushstring(0,$1);}
DICTLH: T_STRING {$$=abc_pushstring2(0,&$1);}
+DICTLH: T_INT {syntaxerror("dictionary keys must be strings");}
+DICTLH: T_UINT {syntaxerror("dictionary keys must be strings");}
+DICTLH: T_FLOAT {syntaxerror("dictionary keys must be strings");}
DICT_EXPRPAIR_LIST : DICTLH ':' NONCOMMAEXPRESSION {
$$.cc = 0;
E : XML {
typedcode_t v;
v.c = 0;
- namespace_t ns = {ACCESS_PACKAGE, ""};
- multiname_t m = {QNAME, &ns, 0, "XML"};
+ multiname_t m = {QNAME, &stdns, 0, "XML"};
v.c = abc_getlex2(v.c, &m);
v.c = abc_pushstring(v.c, $1);
v.c = abc_construct(v.c, 1);
E : T_REGEXP {
typedcode_t v;
v.c = 0;
- namespace_t ns = {ACCESS_PACKAGE, ""};
- multiname_t m = {QNAME, &ns, 0, "RegExp"};
+ multiname_t m = {QNAME, &stdns, 0, "RegExp"};
if(!$1.options) {
v.c = abc_getlex2(v.c, &m);
v.c = abc_pushstring(v.c, $1.pattern);
$$ = mkcodenode(v);
}
+E : KW_ARGUMENTS {
+ PASS1
+ state->method->need_arguments = 1;
+ PASS2
+ typedcode_t v;
+ v.c = abc_getlocal(0, state->method->need_arguments);
+ v.t = TYPE_ARRAY;
+ $$ = mkcodenode(v);
+}
+
/* array */
E : '[' MAYBE_EXPRESSION_LIST ']' {
typedcode_t v;
}
E : '@' T_IDENTIFIER {
- // attribute occuring in .() loops
- // TODO
- $$ = mkdummynode();
- as3_warning("ignored @ operator");
+ typedcode_t v;
+ multiname_t m = {MULTINAMEA, 0, &nopackage_namespace_set, $2};
+ v.c = abc_getlex2(0, &m);
+ v.t = TYPE_STRING;
+ $$ = mkcodenode(v);
}
-E : E '.' '(' E ')' {
- // filter
- // TODO: this needs to be implemented using a loop
- $$ = mkdummynode();
- as3_warning("ignored .() operator");
+E : E '.' '(' {PASS12 new_state();state->xmlfilter=1;} E ')' {
+ PASS1 old_state();
+ PASS2
+ typedcode_t v = node_read($1);
+ typedcode_t w = node_read($5);
+ code_t*c = 0;
+ int index = alloc_local();
+ int result = alloc_local();
+ int tmp = alloc_local();
+ int xml = alloc_local();
+
+ c = code_append(c, v.c);
+ c = abc_checkfilter(c);
+ c = abc_coerce_a(c); //hasnext2 converts to *
+ c = abc_setlocal(c, xml);
+ multiname_t m = {QNAME, &stdns, 0, "XMLList"};
+ c = abc_getlex2(c, &m);
+ c = abc_construct(c, 0);
+ c = abc_setlocal(c, result);
+ c = abc_pushbyte(c, 0);
+ c = abc_setlocal(c, index);
+ code_t*jmp = c = abc_jump(c, 0);
+ code_t*loop = c = abc_label(c);
+ c = abc_getlocal(c, xml);
+ c = abc_getlocal(c, index);
+ c = abc_nextvalue(c);
+ c = abc_dup(c);
+ c = abc_setlocal(c, tmp);
+ c = abc_pushwith(c);
+ c = code_append(c, w.c);
+ c = abc_popscope(c);
+ code_t*b = c = abc_iffalse(c, 0);
+ c = abc_getlocal(c, result);
+ c = abc_getlocal(c, index);
+ c = abc_getlocal(c, tmp);
+ multiname_t m2 = {MULTINAMEL, 0, &nopackage_namespace_set, 0};
+ c = abc_setproperty2(c, &m2);
+ c = b->branch = jmp->branch = abc_nop(c);
+ c = abc_kill(c, tmp);
+ c = abc_hasnext2(c, xml, index);
+ c = abc_iftrue(c, loop);
+ c = abc_getlocal(c, result);
+ c = abc_kill(c, xml);
+ c = abc_kill(c, result);
+ c = abc_kill(c, index);
+
+ c = var_block(c);
+ old_state();
+ typedcode_t r;
+ r.c = c;
+ r.t = TYPE_XMLLIST;
+ $$ = mkcodenode(r);
}
ID_OR_NS : T_IDENTIFIER {$$=$1;}
+ID_OR_NS : '*' {$$="*";}
ID_OR_NS : T_NAMESPACE {$$=(char*)$1;}
-SUBNODE: T_IDENTIFIER
+SUBNODE: X_IDENTIFIER
| '*' {$$="*";}
+/*
+MAYBE_NS: T_IDENTIFIER "::" {$$=$1;}
+ | T_NAMESPACE "::" {$$=(char*)$1;}
+ | '*' "::" {$$="*";}
+ | {$$=0;}*/
+
E : E '.' ID_OR_NS "::" SUBNODE {
typedcode_t v = node_read($1);
typedcode_t w = node_read(resolve_identifier($3));
/* when resolving a property on an unknown type, we do know the
name of the property (and don't seem to need the package), but
we need to make avm2 try out all access modes */
- as3_warning("Resolving %s on unknown type", $3);
+ as3_softwarning("Resolving %s on unknown type", $3);
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
$$.c = abc_getproperty2($$.c, &m);
$$.c = abc_coerce_a($$.c);
return mkcodenode(o);
}
- int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
+ int i_am_static = state->method->is_static;
/* look at current class' members */
if(!state->method->inner &&
+ !state->xmlfilter &&
state->cls &&
(f = findmember_nsset(state->cls->info, name, 1)))
{
o.c = abc_getslot(o.c, f->slot);
return mkcodenode(o);
} else {
- namespace_t ns = {f->access, f->package};
- multiname_t m = {QNAME, &ns, 0, name};
+ MEMBER_MULTINAME(m, f, name);
o.c = abc_getlocal_0(o.c);
o.c = abc_getproperty2(o.c, &m);
return mkcodenode(o);
}
/* look at actual classes, in the current package and imported */
- if((a = find_class(name))) {
- o = push_class(a);
+ if(!state->xmlfilter && (a = find_class(name))) {
+ if(state->cls && state->cls->info == (classinfo_t*)a && i_am_static) {
+ o.c = abc_getlocal_0(0);
+ o.t = TYPE_CLASS((classinfo_t*)a);
+ } else {
+ o = push_class(a);
+ }
return mkcodenode(o);
}
/* look through package prefixes */
- if(dict_contains(state->import_toplevel_packages, name) ||
- registry_ispackage(name)) {
+ if(!state->xmlfilter &&
+ (dict_contains(state->import_toplevel_packages, name) ||
+ registry_ispackage(name))) {
o.c = abc___pushpackage__(o.c, name);
o.t = 0;
return mkcodenode(o); //?
/* unknown object, let the avm2 resolve it */
if(1) {
- //as3_softwarning("Couldn't resolve '%s', doing late binding", name);
- as3_warning("Couldn't resolve '%s', doing late binding", name);
+ if(!state->method->inner && !state->xmlfilter) {
+ /* we really should make inner functions aware of the class context */
+ as3_warning("Couldn't resolve '%s', doing late binding", name);
+ }
state->method->late_binding = 1;
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, name};
etc. which is *correct* because local variables of the parent function
would shadow those.
*/
+
if(!find_variable(state, $1)) {
if(state->method->inner) {
unknown_variable($1);
$$=0;
}
+DEFAULT_NAMESPACE : "default xml" "namespace" '=' E
+{
+ as3_warning("default xml namespaces not supported yet");
+}
+
USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
PASS12
const char*url = $3->name;