just made compileable- it'll be replaced soon
[swftools.git] / lib / as3 / parser.y
index 8da6dd0..3783b29 100644 (file)
@@ -31,6 +31,7 @@
 #include "registry.h"
 #include "code.h"
 #include "opcodes.h"
+#include "compiler.h"
 
 extern int a3_lex();
 
@@ -199,8 +200,8 @@ extern int a3_lex();
 %type <classinfo_list> IMPLEMENTS_LIST
 %type <classinfo> EXTENDS
 %type <classinfo_list> EXTENDS_LIST
-%type <classinfo> CLASS PACKAGEANDCLASS QNAME
-%type <classinfo_list> QNAME_LIST
+%type <classinfo> CLASS PACKAGEANDCLASS CLASS_SPEC
+%type <classinfo_list> CLASS_SPEC_LIST
 %type <classinfo> TYPE
 //%type <token> VARIABLE
 %type <value> VAR_READ
@@ -235,18 +236,21 @@ extern int a3_lex();
 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
 %left "--" "++" 
 %nonassoc below_curly
-%left '[' ']' '{' "new" '.' ".." "::"
+
+%left '('
+%left new2
+%left '[' ']' "new" '{' '.' ".." "::"
+
 %nonassoc T_IDENTIFIER
 %left above_identifier
 %left below_else
 %nonassoc "else"
-%left '('
 
 // needed for "return" precedence:
 %nonassoc T_STRING T_REGEXP
 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
 %nonassoc "false" "true" "null" "undefined" "super" "function"
-%nonassoc above_function
+%left above_function
 
 
      
@@ -455,8 +459,11 @@ static void old_state()
 
 void initialize_file(char*filename)
 {
+    if(state) {
+        syntaxerror("invalid call to initialize_file during parsing of another file");
+    }
     new_state();
-    state->package = filename;
+    state->package = strdup(filename);
     
     state->method = rfx_calloc(sizeof(methodstate_t));
     state->method->variable_count = 1;
@@ -467,6 +474,10 @@ void finish_file()
     if(!state || state->level!=1) {
         syntaxerror("unexpected end of file in pass %d", as3_pass);
     }
+    free(state->method);state->method=0;
+
+    //free(state->package);state->package=0; // used in registry
+
     state_destroy(state);state=0;
 }
 
@@ -625,6 +636,44 @@ code_t* var_block(code_t*body)
     return c;
 }
 
+#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);
+}
+
+   
+code_t* method_header()
+{
+    code_t*c = 0;
+    if(state->method->late_binding && !state->method->inner) {
+        c = abc_getlocal_0(c);
+        c = abc_pushscope(c);
+    }
+    /*if(state->method->innerfunctions) {
+        c = abc_newactivation(c);
+        c = abc_pushscope(c);
+    }*/
+    if(state->method->is_constructor && !state->method->has_super) {
+        // call default constructor
+        c = abc_getlocal_0(c);
+        c = abc_constructsuper(c, 0);
+    }
+    methodstate_list_t*l = state->method->innerfunctions;
+    while(l) {
+        parserassert(l->methodstate->abc);
+        c = abc_newfunction(c, l->methodstate->abc);
+        c = abc_setlocal(c, l->methodstate->var_index);
+        free(l->methodstate);l->methodstate=0;
+        l = l->next;
+    }
+    list_free(state->method->innerfunctions);
+    state->method->innerfunctions = 0;
+    return c;
+}
+    
+
 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
 {
     c = code_append(c, header);
@@ -654,14 +703,6 @@ static void endpackage()
     old_state();
 }
 
-#define _TRACE_ {printf("vfw: %s: %d (%s)\n",__FILE__,__LINE__,__func__);fflush(stdout);}
-#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);
-}
-
 
 char*as3_globalclass=0;
 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
@@ -671,8 +712,6 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     }
     new_state();
     state->cls = rfx_calloc(sizeof(classstate_t));
-    state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
-    state->method->variable_count = 1;
 
     token_list_t*t=0;
     classinfo_list_t*mlist=0;
@@ -688,7 +727,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     char*package=0;
 
     if(!(flags&FLAG_PUBLIC) && !state->package) {
-        access = ACCESS_PRIVATE; package = current_filename;
+        access = ACCESS_PRIVATE; package = strdup(current_filename_short);
     } else if(!(flags&FLAG_PUBLIC) && state->package) {
         access = ACCESS_PACKAGEINTERNAL; package = state->package;
     } else if(state->package) {
@@ -698,6 +737,10 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     }
 
     if(as3_pass==1) {
+        state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
+        state->method->variable_count = 1;
+        dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
+
         if(registry_findclass(package, classname)) {
             syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
         }
@@ -707,6 +750,8 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     }
     
     if(as3_pass == 2) {
+        state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
+
         state->cls->info = registry_findclass(package, classname);
         parserassert((int)state->cls->info);
 
@@ -1276,7 +1321,7 @@ static classinfo_t* find_class(char*name)
     /* try global package */
     c = registry_findclass("", name);
     if(c) return c;
-   
+  
     /* try local "filename" package */
     c = registry_findclass(current_filename_short, name);
     if(c) return c;
@@ -1315,7 +1360,6 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
 
        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
     */
-    
     if(in && in->opcode == OPCODE_COERCE_A) {
         in = code_cutlast(in);
     }
@@ -1435,6 +1479,7 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
             c = code_append(c, write);
             c = code_append(c, r);
         } else {
+            code_free(r);r=0;
             temp = gettempvar();
             if(prefix) {
                 c = code_append(c, prefix);
@@ -1605,6 +1650,7 @@ PROGRAM_CODE: PACKAGE_DECLARATION
             | FUNCTION_DECLARATION
             | SLOT_DECLARATION
             | PACKAGE_INITCODE
+            | T_IDENTIFIER "::" T_IDENTIFIER '{' PROGRAM_CODE_LIST '}' // conditional compilation
             | ';'
 
 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
@@ -1616,6 +1662,7 @@ INPACKAGE_CODE: INTERFACE_DECLARATION
               | FUNCTION_DECLARATION
               | SLOT_DECLARATION
               | PACKAGE_INITCODE
+              | T_IDENTIFIER "::" T_IDENTIFIER '{' INPACKAGE_CODE_LIST '}' // conditional compilation
               | ';'
 
 MAYBECODE: CODE {$$=$1;}
@@ -1691,6 +1738,7 @@ ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
             $$ = converttype($$, $3.t, $2);
             $$ = abc_setlocal($$, index);
         } else {
+            code_free($3.c);
             $$ = defaultvalue(0, $2);
             $$ = abc_setlocal($$, index);
         }
@@ -1700,6 +1748,7 @@ ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
             $$ = abc_coerce_a($$);
             $$ = abc_setlocal($$, index);
         } else {
+            code_free($3.c);
             $$ = code_new();
         }
     }
@@ -2049,7 +2098,13 @@ PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2
 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} 
                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
 
-IMPORT : "import" QNAME {
+IMPORT : "import" PACKAGEANDCLASS {
+       PASS1 
+       if(!registry_findclass($2->package, $2->name)) {
+           as3_schedule_class($2->package, $2->name);
+       }
+
+       PASS2
        classinfo_t*c = $2;
        if(!c) 
             syntaxerror("Couldn't import class\n");
@@ -2058,6 +2113,12 @@ IMPORT : "import" QNAME {
        $$=0;
 }
 IMPORT : "import" PACKAGE '.' '*' {
+       PASS1 
+       if(strncmp("flash.", $2, 6)) {
+           as3_schedule_package($2);
+       }
+
+       PASS2
        NEW(import_t,i);
        i->package = $2;
        state_has_imports();
@@ -2083,13 +2144,13 @@ MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
          | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
 
 EXTENDS : {$$=registry_getobjectclass();}
-EXTENDS : KW_EXTENDS QNAME {$$=$2;}
+EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
 
 EXTENDS_LIST : {PASS12 $$=list_new();}
-EXTENDS_LIST : KW_EXTENDS QNAME_LIST {PASS12 $$=$2;}
+EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
 
 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
-IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {PASS12 $$=$2;}
+IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
 
 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
                               EXTENDS IMPLEMENTS_LIST 
@@ -2135,6 +2196,7 @@ IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LI
     }
     startfunction(0,$1,$3,$4,&$6,$8);
     endfunction(0,$1,$3,$4,&$6,$8, 0);
+    list_deep_free($6.list);
 }
 
 /* ------------ classes and interfaces (body, slots ) ------- */
@@ -2207,7 +2269,7 @@ 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);}
+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);}
@@ -2274,37 +2336,15 @@ GETSET : "get" {$$=$1;}
 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
                       MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}' 
 {
-    PASS1 old_state();
+    PASS1 old_state();list_deep_free($6.list);
     PASS2
     if(!state->method->info) syntaxerror("internal error");
-    code_t*c = 0;
-    if(state->method->late_binding) {
-        c = abc_getlocal_0(c);
-        c = abc_pushscope(c);
-    }
-    /*if(state->method->innerfunctions) {
-        c = abc_newactivation(c);
-        c = abc_pushscope(c);
-    }*/
-    if(state->method->is_constructor && !state->method->has_super) {
-        // call default constructor
-        c = abc_getlocal_0(c);
-        c = abc_constructsuper(c, 0);
-    }
-    methodstate_list_t*l = state->method->innerfunctions;
-    while(l) {
-        parserassert(l->methodstate->abc);
-        c = abc_newfunction(c, l->methodstate->abc);
-        c = abc_setlocal(c, l->methodstate->var_index);
-        free(l->methodstate);l->methodstate=0;
-        l = l->next;
-    }
-    list_free(state->method->innerfunctions);
-    state->method->innerfunctions = 0;
-
+    
+    code_t*c = method_header();
     c = wrap_function(c, 0, $11);
 
     endfunction(0,$1,$3,$4,&$6,$8,c);
+    list_deep_free($6.list);
     $$=0;
 }
 
@@ -2313,16 +2353,17 @@ MAYBE_IDENTIFIER: {PASS12 $$=0;}
 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE 
                '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
 {
-    PASS1 old_state();
+    PASS1 old_state();list_deep_free($4.list);
     PASS2
     memberinfo_t*f = state->method->info;
     if(!f) syntaxerror("internal error");
-
-    code_t*c = 0;
+    
+    code_t*c = method_header();
     c = wrap_function(c, 0, $9);
 
     int index = state->method->var_index;
     endfunction(0,0,0,$2,&$4,$6,c);
+    list_deep_free($4.list);
     
     $$.c = abc_getlocal(0, index);
     $$.t = TYPE_FUNCTION(f);
@@ -2340,20 +2381,24 @@ CLASS: T_IDENTIFIER {
 }
 
 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
-    PASS1 $$=0;
+    PASS1 static classinfo_t c;
+          memset(&c, 0, sizeof(c));
+          c.package = $1;
+          c.name = $3;
+          $$=&c;
     PASS2
     $$ = registry_findclass($1, $3);
     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
     free($1);$1=0;
 }
 
-QNAME: PACKAGEANDCLASS
-     | CLASS
+CLASS_SPEC: PACKAGEANDCLASS
+          | CLASS
 
-QNAME_LIST : QNAME {PASS12 $$=list_new();list_append($$, $1);}
-QNAME_LIST : QNAME_LIST ',' QNAME {PASS12 $$=$1;list_append($$,$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 : QNAME      {$$=$1;}
+TYPE : CLASS_SPEC {$$=$1;}
      | '*'        {$$=registry_getanytype();}
      | "void"     {$$=registry_getanytype();}
     /*
@@ -2381,35 +2426,38 @@ EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
                                                   $$.len= $1.len+1;
                                                   $$.cc = code_append($1.cc, $3.c);
                                                   }
-
-/*NEW : "new" E {
-    $$ = $2;
-    if($2.c->opcode == OPCODE_CALL)
-        $2.c->opcode = OPCODE_CONSTRUCT;
-    else if($2.c->opcode == OPCODE_CALLPROPERTY)
-        $2.c->opcode = OPCODE_CONSTRUCTPROP;
-    else
-        as3_error("invalid argument to 'new'");
-}*/
-
-NEW : "new" CLASS MAYBE_PARAM_VALUES {
-    MULTINAME(m, $2);
-    $$.c = code_new();
-
-    if($2->slot) {
-        $$.c = abc_getglobalscope($$.c);
-        $$.c = abc_getslot($$.c, $2->slot);
+               
+XX : %prec new2
+NEW : "new" E XX MAYBE_PARAM_VALUES {
+    $$.c = $2.c;
+    if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
+    
+    code_t*paramcode = $4.cc;
+    if($$.c->opcode == OPCODE_GETPROPERTY) {
+        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);
+        multiname_destroy(name);
+    } else if($$.c->opcode == OPCODE_GETSLOT) {
+        int slot = (int)(ptroff_t)$$.c->data[0];
+        trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
+        multiname_t*name = t->name;
+        $$.c = code_cutlast($$.c);
+        $$.c = code_append($$.c, paramcode);
+        $$.c = abc_constructprop2($$.c, name, $4.len);
     } else {
-        $$.c = abc_findpropstrict2($$.c, &m);
+        $$.c = code_append($$.c, paramcode);
+        $$.c = abc_construct($$.c, $4.len);
+    }
+   
+    $$.t = TYPE_ANY;
+    if(TYPE_IS_CLASS($2.t) && $2.t->cls) {
+        $$.t = $2.t->cls;
+    } else {
+        $$.c = abc_coerce_a($$.c);
+        $$.t = TYPE_ANY;
     }
-
-    $$.c = code_append($$.c, $3.cc);
-
-    if($2->slot)
-        $$.c = abc_construct($$.c, $3.len);
-    else
-        $$.c = abc_constructprop2($$.c, &m, $3.len);
-    $$.t = $2;
 }
 
 /* TODO: use abc_call (for calling local variables),
@@ -2454,8 +2502,6 @@ FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
         $$.c = abc_call($$.c, $3.len);
     }
    
-    memberinfo_t*f = 0;
-   
     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
         $$.t = $1.t->function->return_type;
     } else {
@@ -2576,7 +2622,7 @@ CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
                     $$.t = TYPE_FLOAT;
                    }
-CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
+CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
                      $$.t = TYPE_STRING;
                     }
 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);