+X_IDENTIFIER: T_IDENTIFIER
+ | "package" {PASS12 $$="package";}
+
+PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
+PACKAGE: X_IDENTIFIER {PASS12 $$=strdup($1);}
+
+PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
+ MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
+PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");}
+ MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
+
+IMPORT : "import" QNAME {
+ classinfo_t*c = $2;
+ if(!c)
+ syntaxerror("Couldn't import class\n");
+ state_has_imports();
+ dict_put(state->imports, c->name, c);
+ $$=0;
+}
+IMPORT : "import" PACKAGE '.' '*' {
+ NEW(import_t,i);
+ i->package = $2;
+ state_has_imports();
+ list_append(state->wildcard_imports, i);
+ $$=0;
+}
+
+/* ------------ classes and interfaces (header) -------------- */
+
+MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
+MAYBE_MODIFIERS : MODIFIER_LIST {PASS12 $$=$1;}
+MODIFIER_LIST : MODIFIER {PASS12 $$=$1;}
+MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
+
+MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
+ | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
+ | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
+ | KW_STATIC {PASS12 $$=FLAG_STATIC;}
+ | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
+ | KW_FINAL {PASS12 $$=FLAG_FINAL;}
+ | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
+ | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
+ | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
+
+EXTENDS : {$$=registry_getobjectclass();}
+EXTENDS : KW_EXTENDS QNAME {$$=$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;}
+
+CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER
+ EXTENDS IMPLEMENTS_LIST
+ '{' {PASS12 startclass($1,$3,$4,$5, 0);}
+ MAYBE_CLASS_BODY
+ '}' {PASS12 endclass();$$=0;}
+
+INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER
+ EXTENDS_LIST
+ '{' {PASS12 startclass($1,$3,0,$4,1);}
+ MAYBE_INTERFACE_BODY
+ '}' {PASS12 endclass();$$=0;}
+
+/* ------------ classes and interfaces (body) -------------- */
+
+MAYBE_CLASS_BODY :
+MAYBE_CLASS_BODY : CLASS_BODY
+CLASS_BODY : CLASS_BODY_ITEM
+CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
+CLASS_BODY_ITEM : ';'
+CLASS_BODY_ITEM : SLOT_DECLARATION
+CLASS_BODY_ITEM : FUNCTION_DECLARATION
+
+CLASS_BODY_ITEM : CODE_STATEMENT {
+ code_t*c = state->cls->static_init;
+ c = code_append(c, $1);
+ state->cls->static_init = c;
+}
+
+MAYBE_INTERFACE_BODY :
+MAYBE_INTERFACE_BODY : INTERFACE_BODY
+INTERFACE_BODY : IDECLARATION
+INTERFACE_BODY : INTERFACE_BODY IDECLARATION
+IDECLARATION : ';'
+IDECLARATION : "var" T_IDENTIFIER {
+ syntaxerror("variable declarations not allowed in interfaces");
+}
+IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
+ PASS12
+ $1 |= FLAG_PUBLIC;
+ if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
+ syntaxerror("invalid method modifiers: interface methods always need to be public");
+ }
+ startfunction(0,$1,$3,$4,&$6,$8);
+ endfunction(0,$1,$3,$4,&$6,$8, 0);
+}
+
+/* ------------ classes and interfaces (body, slots ) ------- */
+
+VARCONST: "var" | "const"
+
+SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
+ int flags = $1;
+ 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;
+
+ /* slot name */
+ namespace_t mname_ns = {flags2access(flags), ""};
+ multiname_t mname = {QNAME, &mname_ns, 0, $3};
+
+ trait_list_t**traits;
+ code_t**code;
+ if(!state->cls) {
+ // global variable
+ mname_ns.name = state->package;
+ 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 {
+ // 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)) {
+ c = abc_getlocal_0(c);
+ c = code_append(c, $5.c);
+ c = converttype(c, $5.t, $4);
+ c = abc_setslot(c, t->slot_id);
+ }
+
+ *code = code_append(*code, c);
+
+ if($2==KW_CONST) {
+ t->kind= TRAIT_CONST;
+ }
+
+ $$=0;
+}
+
+/* ------------ constants -------------------------------------- */
+
+MAYBESTATICCONSTANT: {$$=0;}
+MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
+
+STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
+STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
+STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
+STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
+STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
+//STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
+STATICCONSTANT : "true" {$$ = constant_new_true($1);}
+STATICCONSTANT : "false" {$$ = constant_new_false($1);}
+STATICCONSTANT : "null" {$$ = constant_new_null($1);}
+
+/* ------------ classes and interfaces (body, functions) ------- */
+
+// non-vararg version
+MAYBE_PARAM_LIST: {
+ memset(&$$,0,sizeof($$));
+}
+MAYBE_PARAM_LIST: PARAM_LIST {
+ $$=$1;
+}
+
+// vararg version
+MAYBE_PARAM_LIST: "..." PARAM {
+ memset(&$$,0,sizeof($$));
+ $$.varargs=1;
+ list_append($$.list, $2);
+}
+MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
+ $$ =$1;
+ $$.varargs=1;
+ list_append($$.list, $4);
+}
+
+// non empty
+PARAM_LIST: PARAM_LIST ',' PARAM {
+ $$ = $1;
+ list_append($$.list, $3);
+}
+PARAM_LIST: PARAM {
+ memset(&$$,0,sizeof($$));
+ list_append($$.list, $1);
+}
+
+PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
+ $$ = malloc(sizeof(param_t));
+ $$->name=$1;
+ $$->type = $3;
+ $$->value = $4;
+}
+PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
+ $$ = malloc(sizeof(param_t));
+ $$->name=$1;
+ $$->type = TYPE_ANY;
+ $$->value = $2;
+}
+GETSET : "get" {$$=$1;}
+ | "set" {$$=$1;}
+ | {$$=0;}
+
+FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
+ MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}'
+{
+ 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);
+ c = abc_pushscope(c);
+ }
+ if(state->method->is_constructor && !state->method->has_super) {
+ // call default constructor
+ c = abc_getlocal_0(c);
+ c = abc_constructsuper(c, 0);
+ }
+
+ c = wrap_function(c, 0, $11);
+
+ endfunction(0,$1,$3,$4,&$6,$8,c);
+ $$=0;
+}
+
+MAYBE_IDENTIFIER: T_IDENTIFIER
+MAYBE_IDENTIFIER: {PASS12 $$=0;}
+INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE
+ '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
+{
+ 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);
+}
+
+
+/* ------------- package + class ids --------------- */
+
+CLASS: T_IDENTIFIER {
+ PASS1 $$=0;
+ PASS2
+ /* try current package */
+ $$ = find_class($1);
+ if(!$$) syntaxerror("Could not find class %s\n", $1);
+}
+
+PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
+ PASS1 $$=0;
+ PASS2
+ $$ = registry_findclass($1, $3);
+ if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
+ free($1);$1=0;
+}