implemented url resolving in namespaces
[swftools.git] / lib / as3 / parser.y
index 5670793..1d18b74 100644 (file)
@@ -356,6 +356,7 @@ typedef struct _state {
     dict_t*imports;
     namespace_list_t*active_namespaces;
     namespace_decl_list_t*new_namespaces;
+    dict_t*namespace2url;
     char has_own_imports;
     char new_vars; // e.g. transition between two functions
   
@@ -363,6 +364,8 @@ typedef struct _state {
     methodstate_t*method;
 
     char*exception_name;
+
+    int switch_var;
     
     dict_t*vars;
 } state_t;
@@ -443,6 +446,7 @@ static void new_state()
     state->vars = dict_new(); 
     state->old = oldstate;
     state->new_vars = 0;
+    state->namespace2url = 0;
 }
 static void state_has_imports()
 {
@@ -500,6 +504,8 @@ static void old_state()
         tokenizer_unregister_namespace(nl->namespace_decl->name);
         nl = nl->next;
     }
+    if(leaving->namespace2url)
+        dict_destroy(leaving->namespace2url);
     
     if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
         free(leaving->method);
@@ -649,6 +655,11 @@ static char variable_exists(char*name)
 }
 code_t*defaultvalue(code_t*c, classinfo_t*type);
 
+static int alloc_local()
+{
+    return state->method->variable_count++;
+}
+
 static variable_t* new_variable2(const char*name, classinfo_t*type, char init, char maybeslot)
 {
     if(maybeslot) {
@@ -658,7 +669,7 @@ static variable_t* new_variable2(const char*name, classinfo_t*type, char init, c
     }
 
     NEW(variable_t, v);
-    v->index = state->method->variable_count++;
+    v->index = alloc_local();
     v->type = type;
     v->init = init;
  
@@ -837,7 +848,14 @@ static namespace_t modifiers2access(modifiers_t*mod)
         if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
             syntaxerror("invalid combination of access levels and namespaces");
         ns.access = ACCESS_NAMESPACE;
-        ns.name = mod->ns;
+        state_t*s = state;
+        const char*url = (const char*)dict_lookup(state->namespace2url, mod->ns);
+        if(!url) {
+            /* shouldn't happen- the tokenizer only reports something as a namespace
+               if it was already registered */
+            syntaxerror("unknown namespace: %s", mod->ns);
+        }
+        ns.name = url;
     } else if(mod->flags&FLAG_PUBLIC)  {
         if(mod->flags&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
             syntaxerror("invalid combination of access levels");
@@ -1367,8 +1385,6 @@ static void startfunction(modifiers_t*mod, enum yytokentype getset, char*name,
 static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*name,
                           params_t*params, classinfo_t*return_type, code_t*body)
 {
-    int flags = mod?mod->flags:0;
-
     if(as3_pass==1) {
         // store inner methods in variables
         function_initvars(state->method, 0, 0, 0);
@@ -1441,10 +1457,10 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
         } else if(state->method->is_constructor) {
             f = abc_class_getconstructor(state->cls->abc, type2);
         } else if(!state->method->is_global) {
-            namespace_t mname_ns = {state->method->info->access, ""};
+            namespace_t mname_ns = modifiers2access(mod);
             multiname_t mname = {QNAME, &mname_ns, 0, name};
 
-            if(flags&FLAG_STATIC)
+            if(mod->flags&FLAG_STATIC)
                 f = abc_class_staticmethod(state->cls->abc, type2, &mname);
             else
                 f = abc_class_method(state->cls->abc, type2, &mname);
@@ -1460,7 +1476,7 @@ static abc_method_t* endfunction(modifiers_t*mod, enum yytokentype getset, char*
         //flash doesn't seem to allow us to access function slots
         //state->method->info->slot = slot;
 
-        if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
+        if(mod->flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
         if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
         if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
         if(params->varargs) f->flags |= METHOD_NEED_REST;
@@ -1934,6 +1950,18 @@ char is_break_or_jump(code_t*c)
     return 0;
 }
 
+void register_namespace(const char*name, const char*url)
+{
+    NEW(namespace_decl_t,n);
+    n->name = name;
+    n->url = url;
+    if(!state->namespace2url) {
+        state->namespace2url = dict_new();
+    }
+    dict_put(state->namespace2url, name, url);
+    list_append(state->new_namespaces, n);
+    tokenizer_register_namespace(name);
+}
 
 #define IS_FINALLY_TARGET(op) \
         ((op) == OPCODE___CONTINUE__ || \
@@ -2376,7 +2404,7 @@ CASE_LIST: CASE             {$$=$1;}
 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
 
 CASE: "case" E ':' MAYBECODE {
-    $$ = abc_dup(0);
+    $$ = abc_getlocal(0, state->switch_var);
     $$ = code_append($$, $2.c);
     code_t*j = $$ = abc_ifne($$, 0);
     $$ = code_append($$, $4);
@@ -2389,10 +2417,12 @@ CASE: "case" E ':' MAYBECODE {
 DEFAULT: "default" ':' MAYBECODE {
     $$ = $3;
 }
-SWITCH : T_SWITCH '(' {PASS12 new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
+SWITCH : T_SWITCH '(' {PASS12 new_state();state->switch_var=alloc_local();} E ')' '{' MAYBE_CASE_LIST '}' {
     $$=$4.c;
+    $$ = abc_setlocal($$, state->switch_var);
     $$ = code_append($$, $7);
-    code_t*out = $$ = abc_pop($$);
+
+    code_t*out = $$ = abc_kill($$, state->switch_var);
     breakjumpsto($$, $1, out);
     
     code_t*c = $$,*lastblock=0;
@@ -2546,9 +2576,7 @@ THROW : "throw" %prec prec_none {
 WITH_HEAD : "with" '(' EXPRESSION ')' {
      new_state();
      if(state->method->has_exceptions) {
-         char var[32];
-         sprintf(var, "#with#_%d", as3_tokencount);
-         int v = new_variable(var,$3.t,0,0);
+         int v = alloc_local();
          state->method->scope_code = abc_getlocal(state->method->scope_code, v);
          state->method->scope_code = abc_pushwith(state->method->scope_code);
          $$.number = v;
@@ -2574,6 +2602,7 @@ WITH : WITH_HEAD CODEBLOCK {
 
 X_IDENTIFIER: T_IDENTIFIER
             | "package" {PASS12 $$="package";}
+            | T_NAMESPACE {PASS12 $$=$1;}
 
 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
 PACKAGE: X_IDENTIFIER             {PASS12 $$=strdup($1);}
@@ -2904,7 +2933,7 @@ INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
 
 /* ------------- package + class ids --------------- */
 
-CLASS: T_IDENTIFIER {
+CLASS: X_IDENTIFIER {
     PASS1 NEW(unresolvedinfo_t,c);
           memset(c, 0, sizeof(*c));
           c->kind = INFOTYPE_UNRESOLVED;
@@ -2923,7 +2952,7 @@ CLASS: T_IDENTIFIER {
     $$ = (classinfo_t*)s;
 }
 
-PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
+PACKAGEANDCLASS : PACKAGE '.' X_IDENTIFIER {
     PASS1 NEW(unresolvedinfo_t,c);
           memset(c, 0, sizeof(*c));
           c->kind = INFOTYPE_UNRESOLVED;
@@ -3793,7 +3822,7 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER {
     PASS12
     NEW(namespace_decl_t,n);
     n->name = $2;
-    n->url = 0;
+    n->url = $2;
     $$=n;
 }
 NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_IDENTIFIER {
@@ -3812,20 +3841,23 @@ NAMESPACE_ID : "namespace" T_IDENTIFIER '=' T_STRING {
 }
 NAMESPACE_DECLARATION : MAYBE_MODIFIERS NAMESPACE_ID {
     PASS12
-    list_append(state->new_namespaces, $2);
-    tokenizer_register_namespace($2->name);
+    register_namespace($2->name, $2->url);
+
+    namespace_t access = modifiers2access(&$1);
+    varinfo_t* var = varinfo_register_global(access.access, state->package, $2->name);
+    var->type = TYPE_NAMESPACE;
+    namespace_t ns;
+    ns.access = ACCESS_NAMESPACE;
+    ns.name = $2->url;
+    var->value = constant_new_namespace(&ns);
+
     $$=0;
 }
 
 USE_NAMESPACE : "use" "namespace" CLASS_SPEC {
     PASS12
-    NEW(namespace_decl_t,n);
-    n->name = $3->name;
-    n->url = 0;
-    /* FIXME: for pass2, we should now try to figure out what the URL of 
-              this thing is */
-    list_append(state->new_namespaces, n);
-    tokenizer_register_namespace($3->name);
+    char*url = 0;
+    register_namespace($3->name, url);
     $$=0;
 }