%type <code> INTERFACE_DECLARATION
%type <code> VOIDEXPRESSION
%type <value> EXPRESSION NONCOMMAEXPRESSION
-%type <value> MAYBEEXPRESSION
+%type <node> MAYBEEXPRESSION
%type <value> DELETE
%type <node> E COMMA_EXPRESSION
+%type <node> VAR_READ
%type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY
%type <value> INNERFUNCTION
%type <code> USE_NAMESPACE
%type <classinfo> TYPE
//%type <token> VARIABLE
-%type <value> VAR_READ MEMBER
+%type <value> MEMBER
%type <value> NEW
//%type <token> T_IDENTIFIER
%type <value> FUNCTIONCALL
int gettempvar()
{
variable_t*v = find_variable(state, TEMPVARNAME);
+ int i;
if(v)
- return v->index;
- return new_variable(TEMPVARNAME, 0, 0, 0);
+ i = v->index;
+ else
+ i = new_variable(TEMPVARNAME, 0, 0, 0);
+ parserassert(i);
+ return i;
}
static code_t* var_block(code_t*body)
index = new_variable((flags&FLAG_STATIC)?"class":"this", state->cls?state->cls->info:0, 0, 0);
else
index = new_variable("globalscope", 0, 0, 0);
- if(index)
- *(int*)0=0;
parserassert(!index);
}
state->cls = rfx_calloc(sizeof(classstate_t));
state->cls->init = rfx_calloc(sizeof(methodstate_t));
state->cls->static_init = rfx_calloc(sizeof(methodstate_t));
+ state->cls->static_init->variable_count=1;
/* notice: we make no effort to initialize the top variable (local0) here,
even though it has special meaning. We just rely on the facat
that pass 1 won't do anything with variables */
// not sure wether to look into superclasses here, too
minfo = (methodinfo_t*)registry_findmember(state->cls->info, ns.name, name, 1);
if(minfo) {
- if(minfo->kind!=INFOTYPE_SLOT)
+ if(minfo->kind!=INFOTYPE_VAR)
syntaxerror("class already contains a method called '%s'", name);
if(!(minfo->subtype & (SUBTYPE_GETSET)))
syntaxerror("class already contains a field called '%s'", name);
}*/
} else {
minfo = methodinfo_register_onclass(state->cls->info, ns.access, ns.name, name);
- minfo->kind = INFOTYPE_SLOT; //hack
+ minfo->kind = INFOTYPE_VAR; //hack
minfo->subtype = gs;
minfo->return_type = 0;
}
}
};
-MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
- | {$$.c=abc_pushundefined(0);
- $$.t=TYPE_ANY;
- }
+MAYBEEXPRESSION : '=' E {$$=$2;}
+ | {$$=mkdummynode();}
VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
new_variable($1, 0, 1, 0);
PASS2
- if(!is_subtype_of($3.t, $2)) {
- syntaxerror("Can't convert %s to %s", $3.t->name,
- $2->name);
- }
-
char slot = 0;
int index = 0;
if(state->method->uses_slots) {
$$ = slot?abc_getscopeobject(0, 1):0;
+ typedcode_t v = node_read($3);
+ if(!is_subtype_of(v.t, $2)) {
+ syntaxerror("Can't convert %s to %s", v.t->name, $2->name);
+ }
if($2) {
- if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
- $$ = code_append($$, $3.c);
- $$ = converttype($$, $3.t, $2);
+ if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
+ $$ = code_append($$, v.c);
+ $$ = converttype($$, v.t, $2);
} else {
- code_free($3.c);
+ code_free(v.c);
$$ = defaultvalue($$, $2);
}
} else {
- if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
- $$ = code_append($$, $3.c);
+ if(v.c->prev || v.c->opcode != OPCODE_PUSHUNDEFINED) {
+ $$ = code_append($$, v.c);
$$ = abc_coerce_a($$);
} else {
// don't do anything
- code_free($3.c);
+ code_free(v.c);
code_free($$);
$$ = 0;
break;
t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
}
info->slot = t->slot_id;
-
- /* initalization code (if needed) */
- code_t*c = 0;
- if($3.c && !is_pushundefined($3.c)) {
- c = abc_getlocal_0(c);
- c = code_append(c, $3.c);
- c = converttype(c, $3.t, $2);
- c = abc_setslot(c, t->slot_id);
+
+ constant_t cval = $3->type->eval($3);
+ if(cval.type!=CONSTANT_UNKNOWN) {
+ /* compile time constant */
+ t->value = malloc(sizeof(constant_t));
+ memcpy(t->value, &cval, sizeof(constant_t));
+ info->value = constant_clone(t->value);
+ } else {
+ typedcode_t v = node_read($3);
+ /* initalization code (if needed) */
+ code_t*c = 0;
+ if(v.c && !is_pushundefined(v.c)) {
+ c = abc_getlocal_0(c);
+ c = code_append(c, v.c);
+ c = converttype(c, v.t, $2);
+ c = abc_setslot(c, t->slot_id);
+ }
+ *code = code_append(*code, c);
}
- *code = code_append(*code, c);
-
if(slotstate_varconst==KW_CONST) {
t->kind= TRAIT_CONST;
+ info->flags |= FLAG_CONST;
}
}
/* ------------ constants -------------------------------------- */
MAYBECONSTANT: {$$=0;}
-MAYBECONSTANT: '=' CONSTANT {$$=$2;}
+MAYBECONSTANT: '=' E {
+ $$ = malloc(sizeof(constant_t));
+ *$$ = node_eval($2);
+ if($$->type == CONSTANT_UNKNOWN)
+ syntaxerror("can't evaluate default parameter value (needs to be a compile-time constant)");
+}
//CONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
CONSTANT : T_INT {$$ = constant_new_int($1);}
CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
TYPE : CLASS_SPEC {PASS12 $$=$1;}
- | '*' {PASS12 $$=registry_getanytype();}
- | "void" {PASS12 $$=registry_getanytype();}
+ | '*' {PASS12 $$=TYPE_ANY;}
+ | "void" {PASS12 $$=TYPE_ANY;}
/*
| "String" {$$=registry_getstringclass();}
| "int" {$$=registry_getintclass();}
// ----------------------- expression evaluation -------------------------------------
E : INNERFUNCTION %prec prec_none {$$ = mkcodenode($1);}
-E : VAR_READ %prec T_IDENTIFIER {$$ = mkcodenode($1);}
E : MEMBER %prec '.' {$$ = mkcodenode($1);}
E : NEW {$$ = mkcodenode($1);}
E : DELETE {$$ = mkcodenode($1);}
E : FUNCTIONCALL {$$ = mkcodenode($1);}
+E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
E : CONSTANT {
$$ = mkconstnode($1);
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
$$.c = abc_getproperty2($$.c, &m);
$$.c = abc_coerce_a($$.c);
- $$.t = registry_getanytype();
+ $$.t = TYPE_ANY;
}
}
as3_schedule_class_noerror(state->package, $1);
PASS2
- $$.t = 0;
- $$.c = 0;
+ typedcode_t o;
+ o.t = 0;
+ o.c = 0;
+ $$ = 0;
+
slotinfo_t*a = 0;
memberinfo_t*f = 0;
/* look at variables */
if((v = find_variable(state, $1))) {
// $1 is a local variable
- $$.c = abc_getlocal($$.c, v->index);
- $$.t = v->type;
+ o.c = abc_getlocal(o.c, v->index);
+ o.t = v->type;
+ $$ = mkcodenode(o);
break;
}
if((v = find_slot(state, $1))) {
- $$.c = abc_getscopeobject($$.c, 1);
- $$.c = abc_getslot($$.c, v->index);
- $$.t = v->type;
+ o.c = abc_getscopeobject(o.c, 1);
+ o.c = abc_getslot(o.c, v->index);
+ o.t = v->type;
+ $$ = mkcodenode(o);
break;
}
/* look at current class' members */
if(!state->method->inner &&
state->cls &&
- (f = findmember_nsset(state->cls->info, $1, 1)) &&
- (f->flags&FLAG_STATIC) >= i_am_static)
+ (f = findmember_nsset(state->cls->info, $1, 1)))
{
- // $1 is a function in this class
+ // $1 is a member or attribute in this class
int var_is_static = (f->flags&FLAG_STATIC);
- if(f->kind == INFOTYPE_METHOD) {
- $$.t = TYPE_FUNCTION(f);
- } else {
- $$.t = f->type;
- }
- if(var_is_static && !i_am_static) {
- /* access to a static member from a non-static location.
- do this via findpropstrict:
- there doesn't seem to be any non-lookup way to access
- static properties of a class */
- state->method->late_binding = 1;
- $$.t = f->type;
- namespace_t ns = {f->access, f->package};
- multiname_t m = {QNAME, &ns, 0, $1};
- $$.c = abc_findpropstrict2($$.c, &m);
- $$.c = abc_getproperty2($$.c, &m);
- break;
- } else if(f->slot>0) {
- $$.c = abc_getlocal_0($$.c);
- $$.c = abc_getslot($$.c, f->slot);
- break;
- } else {
- namespace_t ns = {f->access, f->package};
- multiname_t m = {QNAME, &ns, 0, $1};
- $$.c = abc_getlocal_0($$.c);
- $$.c = abc_getproperty2($$.c, &m);
- break;
+ if(f->kind == INFOTYPE_VAR && (f->flags&FLAG_CONST)) {
+ /* if the variable is a constant (and we know what is evaluates to), we
+ can just use the value itself */
+ varinfo_t*v = (varinfo_t*)f;
+ if(v->value) {
+ $$ = mkconstnode(v->value);
+ break;
+ }
+ }
+
+ if(var_is_static >= i_am_static) {
+ if(f->kind == INFOTYPE_METHOD) {
+ o.t = TYPE_FUNCTION(f);
+ } else {
+ o.t = f->type;
+ }
+
+ if(var_is_static && !i_am_static) {
+ /* access to a static member from a non-static location.
+ do this via findpropstrict:
+ there doesn't seem to be any non-lookup way to access
+ static properties of a class */
+ state->method->late_binding = 1;
+ o.t = f->type;
+ namespace_t ns = {f->access, f->package};
+ multiname_t m = {QNAME, &ns, 0, $1};
+ o.c = abc_findpropstrict2(o.c, &m);
+ o.c = abc_getproperty2(o.c, &m);
+ $$ = mkcodenode(o);
+ break;
+ } else if(f->slot>0) {
+ o.c = abc_getlocal_0(o.c);
+ o.c = abc_getslot(o.c, f->slot);
+ $$ = mkcodenode(o);
+ break;
+ } else {
+ namespace_t ns = {f->access, f->package};
+ multiname_t m = {QNAME, &ns, 0, $1};
+ o.c = abc_getlocal_0(o.c);
+ o.c = abc_getproperty2(o.c, &m);
+ $$ = mkcodenode(o);
+ break;
+ }
}
}
/* look at actual classes, in the current package and imported */
if((a = find_class($1))) {
- $$ = push_class(a);
+ o = push_class(a);
+ $$ = mkcodenode(o);
break;
}
/* look through package prefixes */
if(dict_contains(state->import_toplevel_packages, $1) ||
registry_ispackage($1)) {
- $$.c = abc___pushpackage__($$.c, $1);
- $$.t = 0;
+ o.c = abc___pushpackage__(o.c, $1);
+ o.t = 0;
+ $$ = mkcodenode(o); //?
break;
}
multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
- $$.t = 0;
- $$.c = abc_findpropstrict2($$.c, &m);
- $$.c = abc_getproperty2($$.c, &m);
+ o.t = 0;
+ o.c = abc_findpropstrict2(o.c, &m);
+ o.c = abc_getproperty2(o.c, &m);
+ $$ = mkcodenode(o);
+ break;
}
}
syntaxerror("Couldn't resolve namespace %s", $3->name);
}
- if(!s || s->kind != INFOTYPE_SLOT)
+ if(!s || s->kind != INFOTYPE_VAR)
syntaxerror("%s.%s is not a public namespace (%d)", $3->package, $3->name, s?s->kind:-1);
if(!s->value || !NS_TYPE(s->value->type))
syntaxerror("%s.%s is not a namespace", $3->package, $3->name);