fixed vertical alignment bug
[swftools.git] / lib / as3 / parser.y
index a1edea6..d2188ef 100644 (file)
@@ -58,6 +58,8 @@
     char*id;
     constant_t*constant;
     for_start_t for_start;
+    abc_exception_t *exception;
+    abc_exception_list_t *exception_list;
 }
 
 
 %token<id> T_DO "do"
 %token<id> T_SWITCH "switch"
 
-%token<token> KW_IMPLEMENTS
+%token<token> KW_IMPLEMENTS "implements"
 %token<token> KW_NAMESPACE "namespace"
 %token<token> KW_PACKAGE "package"
-%token<token> KW_PROTECTED
-%token<token> KW_PUBLIC
-%token<token> KW_PRIVATE
+%token<token> KW_PROTECTED "protected"
+%token<token> KW_PUBLIC "public"
+%token<token> KW_PRIVATE "private"
 %token<token> KW_USE "use"
-%token<token> KW_INTERNAL
+%token<token> KW_INTERNAL "internal"
 %token<token> KW_NEW "new"
-%token<token> KW_NATIVE
+%token<token> KW_NATIVE "native"
 %token<token> KW_FUNCTION "function"
 %token<token> KW_UNDEFINED "undefined"
 %token<token> KW_CONTINUE "continue"
@@ -95,7 +97,9 @@
 %token<token> KW_CASE "case"
 %token<token> KW_SET "set"
 %token<token> KW_VOID "void"
-%token<token> KW_STATIC
+%token<token> KW_THROW "throw"
+%token<token> KW_STATIC "static"
+%token<token> KW_WITH "with"
 %token<token> KW_INSTANCEOF "instanceof"
 %token<token> KW_IMPORT "import"
 %token<token> KW_RETURN "return"
 %token<token> KW_NULL "null"
 %token<token> KW_VAR "var"
 %token<token> KW_DYNAMIC "dynamic"
-%token<token> KW_OVERRIDE
-%token<token> KW_FINAL
+%token<token> KW_OVERRIDE "override"
+%token<token> KW_FINAL "final"
 %token<token> KW_EACH "each"
 %token<token> KW_GET "get"
 %token<token> KW_TRY "try"
 %token<token> KW_SUPER "super"
-%token<token> KW_EXTENDS
+%token<token> KW_EXTENDS "extends"
 %token<token> KW_FALSE "false"
 %token<token> KW_TRUE "true"
 %token<token> KW_BOOLEAN "Boolean"
 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
 %type <token> VARCONST
 %type <code> CODE
-%type <code> CODEPIECE
-%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
-%type <token> PACKAGE_DECLARATION
-%type <token> FUNCTION_DECLARATION
-%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
-%type <token> CLASS_DECLARATION
-%type <token> NAMESPACE_DECLARATION
-%type <token> INTERFACE_DECLARATION
+%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> FUNCTION_DECLARATION PACKAGE_INITCODE
+%type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW 
+%type <exception> CATCH
+%type <exception_list> CATCH_LIST
+%type <code> CLASS_DECLARATION
+%type <code> NAMESPACE_DECLARATION
+%type <code> INTERFACE_DECLARATION
 %type <code> VOIDEXPRESSION
 %type <value> EXPRESSION NONCOMMAEXPRESSION
 %type <value> MAYBEEXPRESSION
 %type <value> E DELETE
 %type <value> CONSTANT
-%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
+%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
 %type <token> USE_NAMESPACE
 %type <code> FOR_INIT
-%type <token> IMPORT
+%type <code> IMPORT
 %type <classinfo> MAYBETYPE
 %type <token> GETSET
 %type <param> PARAM
@@ -288,6 +294,8 @@ typedef struct _methodstate {
     code_t*initcode;
     char is_constructor;
     char has_super;
+    char is_global;
+    abc_exception_list_t*exceptions;
 } methodstate_t;
 
 typedef struct _state {
@@ -301,6 +309,8 @@ typedef struct _state {
   
     classstate_t*cls;   
     methodstate_t*method;
+
+    char*exception_name;
     
     dict_t*vars;
 } state_t;
@@ -359,11 +369,6 @@ static namespace_list_t nl2 = {&ns2,&nl3};
 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);
@@ -376,7 +381,7 @@ static void new_state()
     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()
@@ -424,11 +429,14 @@ static void old_state()
 }
 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;
@@ -489,12 +497,10 @@ void* finalize_state()
 
 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()
 {
@@ -513,6 +519,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
         syntaxerror("inner classes now allowed"); 
     }
     new_state();
+    global->variable_count = 1;
     state->cls = rfx_calloc(sizeof(classstate_t));
 
     token_list_t*t=0;
@@ -722,6 +729,7 @@ static int new_variable(char*name, classinfo_t*type, char init)
     NEW(variable_t, v);
     v->index = global->variable_count;
     v->type = type;
+    
     dict_put(state->vars, name, v);
 
     if(init && state->method && type) {
@@ -794,10 +802,33 @@ static void check_constant_against_type(classinfo_t*t, constant_t*c)
    }
 }
 
+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);
@@ -814,6 +845,7 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
         // 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)
@@ -849,24 +881,6 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
     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)
 {
@@ -874,17 +888,24 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
         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);
@@ -897,21 +918,28 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
 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;
@@ -938,11 +966,13 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
     }
     check_code_for_break(body);
 
-    if(f->body)
+    if(f->body) {
         f->body->code = body;
-    else //interface
+        f->body->exceptions = state->method->exceptions;
+    } else { //interface
         if(body)
             syntaxerror("interface methods can't have a method body");
+    }
        
     free(state->method);state->method=0;
     old_state();
@@ -1068,14 +1098,15 @@ static classinfo_t* find_class(char*name)
     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;
     }
@@ -1083,18 +1114,21 @@ static classinfo_t* find_class(char*name)
     /* 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)
@@ -1253,47 +1287,72 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
 
 /* ------------ 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_STATEMENT: WITH
+CODE_STATEMENT: TRY
+
+// code which may appear anywhere
+CODEPIECE: ';' {$$=0;}
+CODEPIECE: VARIABLE_DECLARATION
+CODEPIECE: CODE_STATEMENT
+CODEPIECE: BREAK
+CODEPIECE: CONTINUE
+CODEPIECE: RETURN
+CODEPIECE: THROW
+
+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;}
@@ -1536,6 +1595,79 @@ SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
     old_state();
 }
 
+/* ------------ try / catch /finally ---------------- */
+
+FINALLY: "finally" '{' CODE '}'
+MAYBE_FINALLY: | FINALLY 
+
+CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
+        '{' CODE '}' {
+    code_t*c = 0;
+    int i = find_variable_safe($3)->index;
+    c = abc_setlocal(c, i);
+    c = code_append(c, $8);
+    c = abc_kill(c, i);
+    
+    namespace_t name_ns = {ACCESS_PACKAGE, ""};
+    multiname_t name = {QNAME, &name_ns, 0, $3};
+
+    NEW(abc_exception_t, e)
+    e->exc_type = sig2mname($4);
+    e->var_name = multiname_clone(&name);
+    e->target = code_start(c);
+    $$ = e;
+    old_state();
+}
+
+CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
+CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
+
+TRY : "try" '{' CODE '}' CATCH_LIST MAYBE_FINALLY {
+    code_t*start = code_start($3);
+    $$=$3;
+
+    code_t*out = abc_nop(0);
+    code_t*jmp = $$ = abc_jump($$, out);
+
+    abc_exception_list_t*l = $5;
+    while(l) {
+        abc_exception_t*e = l->abc_exception;
+        e->from = start;
+        e->to = jmp;
+        $$ = code_append($$, e->target);
+        $$ = abc_jump($$, out);
+        l = l->next;
+    }
+    $$ = code_append($$, out);
+    jmp->branch = out;
+        
+    list_concat(state->method->exceptions, $5);
+}
+
+/* ------------ throw ------------------------------- */
+
+THROW : "throw" EXPRESSION {
+    $$=$2.c;
+    $$=abc_throw($$);
+}
+THROW : "throw" %prec prec_none {
+    if(!state->exception_name)
+        syntaxerror("re-throw only possible within a catch block");
+    variable_t*v = find_variable(state->exception_name);
+    $$=code_new();
+    $$=abc_getlocal($$, v->index);
+    $$=abc_throw($$);
+}
+
+/* ------------ with -------------------------------- */
+
+WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
+     $$ = $3.c;
+     $$ = abc_pushscope($$);
+     $$ = code_append($$, $5);
+     $$ = abc_popscope($$);
+}
+
 /* ------------ packages and imports ---------------- */
 
 X_IDENTIFIER: T_IDENTIFIER
@@ -1544,8 +1676,8 @@ X_IDENTIFIER: T_IDENTIFIER
 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;
@@ -1592,29 +1724,35 @@ IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$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");
@@ -1634,45 +1772,58 @@ VARCONST: "var" | "const"
 
 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 -------------------------------------- */
@@ -1753,6 +1904,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P
     }
     c = wrap_function(c, state->method->initcode, $11);
     endfunction(0,$1,$3,$4,&$6,$8,c);
+    $$=0;
 }
 
 /* ------------- package + class ids --------------- */
@@ -2407,7 +2559,7 @@ VAR_READ : T_IDENTIFIER {
         $$.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);
@@ -2476,9 +2628,9 @@ VAR_READ : T_IDENTIFIER {
 
 // ----------------- 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;}