#include "abc.h"
#include "pool.h"
#include "files.h"
+#include "common.h"
#include "tokenizer.h"
#include "registry.h"
#include "code.h"
#include "opcodes.h"
#include "compiler.h"
+#include "expr.h"
extern int a3_lex();
abc_exception_t *exception;
regexp_t regexp;
modifiers_t flags;
+ namespace_decl_t* namespace_decl;
+ node_t*node;
struct {
abc_exception_list_t *l;
code_t*finally;
%token<token> T_EMPTY
%token<number_int> T_INT
%token<number_uint> T_UINT
-%token<number_uint> T_BYTE
-%token<number_uint> T_SHORT
%token<number_float> T_FLOAT
%token<id> T_FOR "for"
%token<token> KW_FUNCTION "function"
%token<token> KW_FINALLY "finally"
%token<token> KW_UNDEFINED "undefined"
+%token<token> KW_NAN "NaN"
%token<token> KW_CONTINUE "continue"
%token<token> KW_CLASS "class"
%token<token> KW_CONST "const"
%token<token> T_DIVBY "/="
%token<token> T_MODBY "%="
%token<token> T_MULBY "*="
+%token<token> T_ANDBY "&="
%token<token> T_PLUSBY "+="
%token<token> T_MINUSBY "-="
%token<token> T_XORBY "^="
%token<token> T_USHR ">>>"
%token<token> T_SHR ">>"
+%type <number_int> CONDITIONAL_COMPILATION
%type <for_start> FOR_START
-%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER NAMESPACE_ID
+%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
+%type <namespace_decl> NAMESPACE_ID
%type <token> VARCONST
%type <code> CODE
%type <code> CODEPIECE CODE_STATEMENT
%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
-%type <code> PACKAGE_DECLARATION SLOT_DECLARATION
+%type <code> PACKAGE_DECLARATION SLOT_DECLARATION SLOT_LIST ONE_SLOT
%type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW
%type <exception> CATCH FINALLY
%type <code> VOIDEXPRESSION
%type <value> EXPRESSION NONCOMMAEXPRESSION
%type <value> MAYBEEXPRESSION
-%type <value> E DELETE
-%type <value> CONSTANT
+%type <value> DELETE
+%type <node> E COMMA_EXPRESSION
%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
%type <value> INNERFUNCTION
%type <code> USE_NAMESPACE
%type <flags> MAYBE_MODIFIERS
%type <flags> MODIFIER_LIST
%type <flags> MODIFIER
-%type <constant> STATICCONSTANT MAYBESTATICCONSTANT
+%type <constant> CONSTANT MAYBECONSTANT
%type <classinfo_list> IMPLEMENTS_LIST
%type <classinfo> EXTENDS CLASS_SPEC
%type <classinfo_list> EXTENDS_LIST
%type <classinfo> TYPE
//%type <token> VARIABLE
-%type <value> VAR_READ
+%type <value> VAR_READ MEMBER
%type <value> NEW
//%type <token> T_IDENTIFIER
%type <value> FUNCTIONCALL
-%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
+%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST EXPRESSION_LIST_AND_COMMA MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST WITH_HEAD
// precedence: from low to high
// needed for "return" precedence:
%nonassoc T_STRING T_REGEXP
-%nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
+%nonassoc T_INT T_UINT T_FLOAT KW_NAN
%nonassoc "false" "true" "null" "undefined" "super" "function"
%left above_function
return 0; //make gcc happy
}
+static void parsererror(const char*file, int line, const char*f)
+{
+ syntaxerror("internal error in %s, %s:%d", f, file, line);
+}
+
+#define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
+
static char* concat2(const char* t1, const char* t2)
{
typedef struct _import {
char*package;
} import_t;
-
DECLARE_LIST(import);
DECLARE(methodstate);
struct _methodstate {
/* method data */
methodinfo_t*info;
+ char has_exceptions;
char late_binding;
char is_constructor;
char has_super;
char uses_parent_function;
int uses_slots;
dict_t*slots;
+ int activation_var;
abc_method_t*abc;
int var_index; // for inner methods
char is_a_slot; // for inner methods
code_t*header;
+
+ code_t*scope_code;
abc_exception_list_t*exceptions;
methodstate_list_t*innerfunctions;
char*package;
import_list_t*wildcard_imports;
- namespace_list_t*active_namespaces;
+ dict_t*import_toplevel_packages;
dict_t*imports;
+
+ namespace_list_t*active_namespace_urls;
+
char has_own_imports;
char new_vars; // e.g. transition between two functions
methodstate_t*method;
char*exception_name;
+
+ int switch_var;
dict_t*vars;
} state_t;
static namespace_list_t nl1 = {&ns1,&nl2};
static namespace_set_t nopackage_namespace_set = {&nl1};
+static dict_t*definitions=0;
+void as3_set_define(const char*c)
+{
+ if(!definitions)
+ definitions = dict_new();
+ if(!dict_contains(definitions,c))
+ dict_put(definitions,c,0);
+}
+
static void new_state()
{
NEW(state_t, s);
if(!s->imports) {
s->imports = dict_new();
}
+ if(!s->import_toplevel_packages) {
+ s->import_toplevel_packages = dict_new();
+ }
state = s;
state->level++;
state->has_own_imports = 0;
state->vars = dict_new();
state->old = oldstate;
state->new_vars = 0;
-}
-static void state_has_imports()
-{
- state->wildcard_imports = list_clone(state->wildcard_imports);
- state->imports = dict_clone(state->imports);
- state->has_own_imports = 1;
+
+ trie_remember(active_namespaces);
+
+ if(oldstate)
+ state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
}
static void state_destroy(state_t*state)
dict_destroy(state->vars);state->vars=0;
}
+ list_free(state->active_namespace_urls)
+ state->active_namespace_urls = 0;
+
free(state);
}
static void old_state()
{
+ trie_rollback(active_namespaces);
+
if(!state || !state->old)
syntaxerror("invalid nesting");
state_t*leaving = state;
state = state->old;
-
+
if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
free(leaving->method);
leaving->method=0;
free(leaving->cls);
leaving->cls=0;
}
-
+
state_destroy(leaving);
}
if(state) {
syntaxerror("invalid call to initialize_file during parsing of another file");
}
+
+ active_namespaces = trie_new();
+
new_state();
state->package = internal_filename_package = strdup(filename);
if(as3_pass==1) {
state->method = rfx_calloc(sizeof(methodstate_t));
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
+ state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
} else {
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);
global->init = abc_initscript(global->file);
- state->method->late_binding = 1; // init scripts use getglobalscope, so we need a getlocal0/pushscope
}
}
if(!state || state->level!=1) {
syntaxerror("unexpected end of file in pass %d", as3_pass);
}
-
+
if(as3_pass==2) {
+ dict_del(global->file2token2info, current_filename);
+
code_t*header = method_header(state->method);
code_t*c = wrap_function(header, 0, global->init->method->body->code);
global->init->method->body->code = c;
void* finish_parser()
{
dict_free_all(global->file2token2info, 1, (void*)dict_destroy);
-
global->token2info=0;
-
return global->file;
}
-
-static void xx_scopetest()
-{
- /* findpropstrict doesn't just return a scope object- it
- also makes it "active" somehow. Push local_0 on the
- scope stack and read it back with findpropstrict, it'll
- contain properties like "trace". Trying to find the same
- property on a "vanilla" local_0 yields only a "undefined" */
- //c = abc_findpropstrict(c, "[package]::trace");
-
- /*c = abc_getlocal_0(c);
- c = abc_findpropstrict(c, "[package]::trace");
- c = abc_coerce_a(c);
- c = abc_setlocal_1(c);
-
- c = abc_pushbyte(c, 0);
- c = abc_setlocal_2(c);
-
- code_t*xx = c = abc_label(c);
- c = abc_findpropstrict(c, "[package]::trace");
- c = abc_pushstring(c, "prop:");
- c = abc_hasnext2(c, 1, 2);
- c = abc_dup(c);
- c = abc_setlocal_3(c);
- c = abc_callpropvoid(c, "[package]::trace", 2);
- c = abc_getlocal_3(c);
- c = abc_kill(c, 3);
- c = abc_iftrue(c,xx);*/
-}
-
typedef struct _variable {
int index;
classinfo_t*type;
char init;
+ char is_parameter;
methodstate_t*is_inner_method;
} variable_t;
syntaxerror("undefined variable: %s", name);
return v;
}
+
static char variable_exists(char*name)
{
return dict_contains(state->vars, name);
}
-code_t*defaultvalue(code_t*c, classinfo_t*type);
+
+static code_t*defaultvalue(code_t*c, classinfo_t*type)
+{
+ if(TYPE_IS_INT(type)) {
+ c = abc_pushbyte(c, 0);
+ } else if(TYPE_IS_UINT(type)) {
+ c = abc_pushuint(c, 0);
+ } else if(TYPE_IS_FLOAT(type)) {
+ c = abc_pushnan(c);
+ } else if(TYPE_IS_BOOLEAN(type)) {
+ c = abc_pushfalse(c);
+ } else if(!type) {
+ //c = abc_pushundefined(c);
+ syntaxerror("internal error: can't generate default value for * type");
+ } else {
+ c = abc_pushnull(c);
+ MULTINAME(m, type);
+ c = abc_coerce2(c, &m);
+ }
+ return c;
+}
+
+static int alloc_local()
+{
+ return state->method->variable_count++;
+}
static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
{
}
NEW(variable_t, v);
- v->index = state->method->variable_count++;
+ v->index = alloc_local();
v->type = type;
v->init = init;
-
- dict_put(state->vars, name, v);
+
+ if(name)
+ dict_put(state->vars, name, v);
return v;
}
}
#define TEMPVARNAME "__as3_temp__"
-static int gettempvar()
+int gettempvar()
{
variable_t*v = find_variable(state, TEMPVARNAME);
if(v)
return new_variable(TEMPVARNAME, 0, 0, 0);
}
-code_t* var_block(code_t*body)
+static code_t* var_block(code_t*body)
{
code_t*c = 0;
code_t*k = 0;
return c;
}
-void unknown_variable(char*name)
+static void unknown_variable(char*name)
{
if(!state->method->unresolved_variables)
state->method->unresolved_variables = dict_new();
dict_put(state->method->unresolved_variables, name, 0);
}
-#define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
-
-static void parsererror(const char*file, int line, const char*f)
+static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
{
- syntaxerror("internal error in %s, %s:%d", f, file, line);
-}
-
-
-static code_t* method_header(methodstate_t*m)
-{
- code_t*c = 0;
- if(m->uses_slots || (m->late_binding && !m->inner)) {
+ if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
c = abc_getlocal_0(c);
c = abc_pushscope(c);
}
if(m->uses_slots) {
- c = abc_newactivation(c);
- c = abc_pushscope(c);
+ /* FIXME: this alloc_local() causes variable indexes to be
+ different in pass2 than in pass1 */
+ if(!m->activation_var)
+ m->activation_var = alloc_local();
+ if(init) {
+ c = abc_newactivation(c);
+ c = abc_dup(c);
+ c = abc_pushscope(c);
+ c = abc_setlocal(c, m->activation_var);
+ } else {
+ c = abc_getlocal(c, m->activation_var);
+ c = abc_pushscope(c);
+ }
}
+ return c;
+}
+
+static code_t* method_header(methodstate_t*m)
+{
+ code_t*c = 0;
+
+ c = add_scope_code(c, m, 1);
+
methodstate_list_t*l = m->innerfunctions;
while(l) {
parserassert(l->methodstate->abc);
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;
return c;
}
-
static void startpackage(char*name)
{
new_state();
- /*printf("entering package \"%s\"\n", name);*/
state->package = strdup(name);
}
static void endpackage()
{
- /*printf("leaving package \"%s\"\n", state->package);*/
-
//used e.g. in classinfo_register:
//free(state->package);state->package=0;
-
old_state();
}
if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL))
syntaxerror("invalid combination of access levels and namespaces");
ns.access = ACCESS_NAMESPACE;
- ns.name = mod->ns;
+ state_t*s = state;
+ const char*url = (const char*)trie_lookup(active_namespaces, mod->ns);
+ if(!url) {
+ /* shouldn't happen- the tokenizer only reports something as a namespace
+ if it was already registered */
+ trie_dump(active_namespaces);
+ syntaxerror("unknown namespace: %s", 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");
}
return ns;
}
+static slotinfo_t* find_class(const char*name);
+
+static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char recurse)
+{
+ 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)
{
*(int*)0=0;
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;
+ m->variable_count = m->uses_slots;
}
if(params) {
param_list_t*p=0;
for(p=params->list;p;p=p->next) {
- new_variable(p->param->name, p->param->type, 0, 1);
+ variable_t*v = new_variable2(p->param->name, p->param->type, 0, 1);
+ v->is_parameter = 1;
}
}
-
+
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;
}
+
+ 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);
+ }
+ v->type = type;
+ }
+ }
+ }
}
if(state->cls) {
syntaxerror("inner classes now allowed");
}
+
new_state();
token_list_t*t=0;
classinfo_list_t*mlist=0;
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_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;
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);
+
+ 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) {
if(extends && (extends->flags & FLAG_FINAL))
syntaxerror("Can't extend final class '%s'", extends->name);
-
- /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
- state->cls->info->superclass = extends?extends:TYPE_OBJECT;
+
int pos = 0;
- classinfo_list_t*l = implements;
- for(l=implements;l;l=l->next) {
- if(!(l->classinfo->flags & FLAG_INTERFACE))
- syntaxerror("'%s' is not an interface", l->classinfo->name);
- state->cls->info->interfaces[pos++] = l->classinfo;
+ 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++;
}
+ /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
+ state->cls->info->superclass = extends;
+
/* generate the abc code for this class */
MULTINAME(classname2,state->cls->info);
multiname_t*extends2 = sig2mname(extends);
}
}
-static void setstaticfunction(int x)
-{
- if(state->cls) {
- if(x&FLAG_STATIC) {
- state->method = state->cls->static_init;
- } else {
- state->method = state->cls->init;
- }
- } else {
- parserassert(state->method);
- }
-}
-
static void endclass()
{
if(as3_pass == 2) {
char*name = string_cstr(c->data[0]);
syntaxerror("Unresolved \"continue %s\"", name);
}
+ if(c->opcode == OPCODE___RETHROW__) {
+ syntaxerror("Unresolved \"rethrow\"");
+ }
+ if(c->opcode == OPCODE___FALLTHROUGH__) {
+ syntaxerror("Unresolved \"fallthrough\"");
+ }
+ if(c->opcode == OPCODE___PUSHPACKAGE__) {
+ char*name = string_cstr(c->data[0]);
+ syntaxerror("Can't reference a package (%s) as such", name);
+ }
c=c->prev;
}
}
-
static void check_constant_against_type(classinfo_t*t, constant_t*c)
{
#define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
return;
if(m->flags & FLAG_FINAL)
syntaxerror("can't override final member %s", m->name);
+
+ /* allow this. it's no issue.
if((m->flags & FLAG_STATIC) && !(flags&FLAG_STATIC))
- syntaxerror("can't override static member %s", m->name);
+ syntaxerror("can't override static member %s", m->name);*/
+
if(!(m->flags & FLAG_STATIC) && (flags&FLAG_STATIC))
syntaxerror("can't override non-static member %s with static declaration", m->name);
- if(!(flags&FLAG_OVERRIDE)) {
+ if(!(flags&FLAG_OVERRIDE) && !(flags&FLAG_STATIC) && !(m->flags&FLAG_STATIC)) {
if(m->parent && !(m->parent->flags&FLAG_INTERFACE)) {
if(m->kind == INFOTYPE_METHOD)
syntaxerror("can't override without explicit 'override' declaration");
if(!state->cls) {
//package method
minfo = methodinfo_register_global(ns.access, state->package, name);
- minfo->return_type = return_type;
+ minfo->return_type = 0; // save this for pass 2
} else if(getset != KW_GET && getset != KW_SET) {
//class method
memberinfo_t* m = registry_findmember(state->cls->info, ns.name, name, 0);
if(m) {
- printf("%s.%s | %s.%s\n",
- m->package, m->name,
- ns.name, name);
syntaxerror("class already contains a %s '%s'", infotypename((slotinfo_t*)m), m->name);
}
minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
- minfo->return_type = return_type;
+ minfo->return_type = 0; // save this for pass 2
// getslot on a member slot only returns "undefined", so no need
// to actually store these
//state->minfo->slot = state->method->abc->method->trait->slot_id;
//class getter/setter
int gs = getset==KW_GET?SUBTYPE_GET:SUBTYPE_SET;
classinfo_t*type=0;
- if(getset == KW_GET)
+ if(getset == KW_GET) {
type = return_type;
- else if(params->list && params->list->param)
+ } else if(params->list && params->list->param && !params->list->next) {
type = params->list->param->type;
+ } else
+ syntaxerror("setter function needs to take exactly one argument");
// not sure wether to look into superclasses here, too
minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
if(minfo) {
syntaxerror("getter/setter for '%s' already defined", name);
/* make a setter or getter into a getset */
minfo->subtype |= gs;
- if(!minfo->return_type) {
- minfo->return_type = type;
- } else {
- if(minfo && minfo->return_type != type)
- syntaxerror("different type in getter and setter");
- }
+
+ /*
+ FIXME: this check needs to be done in pass 2
+
+ if((!minfo->return_type != !type) ||
+ (minfo->return_type && type &&
+ !strcmp(minfo->return_type->name, type->name))) {
+ syntaxerror("different type in getter and setter: %s and %s",
+ minfo->return_type?minfo->return_type->name:"*",
+ type?type->name:"*");
+ }*/
} else {
minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
minfo->kind = INFOTYPE_SLOT; //hack
minfo->subtype = gs;
- minfo->return_type = type;
+ minfo->return_type = 0;
}
/* can't assign a slot as getter and setter might have different slots */
//minfo->slot = slot;
list_append(parent_method->innerfunctions, state->method);
dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
-
+
function_initvars(state->method, params, 0, 1);
}
if(state->method->is_constructor)
name = "__as3_constructor__";
- return_type = 0;
state->method->info = registerfunction(getset, mod, name, params, return_type, 0);
function_initvars(state->method, params, mod->flags, 1);
static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
params_t*params, classinfo_t*return_type, code_t*body)
{
- int flags = mod?mod->flags:0;
-
if(as3_pass==1) {
// store inner methods in variables
function_initvars(state->method, 0, 0, 0);
methodstate_list_t*ml = state->method->innerfunctions;
+
dict_t*xvars = dict_new();
+
while(ml) {
methodstate_t*m = ml->methodstate;
parserassert(m->inner);
dictentry_t*l = d->slots[t];
while(l) {
/* check parent method's variables */
- if(find_variable(state, l->key)) {
+ 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);
}
ml = ml->next;
}
+
if(state->method->uses_slots) {
state->method->slots = dict_new();
int i = 1;
DICT_ITERATE_ITEMS(state->vars, char*, name, variable_t*, v) {
+ if(!name) syntaxerror("internal error");
if(v->index && dict_contains(xvars, name)) {
v->init = 0;
v->index = i++;
state->method->uses_slots = i;
dict_destroy(state->vars);state->vars = 0;
}
- dict_destroy(xvars);
-
old_state();
return 0;
}
} else if(state->method->is_constructor) {
f = abc_class_getconstructor(state->cls->abc, type2);
} else if(!state->method->is_global) {
- namespace_t mname_ns = {state->method->info->access, ""};
+ namespace_t mname_ns = modifiers2access(mod);
multiname_t mname = {QNAME, &mname_ns, 0, name};
- if(flags&FLAG_STATIC)
+ if(mod->flags&FLAG_STATIC)
f = abc_class_staticmethod(state->cls->abc, type2, &mname);
else
f = abc_class_method(state->cls->abc, type2, &mname);
//flash doesn't seem to allow us to access function slots
//state->method->info->slot = slot;
- if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
+ if(mod && mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
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;
check_code_for_break(body);
+ /* Seems this works now.
+ if(state->method->exceptions && state->method->uses_slots) {
+ as3_warning("try/catch and activation not supported yet within the same method");
+ }*/
+
if(f->body) {
f->body->code = body;
f->body->exceptions = state->method->exceptions;
return 0;
}
-char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
-{
- return 1; // FIXME
-}
-
void breakjumpsto(code_t*c, char*name, code_t*jump)
{
while(c) {
}
}
-#define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
#define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
-#define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
-classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
-{
- if(!type1 || !type2)
- return registry_getanytype();
- if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
- return registry_getanytype();
-
- if(op=='+') {
- if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
- return TYPE_NUMBER;
- } else {
- return TYPE_ANY;
- }
- }
-
- if(type1 == type2)
- return type1;
- return registry_getanytype();
-}
code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
{
if(from==to)
if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
(TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
// allow conversion between number types
+ if(TYPE_IS_UINT(to))
+ return abc_convert_u(c);
+ else if(TYPE_IS_INT(to))
+ return abc_convert_i(c);
+ else if(TYPE_IS_NUMBER(to))
+ return abc_convert_d(c);
return abc_coerce2(c, &m);
}
- //printf("%s.%s\n", from.package, from.name);
- //printf("%s.%s\n", to.package, to.name);
+
+ if(TYPE_IS_BOOLEAN(to))
+ return abc_convert_b(c);
+ if(TYPE_IS_STRING(to))
+ return abc_convert_s(c);
+ if(TYPE_IS_OBJECT(to))
+ return abc_convert_o(c);
classinfo_t*supertype = from;
while(supertype) {
return c;
as3_error("can't convert type %s%s%s to %s%s%s",
- from->package, from->package?".":"", from->name,
- to->package, to->package?".":"", to->name);
- return c;
-}
+ from->package, from->package[0]?".":"", from->name,
+ to->package, to->package[0]?".":"", to->name);
-code_t*defaultvalue(code_t*c, classinfo_t*type)
-{
- if(TYPE_IS_INT(type)) {
- c = abc_pushbyte(c, 0);
- } else if(TYPE_IS_UINT(type)) {
- c = abc_pushuint(c, 0);
- } else if(TYPE_IS_FLOAT(type)) {
- c = abc_pushnan(c);
- } else if(TYPE_IS_BOOLEAN(type)) {
- c = abc_pushfalse(c);
- } else if(!type) {
- //c = abc_pushundefined(c);
- } else {
- c = abc_pushnull(c);
- MULTINAME(m, type);
- c = abc_coerce2(c, &m);
- }
return c;
}
+/* move to ast.c todo end */
char is_pushundefined(code_t*c)
{
return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
}
-static slotinfo_t* find_class(char*name)
+static const char* get_package_from_name(const char*name)
+{
+ /* try explicit imports */
+ dictentry_t* e = dict_get_slot(state->imports, name);
+ while(e) {
+ if(!strcmp(e->key, name)) {
+ slotinfo_t*c = (slotinfo_t*)e->data;
+ if(c) return c->package;
+ }
+ e = e->next;
+ }
+ return 0;
+}
+static namespace_list_t*get_current_imports()
+{
+ namespace_list_t*searchlist = 0;
+
+ list_append(searchlist, namespace_new_package(state->package));
+
+ import_list_t*l = state->wildcard_imports;
+ while(l) {
+ namespace_t*ns = namespace_new_package(l->import->package);
+ list_append(searchlist, ns);
+ l = l->next;
+ }
+ list_append(searchlist, namespace_new_package(""));
+ list_append(searchlist, namespace_new_package(internal_filename_package));
+ return searchlist;
+}
+
+static slotinfo_t* find_class(const char*name)
{
slotinfo_t*c=0;
return 0;
}
-
-static char is_getlocal(code_t*c)
+typedcode_t push_class(slotinfo_t*a)
{
- if(!c || c->prev || c->next)
- return 0;
- return(c->opcode == OPCODE_GETLOCAL
- || c->opcode == OPCODE_GETLOCAL_0
- || c->opcode == OPCODE_GETLOCAL_1
- || c->opcode == OPCODE_GETLOCAL_2
- || c->opcode == OPCODE_GETLOCAL_3);
-}
-static int getlocalnr(code_t*c)
-{
- if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
- else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
- else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
- else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
- else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
- else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
- return 0;
-}
-
-static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
-{
- /* converts this:
-
- [prefix code] [read instruction]
-
- to this:
-
- [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
- */
- if(in && in->opcode == OPCODE_COERCE_A) {
- in = code_cutlast(in);
- }
- if(in->next)
- syntaxerror("internal error");
-
- /* chop off read instruction */
- code_t*prefix = in;
- code_t*r = in;
- if(r->prev) {
- prefix = r->prev;r->prev = 0;
- prefix->next=0;
- } else {
- prefix = 0;
- }
-
- char use_temp_var = readbefore;
-
- /* generate the write instruction, and maybe append a dup to the prefix code */
- code_t* write = abc_nop(0);
- if(r->opcode == OPCODE_GETPROPERTY) {
- write->opcode = OPCODE_SETPROPERTY;
- multiname_t*m = (multiname_t*)r->data[0];
- write->data[0] = multiname_clone(m);
- if(m->type == QNAME || m->type == MULTINAME) {
- if(!justassign) {
- prefix = abc_dup(prefix); // we need the object, too
- }
- use_temp_var = 1;
- } else if(m->type == MULTINAMEL) {
- if(!justassign) {
- /* dupping two values on the stack requires 5 operations and one register-
- couldn't adobe just have given us a dup2? */
- int temp = gettempvar();
- prefix = abc_setlocal(prefix, temp);
- prefix = abc_dup(prefix);
- 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;
+ typedcode_t x;
+ x.c = 0;
+ x.t = 0;
+ if(a->access == ACCESS_PACKAGEINTERNAL &&
+ strcmp(a->package, state->package) &&
+ strcmp(a->package, internal_filename_package)
+ ) {
+ syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
+ infotypename(a), a->name, a->package, state->package);
+ }
+
+ if(a->kind != INFOTYPE_CLASS) {
+ MULTINAME(m, a);
+ x.c = abc_findpropstrict2(x.c, &m);
+ x.c = abc_getproperty2(x.c, &m);
+ if(a->kind == INFOTYPE_METHOD) {
+ methodinfo_t*f = (methodinfo_t*)a;
+ x.t = TYPE_FUNCTION(f);
} else {
- syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
- }
- } else if(r->opcode == OPCODE_GETSLOT) {
- write->opcode = OPCODE_SETSLOT;
- write->data[0] = r->data[0];
- if(!justassign) {
- 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 if(r->opcode == OPCODE_GETLOCAL_0) {
- write->opcode = OPCODE_SETLOCAL_0;
- } else if(r->opcode == OPCODE_GETLOCAL_1) {
- write->opcode = OPCODE_SETLOCAL_1;
- } else if(r->opcode == OPCODE_GETLOCAL_2) {
- write->opcode = OPCODE_SETLOCAL_2;
- } else if(r->opcode == OPCODE_GETLOCAL_3) {
- write->opcode = OPCODE_SETLOCAL_3;
- } else {
- code_dump(r);
- syntaxerror("illegal lvalue: can't assign a value to this expression");
- }
- code_t* c = 0;
-
- int temp = -1;
- if(!justassign) {
- if(use_temp_var) {
- /* with getproperty/getslot, we have to be extra careful not
- to execute the read code twice, as it might have side-effects
- (e.g. if the property is in fact a setter/getter combination)
-
- So read the value, modify it, and write it again,
- using prefix only once and making sure (by using a temporary
- register) that the return value is what we just wrote */
- temp = gettempvar();
- c = code_append(c, prefix);
- c = code_append(c, r);
- if(readbefore) {
- c = abc_dup(c);
- c = abc_setlocal(c, temp);
- }
- c = code_append(c, middlepart);
- if(!readbefore) {
- c = abc_dup(c);
- c = abc_setlocal(c, temp);
- }
- c = code_append(c, write);
- c = abc_getlocal(c, temp);
- c = abc_kill(c, temp);
- } else {
- /* if we're allowed to execute the read code twice *and*
- the middlepart doesn't modify the code, things are easier.
- */
- code_t* r2 = code_dup(r);
- //c = code_append(c, prefix);
- parserassert(!prefix);
- c = code_append(c, r);
- c = code_append(c, middlepart);
- c = code_append(c, write);
- c = code_append(c, r2);
+ varinfo_t*v = (varinfo_t*)a;
+ x.t = v->type;
}
} else {
- /* even smaller version: overwrite the value without reading
- it out first */
- 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);
+ classinfo_t*c = (classinfo_t*)a;
+ if(c->slot) {
+ x.c = abc_getglobalscope(x.c);
+ x.c = abc_getslot(x.c, c->slot);
} else {
- code_free(r);r=0;
- temp = gettempvar();
- if(prefix) {
- c = code_append(c, prefix);
- }
- 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 = abc_kill(c, temp);
+ MULTINAME(m, c);
+ x.c = abc_getlex2(x.c, &m);
}
+ x.t = TYPE_CLASS(c);
}
- return c;
+ return x;
}
+
char is_break_or_jump(code_t*c)
{
if(!c)
return 0;
}
-
#define IS_FINALLY_TARGET(op) \
((op) == OPCODE___CONTINUE__ || \
(op) == OPCODE___BREAK__ || \
int lookup_version_cost = 4*num_insertion_points + 5;
if(cantdup || simple_version_cost > lookup_version_cost) {
- printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
+ //printf("(use lookup) simple=%d > lookup=%d\n", simple_version_cost, lookup_version_cost);
return insert_finally_lookup(c, finally, tempvar);
} else {
- printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
+ //printf("(use simple) simple=%d < lookup=%d\n", simple_version_cost, lookup_version_cost);
return insert_finally_simple(c, finally, tempvar);
}
}
#define PASS1 }} if(as3_pass == 1) {{
#define PASS1END }} if(as3_pass == 2) {{
#define PASS2 }} if(as3_pass == 2) {{
-#define PASS12 }} {{
+#define PASS12 }} if(as3_pass == 1 || as3_pass == 2) {{
#define PASS12END }} if(as3_pass == 2) {{
+#define PASS_ALWAYS }} {{
%}
| FUNCTION_DECLARATION
| SLOT_DECLARATION
| PACKAGE_INITCODE
- | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
+ | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
| ';'
MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
| FUNCTION_DECLARATION
| SLOT_DECLARATION
| PACKAGE_INITCODE
- | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
+ | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' {PASS_ALWAYS as3_pass=$1;}
| ';'
MAYBECODE: CODE {$$=$1;}
CODEPIECE: CONTINUE
CODEPIECE: RETURN
CODEPIECE: THROW
-CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
+CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {PASS_ALWAYS as3_pass=$1;}
//CODEBLOCK : '{' CODE '}' {$$=$2;}
//CODEBLOCK : '{' '}' {$$=0;}
/* ------------ conditional compilation ------------- */
-CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER
+CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER {
+ PASS12
+ $$=as3_pass;
+ char*key = concat3($1,"::",$3);
+ if(!definitions || !dict_contains(definitions, key)) {
+ as3_pass=0;
+ }
+ free(key);
+}
/* ------------ variables --------------------------- */
+%code {
+ char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
+ {
+ return 1; // FIXME
+ }
+};
+
MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
| {$$.c=abc_pushundefined(0);
$$.t=TYPE_ANY;
FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
variable_t*var = find_variable(state, $2);
+ if(!var) {
+ syntaxerror("variable %s not known in this scope", $2);
+ }
+
char*tmp1name = concat2($2, "__tmp1__");
int it = new_variable(tmp1name, TYPE_INT, 0, 0);
char*tmp2name = concat2($2, "__array__");
CASE_LIST: CASE_LIST CASE {$$=code_append($$,$2);}
CASE: "case" E ':' MAYBECODE {
- $$ = abc_dup(0);
- $$ = code_append($$, $2.c);
+ $$ = abc_getlocal(0, state->switch_var);
+ $$ = code_append($$, node_read($2).c);
code_t*j = $$ = abc_ifne($$, 0);
$$ = code_append($$, $4);
if($$->opcode != OPCODE___BREAK__) {
DEFAULT: "default" ':' MAYBECODE {
$$ = $3;
}
-SWITCH : T_SWITCH '(' {PASS12 new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
- $$=$4.c;
+SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
+ $$ = node_read($4).c;
+ $$ = abc_setlocal($$, state->switch_var);
$$ = code_append($$, $7);
- code_t*out = $$ = abc_pop($$);
+
+ code_t*out = $$ = abc_kill($$, state->switch_var);
breakjumpsto($$, $1, out);
code_t*c = $$,*lastblock=0;
int i = find_variable_safe(state, $3)->index;
e->target = c = abc_nop(0);
c = abc_setlocal(c, i);
+ c = code_append(c, code_dup(state->method->scope_code));
c = code_append(c, $8);
c = abc_kill(c, i);
}
}
-TRY : "try" '{' {PASS12 new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
+TRY : "try" '{' {PASS12 new_state();
+ state->method->has_exceptions=1;
+ state->method->late_binding=1;//for invariant scope_code
+ } MAYBECODE '}' CATCH_FINALLY_LIST {
code_t*out = abc_nop(0);
code_t*start = abc_nop(0);
parserassert((ptroff_t)$6.finally);
// finally block
e->target = $$ = abc_nop($$);
+ $$ = code_append($$, code_dup(state->method->scope_code));
$$ = abc___rethrow__($$);
}
/* ------------ with -------------------------------- */
-WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
- $$ = $3.c;
- $$ = abc_pushscope($$);
- $$ = code_append($$, $5);
+WITH_HEAD : "with" '(' EXPRESSION ')' {
+ new_state();
+ if(state->method->has_exceptions) {
+ int v = alloc_local();
+ state->method->scope_code = abc_getlocal(state->method->scope_code, v);
+ state->method->scope_code = abc_pushwith(state->method->scope_code);
+ $$.number = v;
+ }
+ $$.cc = $3.c;
+}
+WITH : WITH_HEAD CODEBLOCK {
+ /* remove getlocal;pushwith from scope code again */
+ state->method->scope_code = code_cutlast(code_cutlast(state->method->scope_code));
+
+ $$ = $1.cc;
+ if(state->method->has_exceptions) {
+ $$ = abc_dup($$);
+ $$ = abc_setlocal($$, $1.number);
+ }
+ $$ = abc_pushwith($$);
+ $$ = code_append($$, $2);
$$ = abc_popscope($$);
+ old_state();
}
/* ------------ packages and imports ---------------- */
X_IDENTIFIER: T_IDENTIFIER
| "package" {PASS12 $$="package";}
+ | T_NAMESPACE {PASS12 $$=$1;}
PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
+%code {
+ static void state_has_imports()
+ {
+ state->wildcard_imports = list_clone(state->wildcard_imports);
+ state->imports = dict_clone(state->imports);
+ state->has_own_imports = 1;
+ }
+ static void import_toplevel(const char*package)
+ {
+ char* s = strdup(package);
+ while(1) {
+ dict_put(state->import_toplevel_packages, s, 0);
+ char*x = strrchr(s, '.');
+ if(!x)
+ break;
+ *x = 0;
+ }
+ free(s);
+ }
+};
IMPORT : "import" PACKAGEANDCLASS {
PASS12
slotinfo_t*s = registry_find($2->package, $2->name);
- if(!s) {// || !(s->flags&FLAG_BUILTIN)) {
+ if(!s && as3_pass==1) {// || !(s->flags&FLAG_BUILTIN)) {
as3_schedule_class($2->package, $2->name);
}
-
- PASS2
classinfo_t*c = $2;
if(!c)
syntaxerror("Couldn't import class\n");
state_has_imports();
dict_put(state->imports, c->name, c);
+ import_toplevel(c->package);
$$=0;
}
IMPORT : "import" PACKAGE '.' '*' {
PASS12
- if(strncmp("flash.", $2, 6)) {
+ if(strncmp("flash.", $2, 6) && as3_pass==1) {
as3_schedule_package($2);
}
- PASS2
NEW(import_t,i);
i->package = $2;
state_has_imports();
list_append(state->wildcard_imports, i);
+ import_toplevel(i->package);
$$=0;
}
$$.ns=$1.ns?$1.ns:$2.ns;
}
-
MODIFIER : KW_PUBLIC {PASS12 $$.flags=FLAG_PUBLIC;$$.ns=0;}
| KW_PRIVATE {PASS12 $$.flags=FLAG_PRIVATE;$$.ns=0;}
| KW_PROTECTED {PASS12 $$.flags=FLAG_PROTECTED;$$.ns=0;}
$$.ns=$1;
}
-EXTENDS : {$$=registry_getobjectclass();}
-EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
+EXTENDS : {PASS12 $$=0;}
+EXTENDS : KW_EXTENDS CLASS_SPEC {PASS12 $$=$2;}
EXTENDS_LIST : {PASS12 $$=list_new();}
EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
CLASS_BODY : CLASS_BODY_ITEM
CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
CLASS_BODY_ITEM : ';'
-CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
+CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}' {PASS_ALWAYS as3_pass=$1;}
CLASS_BODY_ITEM : SLOT_DECLARATION
CLASS_BODY_ITEM : FUNCTION_DECLARATION
/* ------------ classes and interfaces (body, slots ) ------- */
+%code {
+ static int slotstate_varconst = 0;
+ static modifiers_t*slotstate_flags = 0;
+ static void setslotstate(modifiers_t* flags, int varconst)
+ {
+ slotstate_varconst = varconst;
+ slotstate_flags = flags;
+ if(state->cls) {
+ if(flags && flags->flags&FLAG_STATIC) {
+ state->method = state->cls->static_init;
+ } else {
+ state->method = state->cls->init;
+ }
+ } else {
+ parserassert(state->method);
+ }
+ }
+};
+
VARCONST: "var" | "const"
-SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1.flags);} MAYBETYPE MAYBEEXPRESSION {
- int flags = $1.flags;
- namespace_t ns = modifiers2access(&$1);
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
- varinfo_t* info = 0;
- if(state->cls) {
- memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $3, 1);
- if(i) {
- check_override(i, flags);
- }
- info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $3);
- } else {
- slotinfo_t*i = registry_find(state->package, $3);
- if(i) {
- syntaxerror("package %s already contains '%s'", state->package, $3);
- }
- if(ns.name && ns.name[0]) {
- syntaxerror("namespaces not allowed on package-level variables");
- }
- info = varinfo_register_global(ns.access, state->package, $3);
- }
+SLOT_LIST: ONE_SLOT {PASS12 $$=0;}
+SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
- info->type = $5;
- info->flags = flags;
+ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
+{
+PASS12
+ int flags = slotstate_flags->flags;
+ namespace_t ns = modifiers2access(slotstate_flags);
- /* slot name */
- multiname_t mname = {QNAME, &ns, 0, $3};
-
- trait_list_t**traits;
- code_t**code;
- if(!state->cls) {
- // global variable
- ns.name = state->package;
- traits = &global->init->traits;
- code = &global->init->method->body->code;
- } else if(flags&FLAG_STATIC) {
- // static variable
- traits = &state->cls->abc->static_traits;
- code = &state->cls->static_init->header;
- } else {
- // instance variable
- traits = &state->cls->abc->traits;
- code = &state->cls->init->header;
- }
-
- trait_t*t=0;
- if($5) {
- MULTINAME(m, $5);
- t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
- } else {
- t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
- }
- info->slot = t->slot_id;
-
- /* initalization code (if needed) */
- code_t*c = 0;
- if($6.c && !is_pushundefined($6.c)) {
- c = abc_getlocal_0(c);
- c = code_append(c, $6.c);
- c = converttype(c, $6.t, $5);
- c = abc_setslot(c, t->slot_id);
+ if(as3_pass == 1) {
+
+ varinfo_t* info = 0;
+ if(state->cls) {
+ memberinfo_t*i = registry_findmember(state->cls->info, ns.name, $1, 1);
+ if(i) {
+ check_override(i, flags);
+ }
+ info = varinfo_register_onclass(state->cls->info, ns.access, ns.name, $1);
+ } else {
+ slotinfo_t*i = registry_find(state->package, $1);
+ if(i) {
+ syntaxerror("package %s already contains '%s'", state->package, $1);
+ }
+ if(ns.name && ns.name[0]) {
+ syntaxerror("namespaces not allowed on package-level variables");
+ }
+ info = varinfo_register_global(ns.access, state->package, $1);
+ }
+
+ info->type = $2;
+ info->flags = flags;
+
+ dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, info);
}
- *code = code_append(*code, c);
+ if(as3_pass == 2) {
+ varinfo_t*info = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+
+ /* slot name */
+ multiname_t mname = {QNAME, &ns, 0, $1};
+
+ trait_list_t**traits;
+ code_t**code;
+ if(!state->cls) {
+ // global variable
+ ns.name = state->package;
+ traits = &global->init->traits;
+ code = &global->init->method->body->code;
+ } else if(flags&FLAG_STATIC) {
+ // static variable
+ traits = &state->cls->abc->static_traits;
+ code = &state->cls->static_init->header;
+ } else {
+ // instance variable
+ traits = &state->cls->abc->traits;
+ code = &state->cls->init->header;
+ }
+
+ trait_t*t=0;
+ if($2) {
+ MULTINAME(m, $2);
+ t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
+ } else {
+ t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
+ }
+ info->slot = t->slot_id;
+
+ /* initalization code (if needed) */
+ code_t*c = 0;
+ if($3.c && !is_pushundefined($3.c)) {
+ c = abc_getlocal_0(c);
+ c = code_append(c, $3.c);
+ c = converttype(c, $3.t, $2);
+ c = abc_setslot(c, t->slot_id);
+ }
- if($2==KW_CONST) {
- t->kind= TRAIT_CONST;
+ *code = code_append(*code, c);
+
+ if(slotstate_varconst==KW_CONST) {
+ t->kind= TRAIT_CONST;
+ }
}
$$=0;
- setstaticfunction(0);
}
/* ------------ constants -------------------------------------- */
-MAYBESTATICCONSTANT: {$$=0;}
-MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
-
-STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
-STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
-STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
-STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
-STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
-//STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
-STATICCONSTANT : "true" {$$ = constant_new_true($1);}
-STATICCONSTANT : "false" {$$ = constant_new_false($1);}
-STATICCONSTANT : "null" {$$ = constant_new_null($1);}
-STATICCONSTANT : T_IDENTIFIER {
- // TODO
- as3_warning("Couldn't resolve %s", $1);
- $$ = constant_new_null($1);
-}
+MAYBECONSTANT: {$$=0;}
+MAYBECONSTANT: '=' CONSTANT {$$=$2;}
+
+//CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
+CONSTANT : T_INT {$$ = constant_new_int($1);}
+CONSTANT : T_UINT {
+ $$ = constant_new_uint($1);
+}
+CONSTANT : T_FLOAT {$$ = constant_new_float($1);}
+CONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
+CONSTANT : "true" {$$ = constant_new_true($1);}
+CONSTANT : "false" {$$ = constant_new_false($1);}
+CONSTANT : "null" {$$ = constant_new_null($1);}
+CONSTANT : "undefined" {$$ = constant_new_undefined($1);}
+CONSTANT : KW_NAN {$$ = constant_new_float(__builtin_nan(""));}
+
+/*
+CONSTANT : T_IDENTIFIER {
+ if(!strcmp($1, "NaN")) {
+ $$ = constant_new_float(__builtin_nan(""));
+ } else {
+ as3_warning("Couldn't evaluate constant value of %s", $1);
+ $$ = constant_new_null($1);
+ }
+}*/
/* ------------ classes and interfaces (body, functions) ------- */
list_append($$.list, $1);
}
-PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
+PARAM: T_IDENTIFIER ':' TYPE MAYBECONSTANT {
PASS12
$$ = rfx_calloc(sizeof(param_t));
$$->name=$1;
PASS2
$$->value = $4;
}
-PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
+PARAM: T_IDENTIFIER MAYBECONSTANT {
PASS12
$$ = rfx_calloc(sizeof(param_t));
$$->name=$1;
/* ------------- package + class ids --------------- */
-CLASS: T_IDENTIFIER {
- PASS1 static slotinfo_t c;
- memset(&c, 0, sizeof(c));
- c.name = $1;
- $$ = (classinfo_t*)&c;
+CLASS: X_IDENTIFIER {
+ PASS1 NEW(unresolvedinfo_t,c);
+ memset(c, 0, sizeof(*c));
+ c->kind = INFOTYPE_UNRESOLVED;
+ c->name = $1;
+ c->package = get_package_from_name($1);
+ if(!c->package) {
+ c->nsset = get_current_imports();
+ /* make the compiler look for this class in the current directory,
+ just in case: */
+ as3_schedule_class_noerror(state->package, $1);
+ }
+ $$ = (classinfo_t*)c;
PASS2
slotinfo_t*s = find_class($1);
if(!s) syntaxerror("Could not find class/method %s (current package: %s)\n", $1, state->package);
$$ = (classinfo_t*)s;
}
-PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
- PASS1 static slotinfo_t c;
- memset(&c, 0, sizeof(c));
- c.package = $1;
- c.name = $3;
- $$=(classinfo_t*)&c;
+PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
+ PASS1 NEW(unresolvedinfo_t,c);
+ memset(c, 0, sizeof(*c));
+ c->kind = INFOTYPE_UNRESOLVED;
+ c->package = $1;
+ c->name = $3;
+ $$ = (classinfo_t*)c;
PASS2
slotinfo_t*s = registry_find($1, $3);
if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
-TYPE : CLASS_SPEC {$$=$1;}
- | '*' {$$=registry_getanytype();}
- | "void" {$$=registry_getanytype();}
+TYPE : CLASS_SPEC {PASS12 $$=$1;}
+ | '*' {PASS12 $$=registry_getanytype();}
+ | "void" {PASS12 $$=registry_getanytype();}
/*
| "String" {$$=registry_getstringclass();}
| "int" {$$=registry_getintclass();}
| "Number" {$$=registry_getnumberclass();}
*/
-MAYBETYPE: ':' TYPE {$$=$2;}
-MAYBETYPE: {$$=0;}
+MAYBETYPE: ':' TYPE {PASS12 $$=$2;}
+MAYBETYPE: {PASS12 $$=0;}
/* ----------function calls, delete, constructor calls ------ */
-MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.len=0;}
+MAYBE_PARAM_VALUES : %prec prec_none {$$.cc=0;$$.number=0;}
MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
-MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
+MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.number=0;}
MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
-EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.len=1;
+EXPRESSION_LIST : NONCOMMAEXPRESSION {$$.number=1;
$$.cc = $1.c;
}
EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
- $$.len= $1.len+1;
+ $$.number= $1.number+1;
$$.cc = code_append($1.cc, $2.c);
}
XX : %prec new2
NEW : "new" E XX MAYBE_PARAM_VALUES {
- $$.c = $2.c;
+ typedcode_t v = node_read($2);
+ $$.c = v.c;
if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
code_t*paramcode = $4.cc;
multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
$$.c = code_cutlast($$.c);
$$.c = code_append($$.c, paramcode);
- $$.c = abc_constructprop2($$.c, name, $4.len);
+ $$.c = abc_constructprop2($$.c, name, $4.number);
multiname_destroy(name);
} else if($$.c->opcode == OPCODE_GETSLOT) {
int slot = (int)(ptroff_t)$$.c->data[0];
multiname_t*name = t->name;
$$.c = code_cutlast($$.c);
$$.c = code_append($$.c, paramcode);
- $$.c = abc_constructprop2($$.c, name, $4.len);
+ $$.c = abc_constructprop2($$.c, name, $4.number);
} else {
$$.c = code_append($$.c, paramcode);
- $$.c = abc_construct($$.c, $4.len);
+ $$.c = abc_construct($$.c, $4.number);
}
$$.t = TYPE_ANY;
- if(TYPE_IS_CLASS($2.t) && $2.t->data) {
- $$.t = $2.t->data;
+ if(TYPE_IS_CLASS(v.t) && v.t->data) {
+ $$.t = v.t->data;
} else {
$$.c = abc_coerce_a($$.c);
$$.t = TYPE_ANY;
call (for closures)
*/
FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
-
- $$.c = $1.c;
+
+ typedcode_t v = node_read($1);
+ $$.c = v.c;
if($$.c->opcode == OPCODE_COERCE_A) {
$$.c = code_cutlast($$.c);
}
multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
$$.c = code_cutlast($$.c);
$$.c = code_append($$.c, paramcode);
- $$.c = abc_callproperty2($$.c, name, $3.len);
+ $$.c = abc_callproperty2($$.c, name, $3.number);
multiname_destroy(name);
} else if($$.c->opcode == OPCODE_GETSLOT && $$.c->prev->opcode != OPCODE_GETSCOPEOBJECT) {
int slot = (int)(ptroff_t)$$.c->data[0];
$$.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.len);
+ $$.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);
$$.c = code_append($$.c, paramcode);
- $$.c = abc_callsuper2($$.c, name, $3.len);
+ $$.c = abc_callsuper2($$.c, name, $3.number);
multiname_destroy(name);
} else {
$$.c = abc_getglobalscope($$.c);
$$.c = code_append($$.c, paramcode);
- $$.c = abc_call($$.c, $3.len);
+ $$.c = abc_call($$.c, $3.number);
}
- if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
- $$.t = ((methodinfo_t*)($1.t->data))->return_type;
+ if(TYPE_IS_FUNCTION(v.t) && v.t->data) {
+ $$.t = ((methodinfo_t*)(v.t->data))->return_type;
} else {
$$.c = abc_coerce_a($$.c);
$$.t = TYPE_ANY;
*/
state->method->has_super = 1;
- $$.c = abc_constructsuper($$.c, $3.len);
+ $$.c = abc_constructsuper($$.c, $3.number);
$$.c = abc_pushundefined($$.c);
$$.t = TYPE_ANY;
}
DELETE: "delete" E {
- $$.c = $2.c;
+ typedcode_t v = node_read($2);
+ $$.c = v.c;
if($$.c->opcode == OPCODE_COERCE_A) {
$$.c = code_cutlast($$.c);
}
$$.c = abc_deleteproperty2($$.c, name);
} else {
$$.c = abc_getlocal_0($$.c);
- MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
+ MULTINAME_LATE(m, v.t?v.t->access:ACCESS_PACKAGE, "");
$$.c = abc_deleteproperty2($$.c, &m);
}
$$.t = TYPE_BOOLEAN;
// ----------------------- expression types -------------------------------------
-NONCOMMAEXPRESSION : E %prec below_minus {$$=$1;}
-EXPRESSION : E %prec below_minus {$$ = $1;}
-EXPRESSION : EXPRESSION ',' E %prec below_minus {
- $$.c = $1.c;
- $$.c = cut_last_push($$.c);
- $$.c = code_append($$.c,$3.c);
- $$.t = $3.t;
+NONCOMMAEXPRESSION : E %prec below_minus {
+ $$ = node_read($1);
}
-VOIDEXPRESSION : EXPRESSION %prec below_minus {
- $$=cut_last_push($1.c);
+EXPRESSION : COMMA_EXPRESSION {
+ $$ = node_read($1);
}
-
-// ----------------------- expression evaluation -------------------------------------
-
-E : INNERFUNCTION %prec prec_none {$$ = $1;}
-//V : CONSTANT {$$ = 0;}
-E : CONSTANT
-//V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
-E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
-//V : NEW {$$ = $1.c;}
-E : NEW {$$ = $1;}
-//V : DELETE {$$ = $1.c;}
-E : DELETE {$$ = $1;}
-
-E : FUNCTIONCALL
-
-E : T_REGEXP {
- $$.c = 0;
- namespace_t ns = {ACCESS_PACKAGE, ""};
- multiname_t m = {QNAME, &ns, 0, "RegExp"};
- if(!$1.options) {
- $$.c = abc_getlex2($$.c, &m);
- $$.c = abc_pushstring($$.c, $1.pattern);
- $$.c = abc_construct($$.c, 1);
- } else {
- $$.c = abc_getlex2($$.c, &m);
- $$.c = abc_pushstring($$.c, $1.pattern);
- $$.c = abc_pushstring($$.c, $1.options);
- $$.c = abc_construct($$.c, 2);
- }
- $$.t = TYPE_REGEXP;
-}
-
-CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
- //MULTINAME(m, registry_getintclass());
- //$$.c = abc_coerce2($$.c, &m); // FIXME
- $$.t = TYPE_INT;
- }
-CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
- $$.t = TYPE_INT;
- }
-CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
- $$.t = TYPE_INT;
- }
-CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
- $$.t = TYPE_UINT;
- }
-CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
- $$.t = TYPE_FLOAT;
- }
-CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
- $$.t = TYPE_STRING;
- }
-CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
- $$.t = TYPE_ANY;
- }
-CONSTANT : "true" {$$.c = abc_pushtrue(0);
- $$.t = TYPE_BOOLEAN;
- }
-CONSTANT : "false" {$$.c = abc_pushfalse(0);
- $$.t = TYPE_BOOLEAN;
- }
-CONSTANT : "null" {$$.c = abc_pushnull(0);
- $$.t = TYPE_NULL;
- }
-
-E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-
-E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
- $$.c = $1.c;
- $$.c = converttype($$.c, $1.t, $$.t);
- $$.c = abc_dup($$.c);
- code_t*jmp = $$.c = abc_iftrue($$.c, 0);
- $$.c = cut_last_push($$.c);
- $$.c = code_append($$.c,$3.c);
- $$.c = converttype($$.c, $3.t, $$.t);
- code_t*label = $$.c = abc_label($$.c);
- jmp->branch = label;
- }
-E : E "&&" E {
- $$.t = join_types($1.t, $3.t, 'A');
- /*printf("%08x:\n",$1.t);
- code_dump($1.c, 0, 0, "", stdout);
- printf("%08x:\n",$3.t);
- code_dump($3.c, 0, 0, "", stdout);
- printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
- $$.c = $1.c;
- $$.c = converttype($$.c, $1.t, $$.t);
- $$.c = abc_dup($$.c);
- code_t*jmp = $$.c = abc_iffalse($$.c, 0);
- $$.c = cut_last_push($$.c);
- $$.c = code_append($$.c,$3.c);
- $$.c = converttype($$.c, $3.t, $$.t);
- code_t*label = $$.c = abc_label($$.c);
- jmp->branch = label;
- }
-
-E : '!' E {$$.c=$2.c;
- $$.c = abc_not($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-
-E : '~' E {$$.c=$2.c;
- $$.c = abc_bitnot($$.c);
- $$.t = TYPE_INT;
- }
-
-E : E '&' E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_bitand($$.c);
- $$.t = TYPE_INT;
- }
-
-E : E '^' E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_bitxor($$.c);
- $$.t = TYPE_INT;
- }
-
-E : E '|' E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_bitor($$.c);
- $$.t = TYPE_INT;
- }
-
-E : E ">>" E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_rshift($$.c);
- $$.t = TYPE_INT;
- }
-E : E ">>>" E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_urshift($$.c);
- $$.t = TYPE_INT;
- }
-E : E "<<" E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_lshift($$.c);
- $$.t = TYPE_INT;
- }
-
-E : E '/' E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_divide($$.c);
- $$.t = TYPE_NUMBER;
- }
-E : E '%' E {$$.c = code_append($1.c,$3.c);
- $$.c = abc_modulo($$.c);
- $$.t = TYPE_NUMBER;
- }
-E : E '+' E {$$.c = code_append($1.c,$3.c);
- if(BOTH_INT($1.t, $3.t)) {
- $$.c = abc_add_i($$.c);
- $$.t = TYPE_INT;
- } else {
- $$.c = abc_add($$.c);
- $$.t = join_types($1.t,$3.t,'+');
- }
- }
-E : E '-' E {$$.c = code_append($1.c,$3.c);
- if(BOTH_INT($1.t,$3.t)) {
- $$.c = abc_subtract_i($$.c);
- $$.t = TYPE_INT;
- } else {
- $$.c = abc_subtract($$.c);
- $$.t = TYPE_NUMBER;
- }
- }
-E : E '*' E {$$.c = code_append($1.c,$3.c);
- if(BOTH_INT($1.t,$3.t)) {
- $$.c = abc_multiply_i($$.c);
- $$.t = TYPE_INT;
- } else {
- $$.c = abc_multiply($$.c);
- $$.t = TYPE_NUMBER;
- }
- }
-
-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) && $3.t->data) {
- MULTINAME(m, (classinfo_t*)($3.t->data));
- $$.c = abc_astype2($1.c, &m);
- $$.t = $3.t->data;
- } else {
- $$.c = code_append($1.c, $3.c);
- $$.c = abc_astypelate($$.c);
- $$.t = TYPE_ANY;
- }
- }
-
-E : E "instanceof" E
- {$$.c = code_append($1.c, $3.c);
- $$.c = abc_instanceof($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-
-E : E "is" E {$$.c = code_append($1.c, $3.c);
- $$.c = abc_istypelate($$.c);
- $$.t = TYPE_BOOLEAN;
- }
-
-E : "typeof" '(' E ')' {
- $$.c = $3.c;
- $$.c = abc_typeof($$.c);
- $$.t = TYPE_STRING;
- }
-
-E : "void" E {
- $$.c = cut_last_push($2.c);
- $$.c = abc_pushundefined($$.c);
- $$.t = TYPE_ANY;
- }
-
-E : "void" { $$.c = abc_pushundefined(0);
- $$.t = TYPE_ANY;
- }
-
-E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
-
-E : '-' E {
- $$=$2;
- if(IS_INT($2.t)) {
- $$.c=abc_negate_i($$.c);
- $$.t = TYPE_INT;
- } else {
- $$.c=abc_negate($$.c);
- $$.t = TYPE_NUMBER;
- }
+COMMA_EXPRESSION : E %prec below_minus {
+ $$ = mkmultinode(&node_comma, $1);
}
-
-E : E '[' E ']' {
- $$.c = $1.c;
- $$.c = code_append($$.c, $3.c);
-
- MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
- $$.c = abc_getproperty2($$.c, &m);
- $$.t = 0; // array elements have unknown type
+COMMA_EXPRESSION : COMMA_EXPRESSION ',' E %prec below_minus {
+ $$ = multinode_extend($1, $3);
}
-
-E : '[' MAYBE_EXPRESSION_LIST ']' {
- $$.c = code_new();
- $$.c = code_append($$.c, $2.cc);
- $$.c = abc_newarray($$.c, $2.len);
- $$.t = registry_getarrayclass();
+VOIDEXPRESSION : E %prec below_minus {
+ $$ = node_exec($1);
+}
+VOIDEXPRESSION : VOIDEXPRESSION ',' E %prec below_minus {
+ $$ = $1;
+ $$ = code_append($$, node_exec($3));
}
-MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
+MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.number=0;}
MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
$$.cc = 0;
$$.cc = code_append($$.cc, $1.c);
$$.cc = code_append($$.cc, $3.c);
- $$.len = 2;
+ $$.number = 2;
}
EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
$$.cc = $1.cc;
- $$.len = $1.len+2;
+ $$.number = $1.number+2;
$$.cc = code_append($$.cc, $3.c);
$$.cc = code_append($$.cc, $5.c);
}
-//MAYBECOMMA: ','
-//MAYBECOMMA:
-E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
- $$.c = code_new();
- $$.c = code_append($$.c, $2.cc);
- $$.c = abc_newobject($$.c, $2.len/2);
- $$.t = registry_getobjectclass();
-}
-
-E : E "*=" E {
- code_t*c = $3.c;
- if(BOTH_INT($1.t,$3.t)) {
- c=abc_multiply_i(c);
- } else {
- c=abc_multiply(c);
- }
- c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-
-E : E "%=" E {
- code_t*c = abc_modulo($3.c);
- c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E "<<=" E {
- code_t*c = abc_lshift($3.c);
- c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E ">>=" E {
- code_t*c = abc_rshift($3.c);
- c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E ">>>=" E {
- code_t*c = abc_urshift($3.c);
- c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E "/=" E {
- code_t*c = abc_divide($3.c);
- c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E "|=" E {
- code_t*c = abc_bitor($3.c);
- c=converttype(c, TYPE_INT, $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E "^=" E {
- code_t*c = abc_bitxor($3.c);
- c=converttype(c, TYPE_INT, $1.t);
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E "+=" E {
- code_t*c = $3.c;
-
- if(TYPE_IS_INT($1.t)) {
- c=abc_add_i(c);
- } else {
- c=abc_add(c);
- c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
- }
-
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E "-=" E { code_t*c = $3.c;
- if(TYPE_IS_INT($1.t)) {
- c=abc_subtract_i(c);
- } else {
- c=abc_subtract(c);
- c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
- }
-
- $$.c = toreadwrite($1.c, c, 0, 0);
- $$.t = $1.t;
- }
-E : E '=' E { code_t*c = 0;
- c = code_append(c, $3.c);
- c = converttype(c, $3.t, $1.t);
- $$.c = toreadwrite($1.c, c, 1, 0);
- $$.t = $1.t;
- }
+// ----------------------- expression evaluation -------------------------------------
-E : E '?' E ':' E %prec below_assignment {
- $$.t = join_types($3.t,$5.t,'?');
- $$.c = $1.c;
- code_t*j1 = $$.c = abc_iffalse($$.c, 0);
- $$.c = code_append($$.c, $3.c);
- $$.c = converttype($$.c, $3.t, $$.t);
- code_t*j2 = $$.c = abc_jump($$.c, 0);
- $$.c = j1->branch = abc_label($$.c);
- $$.c = code_append($$.c, $5.c);
- $$.c = converttype($$.c, $5.t, $$.t);
- $$.c = j2->branch = abc_label($$.c);
- }
+E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
+E : VAR_READ %prec T_IDENTIFIER {$$ = mkcodenode($1);}
+E : MEMBER %prec '.' {$$ = mkcodenode($1);}
+E : NEW {$$ = mkcodenode($1);}
+E : DELETE {$$ = mkcodenode($1);}
+E : FUNCTIONCALL {$$ = mkcodenode($1);}
-E : E "++" { code_t*c = 0;
- classinfo_t*type = $1.t;
- if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
- int nr = getlocalnr($1.c);
- code_free($1.c);$1.c=0;
- if(TYPE_IS_INT($1.t)) {
- $$.c = abc_getlocal(0, nr);
- $$.c = abc_inclocal_i($$.c, nr);
- } else if(TYPE_IS_NUMBER($1.t)) {
- $$.c = abc_getlocal(0, nr);
- $$.c = abc_inclocal($$.c, nr);
- } else syntaxerror("internal error");
- } else {
- if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
- c=abc_increment_i(c);
- type = TYPE_INT;
- } else {
- c=abc_increment(c);
- type = TYPE_NUMBER;
- }
- c=converttype(c, type, $1.t);
- $$.c = toreadwrite($1.c, c, 0, 1);
- $$.t = $1.t;
- }
- }
+E : CONSTANT {
+ $$ = mkconstnode($1);
+}
-// TODO: use inclocal, like with ++
-E : E "--" { code_t*c = 0;
- classinfo_t*type = $1.t;
- if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
- c=abc_decrement_i(c);
- type = TYPE_INT;
- } else {
- c=abc_decrement(c);
- type = TYPE_NUMBER;
- }
- c=converttype(c, type, $1.t);
- $$.c = toreadwrite($1.c, c, 0, 1);
- $$.t = $1.t;
- }
+/* regexp */
+E : T_REGEXP {
+ typedcode_t v;
+ v.c = 0;
+ namespace_t ns = {ACCESS_PACKAGE, ""};
+ multiname_t m = {QNAME, &ns, 0, "RegExp"};
+ if(!$1.options) {
+ v.c = abc_getlex2(v.c, &m);
+ v.c = abc_pushstring(v.c, $1.pattern);
+ v.c = abc_construct(v.c, 1);
+ } else {
+ v.c = abc_getlex2(v.c, &m);
+ v.c = abc_pushstring(v.c, $1.pattern);
+ v.c = abc_pushstring(v.c, $1.options);
+ v.c = abc_construct(v.c, 2);
+ }
+ v.t = TYPE_REGEXP;
+ $$ = mkcodenode(v);
+}
-E : "++" %prec plusplus_prefix E { code_t*c = 0;
- classinfo_t*type = $2.t;
- if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
- c=abc_increment_i(c);
- type = TYPE_INT;
- } else {
- c=abc_increment(c);
- type = TYPE_NUMBER;
- }
- c=converttype(c, type, $2.t);
- $$.c = toreadwrite($2.c, c, 0, 0);
- $$.t = $2.t;
- }
+/* array */
+E : '[' MAYBE_EXPRESSION_LIST ']' {
+ typedcode_t v;
+ v.c = code_new();
+ v.c = code_append(v.c, $2.cc);
+ v.c = abc_newarray(v.c, $2.number);
+ v.t = registry_getarrayclass();
+ $$ = mkcodenode(v);
+}
-E : "--" %prec minusminus_prefix E { code_t*c = 0;
- classinfo_t*type = $2.t;
- if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
- c=abc_decrement_i(c);
- type = TYPE_INT;
- } else {
- c=abc_decrement(c);
- type = TYPE_NUMBER;
- }
- c=converttype(c, type, $2.t);
- $$.c = toreadwrite($2.c, c, 0, 0);
- $$.t = $2.t;
- }
+/* dictionary */
+E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
+ typedcode_t v;
+ v.c = code_new();
+ v.c = code_append(v.c, $2.cc);
+ v.c = abc_newobject(v.c, $2.number/2);
+ v.t = registry_getobjectclass();
+ $$ = mkcodenode(v);
+}
+
+E : E '<' E {$$ = mknode2(&node_lt,$1,$3);}
+E : E '>' E {$$ = mknode2(&node_gt,$1,$3);}
+E : E "<=" E {$$ = mknode2(&node_le,$1,$3);}
+E : E ">=" E {$$ = mknode2(&node_ge,$1,$3);}
+E : E "==" E {$$ = mknode2(&node_eqeq,$1,$3);}
+E : E "===" E {$$ = mknode2(&node_eqeqeq,$1,$3);}
+E : E "!==" E {$$ = mknode2(&node_noteqeq,$1,$3);}
+E : E "!=" E {$$ = mknode2(&node_noteq,$1,$3);}
+E : E "||" E {$$ = mknode2(&node_oror,$1,$3);}
+E : E "&&" E {$$ = mknode2(&node_andand,$1,$3);}
+E : '!' E {$$ = mknode1(&node_not, $2);}
+E : '~' E {$$ = mknode1(&node_bitnot, $2);}
+E : E '&' E {$$ = mknode2(&node_bitand, $1, $3);}
+E : E '^' E {$$ = mknode2(&node_bitxor, $1, $3);}
+E : E '|' E {$$ = mknode2(&node_bitor, $1, $3);}
+E : E ">>" E {$$ = mknode2(&node_shr, $1, $3);}
+E : E ">>>" E {$$ = mknode2(&node_ushr, $1, $3);}
+E : E "<<" E {$$ = mknode2(&node_shl, $1, $3);}
+E : E '/' E {$$ = mknode2(&node_div, $1, $3);}
+E : E '%' E {$$ = mknode2(&node_mod, $1, $3);}
+E : E '+' E {$$ = mknode2(&node_plus, $1, $3);}
+E : E '-' E {$$ = mknode2(&node_minus, $1, $3);}
+E : E '*' E {$$ = mknode2(&node_multiply, $1, $3);}
+E : E "in" E {$$ = mknode2(&node_in, $1, $3);}
+E : E "as" E {$$ = mknode2(&node_as, $1, $3);}
+E : E "instanceof" E {$$ = mknode2(&node_instanceof, $1, $3);}
+E : E "is" E {$$ = mknode2(&node_is, $1, $3);}
+E : "typeof" '(' E ')' {$$ = mknode1(&node_typeof, $3);}
+E : "void" E {$$ = mknode1(&node_void, $2);}
+E : "void" { $$ = mkconstnode(constant_new_undefined());}
+E : '(' COMMA_EXPRESSION ')' { $$=$2;}
+E : '-' E {$$ = mknode1(&node_neg, $2);}
+E : E '[' E ']' {$$ = mknode2(&node_arraylookup, $1,$3);}
+E : E "*=" E {$$ = mknode2(&node_muleq, $1, $3);}
+E : E "%=" E {$$ = mknode2(&node_modeq, $1, $3);}
+E : E "<<=" E {$$ = mknode2(&node_shleq, $1, $3);}
+E : E ">>=" E {$$ = mknode2(&node_shreq, $1, $3);}
+E : E ">>>=" E {$$ = mknode2(&node_ushreq, $1, $3);}
+E : E "/=" E { $$ = mknode2(&node_diveq, $1, $3);}
+E : E "|=" E { $$ = mknode2(&node_bitoreq, $1, $3);}
+E : E "^=" E { $$ = mknode2(&node_bitxoreq, $1, $3);}
+E : E "&=" E { $$ = mknode2(&node_bitandeq, $1, $3);}
+E : E "+=" E { $$ = mknode2(&node_pluseq, $1, $3);}
+E : E "-=" E { $$ = mknode2(&node_minuseq, $1, $3);}
+E : E '=' E { $$ = mknode2(&node_assign, $1, $3);}
+E : E '?' E ':' E %prec below_assignment { $$ = mknode3(&node_tenary, $1, $3, $5);}
+
+E : E "++" { $$ = mknode1(&node_rplusplus, $1);}
+E : E "--" { $$ = mknode1(&node_rminusminus, $1);}
+E : "++" %prec plusplus_prefix E {$$ = mknode1(&node_lplusplus, $2); }
+E : "--" %prec minusminus_prefix E {$$ = mknode1(&node_lminusminus, $2); }
E : "super" '.' T_IDENTIFIER
{ if(!state->cls->info)
syntaxerror("super keyword not allowed outside a class");
classinfo_t*t = state->cls->info->superclass;
if(!t) t = TYPE_OBJECT;
-
- memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
-
+ memberinfo_t*f = findmember_nsset(t, $3, 1);
MEMBER_MULTINAME(m, f, $3);
- $$.c = 0;
- $$.c = abc_getlocal_0($$.c);
- $$.c = abc_getsuper2($$.c, &m);
- $$.t = slotinfo_gettype((slotinfo_t*)f);
+ typedcode_t v;
+ v.c = 0;
+ v.c = abc_getlocal_0(v.c);
+ v.c = abc_getsuper2(v.c, &m);
+ v.t = slotinfo_gettype((slotinfo_t*)f);
+ $$ = mkcodenode(v);
}
E : '@' T_IDENTIFIER {
// attribute TODO
- $$.c = abc_pushundefined(0);
- $$.t = 0;
+ $$ = mkdummynode();
as3_warning("ignored @ operator");
}
E : E '.' '@' T_IDENTIFIER {
// child attribute TODO
- $$.c = abc_pushundefined(0);
- $$.t = 0;
+ $$ = mkdummynode();
as3_warning("ignored .@ operator");
}
E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
// namespace declaration TODO
- $$.c = abc_pushundefined(0);
- $$.t = 0;
+ $$ = mkdummynode();
as3_warning("ignored :: operator");
}
E : E ".." T_IDENTIFIER {
// descendants TODO
- $$.c = abc_pushundefined(0);
- $$.t = 0;
+ $$ = mkdummynode();
as3_warning("ignored .. operator");
}
E : E '.' '(' E ')' {
// filter TODO
- $$.c = abc_pushundefined(0);
- $$.t = 0;
+ $$ = mkdummynode();
as3_warning("ignored .() operator");
}
-//VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
-
-
-
-E : E '.' T_IDENTIFIER
- {$$.c = $1.c;
- classinfo_t*t = $1.t;
- char is_static = 0;
- if(TYPE_IS_CLASS(t) && t->data) {
- t = t->data;
- is_static = 1;
- }
- if(t) {
- memberinfo_t*f = registry_findmember_nsset(t, state->active_namespaces, $3, 1);
- char noslot = 0;
- if(f && !is_static != !(f->flags&FLAG_STATIC))
- noslot=1;
- if(f && f->slot && !noslot) {
- $$.c = abc_getslot($$.c, f->slot);
- } else {
- MEMBER_MULTINAME(m, f, $3);
- $$.c = abc_getproperty2($$.c, &m);
- }
- /* determine type */
- $$.t = slotinfo_gettype((slotinfo_t*)f);
- if(!$$.t)
- $$.c = abc_coerce_a($$.c);
- } else {
- /* 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 */
- multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
- $$.c = abc_getproperty2($$.c, &m);
- $$.c = abc_coerce_a($$.c);
- $$.t = registry_getanytype();
- }
+//E : E "::" '[' E ']' {
+// // qualified expression TODO
+// $$.c = abc_pushundefined(0);
+// $$.t = 0;
+// as3_warning("ignored ::[] operator");
+// }
+
+MEMBER : E '.' T_IDENTIFIER {
+ typedcode_t v1 = node_read($1);
+ $$.c = v1.c;
+ classinfo_t*t = v1.t;
+ char is_static = 0;
+ if(TYPE_IS_CLASS(t) && t->data) {
+ t = t->data;
+ is_static = 1;
+ }
+ if(t) {
+ if(t->subtype==INFOTYPE_UNRESOLVED) {
+ syntaxerror("syntaxerror: trying to resolve property '%s' on incomplete object '%s'", $3, t->name);
+ }
+ memberinfo_t*f = findmember_nsset(t, $3, 1);
+ char noslot = 0;
+ if(f && !is_static != !(f->flags&FLAG_STATIC))
+ noslot=1;
+ if(f && f->slot && !noslot) {
+ $$.c = abc_getslot($$.c, f->slot);
+ } else {
+ if(!f) {
+ as3_warning("Access of undefined property '%s' in %s", $3, t->name);
}
+
+ MEMBER_MULTINAME(m, f, $3);
+ $$.c = abc_getproperty2($$.c, &m);
+ }
+ /* determine type */
+ $$.t = slotinfo_gettype((slotinfo_t*)f);
+ if(!$$.t)
+ $$.c = abc_coerce_a($$.c);
+ } else if(v1.c && v1.c->opcode == OPCODE___PUSHPACKAGE__) {
+ string_t*package = v1.c->data[0];
+ char*package2 = concat3(package->str, ".", $3);
+
+ slotinfo_t*a = registry_find(package->str, $3);
+ if(a) {
+ $$ = push_class(a);
+ } else if(dict_contains(state->import_toplevel_packages, package2) ||
+ registry_ispackage(package2)) {
+ $$.c = v1.c;
+ $$.c->data[0] = string_new4(package2);
+ $$.t = 0;
+ } else {
+ syntaxerror("couldn't resolve %s", package2);
+ }
+ } else {
+ /* 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);
+ multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
+ $$.c = abc_getproperty2($$.c, &m);
+ $$.c = abc_coerce_a($$.c);
+ $$.t = registry_getanytype();
+ }
+}
VAR_READ : T_IDENTIFIER {
PASS1
function's variables.
We consider everything which is not a local variable "unresolved".
This encompasses class names, members of the surrounding class
- etc. which *correct* because local variables of the parent function
+ etc. which is *correct* because local variables of the parent function
would shadow those.
*/
if(state->method->inner && !find_variable(state, $1)) {
unknown_variable($1);
}
+
+ /* let the compiler know that it might want to check the current directory/package
+ for this identifier- maybe there's a file $1.as defining $1. */
+ as3_schedule_class_noerror(state->package, $1);
PASS2
$$.t = 0;
int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
/* look at current class' members */
- if(state->cls && (f = registry_findmember_nsset(state->cls->info, state->active_namespaces, $1, 1)) &&
- (f->flags&FLAG_STATIC) >= i_am_static) {
+ if(!state->method->inner &&
+ state->cls &&
+ (f = findmember_nsset(state->cls->info, $1, 1)) &&
+ (f->flags&FLAG_STATIC) >= i_am_static)
+ {
// $1 is a function in this class
int var_is_static = (f->flags&FLAG_STATIC);
static properties of a class */
state->method->late_binding = 1;
$$.t = f->type;
- namespace_t ns = {f->access, ""};
+ namespace_t ns = {f->access, f->package};
multiname_t m = {QNAME, &ns, 0, $1};
$$.c = abc_findpropstrict2($$.c, &m);
$$.c = abc_getproperty2($$.c, &m);
$$.c = abc_getslot($$.c, f->slot);
break;
} else {
- namespace_t ns = {f->access, ""};
+ namespace_t ns = {f->access, f->package};
multiname_t m = {QNAME, &ns, 0, $1};
$$.c = abc_getlocal_0($$.c);
$$.c = abc_getproperty2($$.c, &m);
/* look at actual classes, in the current package and imported */
if((a = find_class($1))) {
- if(a->access == ACCESS_PACKAGEINTERNAL &&
- strcmp(a->package, state->package) &&
- strcmp(a->package, internal_filename_package)
- )
- syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
- infotypename(a),$1, a->package, state->package);
-
- if(a->kind != INFOTYPE_CLASS) {
- MULTINAME(m, a);
- $$.c = abc_findpropstrict2($$.c, &m);
- $$.c = abc_getproperty2($$.c, &m);
- if(a->kind == INFOTYPE_METHOD) {
- methodinfo_t*f = (methodinfo_t*)a;
- $$.t = TYPE_FUNCTION(f);
- } else {
- varinfo_t*v = (varinfo_t*)a;
- $$.t = v->type;
- }
- } else {
- classinfo_t*c = (classinfo_t*)a;
- if(c->slot) {
- $$.c = abc_getglobalscope($$.c);
- $$.c = abc_getslot($$.c, c->slot);
- } else {
- MULTINAME(m, c);
- $$.c = abc_getlex2($$.c, &m);
- }
- $$.t = TYPE_CLASS(c);
- }
+ $$ = push_class(a);
+ break;
+ }
+
+ /* look through package prefixes */
+ if(dict_contains(state->import_toplevel_packages, $1) ||
+ registry_ispackage($1)) {
+ $$.c = abc___pushpackage__($$.c, $1);
+ $$.t = 0;
break;
}
/* unknown object, let the avm2 resolve it */
if(1) {
- as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
+ //as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
+ as3_warning("Couldn't resolve '%s', doing late binding", $1);
state->method->late_binding = 1;
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
NAMESPACE_ID : "namespace" T_IDENTIFIER {
PASS12
- tokenizer_register_namespace($2);
- $$=$2;
+ NEW(namespace_decl_t,n);
+ n->name = $2;
+ n->url = $2;
+ $$=n;
}
-
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
- $$=0;
+NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
+ PASS12
+ NEW(namespace_decl_t,n);
+ n->name = $2;
+ n->url = $4;
+ $$=n;
}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_IDENTIFIER {
- $$=0;
+NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
+ PASS12
+ NEW(namespace_decl_t,n);
+ n->name = $2;
+ n->url = $4.str;
+ $$=n;
}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID '=' T_STRING {
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
+ PASS12
+ trie_put(active_namespaces, $2->name, (void*)$2->url);
+
+ namespace_t access = modifiers2access(&$1);
+ varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
+ var->type = TYPE_NAMESPACE;
+ namespace_t ns;
+ ns.access = ACCESS_NAMESPACE;
+ ns.name = $2->url;
+ var->value = constant_new_namespace(&ns);
+
$$=0;
}
-USE_NAMESPACE : "use" PACKAGEANDCLASS {
+
+%code {
+ void add_active_url(const char*url)
+ {
+ NEW(namespace_t,n);
+ n->name = url;
+ list_append(state->active_namespace_urls, n);
+ }
+};
+
+USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
PASS12
- tokenizer_register_namespace($2->name);
+ const char*url = $3->name;
+
+ varinfo_t*s = (varinfo_t*)$3;
+ if(s->kind == INFOTYPE_UNRESOLVED) {
+ s = (varinfo_t*)registry_resolve((slotinfo_t*)s);
+ if(!s)
+ syntaxerror("Couldn't resolve namespace %s", $3->name);
+ }
+
+ if(!s || s->kind != INFOTYPE_SLOT)
+ syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
+ if(!s->value || !NS_TYPE(s->value->type))
+ syntaxerror("%s.%s is not a namespace", $3->package, $3->name);
+ url = s->value->ns->name;
+
+ trie_put(active_namespaces, $3->name, (void*)url);
+ add_active_url(url);
$$=0;
}