m##_l.namespace = &m##_ns; \
multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
+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_list_t nl3 = {&ns3,&nl4};
+static namespace_list_t nl2 = {&ns2,&nl3};
+static namespace_list_t nl1 = {&ns1,&nl2};
+static namespace_set_t nopackage_namespace_set = {&nl1};
+
static state_list_t*state_stack=0;
static void init_globals()
state->file = abc_file_new();
state->file->flags &= ~ABCFILE_LAZY;
- state->init = abc_initscript(state->file, 0, 0);
+ state->init = abc_initscript(state->file, 0);
code_t*c = state->init->method->body->code;
c = abc_getlocal_0(c);
{
if(state->cls_init) {
if(!state->cls->constructor) {
- abc_method_t*m = abc_class_constructor(state->cls, 0, 0);
+ abc_method_t*m = abc_class_constructor(state->cls, 0);
m->body->code = code_append(m->body->code, state->cls_init);
m->body->code = abc_returnvoid(m->body->code);
} else {
}
if(state->cls_static_init) {
if(!state->cls->static_constructor) {
- abc_method_t*m = abc_class_staticconstructor(state->cls, 0, 0);
- m->body->code = state->cls_static_init;
+ abc_method_t*m = abc_class_staticconstructor(state->cls, 0);
+ m->body->code = code_append(m->body->code, state->cls_static_init);
+ m->body->code = abc_returnvoid(m->body->code);
} else {
state->cls->static_constructor->body->code =
code_append(state->cls_static_init, state->cls->static_constructor->body->code);
}
}
-static memberinfo_t*registerfunction(enum yytokentype getset, char*name, params_t*params, classinfo_t*return_type, int slot)
+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) {
/* can't assign a slot as getter and setter might have different slots */
//minfo->slot = slot;
}
+ if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
+ if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
+ if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
+ if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
+ if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
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)
{
syntaxerror("not able to start another method scope");
}
+ namespace_t mname_ns = {flags2access(flags), ""};
+ multiname_t mname = {QNAME, &mname_ns, 0, name};
+
multiname_t*type2 = sig2mname(return_type);
+ int slot = 0;
if(!strcmp(state->clsinfo->name,name)) {
- state->m = abc_class_constructor(state->cls, type2, 0);
+ state->m = abc_class_constructor(state->cls, type2);
+ name = "__as3_constructor__";
} else {
- state->m = abc_class_method(state->cls, type2, name, 0);
- int slot = state->m->trait->slot_id;
- state->minfo = registerfunction(getset, name, params, return_type, slot);
+ if(flags&FLAG_STATIC)
+ state->m = abc_class_staticmethod(state->cls, type2, &mname);
+ else
+ state->m = abc_class_method(state->cls, type2, &mname);
+ slot = state->m->trait->slot_id;
}
+ state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
}
/* state->vars is initialized by state_new */
- if(new_variable("this", state->clsinfo)!=0) syntaxerror("Internal error");
+ if(new_variable((flags&FLAG_STATIC)?"class":"this", state->clsinfo)!=0) syntaxerror("Internal error");
for(p=params->list;p;p=p->next) {
new_variable(p->param->name, p->param->type);
if(!b) syntaxerror("internal error: assertion failed");
}
+static classinfo_t* find_class(char*name)
+{
+ classinfo_t*c=0;
+
+ c = registry_findclass(state->package, name);
+
+ /* try explicit imports */
+ dictentry_t* e = dict_get_slot(state->imports, name);
+ while(e) {
+ if(c)
+ break;
+ if(!strcmp(e->key, name)) {
+ c = (classinfo_t*)e->data;
+ }
+ e = e->next;
+ }
+
+ /* 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);
+ l = l->next;
+ }
+
+ /* try global package */
+ if(!c) {
+ c = registry_findclass("", name);
+ }
+ return c;
+}
+
static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
{
/* converts this:
write->opcode = OPCODE_SETPROPERTY;
multiname_t*m = (multiname_t*)r->data[0];
write->data[0] = multiname_clone(m);
- if(m->type != QNAME)
+ if(m->type != QNAME && m->type != MULTINAME)
syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
if(!justassign) {
- use_temp_var = 1;
prefix = abc_dup(prefix); // we need the object, too
}
+ use_temp_var = 1;
} else if(r->opcode == OPCODE_GETSLOT) {
write->opcode = OPCODE_SETSLOT;
write->data[0] = r->data[0];
if(!justassign) {
- use_temp_var = 1;
prefix = abc_dup(prefix); // we need the object, too
}
+ use_temp_var = 1;
} else if(r->opcode == OPCODE_GETLOCAL) {
write->opcode = OPCODE_SETLOCAL;
write->data[0] = r->data[0];
} else {
/* even smaller version: overwrite the value without reading
it out first */
- if(prefix) {
- c = code_append(c, prefix);
+ if(!use_temp_var) {
+ if(prefix) {
+ c = code_append(c, prefix);
+ c = abc_dup(c);
+ }
+ c = code_append(c, middlepart);
+ c = code_append(c, write);
+ c = code_append(c, r);
+ } else {
+ temp = gettempvar();
+ if(prefix) {
+ c = code_append(c, prefix);
+ c = abc_dup(c);
+ }
+ c = code_append(c, middlepart);
c = abc_dup(c);
+ c = abc_setlocal(c, temp);
+ c = code_append(c, write);
+ c = abc_getlocal(c, temp);
}
- c = code_append(c, middlepart);
- c = code_append(c, write);
- c = code_append(c, r);
}
return c;
syntaxerror("variable declarations not allowed in interfaces");
}
IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
- if($1&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
- syntaxerror("invalid method modifiers: interface methods are always public");
+ $1 |= FLAG_PUBLIC;
+ if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
+ syntaxerror("invalid method modifiers: interface methods always need to be public");
}
startfunction(0,$1,$3,$4,&$6,$8);
endfunction(0);
/* ------------ classes and interfaces (body, slots ) ------- */
VARCONST: "var" | "const"
-SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
+ int flags = $1;
memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
info->type = $4;
-
+ info->flags = flags;
trait_t*t=0;
- if($4) {
- MULTINAME(m, $4);
- t=abc_class_slot(state->cls, $3, &m);
+
+ 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, &mname, &m);
+ } else {
+ t=abc_class_slot(state->cls, &mname, 0);
+ }
+ info->slot = t->slot_id;
} else {
- t=abc_class_slot(state->cls, $3, 0);
- }
- if($2==KW_CONST) {
- t->kind= TRAIT_CONST;
+ if($4) {
+ MULTINAME(m, $4);
+ t=abc_class_staticslot(state->cls, &mname, &m);
+ } else {
+ t=abc_class_staticslot(state->cls, &mname, 0);
+ }
+ info->slot = t->slot_id;
}
- info->slot = t->slot_id;
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);
- //c = abc_setproperty(c, $3);
- state->cls_init = code_append(state->cls_init, c);
+ 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);
+ }
+ if($2==KW_CONST) {
+ t->kind= TRAIT_CONST;
}
}
CLASS: T_IDENTIFIER {
/* try current package */
- $$ = registry_findclass(state->package, $1);
-
- /* try explicit imports */
- dictentry_t* e = dict_get_slot(state->imports, $1);
- while(e) {
- if($$)
- break;
- if(!strcmp(e->key, $1)) {
- $$ = (classinfo_t*)e->data;
- }
- e = e->next;
- }
-
- /* try package.* imports */
- import_list_t*l = state->wildcard_imports;
- while(l) {
- if($$)
- break;
- //printf("does package %s contain a class %s?\n", l->import->package, $1);
- $$ = registry_findclass(l->import->package, $1);
- l = l->next;
- }
-
- /* try global package */
- if(!$$) {
- $$ = registry_findclass("", $1);
- }
-
+ $$ = find_class($1);
if(!$$) syntaxerror("Could not find class %s\n", $1);
}
MULTINAME(m, $2);
$$.c = code_new();
- /* TODO: why do we have to *find* our own classes? */
- $$.c = abc_findpropstrict2($$.c, &m);
+ if($2->slot) {
+ $$.c = abc_getglobalscope($$.c);
+ $$.c = abc_getslot($$.c, $2->slot);
+ } else {
+ $$.c = abc_findpropstrict2($$.c, &m);
+ }
typedcode_list_t*l = $3;
int len = 0;
l = l->next;
len ++;
}
- $$.c = abc_constructprop2($$.c, &m, len);
+ if($2->slot)
+ $$.c = abc_construct($$.c, len);
+ else
+ $$.c = abc_constructprop2($$.c, &m, len);
$$.t = $2;
}
E : E '.' T_IDENTIFIER
{$$.c = $1.c;
- if($$.t) {
- memberinfo_t*f = registry_findmember($$.t, $3);
+ classinfo_t*t = $1.t;
+ char is_static = 0;
+ if(TYPE_IS_CLASS(t)) {
+ memberinfo_t*m = registry_findmember($1.t, "prototype");
+ if(!m) syntaxerror("identifier '%s' not found in anonymous class", $3);
+ t = m->type;
+ is_static = 1;
+ }
+ if(t) {
+ memberinfo_t*f = registry_findmember(t, $3);
+ char noslot = 0;
+ if(f && !is_static != !(f->flags&FLAG_STATIC))
+ noslot=1;
- if(f && f->slot) {
+ if(f && f->slot && !noslot) {
$$.c = abc_getslot($$.c, f->slot);
} else {
- namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
- multiname_t m = {QNAME, &ns, 0, $3};
- $$.c = abc_getproperty2($$.c, &m);
+ if(f) {
+ namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
+ multiname_t m = {QNAME, &ns, 0, $3};
+ $$.c = abc_getproperty2($$.c, &m);
+ } else {
+ multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
+ $$.c = abc_getproperty2($$.c, &m);
+ }
}
/* determine type */
if(f) {
$$.t = registry_getanytype();
}
} else {
- namespace_t ns = {ACCESS_PACKAGE, ""};
- multiname_t m = {QNAME, &ns, 0, $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 do need to make avm2 try out all access modes */
+ multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
$$.c = abc_getproperty2($$.c, &m);
$$.c = abc_coerce_a($$.c);
$$.t = registry_getanytype();
$$.t = 0;
$$.c = 0;
int i;
+ classinfo_t*a = 0;
memberinfo_t*f = 0;
+
+ /* look at variables */
if((i = find_variable($1, &$$.t)) >= 0) {
// $1 is a local variable
$$.c = abc_getlocal($$.c, i);
+
+ /* look at current class' members */
} else if((f = registry_findmember(state->clsinfo, $1))) {
// $1 is a function in this class
+ int var_is_static = (f->flags&FLAG_STATIC);
+ int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
+ if(var_is_static != i_am_static) {
+ /* there doesn't seem to be any "static" way to access
+ static properties of a class */
+ state->late_binding = 1;
+ $$.t = f->type;
+ namespace_t ns = {flags2access(f->flags), ""};
+ multiname_t m = {QNAME, &ns, 0, $1};
+ $$.c = abc_findpropstrict2($$.c, &m);
+ $$.c = abc_getproperty2($$.c, &m);
+ } else {
+ if(f->slot>0) {
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = abc_getslot($$.c, f->slot);
+ } else {
+ namespace_t ns = {flags2access(f->flags), ""};
+ multiname_t m = {QNAME, &ns, 0, $1};
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = abc_getproperty2($$.c, &m);
+ }
+ }
if(f->kind == MEMBER_METHOD) {
$$.t = TYPE_FUNCTION(f);
} else {
$$.t = f->type;
}
- if(f->slot>0) {
- $$.c = abc_getlocal_0($$.c);
- $$.c = abc_getslot($$.c, f->slot);
+
+ /* look at classes in the current package and imported classes */
+ } else if((a = find_class($1))) {
+ if(a->slot) {
+ $$.c = abc_getglobalscope($$.c);
+ $$.c = abc_getslot($$.c, a->slot);
} else {
- namespace_t ns = {state->clsinfo->access, ""};
- multiname_t m = {QNAME, &ns, 0, $1};
- $$.c = abc_getlocal_0($$.c);
- $$.c = abc_getproperty2($$.c, &m);
+ MULTINAME(m, a);
+ $$.c = abc_getlex2($$.c, &m);
}
+ $$.t = TYPE_CLASS(a);
+
+ /* unknown object, let the avm2 resolve it */
} else {
- // let the avm2 resolve $1
if(strcmp($1,"trace"))
- warning("Couldn't resolve %s, doing late binding", $1);
+ warning("Couldn't resolve %s, doing late binding", $1);
state->late_binding = 1;
+
+ multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
$$.t = 0;
- $$.c = abc_findpropstrict($$.c, $1);
- $$.c = abc_getproperty($$.c, $1);
+ $$.c = abc_findpropstrict2($$.c, &m);
+ $$.c = abc_getproperty2($$.c, &m);
}
}