started integrating expression ast
[swftools.git] / lib / as3 / parser.y
index d0927b2..a1ce232 100644 (file)
 #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 "ast.h"
 
 extern int a3_lex();
 
@@ -79,8 +81,6 @@ extern int a3_lex();
 %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"
@@ -101,6 +101,7 @@ extern int a3_lex();
 %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"
@@ -170,6 +171,7 @@ extern int a3_lex();
 %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
 %type <namespace_decl>  NAMESPACE_ID
@@ -189,7 +191,6 @@ extern int a3_lex();
 %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 TRY 
 %type <value> INNERFUNCTION
 %type <code> USE_NAMESPACE
@@ -203,7 +204,7 @@ extern int a3_lex();
 %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
@@ -256,7 +257,7 @@ extern int a3_lex();
 
 // 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
 
@@ -270,6 +271,13 @@ static int a3_error(char*s)
    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)
 {
@@ -297,7 +305,6 @@ static char* concat3(const char* t1, const char* t2, const char* t3)
 typedef struct _import {
     char*package;
 } import_t;
-
 DECLARE_LIST(import);
 
 DECLARE(methodstate);
@@ -428,6 +435,15 @@ static namespace_list_t nl2 = {&ns2,&nl3};
 static namespace_list_t nl1 = {&ns1,&nl2};
 static namespace_set_t nopackage_namespace_set = {&nl1};
 
+static dict_t*definitions=0;
+void as3_set_definition(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);
@@ -452,24 +468,6 @@ static void new_state()
     if(oldstate)
         state->active_namespace_urls = list_clone(oldstate->active_namespace_urls);
 }
-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);
-}
 
 static void state_destroy(state_t*state)
 {
@@ -585,42 +583,10 @@ void initialize_parser()
 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;
@@ -654,11 +620,32 @@ static variable_t* find_variable_safe(state_t*s, char*name)
         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()
 {
@@ -697,7 +684,7 @@ static int gettempvar()
     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;
@@ -741,7 +728,7 @@ code_t* var_block(code_t*body)
     return c;
 }
 
-void unknown_variable(char*name) 
+static void unknown_variable(char*name) 
 {
     if(!state->method->unresolved_variables)
         state->method->unresolved_variables = dict_new();
@@ -749,14 +736,6 @@ void unknown_variable(char*name)
         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)
-{
-    syntaxerror("internal error in %s, %s:%d", f, file, line);
-}
-
-   
 static code_t* add_scope_code(code_t*c, methodstate_t*m, char init)
 {
     if(m->uses_slots || (m->late_binding && !m->inner)) { //???? especially inner functions need the pushscope
@@ -843,20 +822,15 @@ static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
     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();
 }
 
@@ -908,13 +882,6 @@ static memberinfo_t* findmember_nsset(classinfo_t*cls, const char*name, char rec
     return registry_findmember_nsset(cls, state->active_namespace_urls, name, recurse);
 }
 
-void add_active_url(const char*url)
-{
-    NEW(namespace_t,n);
-    n->name = url;
-    list_append(state->active_namespace_urls, n);
-}
-
 static void function_initvars(methodstate_t*m, params_t*params, int flags, char var0)
 {
     if(var0) {
@@ -945,9 +912,6 @@ static void function_initvars(methodstate_t*m, params_t*params, int flags, char
             v->is_parameter = 1;
         }
     }
-    if(m->uses_slots) {
-        dict_dump(m->slots, stdout, "");
-    }
 
     methodstate_list_t*l = m->innerfunctions;
     while(l) {
@@ -1149,23 +1113,6 @@ static void startclass(modifiers_t* mod, char*classname, classinfo_t*extends, cl
     }
 }
 
-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);
-    }
-}
-
 static void endclass()
 {
     if(as3_pass == 2) {
@@ -1207,6 +1154,12 @@ void check_code_for_break(code_t*c)
             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);
@@ -1215,10 +1168,8 @@ void check_code_for_break(code_t*c)
     }
 }
 
-
 static void check_constant_against_type(classinfo_t*t, constant_t*c)
 {
-    return;
 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
    if(TYPE_IS_NUMBER(t)) {
         xassert(c->type == CONSTANT_FLOAT
@@ -1277,9 +1228,6 @@ static methodinfo_t*registerfunction(enum yytokentype getset, modifiers_t*mod, c
         //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);
@@ -1573,11 +1521,6 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
     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) {
@@ -1605,11 +1548,11 @@ void continuejumpsto(code_t*c, char*name, code_t*jump)
     }
 }
 
+/* TODO: move this to ast.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)
+static classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
 {
     if(!type1 || !type2) 
         return registry_getanytype();
@@ -1628,6 +1571,26 @@ classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
         return type1;
     return registry_getanytype();
 }
+static char is_getlocal(code_t*c)
+{
+    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;
+}
 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
 {
     if(from==to)
@@ -1645,10 +1608,21 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*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) {
@@ -1674,30 +1648,12 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
         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)
 {
@@ -1809,28 +1765,8 @@ typedcode_t push_class(slotinfo_t*a)
     return x;
 }
 
-static char is_getlocal(code_t*c)
-{
-    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)
+code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore, char pushvalue)
 {
     /* converts this:
 
@@ -1927,29 +1863,36 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
             temp = gettempvar();
             c = code_append(c, prefix);
             c = code_append(c, r);
-            if(readbefore) {
+            if(pushvalue && readbefore) {
                 c = abc_dup(c);
                 c = abc_setlocal(c, temp);
             }
             c = code_append(c, middlepart);
-            if(!readbefore) {
+            if(pushvalue && !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);
+            if(pushvalue) {
+                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);
+            code_t* r2 = 0;
+            if(pushvalue) {
+                r2 = code_dup(r);
+            }
             c = code_append(c, r);
             c = code_append(c, middlepart);
             c = code_append(c, write);
-            c = code_append(c, r2);
+            if(pushvalue) {
+                c = code_append(c, r2);
+            }
         }
     } else {
         /* even smaller version: overwrite the value without reading
@@ -1961,7 +1904,9 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
             }
             c = code_append(c, middlepart);
             c = code_append(c, write);
-            c = code_append(c, r);
+            if(pushvalue) {
+                c = code_append(c, r);
+            }
         } else {
             code_free(r);r=0;
             temp = gettempvar();
@@ -1969,11 +1914,15 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
                 c = code_append(c, prefix);
             }
             c = code_append(c, middlepart);
-            c = abc_dup(c);
-            c = abc_setlocal(c, temp);
+            if(pushvalue) {
+                c = abc_dup(c);
+                c = abc_setlocal(c, temp);
+            }
             c = code_append(c, write);
-            c = abc_getlocal(c, temp);
-            c = abc_kill(c, temp);
+            if(pushvalue) {
+                c = abc_getlocal(c, temp);
+                c = abc_kill(c, temp);
+            }
         }
     }
     return c;
@@ -2112,8 +2061,9 @@ code_t* insert_finally(code_t*c, code_t*finally, int 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 }} {{
 
 %}
 
@@ -2133,7 +2083,7 @@ PROGRAM_CODE: PACKAGE_DECLARATION
             | 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
@@ -2145,7 +2095,7 @@ INPACKAGE_CODE: INTERFACE_DECLARATION
               | 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;}
@@ -2178,7 +2128,7 @@ CODEPIECE: BREAK
 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;}
@@ -2194,10 +2144,25 @@ PACKAGE_INITCODE: CODE_STATEMENT {
 
 /* ------------ 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;
@@ -2643,6 +2608,26 @@ PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2
 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);
@@ -2725,7 +2710,7 @@ MAYBE_CLASS_BODY : CLASS_BODY
 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
 
@@ -2756,81 +2741,110 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
 
 /* ------------ 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 {setslotstate(&$1,$2);} SLOT_LIST {$$=$4;setslotstate(0, 0);}
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST {PASS12 setslotstate(&$1,$2);} SLOT_LIST {PASS12 $$=$4;setslotstate(0, 0);}
 
-SLOT_LIST: ONE_SLOT               {$$ = $1;}
-SLOT_LIST: SLOT_LIST ',' ONE_SLOT {$$ = code_append($1, $3);}
+SLOT_LIST: ONE_SLOT               {PASS12 $$=0;}
+SLOT_LIST: SLOT_LIST ',' ONE_SLOT {PASS12 $$=0;}
 
 ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
 {
+PASS12
     int flags = slotstate_flags->flags;
     namespace_t ns = modifiers2access(slotstate_flags);
 
-    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);
-    }
+    if(as3_pass == 1) {
 
-    info->type = $2;
-    info->flags = flags;
+        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);
+        }
 
-    /* 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);
+        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);
+        }
+
+        *code = code_append(*code, c);
 
-    if(slotstate_varconst==KW_CONST) {
-        t->kind= TRAIT_CONST;
+        if(slotstate_varconst==KW_CONST) {
+            t->kind= TRAIT_CONST;
+        }
     }
 
     $$=0;
@@ -2838,26 +2852,31 @@ ONE_SLOT: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
 
 /* ------------ 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 {
+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) ------- */
 
@@ -2897,7 +2916,7 @@ PARAM_LIST: PARAM {
     list_append($$.list, $1);
 }
 
-PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
+PARAM:  T_IDENTIFIER ':' TYPE MAYBECONSTANT {
      PASS12
      $$ = rfx_calloc(sizeof(param_t));
      $$->name=$1;
@@ -2905,7 +2924,7 @@ PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
      PASS2
      $$->value = $4;
 }
-PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
+PARAM:  T_IDENTIFIER MAYBECONSTANT {
      PASS12
      $$ = rfx_calloc(sizeof(param_t));
      $$->name=$1;
@@ -3182,13 +3201,17 @@ VOIDEXPRESSION : EXPRESSION %prec below_minus {
 // ----------------------- expression evaluation -------------------------------------
 
 E : INNERFUNCTION %prec prec_none {$$ = $1;}
-E : CONSTANT
-E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
-E : NEW                         {$$ = $1;}
-E : DELETE                      {$$ = $1;}
+E : VAR_READ %prec T_IDENTIFIER   {$$ = $1;}
+E : NEW                           {$$ = $1;}
+E : DELETE                        {$$ = $1;}
 
 E : FUNCTIONCALL
 
+E : CONSTANT {
+    node_t*n = mkconstnode($1);
+    $$ = node_read(n);
+}
+
 E : T_REGEXP {
     $$.c = 0;
     namespace_t ns = {ACCESS_PACKAGE, ""};
@@ -3206,39 +3229,6 @@ E : T_REGEXP {
     $$.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;
             }
@@ -3414,7 +3404,7 @@ E : "void" { $$.c = abc_pushundefined(0);
 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
 
 E : '-' E {
-  $$=$2;
+  $$.c = $2.c;
   if(IS_INT($2.t)) {
    $$.c=abc_negate_i($$.c);
    $$.t = TYPE_INT;
@@ -3473,50 +3463,50 @@ E : E "*=" E {
                 c=abc_multiply(c);
                }
                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
-               $$.c = toreadwrite($1.c, c, 0, 0);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.t = $1.t;
               }
 E : E "+=" E { 
@@ -3529,7 +3519,7 @@ E : E "+=" E {
                 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
                }
                
-               $$.c = toreadwrite($1.c, c, 0, 0);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.t = $1.t;
               }
 E : E "-=" E { code_t*c = $3.c; 
@@ -3540,13 +3530,13 @@ E : E "-=" E { code_t*c = $3.c;
                 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
                }
                
-               $$.c = toreadwrite($1.c, c, 0, 0);
+               $$.c = toreadwrite($1.c, c, 0, 0, 1);
                $$.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);
+              $$.c = toreadwrite($1.c, c, 1, 0, 1);
               $$.t = $1.t;
             }
 
@@ -3584,7 +3574,7 @@ E : E "++" { code_t*c = 0;
                      type = TYPE_NUMBER;
                  }
                  c=converttype(c, type, $1.t);
-                 $$.c = toreadwrite($1.c, c, 0, 1);
+                 $$.c = toreadwrite($1.c, c, 0, 1, 1);
                  $$.t = $1.t;
              }
            }
@@ -3600,7 +3590,7 @@ E : E "--" { code_t*c = 0;
                  type = TYPE_NUMBER;
              }
              c=converttype(c, type, $1.t);
-             $$.c = toreadwrite($1.c, c, 0, 1);
+             $$.c = toreadwrite($1.c, c, 0, 1, 1);
              $$.t = $1.t;
             }
 
@@ -3614,7 +3604,7 @@ E : "++" %prec plusplus_prefix E { code_t*c = 0;
                  type = TYPE_NUMBER;
              }
              c=converttype(c, type, $2.t);
-             $$.c = toreadwrite($2.c, c, 0, 0);
+             $$.c = toreadwrite($2.c, c, 0, 0, 1);
              $$.t = $2.t;
            }
 
@@ -3628,7 +3618,7 @@ E : "--" %prec minusminus_prefix E { code_t*c = 0;
                  type = TYPE_NUMBER;
              }
              c=converttype(c, type, $2.t);
-             $$.c = toreadwrite($2.c, c, 0, 0);
+             $$.c = toreadwrite($2.c, c, 0, 0, 1);
              $$.t = $2.t;
            }
 
@@ -3709,8 +3699,9 @@ E : E '.' T_IDENTIFIER {
         if(f && f->slot && !noslot) {
             $$.c = abc_getslot($$.c, f->slot);
         } else {
-            if(!f) 
+            if(!f) {
                 as3_warning("Access of undefined property '%s' in %s", $3, t->name);
+            }
             
             MEMBER_MULTINAME(m, f, $3);
             $$.c = abc_getproperty2($$.c, &m);
@@ -3891,6 +3882,15 @@ NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
     $$=0;
 }
 
+%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
     const char*url = $3->name;