+ code_t*c = 0;
+
+ c = add_scope_code(c, m, 1);
+
+ methodstate_list_t*l = m->innerfunctions;
+ while(l) {
+ parserassert(l->methodstate->abc);
+ if(m->uses_slots && l->methodstate->is_a_slot) {
+ c = abc_getscopeobject(c, 1);
+ c = abc_newfunction(c, l->methodstate->abc);
+ c = abc_dup(c);
+ c = abc_setlocal(c, l->methodstate->var_index);
+ c = abc_setslot(c, l->methodstate->slot_index);
+ } else {
+ c = abc_newfunction(c, l->methodstate->abc);
+ c = abc_setlocal(c, l->methodstate->var_index);
+ }
+ free(l->methodstate);l->methodstate=0;
+ l = l->next;
+ }
+ if(m->header) {
+ c = code_append(c, m->header);
+ m->header = 0;
+ }
+ if(m->is_constructor && !m->has_super) {
+ // call default constructor
+ c = abc_getlocal_0(c);
+ c = abc_constructsuper(c, 0);
+ }
+
+ if(m->slots) {
+ /* all parameters that are used by inner functions
+ need to be copied from local to slot */
+ parserassert(m->activation_var);
+ DICT_ITERATE_ITEMS(m->slots,char*,name,variable_t*,v) {
+ if(v->is_parameter) {
+ c = abc_getlocal(c, m->activation_var);
+ c = abc_getlocal(c, v->index);
+ c = abc_setslot(c, v->index);
+ }
+ }
+ }
+ list_free(m->innerfunctions);
+ m->innerfunctions = 0;
+ return c;
+}
+
+
+static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
+{
+ c = code_append(c, header);
+ c = code_append(c, var_block(body, state->method->no_variable_scoping?state->method->allvars:state->vars));
+ /* append return if necessary */
+ if(!c || (c->opcode != OPCODE_RETURNVOID &&
+ c->opcode != OPCODE_RETURNVALUE)) {
+ c = abc_returnvoid(c);
+ }
+ return c;
+}
+
+static void startpackage(char*name)
+{
+ new_state();
+ state->package = strdup(name);
+}
+static void endpackage()
+{
+ //used e.g. in classinfo_register:
+ //free(state->package);state->package=0;
+ old_state();
+}
+
+#define FLAG_PUBLIC 256
+#define FLAG_PROTECTED 512
+#define FLAG_PRIVATE 1024
+#define FLAG_PACKAGEINTERNAL 2048
+#define FLAG_NAMESPACE 4096
+
+static slotinfo_t* find_class(const char*name);
+
+const char* lookup_namespace(const char*name)
+{
+ state_t*s = state;
+ while(s) {
+ const char*url = dict_lookup(s->namespaces, name);
+ if(url)
+ return url;
+ s = s->old;
+ }
+ varinfo_t*a;
+ registry_find(state->package, name);
+ if(( a = (varinfo_t*)find_class(name) )) {
+ if(a->kind == INFOTYPE_VAR) {
+ if(!a->value || !NS_TYPE(a->value->type))
+ syntaxerror("%s.%s is not a namespace", a->package, a->name);
+ return a->value->ns->name;
+ }
+ }
+ return 0;
+}
+
+static namespace_t modifiers2access(modifiers_t*mod)
+{
+ namespace_t ns;
+ ns.access = 0;
+ ns.name = "";
+ if(mod->flags&FLAG_NAMESPACE) {
+ if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels and namespaces");
+ ns.access = ACCESS_NAMESPACE;
+ const char*url = lookup_namespace(mod->ns);
+ if(!url) {
+ if(as3_pass>1) {
+ syntaxerror("unknown namespace: %s (pass %d)", mod->ns, as3_pass);
+ } else {
+ url = mod->ns;
+ }
+ }
+ ns.name = url;
+ } else if(mod->flags&FLAG_PUBLIC) {
+ if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels");
+ ns.access = ACCESS_PACKAGE;
+ } else if(mod->flags&FLAG_PRIVATE) {
+ if(mod->flags&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels");
+ ns.access = ACCESS_PRIVATE;
+ } else if(mod->flags&FLAG_PROTECTED) {
+ if(mod->flags&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL))
+ syntaxerror("invalid combination of access levels");
+ ns.access = ACCESS_PROTECTED;
+ } else {
+ ns.access = ACCESS_PACKAGEINTERNAL;
+ }
+ return ns;
+}
+
+static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse, char is_static)
+{
+ return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse, is_static);
+}
+
+static void innerfunctions2vars(methodstate_t*m)
+{
+ methodstate_list_t*l = m->innerfunctions;
+ while(l) {
+ methodstate_t*m = l->methodstate;
+
+ variable_t* v = new_variable2(state->method, 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;
+ if(m->inner)
+ index = new_variable(m, "this", 0, 0, 0);
+ else if(!m->is_global)
+ index = new_variable(m, (flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
+ else
+ index = new_variable(m, "globalscope", 0, 0, 0);
+ if(index) {
+ DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
+ printf("%s %d\n", name, v->index);
+ }
+ }
+ parserassert(!index);
+ }
+
+ if(has_params) {
+ param_list_t*p=0;
+ for(p=params->list;p;p=p->next) {
+ variable_t*v = new_variable2(m, 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(m, "arguments", TYPE_ARRAY, 0, 0);
+ m->need_arguments = v->index;
+ }
+ }
+
+ innerfunctions2vars(m);
+
+ if(as3_pass==2) {
+ m->scope_code = add_scope_code(m->scope_code, m, 0);
+ if(m->slots) {
+ /* exchange unresolved identifiers with the actual objects */
+ DICT_ITERATE_ITEMS(m->slots, char*, name, variable_t*, v1) {
+ if(v1->type && v1->type->kind == INFOTYPE_UNRESOLVED) {
+ classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v1->type);
+ if(!type || type->kind != INFOTYPE_CLASS) {
+ syntaxerror("Couldn't find class %s::%s (%s)", v1->type->package, v1->type->name, name);
+ }
+ v1->type = type;
+ }
+ }
+ }
+ if(m->allvars) {
+ DICT_ITERATE_ITEMS(m->allvars, char*, name2, variable_t*, v2) {
+ if(v2->type && v2->type->kind == INFOTYPE_UNRESOLVED) {
+ classinfo_t*type = (classinfo_t*)registry_resolve((slotinfo_t*)v2->type);
+ if(!type || type->kind != INFOTYPE_CLASS) {
+ syntaxerror("Couldn't find class %s::%s (%s)", v2->type->package, v2->type->name, name2);
+ }
+ v2->type = type;
+ }
+ }
+ }
+ }
+}
+
+
+char*as3_globalclass=0;
+static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, classinfo_list_t*implements)
+{
+ if(state->cls) {
+ syntaxerror("inner classes now allowed");
+ }
+
+ new_state();
+ token_list_t*t=0;
+ classinfo_list_t*mlist=0;
+
+ if(mod->flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC|FLAG_INTERFACE))
+ syntaxerror("invalid modifier(s)");
+
+ 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
+ extends = registry_getobjectclass();
+ }
+
+ /* create the class name, together with the proper attributes */
+ int access=0;
+ char*package=0;
+
+ if(!(mod->flags&FLAG_PUBLIC) && state->package==internal_filename_package) {
+ access = ACCESS_PRIVATE; package = internal_filename_package;
+ } else if(!(mod->flags&FLAG_PUBLIC) && state->package!=internal_filename_package) {
+ access = ACCESS_PACKAGEINTERNAL; package = state->package;
+ } else if(state->package!=internal_filename_package) {
+ access = ACCESS_PACKAGE; package = state->package;
+ } else {
+ syntaxerror("public classes only allowed inside a package");
+ }
+
+ if(as3_pass==1) {
+ state->cls = rfx_calloc(sizeof(classstate_t));
+ state->cls->init = methodstate_new();
+ state->cls->static_init = methodstate_new();
+ state->cls->static_init->is_static=FLAG_STATIC;
+ /* notice: we make no effort to initialize the top variable (local0) here,
+ 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);
+
+ /* set current method to constructor- all code within the class-level (except
+ static variable initializations) will be executed during construction time */
+ state->method = state->cls->init;
+
+ if(registry_find(package, classname)) {
+ syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
+ }
+ /* build info struct */
+ int num_interfaces = (list_length(implements));
+ state->cls->info = classinfo_register(access, package, classname, num_interfaces);
+ state->cls->info->flags |= mod->flags & (FLAG_DYNAMIC|FLAG_INTERFACE|FLAG_FINAL);
+ state->cls->info->superclass = extends;
+
+ int pos = 0;
+ classinfo_list_t*l = implements;
+ for(l=implements;l;l=l->next) {
+ state->cls->info->interfaces[pos++] = l->classinfo;
+ }
+ }
+
+ if(as3_pass == 2) {
+ state->cls = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+
+ parserassert(state->cls && state->cls->info);
+
+ state->method = state->cls->static_init;
+
+ function_initvars(state->cls->init, 0, 0, 0, 1);
+ state->cls->static_init->variable_count=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);
+
+ int pos = 0;
+ while(state->cls->info->interfaces[pos]) {
+ if(!(state->cls->info->interfaces[pos]->flags & FLAG_INTERFACE))
+ syntaxerror("'%s' is not an interface",
+ state->cls->info->interfaces[pos]->name);
+ pos++;
+ }
+
+ /* generate the abc code for this class */
+ MULTINAME(classname2,state->cls->info);
+ multiname_t*extends2 = sig2mname(extends);
+
+ /* don't add the class to the class index just yet- that will be done later
+ by initscript */
+ state->cls->abc = abc_class_new(0, &classname2, extends2);
+ state->cls->abc->file = global->file;
+
+ multiname_destroy(extends2);
+ if(state->cls->info->flags&FLAG_FINAL) abc_class_final(state->cls->abc);
+ if(!(state->cls->info->flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
+ if(state->cls->info->flags&FLAG_INTERFACE) {
+ abc_class_interface(state->cls->abc);
+ }
+
+ for(mlist=implements;mlist;mlist=mlist->next) {
+ MULTINAME(m, mlist->classinfo);
+ abc_class_add_interface(state->cls->abc, &m);
+ }
+
+ 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)) {
+ if(state->package && state->package[0]) {
+ as3_globalclass = concat3(state->package, ".", classname);