+EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+ $$.cc = 0;
+ $$.cc = code_append($$.cc, $1.c);
+ $$.cc = code_append($$.cc, $3.c);
+ $$.len = 2;
+}
+EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
+ $$.cc = $1.cc;
+ $$.len = $1.len+2;
+ $$.cc = code_append($$.cc, $3.c);
+ $$.cc = code_append($$.cc, $5.c);
+}
+//MAYBECOMMA: ','
+//MAYBECOMMA:
+
+E : '{' MAYBE_EXPRPAIR_LIST '}' {
+ $$.c = code_new();
+ $$.c = code_append($$.c, $2.cc);
+ $$.c = abc_newobject($$.c, $2.len/2);
+ $$.t = registry_getobjectclass();
+}
+
+E : E "*=" E {
+ code_t*c = $3.c;
+ if(BOTH_INT($1.t,$3.t)) {
+ c=abc_multiply_i(c);
+ } else {
+ c=abc_multiply(c);
+ }
+ c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+
+E : E "%=" E {
+ code_t*c = abc_modulo($3.c);
+ c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E "<<=" E {
+ code_t*c = abc_lshift($3.c);
+ c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E ">>=" E {
+ code_t*c = abc_rshift($3.c);
+ c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E ">>>=" E {
+ code_t*c = abc_urshift($3.c);
+ c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E "/=" E {
+ code_t*c = abc_divide($3.c);
+ c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E "|=" E {
+ code_t*c = abc_bitor($3.c);
+ c=converttype(c, TYPE_INT, $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E "+=" E {
+ code_t*c = $3.c;
+
+ if(TYPE_IS_INT($1.t)) {
+ c=abc_add_i(c);
+ } else {
+ c=abc_add(c);
+ c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
+ }
+
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E "-=" E { code_t*c = $3.c;
+ if(TYPE_IS_INT($1.t)) {
+ c=abc_subtract_i(c);
+ } else {
+ c=abc_subtract(c);
+ c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
+ }
+
+ $$.c = toreadwrite($1.c, c, 0, 0);
+ $$.t = $1.t;
+ }
+E : E '=' E { code_t*c = 0;
+ c = code_append(c, $3.c);
+ c = converttype(c, $3.t, $1.t);
+ $$.c = toreadwrite($1.c, c, 1, 0);
+ $$.t = $1.t;
+ }
+
+E : E '?' E ':' E %prec below_assignment {
+ $$.t = join_types($3.t,$5.t,'?');
+ $$.c = $1.c;
+ code_t*j1 = $$.c = abc_iffalse($$.c, 0);
+ $$.c = code_append($$.c, $3.c);
+ $$.c = converttype($$.c, $3.t, $$.t);
+ code_t*j2 = $$.c = abc_jump($$.c, 0);
+ $$.c = j1->branch = abc_label($$.c);
+ $$.c = code_append($$.c, $5.c);
+ $$.c = converttype($$.c, $3.t, $$.t);
+ $$.c = j2->branch = abc_label($$.c);
+ }
+
+E : E "++" { code_t*c = 0;
+ classinfo_t*type = $1.t;
+ if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
+ int nr = getlocalnr($1.c);
+ code_free($1.c);$1.c=0;
+ if(TYPE_IS_INT($1.t)) {
+ $$.c = abc_getlocal(0, nr);
+ $$.c = abc_inclocal_i($$.c, nr);
+ } else if(TYPE_IS_NUMBER($1.t)) {
+ $$.c = abc_getlocal(0, nr);
+ $$.c = abc_inclocal($$.c, nr);
+ } else syntaxerror("internal error");
+ } else {
+ if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
+ c=abc_increment_i(c);
+ type = TYPE_INT;
+ } else {
+ c=abc_increment(c);
+ type = TYPE_NUMBER;
+ }
+ c=converttype(c, type, $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 1);
+ $$.t = $1.t;
+ }
+ }
+
+// TODO: use inclocal, like with ++
+E : E "--" { code_t*c = 0;
+ classinfo_t*type = $1.t;
+ if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
+ c=abc_decrement_i(c);
+ type = TYPE_INT;
+ } else {
+ c=abc_decrement(c);
+ type = TYPE_NUMBER;
+ }
+ c=converttype(c, type, $1.t);
+ $$.c = toreadwrite($1.c, c, 0, 1);
+ $$.t = $1.t;
+ }
+
+E : "++" %prec plusplus_prefix E { code_t*c = 0;
+ classinfo_t*type = $2.t;
+ if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
+ c=abc_increment_i(c);
+ type = TYPE_INT;
+ } else {
+ c=abc_increment(c);
+ type = TYPE_NUMBER;
+ }
+ c=converttype(c, type, $2.t);
+ $$.c = toreadwrite($2.c, c, 0, 0);
+ $$.t = $2.t;
+ }
+
+E : "--" %prec minusminus_prefix E { code_t*c = 0;
+ classinfo_t*type = $2.t;
+ if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
+ c=abc_decrement_i(c);
+ type = TYPE_INT;
+ } else {
+ c=abc_decrement(c);
+ type = TYPE_NUMBER;
+ }
+ c=converttype(c, type, $2.t);
+ $$.c = toreadwrite($2.c, c, 0, 0);
+ $$.t = $2.t;
+ }
+
+E : "super" '.' T_IDENTIFIER
+ { if(!state->cls->info)
+ syntaxerror("super keyword not allowed outside a class");
+ classinfo_t*t = state->cls->info->superclass;
+ if(!t) t = TYPE_OBJECT;
+
+ memberinfo_t*f = registry_findmember(t, $3, 1);
+ namespace_t ns = flags2namespace(f->flags, "");
+ MEMBER_MULTINAME(m, f, $3);
+ $$.c = 0;
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = abc_getsuper2($$.c, &m);
+ $$.t = memberinfo_gettype(f);
+ }
+
+E : E '.' T_IDENTIFIER
+ {$$.c = $1.c;
+ classinfo_t*t = $1.t;
+ char is_static = 0;
+ if(TYPE_IS_CLASS(t) && t->cls) {
+ t = t->cls;
+ is_static = 1;
+ }
+ if(t) {
+ memberinfo_t*f = registry_findmember(t, $3, 1);
+ char noslot = 0;
+ if(f && !is_static != !(f->flags&FLAG_STATIC))
+ noslot=1;
+ if(f && f->slot && !noslot) {
+ $$.c = abc_getslot($$.c, f->slot);
+ } else {
+ MEMBER_MULTINAME(m, f, $3);
+ $$.c = abc_getproperty2($$.c, &m);
+ }
+ /* determine type */
+ $$.t = memberinfo_gettype(f);
+ if(!$$.t)
+ $$.c = abc_coerce_a($$.c);
+ } else {
+ /* when resolving a property on an unknown type, we do know the
+ name of the property (and don't seem to need the package), but
+ we need to make avm2 try out all access modes */
+ multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
+ $$.c = abc_getproperty2($$.c, &m);
+ $$.c = abc_coerce_a($$.c);
+ $$.t = registry_getanytype();
+ }
+ }
+
+VAR_READ : T_IDENTIFIER {
+ $$.t = 0;
+ $$.c = 0;
+ classinfo_t*a = 0;
+ memberinfo_t*f = 0;
+
+ variable_t*v;
+ /* look at variables */
+ if((v = find_variable($1))) {
+ // $1 is a local variable
+ $$.c = abc_getlocal($$.c, v->index);
+ $$.t = v->type;
+
+ /* look at current class' members */
+ } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
+ // $1 is a function in this class
+ int var_is_static = (f->flags&FLAG_STATIC);
+ int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
+ if(var_is_static != i_am_static) {
+ /* there doesn't seem to be any "static" way to access
+ static properties of a class */
+ state->method->late_binding = 1;
+ $$.t = f->type;
+ namespace_t ns = {flags2access(f->flags), ""};
+ multiname_t m = {QNAME, &ns, 0, $1};
+ $$.c = abc_findpropstrict2($$.c, &m);
+ $$.c = abc_getproperty2($$.c, &m);
+ } else {
+ if(f->slot>0) {
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = abc_getslot($$.c, f->slot);
+ } else {
+ namespace_t ns = {flags2access(f->flags), ""};
+ multiname_t m = {QNAME, &ns, 0, $1};
+ $$.c = abc_getlocal_0($$.c);
+ $$.c = abc_getproperty2($$.c, &m);
+ }
+ }
+ if(f->kind == MEMBER_METHOD) {
+ $$.t = TYPE_FUNCTION(f);
+ } else {
+ $$.t = f->type;
+ }
+
+ /* look at actual classes, in the current package and imported */
+ } else if((a = find_class($1))) {
+ if(a->flags & FLAG_METHOD) {
+ MULTINAME(m, a);
+ $$.c = abc_findpropstrict2($$.c, &m);
+ $$.c = abc_getproperty2($$.c, &m);
+ if(a->function->kind == MEMBER_METHOD) {
+ $$.t = TYPE_FUNCTION(a->function);
+ } else {
+ $$.t = a->function->type;
+ }
+ } else {
+ if(a->slot) {
+ $$.c = abc_getglobalscope($$.c);
+ $$.c = abc_getslot($$.c, a->slot);
+ } else {
+ MULTINAME(m, a);
+ $$.c = abc_getlex2($$.c, &m);
+ }
+ $$.t = TYPE_CLASS(a);
+ }
+
+ /* unknown object, let the avm2 resolve it */
+ } else {
+ if(strcmp($1,"trace"))
+ as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
+ state->method->late_binding = 1;
+
+ multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
+
+ $$.t = 0;
+ $$.c = abc_findpropstrict2($$.c, &m);
+ $$.c = abc_getproperty2($$.c, &m);
+ }
+}