implemented switch
[swftools.git] / lib / as3 / parser.y
index 6e1c2be..8c99eca 100644 (file)
 %token<number_uint> T_SHORT
 %token<number_float> T_FLOAT
 
+%token<id> T_FOR "for"
+%token<id> T_WHILE "while"
+%token<id> T_DO "do"
+%token<id> T_SWITCH "switch"
+
 %token<token> KW_IMPLEMENTS
 %token<token> KW_NAMESPACE "namespace"
 %token<token> KW_PACKAGE "package"
 %token<token> KW_FUNCTION "function"
 %token<token> KW_UNDEFINED "undefined"
 %token<token> KW_CONTINUE "continue"
-%token<token> KW_FOR "for"
 %token<token> KW_CLASS "class"
 %token<token> KW_CONST "const"
+%token<token> KW_CATCH "catch"
+%token<token> KW_CASE "case"
 %token<token> KW_SET "set"
 %token<token> KW_VOID "void"
 %token<token> KW_STATIC
 %token<token> KW_INTERFACE "interface"
 %token<token> KW_NULL "null"
 %token<token> KW_VAR "var"
-%token<token> KW_DYNAMIC
+%token<token> KW_DYNAMIC "dynamic"
 %token<token> KW_OVERRIDE
 %token<token> KW_FINAL
 %token<token> KW_GET "get"
+%token<token> KW_TRY "try"
 %token<token> KW_SUPER "super"
 %token<token> KW_EXTENDS
 %token<token> KW_FALSE "false"
 %token<token> KW_BOOLEAN "Boolean"
 %token<token> KW_UINT "uint"
 %token<token> KW_INT "int"
-%token<token> KW_WHILE "while"
 %token<token> KW_NUMBER "Number"
 %token<token> KW_STRING "String"
+%token<token> KW_DEFAULT "default"
 %token<token> KW_DELETE "delete"
 %token<token> KW_IF "if"
 %token<token> KW_ELSE  "else"
 %token<token> KW_BREAK   "break"
 %token<token> KW_IS "is"
 %token<token> KW_AS "as"
-%token<token> KW_DO "do"
 
 %token<token> T_EQEQ "=="
 %token<token> T_EQEQEQ "==="
 %token<token> T_USHR ">>>"
 %token<token> T_SHR ">>"
 
-%type <id> X_IDENTIFIER PACKAGE MAYBELABEL
+%type <id> X_IDENTIFIER PACKAGE
 %type <token> VARCONST
 %type <code> CODE
 %type <code> CODEPIECE
-%type <code> CODEBLOCK MAYBECODE
+%type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
 %type <token> PACKAGE_DECLARATION
 %type <token> FUNCTION_DECLARATION
 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
 //%type <token> T_IDENTIFIER
 %type <token> MODIFIER
 %type <value> FUNCTIONCALL
-%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
+%type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
 
 // precedence: from low to high
 
 %left '/' '*' '%'
 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
 %left "--" "++" 
+%nonassoc below_curly
 %left '[' ']' '{' "new" '.' ".." "::"
 %nonassoc T_IDENTIFIER
 %left below_else
 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
 %nonassoc "false" "true" "null" "undefined" "super"
 
+
      
 %{
 
@@ -484,7 +492,7 @@ static void startclass(int flags, char*classname, classinfo_t*extends, classinfo
     printf("\n");
     */
 
-    if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
+    if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
         syntaxerror("invalid modifier(s)");
 
     if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
@@ -876,7 +884,12 @@ static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*nam
         }
     }
     check_code_for_break(body);
-    f->body->code = body;
+
+    if(f->body)
+        f->body->code = body;
+    else //interface
+        if(body)
+            syntaxerror("interface methods can't have a method body");
         
     old_state();
 }
@@ -939,19 +952,13 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
         return abc_coerce2(c, &m);
     }
     
-    if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
-        return abc_coerce2(c, &m);
-    }
-    if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
-        return abc_coerce2(c, &m);
-    }
-    /* these are subject to overflow */
-    if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
-        return abc_coerce2(c, &m);
-    }
-    if(TYPE_IS_UINT(from) && TYPE_IS_INT(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
         return abc_coerce2(c, &m);
     }
+    //printf("%s.%s\n", from.package, from.name);
+    //printf("%s.%s\n", to.package, to.name);
 
     classinfo_t*supertype = from;
     while(supertype) {
@@ -962,7 +969,7 @@ code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
         int t=0;
         while(supertype->interfaces[t]) {
             if(supertype->interfaces[t]==to) {
-                // to type is one of from's interfaces
+                // target type is one of from's interfaces
                 return abc_coerce2(c, &m);
             }
             t++;
@@ -1190,10 +1197,14 @@ static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char r
 
 /* ------------ code blocks / statements ---------------- */
 
-PROGRAM: MAYBECODE
+PROGRAM: MAYBECODE {
+    /* todo: do something with this code if we're outside a function */
+    if($1)
+        warning("ignored code");
+}
 
-MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
-MAYBECODE:      {$$=code_new();}
+MAYBECODE: CODE {$$=$1;}
+MAYBECODE: {$$=code_new();}
 
 CODE: CODE CODEPIECE {
     $$=code_append($1,$2);
@@ -1213,6 +1224,7 @@ CODEPIECE: VOIDEXPRESSION        {$$=$1}
 CODEPIECE: FOR                   {$$=$1}
 CODEPIECE: WHILE                 {$$=$1}
 CODEPIECE: DO_WHILE              {$$=$1}
+CODEPIECE: SWITCH                {$$=$1}
 CODEPIECE: BREAK                 {$$=$1}
 CODEPIECE: CONTINUE              {$$=$1}
 CODEPIECE: RETURN                {$$=$1}
@@ -1220,7 +1232,8 @@ CODEPIECE: IF                    {$$=$1}
 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
 
-CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
+CODEBLOCK :  '{' CODE '}' {$$=$2;}
+CODEBLOCK :  '{' '}'      {$$=0;}
 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
 
@@ -1289,7 +1302,7 @@ MAYBEELSE:  %prec below_else {$$ = code_new();}
 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
 
-IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
+IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
     $$ = code_new();
     $$ = code_append($$, $4.c);
     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
@@ -1307,22 +1320,19 @@ IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
     $$ = killvars($$);old_state();
 }
 
-MAYBELABEL : T_IDENTIFIER ':' {$$=$1;}
-MAYBELABEL :                  {$$="";}
-
 FOR_INIT : {$$=code_new();}
 FOR_INIT : VARIABLE_DECLARATION
 FOR_INIT : VOIDEXPRESSION
 
-FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
+FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
     $$ = code_new();
-    $$ = code_append($$, $5);
+    $$ = code_append($$, $4);
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $7.c);
+    $$ = code_append($$, $6.c);
     code_t*myif = $$ = abc_iffalse($$, 0);
-    $$ = code_append($$, $11);
+    $$ = code_append($$, $10);
     code_t*cont = $$ = abc_nop($$);
-    $$ = code_append($$, $9);
+    $$ = code_append($$, $8);
     $$ = abc_jump($$, loopstart);
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
@@ -1332,29 +1342,30 @@ FOR : MAYBELABEL "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRES
     $$ = killvars($$);old_state();
 }
 
-WHILE : MAYBELABEL "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
+WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
     $$ = code_new();
 
     code_t*myjmp = $$ = abc_jump($$, 0);
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $7);
-    myjmp->branch = $$ = abc_nop($$);
-    $$ = code_append($$, $5.c);
+    $$ = code_append($$, $6);
+    code_t*cont = $$ = abc_nop($$);
+    myjmp->branch = cont;
+    $$ = code_append($$, $4.c);
     $$ = abc_iftrue($$, loopstart);
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
-    continuejumpsto($$, $1, loopstart);
+    continuejumpsto($$, $1, cont);
 
     $$ = killvars($$);
     old_state();
 }
 
-DO_WHILE : MAYBELABEL "do" {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
     $$ = code_new();
     code_t*loopstart = $$ = abc_label($$);
-    $$ = code_append($$, $4);
+    $$ = code_append($$, $3);
     code_t*cont = $$ = abc_nop($$);
-    $$ = code_append($$, $7.c);
+    $$ = code_append($$, $6.c);
     $$ = abc_iftrue($$, loopstart);
     code_t*out = $$ = abc_nop($$);
     breakjumpsto($$, $1, out);
@@ -1376,6 +1387,49 @@ CONTINUE : "continue" T_IDENTIFIER {
     $$ = abc___continue__(0, $2);
 }
 
+MAYBE_CASE_LIST :           {$$=0;}
+MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
+MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
+MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
+CASE_LIST: CASE             {$$=$1}
+CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
+
+CASE: "case" CONSTANT ':' MAYBECODE {
+    $$ = abc_dup(0);
+    $$ = code_append($$, $2.c);
+    code_t*j = $$ = abc_ifne($$, 0);
+    $$ = code_append($$, $4);
+    $$ = abc___continue__($$, "");
+    code_t*e = $$ = abc_nop($$);
+    j->branch = e;
+}
+DEFAULT: "default" ':' MAYBECODE {
+    $$ = $3;
+}
+SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
+    $$=$4.c;
+    $$ = code_append($$, $7);
+    code_t*out = $$ = abc_pop($$);
+    breakjumpsto($$, $1, out);
+    
+    code_t*c = $$,*lastblock=0;
+    while(c) {
+        if(c->opcode == OPCODE_IFNE) {
+            lastblock=c->next;
+        } else if(c->opcode == OPCODE___CONTINUE__) {
+            if(lastblock) {
+                c->opcode = OPCODE_JUMP;
+                c->branch = lastblock;
+            } else {
+                /* fall through end of switch */
+                c->opcode = OPCODE_NOP;
+            }
+        }
+        c=c->prev;
+    }
+    old_state();
+}
+
 /* ------------ packages and imports ---------------- */
 
 X_IDENTIFIER: T_IDENTIFIER
@@ -1617,6 +1671,7 @@ QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
 
 TYPE : QNAME      {$$=$1;}
      | '*'        {$$=registry_getanytype();}
+     | "void"     {$$=registry_getanytype();}
     /*
      |  "String"  {$$=registry_getstringclass();}
      |  "int"     {$$=registry_getintclass();}
@@ -2031,6 +2086,37 @@ E : '[' MAYBE_EXPRESSION_LIST ']' {
     $$.t = registry_getarrayclass();
 }
 
+MAYBE_EXPRPAIR_LIST : {$$=0;}
+MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
+
+EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+    typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $1;
+    typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $3;
+    $$ = 0;
+    list_append($$, t1);
+    list_append($$, t2);
+}
+EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+    $$=$1;
+    typedcode_t*t1 = malloc(sizeof(typedcode_t));*t1 = $3;
+    typedcode_t*t2 = malloc(sizeof(typedcode_t));*t2 = $5;
+    list_append($$, t1);
+    list_append($$, t2);
+}
+//MAYBECOMMA: ','
+//MAYBECOMMA:
+
+E : '{' MAYBE_EXPRPAIR_LIST '}' {
+    $$.c = code_new();
+    typedcode_list_t*l = 0;
+    int len = 0;
+    for(l=$2;l;l=l->next) {
+        $$.c = code_append($$.c, l->typedcode->c);len++;
+    }
+    $$.c = abc_newobject($$.c, len/2);
+    $$.t = registry_getobjectclass();
+}
+
 E : E "*=" E { 
                code_t*c = $3.c;
                if(BOTH_INT($1,$3)) {