fixed vertical alignment bug
[swftools.git] / lib / as3 / parser.y
index 32007bc..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 <token> VARCONST
 %type <code> CODE
 %type <code> CODEPIECE CODE_STATEMENT
-%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
+%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
+%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 <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 <code> IMPORT
@@ -289,6 +295,7 @@ typedef struct _methodstate {
     char is_constructor;
     char has_super;
     char is_global;
+    abc_exception_list_t*exceptions;
 } methodstate_t;
 
 typedef struct _state {
@@ -302,6 +309,8 @@ typedef struct _state {
   
     classstate_t*cls;   
     methodstate_t*method;
+
+    char*exception_name;
     
     dict_t*vars;
 } state_t;
@@ -360,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);
@@ -425,9 +429,11 @@ 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;
@@ -491,9 +497,6 @@ 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);
@@ -822,13 +825,7 @@ static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*na
     memberinfo_t*minfo = 0;
     if(!state->cls) {
         //package method
-        minfo = rfx_calloc(sizeof(memberinfo_t));
-        classinfo_t*c = classinfo_register(flags2access(flags), state->package, name, 0);
-        c->flags |= FLAG_METHOD;
-        c->function = minfo;
-        minfo->kind = MEMBER_METHOD;
-        minfo->name = name;
-        minfo->flags = FLAG_STATIC;
+        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
@@ -969,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();
@@ -1099,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;
     }
@@ -1114,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)
@@ -1296,6 +1299,7 @@ PROGRAM_CODE: PACKAGE_DECLARATION
             | FUNCTION_DECLARATION
             | SLOT_DECLARATION
             | PACKAGE_INITCODE
+            | ';'
 
 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
 INPACKAGE_CODE_LIST: INPACKAGE_CODE 
@@ -1306,6 +1310,7 @@ INPACKAGE_CODE: INTERFACE_DECLARATION
               | FUNCTION_DECLARATION
               | SLOT_DECLARATION
               | PACKAGE_INITCODE
+              | ';'
 
 MAYBECODE: CODE {$$=$1;}
 MAYBECODE: {$$=code_new();}
@@ -1322,18 +1327,17 @@ 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: PACKAGE_DECLARATION
-//CODEPIECE: CLASS_DECLARATION
-//CODEPIECE: FUNCTION_DECLARATION
-//CODEPIECE: INTERFACE_DECLARATION
+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;}
@@ -1591,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
@@ -1695,42 +1772,53 @@ 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;
     }