+/* ------------ 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->text;
+ $$->type = $3;
+ $$->value = $4;
+}
+PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
+ $$ = malloc(sizeof(param_t));
+ $$->name=$1->text;$$->type = TYPE_ANY;
+}
+
+FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
+ MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
+{
+ if(!state->m) syntaxerror("internal error: undefined function");
+ endfunction($11);
+}
+
+/* ------------- package + class ids --------------- */
+
+CLASS: T_IDENTIFIER {
+
+ /* try current package */
+ $$ = registry_findclass(state->package, $1->text);
+
+ /* try explicit imports */
+ dictentry_t* e = dict_get_slot(state->imports, $1->text);
+ while(e) {
+ if($$)
+ break;
+ if(!strcmp(e->key, $1->text)) {
+ $$ = (classinfo_t*)e->data;
+ }
+ e = e->next;
+ }
+
+ /* try package.* imports */
+ import_list_t*l = state->wildcard_imports;
+ while(l) {
+ if($$)
+ break;
+ //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
+ $$ = registry_findclass(l->import->package, $1->text);
+ l = l->next;
+ }
+
+ /* try global package */
+ if(!$$) {
+ $$ = registry_findclass("", $1->text);
+ }
+
+ if(!$$) syntaxerror("Could not find class %s\n", $1->text);
+}
+
+PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
+ $$ = registry_findclass($1->text, $3->text);
+ if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
+}
+
+QNAME: PACKAGEANDCLASS
+ | CLASS
+
+
+/* ----------function calls, constructor calls ------ */
+
+MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
+MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
+
+MAYBE_EXPRESSION_LIST : {$$=0;}
+MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
+EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
+ typedcode_t*t = malloc(sizeof(typedcode_t));
+ *t = $1;
+ list_append($$, t);}
+EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
+ typedcode_t*t = malloc(sizeof(typedcode_t));
+ *t = $3;
+ list_append($$, t);}
+
+NEW : "new" CLASS MAYBE_PARAM_VALUES {
+ MULTINAME(m, $2);
+ $$.c = code_new();
+
+ /* TODO: why do we have to *find* our own classes? */
+ $$.c = abc_findpropstrict2($$.c, &m);
+
+ typedcode_list_t*l = $3;
+ int len = 0;
+ while(l) {
+ $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
+ l = l->next;
+ len ++;
+ }
+ $$.c = abc_constructprop2($$.c, &m, len);
+ $$.t = $2;
+}
+
+/* TODO: use abc_call (for calling local variables),
+ abc_callstatic (for calling own methods)
+ call (for closures)
+*/
+FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
+ typedcode_list_t*l = $3;
+ int len = 0;
+ code_t*paramcode = 0;
+ while(l) {
+ paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
+ l = l->next;
+ len ++;
+ }
+
+ $$.c = $1.c;
+ if($$.c->opcode == OPCODE_COERCE_A) {
+ $$.c = code_cutlast($$.c);
+ }
+
+ $$.t = TYPE_ANY;
+ multiname_t*name = 0;
+ if($$.c->opcode == OPCODE_GETPROPERTY) {
+ name = multiname_clone($$.c->data[0]);
+ $$.c = code_cutlast($$.c);
+ $$.c = code_append($$.c, paramcode);
+ $$.c = abc_callproperty2($$.c, name, len);
+ } else if($$.c->opcode == OPCODE_GETSLOT) {
+ int slot = (int)(ptroff_t)$$.c->data[0];
+ trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
+ if(t->kind!=TRAIT_METHOD) {
+ //flash allows to assign closures to members.
+ //syntaxerror("not a function");
+ }
+ name = t->name;
+ $$.c = code_cutlast($$.c);
+ $$.c = code_append($$.c, paramcode);
+ //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
+ $$.c = abc_callproperty2($$.c, name, len);
+ } else {
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = code_append($$.c, paramcode);
+ $$.c = abc_call($$.c, len);
+ }
+
+ memberinfo_t*f = 0;
+
+ if(TYPE_IS_FUNCTION($1.t) &&
+ (f = registry_findmember($1.t, "call"))) {
+ $$.t = f->return_type;
+ } else {
+ $$.c = abc_coerce_a($$.c);
+ $$.t = TYPE_ANY;
+ }
+}
+
+RETURN: "return" %prec prec_none {
+ $$ = abc_returnvoid(0);
+}
+RETURN: "return" EXPRESSION {
+ $$ = $2.c;
+ $$ = abc_returnvalue($$);
+}
+// ----------------------- expression types -------------------------------------
+
+NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
+EXPRESSION : E %prec prec_belowminus {$$ = $1;}
+EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
+ $$.c = $1.c;
+ $$.c = cut_last_push($$.c);
+ $$.c = code_append($$.c,$3.c);
+ $$.t = $3.t;
+}
+VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
+
+// ----------------------- expression evaluation -------------------------------------