%type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
%type <token> VARCONST
%type <code> CODE
-%type <code> CODEPIECE
+%type <code> CODEPIECE CODE_STATEMENT
%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
-%type <token> PACKAGE_DECLARATION
-%type <token> FUNCTION_DECLARATION
+%type <code> PACKAGE_DECLARATION SLOT_DECLARATION
+%type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
-%type <token> CLASS_DECLARATION
-%type <token> NAMESPACE_DECLARATION
-%type <token> INTERFACE_DECLARATION
+%type <code> CLASS_DECLARATION
+%type <code> NAMESPACE_DECLARATION
+%type <code> INTERFACE_DECLARATION
%type <code> VOIDEXPRESSION
%type <value> EXPRESSION NONCOMMAEXPRESSION
%type <value> MAYBEEXPRESSION
%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
%type <token> USE_NAMESPACE
%type <code> FOR_INIT
-%type <token> IMPORT
+%type <code> IMPORT
%type <classinfo> MAYBETYPE
%type <token> GETSET
%type <param> PARAM
code_t*initcode;
char is_constructor;
char has_super;
+ char is_global;
} methodstate_t;
typedef struct _state {
static namespace_list_t nl1 = {&ns1,&nl2};
static namespace_set_t nopackage_namespace_set = {&nl1};
-static void init_globals()
-{
- global = rfx_calloc(sizeof(global_t));
-}
-
static void new_state()
{
NEW(state_t, s);
state = s;
state->level++;
state->has_own_imports = 0;
- state->vars = dict_new();
+ state->vars = dict_new();
state->old = oldstate;
}
static void state_has_imports()
}
void initialize_state()
{
- init_globals();
+ global = rfx_calloc(sizeof(global_t));
new_state();
+ state->package = current_filename;
+
global->file = abc_file_new();
global->file->flags &= ~ABCFILE_LAZY;
+ global->variable_count = 1;
global->init = abc_initscript(global->file, 0);
code_t*c = global->init->method->body->code;
static void startpackage(char*name)
{
- if(state->package) {
- syntaxerror("Packages can not be nested.");
- }
new_state();
/*printf("entering package \"%s\"\n", name);*/
state->package = strdup(name);
+ global->variable_count = 1;
}
static void endpackage()
{
syntaxerror("inner classes now allowed");
}
new_state();
+ global->variable_count = 1;
state->cls = rfx_calloc(sizeof(classstate_t));
token_list_t*t=0;
NEW(variable_t, v);
v->index = global->variable_count;
v->type = type;
+
dict_put(state->vars, name, v);
if(init && state->method && type) {
}
}
+static int flags2access(int flags)
+{
+ int access = 0;
+ if(flags&FLAG_PUBLIC) {
+ if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+ access = ACCESS_PACKAGE;
+ } else if(flags&FLAG_PRIVATE) {
+ if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+ access = ACCESS_PRIVATE;
+ } else if(flags&FLAG_PROTECTED) {
+ if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
+ access = ACCESS_PROTECTED;
+ } else {
+ access = ACCESS_PACKAGEINTERNAL;
+ }
+ return access;
+}
+
static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
{
memberinfo_t*minfo = 0;
- if(getset != KW_GET && getset != KW_SET) {
+ if(!state->cls) {
+ //package method
+ minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
+ minfo->return_type = return_type;
+ } else if(getset != KW_GET && getset != KW_SET) {
+ //class method
if((minfo = registry_findmember(state->cls->info, name, 0))) {
if(minfo->parent == state->cls->info) {
syntaxerror("class already contains a member/method called '%s'", name);
// to actually store these
//state->minfo->slot = state->method->abc->method->trait->slot_id;
} else {
+ //class getter/setter
int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
classinfo_t*type=0;
if(getset == KW_GET)
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");
}
new_state();
+ global->variable_count = 0;
state->method = rfx_calloc(sizeof(methodstate_t));
state->method->initcode = 0;
- state->method->is_constructor = !strcmp(state->cls->info->name,name);
state->method->has_super = 0;
-
- state->cls->has_constructor |= state->method->is_constructor;
+ if(state->cls) {
+ state->method->is_constructor = !strcmp(state->cls->info->name,name);
+ state->cls->has_constructor |= state->method->is_constructor;
+
+ new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
+ } else {
+ state->method->is_global = 1;
+ state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
- global->variable_count = 0;
+ new_variable("globalscope", 0, 0);
+ }
/* state->vars is initialized by state_new */
- if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0)!=0) syntaxerror("Internal error");
+
param_list_t*p=0;
for(p=params->list;p;p=p->next) {
new_variable(p->param->name, p->param->type, 0);
static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
params_t*params, classinfo_t*return_type, code_t*body)
{
- namespace_t mname_ns = {flags2access(flags), ""};
- multiname_t mname = {QNAME, &mname_ns, 0, name};
-
abc_method_t*f = 0;
multiname_t*type2 = sig2mname(return_type);
int slot = 0;
if(state->method->is_constructor) {
f = abc_class_getconstructor(state->cls->abc, type2);
- } else {
+ } else if(!state->method->is_global) {
+ namespace_t mname_ns = {flags2access(flags), ""};
+ multiname_t mname = {QNAME, &mname_ns, 0, name};
+
if(flags&FLAG_STATIC)
f = abc_class_staticmethod(state->cls->abc, type2, &mname);
else
f = abc_class_method(state->cls->abc, type2, &mname);
slot = f->trait->slot_id;
+ } else {
+ namespace_t mname_ns = {flags2access(flags), state->package};
+ multiname_t mname = {QNAME, &mname_ns, 0, name};
+
+ f = abc_method_new(global->file, type2, 1);
+ trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
+ //abc_code_t*c = global->init->method->body->code;
}
//flash doesn't seem to allow us to access function slots
//state->method->info->slot = slot;
classinfo_t*c=0;
c = registry_findclass(state->package, name);
+ if(c) return c;
/* try explicit imports */
dictentry_t* e = dict_get_slot(state->imports, name);
+ if(c) return c;
while(e) {
- if(c)
- break;
if(!strcmp(e->key, name)) {
c = (classinfo_t*)e->data;
+ if(c) return c;
}
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);
+ if(c) return c;
l = l->next;
}
/* try global package */
- if(!c) {
- c = registry_findclass("", name);
- }
- return c;
+ c = registry_findclass("", name);
+ if(c) return c;
+
+ /* try local "filename" package */
+ c = registry_findclass(current_filename, name);
+ if(c) return c;
+
+ return 0;
}
static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
/* ------------ code blocks / statements ---------------- */
-PROGRAM: MAYBECODE {
- /* todo: do something with this code if we're outside a function */
- if($1)
- warning("ignored code");
-}
+PROGRAM: MAYBE_PROGRAM_CODE_LIST
+
+MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST
+PROGRAM_CODE_LIST: PROGRAM_CODE
+ | PROGRAM_CODE_LIST PROGRAM_CODE
+
+PROGRAM_CODE: PACKAGE_DECLARATION
+ | INTERFACE_DECLARATION
+ | CLASS_DECLARATION
+ | FUNCTION_DECLARATION
+ | SLOT_DECLARATION
+ | PACKAGE_INITCODE
+ | ';'
+
+MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
+INPACKAGE_CODE_LIST: INPACKAGE_CODE
+ | INPACKAGE_CODE_LIST INPACKAGE_CODE
+
+INPACKAGE_CODE: INTERFACE_DECLARATION
+ | CLASS_DECLARATION
+ | FUNCTION_DECLARATION
+ | SLOT_DECLARATION
+ | PACKAGE_INITCODE
+ | ';'
MAYBECODE: CODE {$$=$1;}
MAYBECODE: {$$=code_new();}
-CODE: CODE CODEPIECE {
- $$=code_append($1,$2);
-}
-CODE: CODEPIECE {
- $$=$1;
-}
-
-CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
-CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
-CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
-CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
-CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
-CODEPIECE: ';' {$$=code_new();}
-CODEPIECE: VARIABLE_DECLARATION {$$=$1}
-CODEPIECE: VOIDEXPRESSION {$$=$1}
-CODEPIECE: FOR {$$=$1}
-CODEPIECE: FOR_IN {$$=$1}
-CODEPIECE: WHILE {$$=$1}
-CODEPIECE: DO_WHILE {$$=$1}
-CODEPIECE: SWITCH {$$=$1}
-CODEPIECE: BREAK {$$=$1}
-CODEPIECE: CONTINUE {$$=$1}
-CODEPIECE: RETURN {$$=$1}
-CODEPIECE: IF {$$=$1}
-CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
-CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
+CODE: CODE CODEPIECE {$$=code_append($1,$2);}
+CODE: CODEPIECE {$$=$1;}
+
+// code which also may appear outside a method
+CODE_STATEMENT: IMPORT
+CODE_STATEMENT: VOIDEXPRESSION
+CODE_STATEMENT: FOR
+CODE_STATEMENT: FOR_IN
+CODE_STATEMENT: WHILE
+CODE_STATEMENT: DO_WHILE
+CODE_STATEMENT: SWITCH
+CODE_STATEMENT: IF
+
+// code which may appear anywhere
+//CODEPIECE: PACKAGE_DECLARATION
+//CODEPIECE: CLASS_DECLARATION
+//CODEPIECE: FUNCTION_DECLARATION
+//CODEPIECE: INTERFACE_DECLARATION
+CODEPIECE: ';' {$$=0;}
+CODEPIECE: VARIABLE_DECLARATION
+CODEPIECE: CODE_STATEMENT
+CODEPIECE: BREAK
+CODEPIECE: CONTINUE
+CODEPIECE: RETURN
+
+CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
+CODEPIECE: USE_NAMESPACE {/*TODO*/$$=0;}
CODEBLOCK : '{' CODE '}' {$$=$2;}
CODEBLOCK : '{' '}' {$$=0;}
CODEBLOCK : CODEPIECE ';' {$$=$1;}
CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
+/* ------------ package init code ------------------- */
+
+PACKAGE_INITCODE: CODE_STATEMENT {
+ if($1) warning("code ignored");
+}
+
/* ------------ variables --------------------------- */
MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
PACKAGE: X_IDENTIFIER {$$=strdup($1);}
-PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
-PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
+PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
+PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
IMPORT : "import" QNAME {
classinfo_t*c = $2;
CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
EXTENDS IMPLEMENTS_LIST
'{' {startclass($1,$3,$4,$5, 0);}
- MAYBE_DECLARATION_LIST
- '}' {endclass();}
+ MAYBE_CLASS_BODY
+ '}' {endclass();$$=0;}
INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
EXTENDS_LIST
'{' {startclass($1,$3,0,$4,1);}
- MAYBE_IDECLARATION_LIST
- '}' {endclass();}
+ MAYBE_INTERFACE_BODY
+ '}' {endclass();$$=0;}
/* ------------ classes and interfaces (body) -------------- */
-MAYBE_DECLARATION_LIST :
-MAYBE_DECLARATION_LIST : DECLARATION_LIST
-DECLARATION_LIST : DECLARATION
-DECLARATION_LIST : DECLARATION_LIST DECLARATION
-DECLARATION : ';'
-DECLARATION : SLOT_DECLARATION
-DECLARATION : FUNCTION_DECLARATION
-
-MAYBE_IDECLARATION_LIST :
-MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
-IDECLARATION_LIST : IDECLARATION
-IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
+MAYBE_CLASS_BODY :
+MAYBE_CLASS_BODY : CLASS_BODY
+CLASS_BODY : CLASS_BODY_ITEM
+CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
+CLASS_BODY_ITEM : ';'
+CLASS_BODY_ITEM : SLOT_DECLARATION
+CLASS_BODY_ITEM : FUNCTION_DECLARATION
+
+CLASS_BODY_ITEM : CODE_STATEMENT {
+ code_t*c = state->cls->static_init;
+ c = code_append(c, $1);
+ state->cls->static_init = c;
+}
+
+MAYBE_INTERFACE_BODY :
+MAYBE_INTERFACE_BODY : INTERFACE_BODY
+INTERFACE_BODY : IDECLARATION
+INTERFACE_BODY : INTERFACE_BODY IDECLARATION
IDECLARATION : ';'
IDECLARATION : "var" T_IDENTIFIER {
syntaxerror("variable declarations not allowed in interfaces");
SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
int flags = $1;
- memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
+ memberinfo_t* info = state->cls?
+ memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
+ memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
+
info->type = $4;
info->flags = flags;
- trait_t*t=0;
+ /* slot name */
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->abc, &mname, &m);
- } else {
- t=abc_class_slot(state->cls->abc, &mname, 0);
- }
- info->slot = t->slot_id;
+
+ trait_list_t**traits;
+ code_t**code;
+ if(!state->cls) {
+ // global variable
+ 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;
} else {
- if($4) {
- MULTINAME(m, $4);
- t=abc_class_staticslot(state->cls->abc, &mname, &m);
- } else {
- t=abc_class_staticslot(state->cls->abc, &mname, 0);
- }
- info->slot = t->slot_id;
+ // instance variable
+ traits = &state->cls->abc->traits;
+ code = &state->cls->init;
+ }
+
+ trait_t*t=0;
+ if($4) {
+ MULTINAME(m, $4);
+ 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($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);
- 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);
}
+
+ *code = code_append(*code, c);
+
if($2==KW_CONST) {
t->kind= TRAIT_CONST;
}
+
+ $$=0;
}
/* ------------ constants -------------------------------------- */
}
c = wrap_function(c, state->method->initcode, $11);
endfunction(0,$1,$3,$4,&$6,$8,c);
+ $$=0;
}
/* ------------- package + class ids --------------- */
$$.t = v->type;
/* look at current class' members */
- } else if((f = registry_findmember(state->cls->info, $1, 1))) {
+ } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
// $1 is a function in this class
int var_is_static = (f->flags&FLAG_STATIC);
int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
// ----------------- namespaces -------------------------------------------------
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
-NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
+NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
-USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
+USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}