3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
30 #include "tokenizer.h"
44 classinfo_t*classinfo;
45 classinfo_list_t*classinfo_list;
48 unsigned int number_uint;
52 typedcode_list_t*value_list;
60 %token<token> T_IDENTIFIER
61 %token<string> T_STRING
62 %token<token> T_REGEXP
64 %token<number_int> T_INT
65 %token<number_uint> T_UINT
66 %token<number_uint> T_BYTE
67 %token<number_uint> T_SHORT
68 %token<number_float> T_FLOAT
70 %token<token> KW_IMPLEMENTS
71 %token<token> KW_NAMESPACE "namespace"
72 %token<token> KW_PACKAGE "package"
73 %token<token> KW_PROTECTED
74 %token<token> KW_PUBLIC
75 %token<token> KW_PRIVATE
76 %token<token> KW_USE "use"
77 %token<token> KW_INTERNAL
78 %token<token> KW_NEW "new"
79 %token<token> KW_NATIVE
80 %token<token> KW_FUNCTION "function"
81 %token<token> KW_FOR "for"
82 %token<token> KW_CLASS "class"
83 %token<token> KW_CONST "const"
84 %token<token> KW_SET "set"
85 %token<token> KW_STATIC
86 %token<token> KW_IMPORT "import"
87 %token<token> KW_RETURN "return"
88 %token<token> KW_INTERFACE "interface"
89 %token<token> KW_NULL "null"
90 %token<token> KW_VAR "var"
91 %token<token> KW_DYNAMIC
92 %token<token> KW_OVERRIDE
93 %token<token> KW_FINAL
94 %token<token> KW_GET "get"
95 %token<token> KW_EXTENDS
96 %token<token> KW_FALSE "false"
97 %token<token> KW_TRUE "true"
98 %token<token> KW_BOOLEAN "Boolean"
99 %token<token> KW_UINT "uint"
100 %token<token> KW_INT "int"
101 %token<token> KW_WHILE "while"
102 %token<token> KW_NUMBER "Number"
103 %token<token> KW_STRING "String"
104 %token<token> KW_IF "if"
105 %token<token> KW_ELSE "else"
106 %token<token> KW_BREAK "break"
107 %token<token> KW_IS "is"
108 %token<token> KW_AS "as"
110 %token<token> T_EQEQ "=="
111 %token<token> T_EQEQEQ "==="
112 %token<token> T_NE "!="
113 %token<token> T_LE "<="
114 %token<token> T_GE ">="
115 %token<token> T_DIVBY "/="
116 %token<token> T_MODBY "%="
117 %token<token> T_PLUSBY "+="
118 %token<token> T_MINUSBY "-="
119 %token<token> T_SHRBY ">>="
120 %token<token> T_SHLBY "<<="
121 %token<token> T_USHRBY ">>>="
122 %token<token> T_OROR "||"
123 %token<token> T_ANDAND "&&"
124 %token<token> T_COLONCOLON "::"
125 %token<token> T_MINUSMINUS "--"
126 %token<token> T_PLUSPLUS "++"
127 %token<token> T_DOTDOT ".."
128 %token<token> T_DOTDOTDOT "..."
129 %token<token> T_SHL "<<"
130 %token<token> T_USHR ">>>"
131 %token<token> T_SHR ">>"
132 %token<token> T_SEMICOLON ';'
133 %token<token> T_STAR '*'
134 %token<token> T_DOT '.'
136 %type <token> X_IDENTIFIER VARCONST
138 %type <code> CODEPIECE
139 %type <code> CODEBLOCK MAYBECODE
140 %type <token> PACKAGE_DECLARATION
141 %type <token> FUNCTION_DECLARATION
142 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
143 %type <token> CLASS_DECLARATION
144 %type <token> NAMESPACE_DECLARATION
145 %type <token> INTERFACE_DECLARATION
146 %type <code> VOIDEXPRESSION
147 %type <value> EXPRESSION NONCOMMAEXPRESSION
148 %type <value> MAYBEEXPRESSION
150 %type <value> CONSTANT
151 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
152 %type <token> USE_NAMESPACE
153 %type <code> FOR_INIT
155 %type <classinfo> MAYBETYPE
158 %type <params> PARAM_LIST
159 %type <params> MAYBE_PARAM_LIST
160 %type <token> MODIFIERS
161 %type <token> MODIFIER_LIST
162 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
163 %type <classinfo_list> IMPLEMENTS_LIST
164 %type <classinfo> EXTENDS
165 %type <classinfo_list> EXTENDS_LIST
166 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
167 %type <classinfo_list> QNAME_LIST
168 %type <classinfo> TYPE
170 //%type <token> VARIABLE
171 %type <value> VAR_READ
173 //%type <token> T_IDENTIFIER
174 %type <token> MODIFIER
175 %type <token> PACKAGE
176 %type <value> FUNCTIONCALL
177 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
179 // precedence: from low to high
180 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
195 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
197 %left prec_belowminus
212 %nonassoc T_IDENTIFIER
213 %left below_semicolon
218 // needed for "return" precedence:
219 %nonassoc T_STRING T_REGEXP
220 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
221 %nonassoc "new" "false" "true" "null"
228 static int yyerror(char*s)
230 syntaxerror("%s", s);
232 static token_t* concat2(token_t* t1, token_t* t2)
235 int l1 = strlen(t1->text);
236 int l2 = strlen(t2->text);
237 t->text = malloc(l1+l2+1);
238 memcpy(t->text , t1->text, l1);
239 memcpy(t->text+l1, t2->text, l2);
243 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
246 int l1 = strlen(t1->text);
247 int l2 = strlen(t2->text);
248 int l3 = strlen(t3->text);
249 t->text = malloc(l1+l2+l3+1);
250 memcpy(t->text , t1->text, l1);
251 memcpy(t->text+l1, t2->text, l2);
252 memcpy(t->text+l1+l2, t3->text, l3);
253 t->text[l1+l2+l3] = 0;
256 static char* concat3str(const char* t1, const char* t2, const char* t3)
261 char*text = malloc(l1+l2+l3+1);
262 memcpy(text , t1, l1);
263 memcpy(text+l1, t2, l2);
264 memcpy(text+l1+l2, t3, l3);
269 typedef struct _import {
273 DECLARE_LIST(import);
275 typedef struct _state {
283 /* code that needs to be executed at the start of
284 a method (like initializing local registers) */
287 import_list_t*wildcard_imports;
289 char has_own_imports;
295 code_t*cls_static_init;
306 typedef struct _global {
310 static global_t*global = 0;
311 static state_t* state = 0;
315 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
317 /* warning: list length of namespace set is undefined */
318 #define MULTINAME_LATE(m, access, package) \
319 namespace_t m##_ns = {access, package}; \
320 namespace_set_t m##_nsset; \
321 namespace_list_t m##_l;m##_l.next = 0; \
322 m##_nsset.namespaces = &m##_l; \
323 m##_nsset = m##_nsset; \
324 m##_l.namespace = &m##_ns; \
325 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
327 static state_list_t*state_stack=0;
329 static void init_globals()
331 global = rfx_calloc(sizeof(global_t));
334 static void new_state()
337 NEW(state_list_t, sl);
339 state_t*oldstate = state;
341 memcpy(s, state, sizeof(state_t)); //shallow copy
342 sl->next = state_stack;
345 s->local_var_base = oldstate->vars->num + oldstate->local_var_base;
348 s->imports = dict_new();
353 state->vars = dict_new();
355 state->has_own_imports = 0;
357 static void state_has_imports()
359 state->wildcard_imports = list_clone(state->wildcard_imports);
360 state->imports = dict_clone(state->imports);
361 state->has_own_imports = 1;
364 static void old_state()
366 if(!state_stack || !state_stack->next)
367 syntaxerror("invalid nesting");
368 state_t*oldstate = state;
369 state_list_t*old = state_stack;
370 state_stack = state_stack->next;
372 state = state_stack->state;
373 /*if(state->initcode) {
374 printf("residual initcode\n");
375 code_dump(state->initcode, 0, 0, "", stdout);
377 if(oldstate->has_own_imports) {
378 list_free(oldstate->wildcard_imports);
379 dict_destroy(oldstate->imports);oldstate->imports=0;
381 state->initcode = code_append(state->initcode, oldstate->initcode);
383 void initialize_state()
388 state->file = abc_file_new();
389 state->file->flags &= ~ABCFILE_LAZY;
391 state->init = abc_initscript(state->file, 0, 0);
392 code_t*c = state->init->method->body->code;
394 c = abc_getlocal_0(c);
395 c = abc_pushscope(c);
397 /* findpropstrict doesn't just return a scope object- it
398 also makes it "active" somehow. Push local_0 on the
399 scope stack and read it back with findpropstrict, it'll
400 contain properties like "trace". Trying to find the same
401 property on a "vanilla" local_0 yields only a "undefined" */
402 //c = abc_findpropstrict(c, "[package]::trace");
404 /*c = abc_getlocal_0(c);
405 c = abc_findpropstrict(c, "[package]::trace");
407 c = abc_setlocal_1(c);
409 c = abc_pushbyte(c, 0);
410 c = abc_setlocal_2(c);
412 code_t*xx = c = abc_label(c);
413 c = abc_findpropstrict(c, "[package]::trace");
414 c = abc_pushstring(c, "prop:");
415 c = abc_hasnext2(c, 1, 2);
417 c = abc_setlocal_3(c);
418 c = abc_callpropvoid(c, "[package]::trace", 2);
419 c = abc_getlocal_3(c);
421 c = abc_iftrue(c,xx);*/
423 c = abc_findpropstrict(c, "[package]::trace");
424 c = abc_pushstring(c, "[entering global init function]");
425 c = abc_callpropvoid(c, "[package]::trace", 1);
427 state->init->method->body->code = c;
429 void* finalize_state()
431 if(state->level!=1) {
432 syntaxerror("unexpected end of file");
434 abc_method_body_t*m = state->init->method->body;
437 __ findpropstrict(m, "[package]::trace");
438 __ pushstring(m, "[leaving global init function]");
439 __ callpropvoid(m, "[package]::trace", 1);
445 static void startpackage(token_t*t)
448 syntaxerror("Packages can not be nested.");
451 char*name = t?t->text:"";
452 /*printf("entering package \"%s\"\n", name);*/
453 state->package = name;
455 static void endpackage()
457 /*printf("leaving package \"%s\"\n", state->package);*/
462 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
465 syntaxerror("inner classes now allowed");
468 char*classname = name->text;
471 classinfo_list_t*mlist=0;
472 /*printf("entering class %s\n", name->text);
473 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
475 printf(" extends: %s.%s\n", extends->package, extends->name);
476 printf(" implements (%d): ", list_length(implements));
477 for(mlist=implements;mlist;mlist=mlist->next) {
478 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
483 char public=0,internal=0,final=0,sealed=1;
484 for(t=modifiers->tokens;t;t=t->next) {
485 if(t->token->type == KW_INTERNAL) {
486 /* the programmer is being explicit-
487 being internal is the default anyway */
489 } else if(t->token->type == KW_PUBLIC) {
491 } else if(t->token->type == KW_FINAL) {
494 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
498 syntaxerror("public and internal not supported at the same time.");
500 /* create the class name, together with the proper attributes */
504 if(!public && !state->package) {
505 access = ACCESS_PRIVATE; package = current_filename;
506 } else if(!public && state->package) {
507 access = ACCESS_PACKAGEINTERNAL; package = state->package;
508 } else if(state->package) {
509 access = ACCESS_PACKAGE; package = state->package;
511 syntaxerror("public classes only allowed inside a package");
514 if(registry_findclass(package, classname)) {
515 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
518 state->clsinfo = classinfo_register(access, package, classname);
520 MULTINAME(classname2,state->clsinfo);
522 multiname_t*extends2 = sig2mname(extends);
525 state->cls_init = abc_getlocal_0(state->cls_init);
526 state->cls_init = abc_constructsuper(state->cls_init, 0);
529 state->cls = abc_class_new(state->file, &classname2, extends2);
530 if(final) abc_class_final(state->cls);
531 if(sealed) abc_class_sealed(state->cls);
532 if(interface) abc_class_interface(state->cls);
534 for(mlist=implements;mlist;mlist=mlist->next) {
535 MULTINAME(m, mlist->classinfo);
536 abc_class_add_interface(state->cls, &m);
539 /* now write the construction code for this class */
540 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
542 abc_method_body_t*m = state->init->method->body;
543 __ getglobalscope(m);
544 classinfo_t*s = extends;
549 //TODO: take a look at the current scope stack, maybe
550 // we can re-use something
555 multiname_t*s2 = sig2mname(s);
557 multiname_destroy(s2);
559 __ pushscope(m); count++;
560 m->code = m->code->prev->prev; // invert
562 /* continue appending after last op end */
563 while(m->code && m->code->next) m->code = m->code->next;
565 /* TODO: if this is one of *our* classes, we can also
566 do a getglobalscope/getslot <nr> (which references
567 the init function's slots) */
569 __ getlex2(m, extends2);
571 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
572 stack is not the superclass */
573 __ pushscope(m);count++;
576 /* notice: we get a verify error #1107 if the top element on the scope
577 stack is not the global object */
579 __ pushscope(m);count++;
581 __ newclass(m,state->cls);
585 __ setslot(m, slotindex);
587 /* flash.display.MovieClip handling */
588 if(!globalclass && public && classinfo_equals(registry_getMovieClip(),extends)) {
589 if(state->package && state->package[0]) {
590 globalclass = concat3str(state->package, ".", classname);
592 globalclass = strdup(classname);
595 multiname_destroy(extends2);
598 static void endclass()
600 if(state->cls_init) {
601 if(!state->cls->constructor) {
602 abc_method_body_t*m = abc_class_constructor(state->cls, 0, 0);
603 m->code = code_append(m->code, state->cls_init);
604 m->code = abc_returnvoid(m->code);
606 code_t*c = state->cls->constructor->body->code;
607 c = code_append(state->cls_init, c);
608 state->cls->constructor->body->code = c;
612 if(state->cls_static_init) {
613 if(!state->cls->static_constructor) {
614 abc_method_body_t*m = abc_class_staticconstructor(state->cls, 0, 0);
615 m->code = state->cls_static_init;
617 state->cls->static_constructor->body->code =
618 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
625 static token_t* empty_token()
633 void extend(token_t*list, token_t*add) {
634 list_append(list->tokens,add);
636 list->text = add->text;
638 void extend_s(token_t*list, char*seperator, token_t*add) {
639 list_append(list->tokens,add);
640 char*t1 = list->text;
646 list->text = malloc(l1+l2+l3+1);
647 strcpy(list->text, t1);
648 strcpy(list->text+l1, t2);
649 strcpy(list->text+l1+l2, t3);
650 list->text[l1+l2+l3]=0;
653 typedef struct _variable {
658 static int find_variable(char*name, classinfo_t**m)
660 state_list_t* s = state_stack;
662 variable_t*v = dict_lookup(s->state->vars, name);
673 static int find_variable_safe(char*name, classinfo_t**m)
675 int i = find_variable(name, m);
677 syntaxerror("undefined variable: %s", name);
680 static char variable_exists(char*name)
682 return dict_lookup(state->vars, name)!=0;
684 static int new_variable(char*name, classinfo_t*type)
687 v->index = global->variable_count;
689 dict_put(state->vars, name, v);
690 return global->variable_count++;
692 #define TEMPVARNAME "__as3_temp__"
693 static int gettempvar()
695 int i = find_variable(TEMPVARNAME, 0);
697 return new_variable(TEMPVARNAME, 0);
703 code_t* killvars(code_t*c)
706 for(t=0;t<state->vars->num;t++) {
707 //do this always, otherwise register types don't match
708 //in the verifier when doing nested loops
709 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
710 c = abc_kill(c, t+state->local_var_base);
717 static void check_constant_against_type(classinfo_t*t, constant_t*c)
719 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
720 if(TYPE_IS_NUMBER(t)) {
721 xassert(c->type == CONSTANT_FLOAT
722 || c->type == CONSTANT_INT
723 || c->type == CONSTANT_UINT);
724 } else if(TYPE_IS_UINT(t)) {
725 xassert(c->type == CONSTANT_UINT ||
726 (c->type == CONSTANT_INT && c->i>0));
727 } else if(TYPE_IS_INT(t)) {
728 xassert(c->type == CONSTANT_INT);
729 } else if(TYPE_IS_BOOLEAN(t)) {
730 xassert(c->type == CONSTANT_TRUE
731 || c->type == CONSTANT_FALSE);
735 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
736 params_t*params, classinfo_t*type)
740 global->variable_count = 0;
741 state->function = name->text;
744 syntaxerror("not able to start another method scope");
747 multiname_t*type2 = sig2mname(type);
748 if(!strcmp(state->clsinfo->name,name->text)) {
749 state->m = abc_class_constructor(state->cls, type2, 0);
751 state->minfo = memberinfo_register(state->clsinfo, name->text, MEMBER_METHOD);
752 state->minfo->return_type = type;
753 state->m = abc_class_method(state->cls, type2, name->text, 0);
754 // getslot on a member slot only returns "undefined", so no need
755 // to actually store these
756 //state->minfo->slot = state->m->method->trait->slot_id;
758 if(getset->type == KW_GET) {
759 state->m->method->trait->kind = TRAIT_GETTER;
761 if(getset->type == KW_SET) {
762 state->m->method->trait->kind = TRAIT_SETTER;
764 if(params->varargs) {
765 state->m->method->flags |= METHOD_NEED_REST;
770 for(p=params->list;p;p=p->next) {
771 if(params->varargs && !p->next) {
772 break; //varargs: omit last parameter in function signature
774 multiname_t*m = sig2mname(p->param->type);
775 list_append(state->m->method->parameters, m);
776 if(p->param->value) {
777 check_constant_against_type(p->param->type, p->param->value);
778 opt=1;list_append(state->m->method->optional_parameters, p->param->value);
780 syntaxerror("non-optional parameter not allowed after optional parameters");
784 /* state->vars is initialized by state_new */
785 if(new_variable("this", state->clsinfo)!=0) syntaxerror("Internal error");
787 for(p=params->list;p;p=p->next) {
788 new_variable(p->param->name, p->param->type);
791 static void endfunction(code_t*body)
794 if(state->late_binding) {
795 c = abc_getlocal_0(c);
796 c = abc_pushscope(c);
798 c = code_append(c, state->initcode);
799 c = code_append(c, body);
801 /* append return if necessary */
802 if(!c || c->opcode != OPCODE_RETURNVOID &&
803 c->opcode != OPCODE_RETURNVALUE)
804 c = abc_returnvoid(c);
806 if(state->m->code) syntaxerror("internal error");
813 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
818 void breakjumpsto(code_t*c, code_t*jump)
823 if(c->opcode == OPCODE___BREAK__) {
824 c->opcode = OPCODE_JUMP;
831 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
834 return registry_getanytype();
835 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
836 return registry_getanytype();
839 return registry_getanytype();
841 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
846 /*TODO: can omit this if from is zero? */
847 return abc_coerce_a(c);
849 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
850 MULTINAME(m, TYPE_UINT);
851 return abc_coerce2(c, &m);
853 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
854 MULTINAME(m, TYPE_INT);
855 return abc_coerce2(c, &m);
860 code_t*defaultvalue(code_t*c, classinfo_t*type)
862 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
863 c = abc_pushbyte(c, 0);
864 } else if(TYPE_IS_BOOLEAN(type)) {
865 c = abc_pushfalse(c);
872 char is_pushundefined(code_t*c)
874 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
877 void parserassert(int b)
879 if(!b) syntaxerror("internal error: assertion failed");
882 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign)
886 [prefix code] [read instruction]
890 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
893 if(in && in->opcode == OPCODE_COERCE_A) {
894 in = code_cutlast(in);
897 syntaxerror("internal error");
899 /* chop off read instruction */
903 prefix = r->prev;r->prev = 0;
909 int use_temp_var = 0;
911 /* generate the write instruction, and maybe append a dup to the prefix code */
912 code_t* write = abc_nop(0);
913 if(r->opcode == OPCODE_GETPROPERTY) {
914 write->opcode = OPCODE_SETPROPERTY;
915 multiname_t*m = (multiname_t*)r->data[0];
916 write->data[0] = multiname_clone(m);
918 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
920 prefix = abc_dup(prefix); // we need the object, too
923 } else if(r->opcode == OPCODE_GETSLOT) {
924 write->opcode = OPCODE_SETSLOT;
925 write->data[0] = r->data[0];
927 prefix = abc_dup(prefix); // we need the object, too
930 } else if(r->opcode == OPCODE_GETLOCAL) {
931 write->opcode = OPCODE_SETLOCAL;
932 write->data[0] = r->data[0];
933 } else if(r->opcode == OPCODE_GETLOCAL_0) {
934 write->opcode = OPCODE_SETLOCAL_0;
935 } else if(r->opcode == OPCODE_GETLOCAL_1) {
936 write->opcode = OPCODE_SETLOCAL_1;
937 } else if(r->opcode == OPCODE_GETLOCAL_2) {
938 write->opcode = OPCODE_SETLOCAL_2;
939 } else if(r->opcode == OPCODE_GETLOCAL_3) {
940 write->opcode = OPCODE_SETLOCAL_3;
942 code_dump(r, 0, 0, "", stdout);
943 syntaxerror("illegal lvalue: can't assign a value to this expression");
950 /* with getproperty/getslot, we have to be extra careful not
951 to execute the read code twice, as it might have side-effects
952 (e.g. if the property is in fact a setter/getter combination)
954 So read the value, modify it, and write it again,
955 using prefix only once and making sure (by using a temporary
956 register) that the return value is what we just wrote */
958 c = code_append(c, prefix);
959 c = code_append(c, r);
960 c = code_append(c, middlepart);
962 c = abc_setlocal(c, temp);
963 c = code_append(c, write);
964 c = abc_getlocal(c, temp);
965 c = abc_kill(c, temp);
967 /* if we're allowed to execute the read code twice, things
969 code_t* r2 = code_dup(r);
970 //c = code_append(c, prefix);
971 parserassert(!prefix);
972 c = code_append(c, r);
973 c = code_append(c, middlepart);
974 c = code_append(c, write);
975 c = code_append(c, r2);
978 /* even smaller version: overwrite the value without reading
981 c = code_append(c, prefix);
984 c = code_append(c, middlepart);
985 c = code_append(c, write);
986 c = code_append(c, r);
998 /* ------------ code blocks / statements ---------------- */
1002 MAYBECODE: CODE {$$=$1;}
1003 MAYBECODE: {$$=code_new();}
1005 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1006 CODE: CODEPIECE {$$=$1;}
1008 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1009 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1010 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1011 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1012 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1013 CODEPIECE: ';' {$$=code_new();}
1014 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1015 CODEPIECE: VOIDEXPRESSION {$$=$1}
1016 CODEPIECE: FOR {$$=$1}
1017 CODEPIECE: WHILE {$$=$1}
1018 CODEPIECE: BREAK {$$=$1}
1019 CODEPIECE: RETURN {$$=$1}
1020 CODEPIECE: IF {$$=$1}
1021 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1022 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1024 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1025 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1026 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1028 /* ------------ variables --------------------------- */
1030 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1031 | {$$.c=abc_pushundefined(0);
1035 VAR : "const" | "var"
1036 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1038 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1039 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1041 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1043 if(variable_exists($2->text))
1044 syntaxerror("Variable %s already defined", $2->text);
1046 if(!is_subtype_of($4.t, $3)) {
1047 syntaxerror("Can't convert %s to %s", $4.t->name,
1051 int index = new_variable($2->text, $3);
1054 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1056 $$ = converttype($$, $4.t, $3);
1057 $$ = abc_setlocal($$, index);
1059 $$ = defaultvalue(0, $3);
1060 $$ = abc_setlocal($$, index);
1063 /* if this is a typed variable:
1064 push default value for type on stack */
1066 state->initcode = defaultvalue(state->initcode, $3);
1067 state->initcode = abc_setlocal(state->initcode, index);
1070 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1072 $$ = abc_coerce_a($$);
1073 $$ = abc_setlocal($$, index);
1079 /* that's the default for a local register, anyway
1081 state->initcode = abc_pushundefined(state->initcode);
1082 state->initcode = abc_setlocal(state->initcode, index);
1084 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1087 /* ------------ control flow ------------------------- */
1089 MAYBEELSE: %prec prec_none {$$ = code_new();}
1090 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1091 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1093 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1094 $$ = state->initcode;state->initcode=0;
1096 $$ = code_append($$, $4.c);
1097 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1099 $$ = code_append($$, $6);
1101 myjmp = $$ = abc_jump($$, 0);
1103 myif->branch = $$ = abc_label($$);
1105 $$ = code_append($$, $7);
1106 myjmp->branch = $$ = abc_label($$);
1109 $$ = killvars($$);old_state();
1112 FOR_INIT : {$$=code_new();}
1113 FOR_INIT : VARIABLE_DECLARATION
1114 FOR_INIT : VOIDEXPRESSION
1116 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1117 $$ = state->initcode;state->initcode=0;
1119 $$ = code_append($$, $4);
1120 code_t*loopstart = $$ = abc_label($$);
1121 $$ = code_append($$, $6.c);
1122 code_t*myif = $$ = abc_iffalse($$, 0);
1123 $$ = code_append($$, $10);
1124 $$ = code_append($$, $8);
1125 $$ = abc_jump($$, loopstart);
1126 code_t*out = $$ = abc_label($$);
1127 breakjumpsto($$, out);
1130 $$ = killvars($$);old_state();
1133 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1134 $$ = state->initcode;state->initcode=0;
1136 code_t*myjmp = $$ = abc_jump($$, 0);
1137 code_t*loopstart = $$ = abc_label($$);
1138 $$ = code_append($$, $6);
1139 myjmp->branch = $$ = abc_label($$);
1140 $$ = code_append($$, $4.c);
1141 $$ = abc_iftrue($$, loopstart);
1142 code_t*out = $$ = abc_label($$);
1143 breakjumpsto($$, out);
1145 $$ = killvars($$);old_state();
1149 $$ = abc___break__(0);
1152 /* ------------ packages and imports ---------------- */
1154 X_IDENTIFIER: T_IDENTIFIER
1157 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
1158 PACKAGE: X_IDENTIFIER {$$=$1;}
1160 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1161 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
1163 IMPORT : "import" QNAME {
1166 syntaxerror("Couldn't import class\n");
1167 state_has_imports();
1168 dict_put(state->imports, c->name, c);
1171 IMPORT : "import" PACKAGE '.' '*' {
1173 i->package = $2->text;
1174 state_has_imports();
1175 list_append(state->wildcard_imports, i);
1179 /* ------------ classes and interfaces (header) -------------- */
1181 MODIFIERS : {$$=empty_token();}
1182 MODIFIERS : MODIFIER_LIST {$$=$1}
1183 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1184 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
1185 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1187 EXTENDS : {$$=registry_getobjectclass();}
1188 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1190 EXTENDS_LIST : {$$=list_new();}
1191 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1193 IMPLEMENTS_LIST : {$$=list_new();}
1194 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1196 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
1197 EXTENDS IMPLEMENTS_LIST
1198 '{' {startclass($1,$3,$4,$5, 0);}
1199 MAYBE_DECLARATION_LIST
1202 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
1204 '{' {startclass($1,$3,0,$4,1);}
1205 MAYBE_IDECLARATION_LIST
1208 /* ------------ classes and interfaces (body) -------------- */
1210 MAYBE_DECLARATION_LIST :
1211 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1212 DECLARATION_LIST : DECLARATION
1213 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1215 DECLARATION : SLOT_DECLARATION
1216 DECLARATION : FUNCTION_DECLARATION
1218 /* ------------ classes and interfaces (body, slots ) ------- */
1220 VARCONST: "var" | "const"
1221 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1223 memberinfo_t* info = memberinfo_register(state->clsinfo, $3->text, MEMBER_SLOT);
1229 t=abc_class_slot(state->cls, $3->text, &m);
1231 t=abc_class_slot(state->cls, $3->text, 0);
1233 if($2->type==KW_CONST) {
1234 t->kind= TRAIT_CONST;
1236 info->slot = t->slot_id;
1237 if($5.c && !is_pushundefined($5.c)) {
1239 c = abc_getlocal_0(c);
1240 c = code_append(c, $5.c);
1241 c = converttype(c, $5.t, $4);
1242 c = abc_setslot(c, t->slot_id);
1243 //c = abc_setproperty(c, $3->text);
1244 state->cls_init = code_append(state->cls_init, c);
1248 /* ------------ constants -------------------------------------- */
1250 MAYBESTATICCONSTANT: {$$=0;}
1251 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1253 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1254 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1255 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1256 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1257 STATICCONSTANT : T_STRING {$$ = constant_new_string($1);}
1258 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1259 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1260 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1261 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1263 /* ------------ classes and interfaces (body, functions) ------- */
1265 // non-vararg version
1267 memset(&$$,0,sizeof($$));
1269 MAYBE_PARAM_LIST: PARAM_LIST {
1274 MAYBE_PARAM_LIST: "..." PARAM {
1275 memset(&$$,0,sizeof($$));
1277 list_append($$.list, $2);
1279 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1282 list_append($$.list, $4);
1286 PARAM_LIST: PARAM_LIST ',' PARAM {
1288 list_append($$.list, $3);
1291 memset(&$$,0,sizeof($$));
1292 list_append($$.list, $1);
1294 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1295 $$ = malloc(sizeof(param_t));
1300 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1301 $$ = malloc(sizeof(param_t));
1302 $$->name=$1->text;$$->type = TYPE_ANY;
1305 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1306 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1308 if(!state->m) syntaxerror("internal error: undefined function");
1312 /* ------------- package + class ids --------------- */
1314 CLASS: T_IDENTIFIER {
1316 /* try current package */
1317 $$ = registry_findclass(state->package, $1->text);
1319 /* try explicit imports */
1320 dictentry_t* e = dict_get_slot(state->imports, $1->text);
1324 if(!strcmp(e->key, $1->text)) {
1325 $$ = (classinfo_t*)e->data;
1330 /* try package.* imports */
1331 import_list_t*l = state->wildcard_imports;
1335 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1336 $$ = registry_findclass(l->import->package, $1->text);
1340 /* try global package */
1342 $$ = registry_findclass("", $1->text);
1345 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1348 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1349 $$ = registry_findclass($1->text, $3->text);
1350 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1353 QNAME: PACKAGEANDCLASS
1357 /* ----------function calls, constructor calls ------ */
1359 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1360 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1362 MAYBE_EXPRESSION_LIST : {$$=0;}
1363 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1364 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1365 typedcode_t*t = malloc(sizeof(typedcode_t));
1367 list_append($$, t);}
1368 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1369 typedcode_t*t = malloc(sizeof(typedcode_t));
1371 list_append($$, t);}
1373 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1377 /* TODO: why do we have to *find* our own classes? */
1378 $$.c = abc_findpropstrict2($$.c, &m);
1380 typedcode_list_t*l = $3;
1383 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1387 $$.c = abc_constructprop2($$.c, &m, len);
1391 /* TODO: use abc_call (for calling local variables),
1392 abc_callstatic (for calling own methods)
1395 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1396 typedcode_list_t*l = $3;
1398 code_t*paramcode = 0;
1400 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1406 if($$.c->opcode == OPCODE_COERCE_A) {
1407 $$.c = code_cutlast($$.c);
1411 multiname_t*name = 0;
1412 if($$.c->opcode == OPCODE_GETPROPERTY) {
1413 name = multiname_clone($$.c->data[0]);
1414 $$.c = code_cutlast($$.c);
1415 $$.c = code_append($$.c, paramcode);
1416 $$.c = abc_callproperty2($$.c, name, len);
1417 } else if($$.c->opcode == OPCODE_GETSLOT) {
1418 int slot = (int)(ptroff_t)$$.c->data[0];
1419 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1420 if(t->kind!=TRAIT_METHOD) {
1421 //flash allows to assign closures to members.
1422 //syntaxerror("not a function");
1425 $$.c = code_cutlast($$.c);
1426 $$.c = code_append($$.c, paramcode);
1427 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1428 $$.c = abc_callproperty2($$.c, name, len);
1430 $$.c = abc_getlocal_0($$.c);
1431 $$.c = code_append($$.c, paramcode);
1432 $$.c = abc_call($$.c, len);
1437 if(TYPE_IS_FUNCTION($1.t) &&
1438 (f = registry_findmember($1.t, "call"))) {
1439 $$.t = f->return_type;
1441 $$.c = abc_coerce_a($$.c);
1446 RETURN: "return" %prec prec_none {
1447 $$ = abc_returnvoid(0);
1449 RETURN: "return" EXPRESSION {
1451 $$ = abc_returnvalue($$);
1453 // ----------------------- expression types -------------------------------------
1455 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1456 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1457 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1459 $$.c = cut_last_push($$.c);
1460 $$.c = code_append($$.c,$3.c);
1463 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1465 // ----------------------- expression evaluation -------------------------------------
1468 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1470 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1474 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1475 $$.t = TYPE_BOOLEAN;
1477 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1478 $$.t = TYPE_BOOLEAN;
1480 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1481 $$.t = TYPE_BOOLEAN;
1483 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1484 $$.t = TYPE_BOOLEAN;
1486 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1487 $$.t = TYPE_BOOLEAN;
1489 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1490 $$.t = TYPE_BOOLEAN;
1492 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1493 $$.t = TYPE_BOOLEAN;
1496 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1498 $$.c = converttype($$.c, $1.t, $$.t);
1499 $$.c = abc_dup($$.c);
1500 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1501 $$.c = cut_last_push($$.c);
1502 $$.c = code_append($$.c,$3.c);
1503 $$.c = converttype($$.c, $3.t, $$.t);
1504 code_t*label = $$.c = abc_label($$.c);
1505 jmp->branch = label;
1508 $$.t = join_types($1.t, $3.t, 'A');
1509 /*printf("%08x:\n",$1.t);
1510 code_dump($1.c, 0, 0, "", stdout);
1511 printf("%08x:\n",$3.t);
1512 code_dump($3.c, 0, 0, "", stdout);
1513 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1515 $$.c = converttype($$.c, $1.t, $$.t);
1516 $$.c = abc_dup($$.c);
1517 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1518 $$.c = cut_last_push($$.c);
1519 $$.c = code_append($$.c,$3.c);
1520 $$.c = converttype($$.c, $3.t, $$.t);
1521 code_t*label = $$.c = abc_label($$.c);
1522 jmp->branch = label;
1525 E : '!' E {$$.c=$2.c;
1526 $$.c = abc_not($$.c);
1527 $$.t = TYPE_BOOLEAN;
1532 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1533 $$.t = join_types($1.t, $3.t, '+');
1535 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1536 $$.t = join_types($1.t, $3.t, '%');
1538 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1539 $$.t = join_types($1.t, $3.t, '*');
1544 E : '(' E ')' {$$=$2;}
1549 $$.c = code_append($$.c, $3.c);
1551 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1552 $$.c = abc_getproperty2($$.c, &m);
1557 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1562 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1564 $$.c = toreadwrite($1.c, c, 0);
1567 E : E "-=" E { code_t*c = $3.c;
1568 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1569 c=abc_subtract_i(c);
1573 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1575 $$.c = toreadwrite($1.c, c, 0);
1578 E : E '=' E { code_t*c = 0;
1579 c = code_append(c, $3.c);
1580 c = converttype(c, $3.t, $1.t);
1581 $$.c = toreadwrite($1.c, c, 1);
1585 // TODO: use inclocal where appropriate
1586 E : E "++" { code_t*c = 0;
1587 classinfo_t*type = $1.t;
1588 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1589 c=abc_increment_i(c);
1594 c=converttype(c, type, $1.t);
1595 $$.c = toreadwrite($1.c, c, 0);
1598 E : E "--" { code_t*c = 0;
1599 classinfo_t*type = $1.t;
1600 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1601 c=abc_increment_i(c);
1606 c=converttype(c, type, $1.t);
1607 $$.c = toreadwrite($1.c, c, 0);
1611 E : E '.' T_IDENTIFIER
1614 memberinfo_t*f = registry_findmember($$.t, $3->text);
1617 $$.c = abc_getslot($$.c, f->slot);
1619 namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
1620 multiname_t m = {QNAME, &ns, 0, $3->text};
1621 $$.c = abc_getproperty2($$.c, &m);
1623 /* determine type */
1625 if(f->kind == MEMBER_METHOD) {
1626 $$.t = TYPE_FUNCTION(f);
1631 $$.c = abc_coerce_a($$.c);
1632 $$.t = registry_getanytype();
1635 namespace_t ns = {ACCESS_PACKAGE, ""};
1636 multiname_t m = {QNAME, &ns, 0, $3->text};
1637 $$.c = abc_getproperty2($$.c, &m);
1638 $$.c = abc_coerce_a($$.c);
1639 $$.t = registry_getanytype();
1643 VAR_READ : T_IDENTIFIER {
1648 if((i = find_variable($1->text, &$$.t)) >= 0) {
1649 // $1 is a local variable
1650 $$.c = abc_getlocal($$.c, i);
1651 } else if((f = registry_findmember(state->clsinfo, $1->text))) {
1652 // $1 is a function in this class
1653 if(f->kind == MEMBER_METHOD) {
1654 $$.t = TYPE_FUNCTION(f);
1659 $$.c = abc_getlocal_0($$.c);
1660 $$.c = abc_getslot($$.c, f->slot);
1662 namespace_t ns = {state->clsinfo->access, ""};
1663 multiname_t m = {QNAME, &ns, 0, $1->text};
1664 $$.c = abc_getlocal_0($$.c);
1665 $$.c = abc_getproperty2($$.c, &m);
1668 // let the avm2 resolve $1
1669 if(strcmp($1->text,"trace"))
1670 warning("Couldn't resolve %s, doing late binding", $1->text);
1671 state->late_binding = 1;
1674 $$.c = abc_findpropstrict($$.c, $1->text);
1675 $$.c = abc_getproperty($$.c, $1->text);
1680 // ------------------------------------------------------------------------------
1683 TYPE : QNAME {$$=$1;}
1684 | '*' {$$=registry_getanytype();}
1685 | "String" {$$=registry_getstringclass();}
1686 | "int" {$$=registry_getintclass();}
1687 | "uint" {$$=registry_getuintclass();}
1688 | "Boolean" {$$=registry_getbooleanclass();}
1689 | "Number" {$$=registry_getnumberclass();}
1691 MAYBETYPE: ':' TYPE {$$=$2;}
1694 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
1695 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1698 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1699 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1700 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1702 //NAMESPACE : {$$=empty_token();}
1703 //NAMESPACE : T_IDENTIFIER {$$=$1};
1705 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1706 //MULTINAME(m, registry_getintclass());
1707 //$$.c = abc_coerce2($$.c, &m); // FIXME
1710 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1713 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1716 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1719 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1722 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1725 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1726 $$.t = TYPE_BOOLEAN;
1728 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1729 $$.t = TYPE_BOOLEAN;
1731 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1735 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1738 //VARIABLE : T_IDENTIFIER
1739 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1740 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1741 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1742 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1743 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1745 GETSET : "get" {$$=$1;}
1747 | {$$=empty_token();}
1749 IDECLARATION : VARIABLE_DECLARATION
1750 IDECLARATION : FUNCTION_DECLARATION
1752 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1753 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1755 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1756 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1759 MAYBE_IDECLARATION_LIST :
1760 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1761 IDECLARATION_LIST : IDECLARATION
1762 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1765 // keywords: as break case catch class const continue default delete do else extends false finally for function if implements import in instanceof interface internal is native new null package private protected public return super switch this throw to true try typeof use var void while with
1766 // syntactic keywords: each get set namespace include dynamic final native override static