%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_NATIVE
%token<token> KW_FUNCTION "function"
%token<token> KW_UNDEFINED "undefined"
-%token<token> KW_FOR "for"
+%token<token> KW_CONTINUE "continue"
%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"
%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 <value> MAYBEEXPRESSION
%type <value> E DELETE
%type <value> CONSTANT
-%type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
+%type <code> FOR IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
%type <token> USE_NAMESPACE
%type <code> FOR_INIT
%type <token> IMPORT
//%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"
+
%{
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))
return c;
}
+void check_code_for_break(code_t*c)
+{
+ while(c) {
+ if(c->opcode == OPCODE___BREAK__) {
+ char*name = string_cstr(c->data[0]);
+ syntaxerror("Unresolved \"break %s\"", name);
+ }
+ if(c->opcode == OPCODE___CONTINUE__) {
+ char*name = string_cstr(c->data[0]);
+ syntaxerror("Unresolved \"continue %s\"", name);
+ }
+ c=c->prev;
+ }
+}
+
static void check_constant_against_type(classinfo_t*t, constant_t*c)
{
syntaxerror("non-optional parameter not allowed after optional parameters");
}
}
- f->body->code = body;
+ check_code_for_break(body);
+
+ if(f->body)
+ f->body->code = body;
+ else //interface
+ if(body)
+ syntaxerror("interface methods can't have a method body");
old_state();
}
return 1; // FIXME
}
-void breakjumpsto(code_t*c, code_t*jump)
+void breakjumpsto(code_t*c, char*name, code_t*jump)
{
- while(c->prev)
- c=c->prev;
while(c) {
if(c->opcode == OPCODE___BREAK__) {
- c->opcode = OPCODE_JUMP;
- c->branch = jump;
+ string_t*name2 = c->data[0];
+ if(!name2->len || !strncmp(name2->str, name, name2->len)) {
+ c->opcode = OPCODE_JUMP;
+ c->branch = jump;
+ }
}
- c = c->next;
+ c=c->prev;
+ }
+}
+void continuejumpsto(code_t*c, char*name, code_t*jump)
+{
+ while(c) {
+ if(c->opcode == OPCODE___CONTINUE__) {
+ string_t*name2 = c->data[0];
+ if(!name2->len || !strncmp(name2->str, name, name2->len)) {
+ c->opcode = OPCODE_JUMP;
+ c->branch = jump;
+ }
+ }
+ c = c->prev;
}
}
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) {
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++;
/* ------------ 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);}
-CODE: CODEPIECE {$$=$1;}
+CODE: CODE CODEPIECE {
+ $$=code_append($1,$2);
+}
+CODE: CODEPIECE {
+ $$=$1;
+}
CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
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}
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;}
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);
FOR_INIT : VARIABLE_DECLARATION
FOR_INIT : VOIDEXPRESSION
-FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
+FOR : T_FOR '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
$$ = code_new();
$$ = code_append($$, $4);
code_t*loopstart = $$ = abc_label($$);
$$ = code_append($$, $6.c);
code_t*myif = $$ = abc_iffalse($$, 0);
$$ = code_append($$, $10);
+ code_t*cont = $$ = abc_nop($$);
$$ = code_append($$, $8);
$$ = abc_jump($$, loopstart);
code_t*out = $$ = abc_nop($$);
- breakjumpsto($$, out);
+ breakjumpsto($$, $1, out);
+ continuejumpsto($$, $1, cont);
myif->branch = out;
$$ = killvars($$);old_state();
}
-WHILE : "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($$, $6);
- myjmp->branch = $$ = abc_nop($$);
+ code_t*cont = $$ = abc_nop($$);
+ myjmp->branch = cont;
$$ = code_append($$, $4.c);
$$ = abc_iftrue($$, loopstart);
code_t*out = $$ = abc_nop($$);
- breakjumpsto($$, out);
+ breakjumpsto($$, $1, out);
+ continuejumpsto($$, $1, cont);
- $$ = killvars($$);old_state();
+ $$ = killvars($$);
+ old_state();
}
-BREAK : "break" {
- $$ = abc___break__(0);
+DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
+ $$ = code_new();
+ code_t*loopstart = $$ = abc_label($$);
+ $$ = code_append($$, $3);
+ code_t*cont = $$ = abc_nop($$);
+ $$ = code_append($$, $6.c);
+ $$ = abc_iftrue($$, loopstart);
+ code_t*out = $$ = abc_nop($$);
+ breakjumpsto($$, $1, out);
+ continuejumpsto($$, $1, cont);
+ $$ = killvars($$);
+ old_state();
+}
+
+BREAK : "break" %prec prec_none {
+ $$ = abc___break__(0, "");
+}
+BREAK : "break" T_IDENTIFIER {
+ $$ = abc___break__(0, $2);
+}
+CONTINUE : "continue" %prec prec_none {
+ $$ = abc___continue__(0, "");
+}
+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 ---------------- */
TYPE : QNAME {$$=$1;}
| '*' {$$=registry_getanytype();}
+ | "void" {$$=registry_getanytype();}
/*
| "String" {$$=registry_getstringclass();}
| "int" {$$=registry_getintclass();}
$$.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)) {