fixed dynamicobj test case
[swftools.git] / lib / as3 / parser.y
index ffc9960..0b35fc9 100644 (file)
      
 %{
 
-static int yyerror(char*s)
+static int a3_error(char*s)
 {
    syntaxerror("%s", s); 
    return 0; //make gcc happy
 }
 
+
 static char* concat2(const char* t1, const char* t2)
 {
     int l1 = strlen(t1);
@@ -301,6 +302,8 @@ typedef struct _methodstate {
     char is_constructor;
     char has_super;
     char is_global;
+    char inner;
+    int variable_count;
     abc_exception_list_t*exceptions;
 } methodstate_t;
 
@@ -324,8 +327,6 @@ typedef struct _state {
 typedef struct _global {
     abc_file_t*file;
     abc_script_t*init;
-
-    int variable_count;
 } global_t;
 
 static global_t*global = 0;
@@ -445,14 +446,11 @@ void initialize_parser()
     global = rfx_calloc(sizeof(global_t));
     global->file = abc_file_new();
     global->file->flags &= ~ABCFILE_LAZY;
-    global->variable_count = 1;
+    
     global->init = abc_initscript(global->file);
     code_t*c = global->init->method->body->code;
     c = abc_getlocal_0(c);
     c = abc_pushscope(c);
-    /*c = abc_findpropstrict(c, "[package]::trace");
-    c = abc_pushstring(c, "[entering global init function]");
-    c = abc_callpropvoid(c, "[package]::trace", 1);*/
     global->init->method->body->code = c;
 }
 
@@ -460,9 +458,11 @@ void initialize_file(char*filename)
 {
     new_state();
     state->package = filename;
-    // needed for state->method->late_binding:
+    
     state->method = rfx_calloc(sizeof(methodstate_t));
+    state->method->variable_count = 1;
 }
+
 void finish_file()
 {
     if(!state || state->level!=1) {
@@ -548,13 +548,13 @@ code_t*defaultvalue(code_t*c, classinfo_t*type);
 static int new_variable(char*name, classinfo_t*type, char init)
 {
     NEW(variable_t, v);
-    v->index = global->variable_count;
+    v->index = state->method->variable_count;
     v->type = type;
     v->init = init;
     
     dict_put(state->vars, name, v);
 
-    return global->variable_count++;
+    return state->method->variable_count++;
 }
 #define TEMPVARNAME "__as3_temp__"
 static int gettempvar()
@@ -627,7 +627,6 @@ static void startpackage(char*name)
     new_state();
     /*printf("entering package \"%s\"\n", name);*/
     state->package = strdup(name);
-    global->variable_count = 1;
 }
 static void endpackage()
 {
@@ -652,9 +651,9 @@ 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));
     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;
@@ -929,6 +928,53 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
     return minfo;
 }
 
+static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
+{
+    parserassert(state->method && state->method->info);
+    memberinfo_t*parent_method = state->method->info;
+
+    if(as3_pass==1) {
+        // not valid yet
+        params = 0;
+        return_type = 0;
+    }
+
+    new_state();
+    state->method = rfx_calloc(sizeof(methodstate_t));
+    state->method->inner = 1;
+    state->method->variable_count = 0;
+   
+    memberinfo_t*minfo = 0;
+
+    /* TODO: we need some better way to pass things from pass1 to pass2 */
+    char myname[200];
+    sprintf(myname, "as3-innerfunction-%d-%d", current_line, current_column);
+
+    if(as3_pass == 1) {
+        minfo = rfx_calloc(sizeof(memberinfo_t));
+        minfo->name = name;
+        if(!parent_method->subfunctions) 
+            parent_method->subfunctions = dict_new();
+        if(name)
+            dict_put(parent_method->subfunctions, name, minfo);
+        dict_put(parent_method->subfunctions, myname, minfo);
+    }
+
+    if(as3_pass == 2) {
+        minfo = dict_lookup(parent_method->subfunctions, myname);
+        parserassert(minfo);
+
+        minfo->return_type = return_type;
+
+        new_variable("FIXME", 0, 0); //FIXME: is local_0 "this"?
+        param_list_t*p=0;
+        for(p=params->list;p;p=p->next) {
+            new_variable(p->param->name, p->param->type, 0);
+        }
+    }
+    state->method->info = minfo;
+}
+
 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type)
 {
@@ -938,6 +984,7 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
     new_state();
     state->method = rfx_calloc(sizeof(methodstate_t));
     state->method->has_super = 0;
+    state->method->variable_count = 0;
 
     if(state->cls) {
         state->method->is_constructor = !strcmp(state->cls->info->name,name);
@@ -961,7 +1008,6 @@ static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*n
         else            state->method->info = registry_findmember(state->cls->info, name, 0);
         state->method->info->return_type = return_type;
 
-        global->variable_count = 0;
         /* state->vars is initialized by state_new */
         if(!state->method->is_global)
             new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
@@ -974,19 +1020,21 @@ 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,
+static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type, code_t*body)
 {
     if(as3_pass==1) {
         old_state();
-        return;
+        return 0;
     }
 
     abc_method_t*f = 0;
 
     multiname_t*type2 = sig2mname(return_type);
     int slot = 0;
-    if(state->method->is_constructor) {
+    if(state->method->inner) {
+        f = abc_method_new(global->file, type2, 1);
+    } else if(state->method->is_constructor) {
         f = abc_class_getconstructor(state->cls->abc, type2);
     } else if(!state->method->is_global) {
         namespace_t mname_ns = flags2namespace(flags, "");
@@ -1039,10 +1087,9 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
     }
        
     old_state();
+    return f;
 }
 
-
-
 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
 {
     return 1; // FIXME
@@ -2008,8 +2055,8 @@ MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
 EXTENDS : {$$=registry_getobjectclass();}
 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
 
-EXTENDS_LIST : {$$=list_new();}
-EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
+EXTENDS_LIST : {PASS12 $$=list_new();}
+EXTENDS_LIST : KW_EXTENDS QNAME_LIST {PASS12 $$=$2;}
 
 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {PASS12 $$=$2;}
@@ -2189,6 +2236,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P
 {
     PASS1 old_state();
     PASS2
+    if(!state->method->info) syntaxerror("internal error");
     code_t*c = 0;
     if(state->method->late_binding) {
         c = abc_getlocal_0(c);
@@ -2199,6 +2247,7 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P
         c = abc_getlocal_0(c);
         c = abc_constructsuper(c, 0);
     }
+
     c = wrap_function(c, 0, $11);
 
     endfunction(0,$1,$3,$4,&$6,$8,c);
@@ -2206,10 +2255,22 @@ FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_P
 }
 
 MAYBE_IDENTIFIER: T_IDENTIFIER
-MAYBE_IDENTIFIER: {$$=0;}
-INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
+MAYBE_IDENTIFIER: {PASS12 $$=0;}
+INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE 
+               '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
 {
-    syntaxerror("nested functions not supported yet");
+    PASS1 old_state();
+    PASS2
+    memberinfo_t*f = state->method->info;
+    if(!f) syntaxerror("internal error");
+
+    code_t*c = 0;
+    c = wrap_function(c, 0, $9);
+
+    abc_method_t*abc = endfunction(0,0,0,$2,&$4,$6,c);
+    
+    $$.c = abc_newfunction(0, abc);
+    $$.t = TYPE_FUNCTION(f);
 }