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;
59 %token<token> T_IDENTIFIER
60 %token<string> T_STRING
61 %token<token> T_REGEXP
63 %token<number_int> T_INT
64 %token<number_uint> T_UINT
65 %token<number_uint> T_BYTE
66 %token<number_uint> T_SHORT
67 %token<number_float> T_FLOAT
69 %token<token> KW_IMPLEMENTS
70 %token<token> KW_NAMESPACE "namespace"
71 %token<token> KW_PACKAGE "package"
72 %token<token> KW_PROTECTED
73 %token<token> KW_PUBLIC
74 %token<token> KW_PRIVATE
75 %token<token> KW_USE "use"
76 %token<token> KW_INTERNAL
77 %token<token> KW_NEW "new"
78 %token<token> KW_NATIVE
79 %token<token> KW_FUNCTION "function"
80 %token<token> KW_FOR "for"
81 %token<token> KW_CLASS "class"
82 %token<token> KW_CONST "const"
83 %token<token> KW_SET "set"
84 %token<token> KW_STATIC
85 %token<token> KW_IMPORT "import"
86 %token<token> KW_RETURN "return"
87 %token<token> KW_INTERFACE "interface"
88 %token<token> KW_NULL "null"
89 %token<token> KW_VAR "var"
90 %token<token> KW_DYNAMIC
91 %token<token> KW_OVERRIDE
92 %token<token> KW_FINAL
93 %token<token> KW_GET "get"
94 %token<token> KW_EXTENDS
95 %token<token> KW_FALSE "false"
96 %token<token> KW_TRUE "true"
97 %token<token> KW_BOOLEAN "Boolean"
98 %token<token> KW_UINT "uint"
99 %token<token> KW_INT "int"
100 %token<token> KW_WHILE "while"
101 %token<token> KW_NUMBER "Number"
102 %token<token> KW_STRING "String"
103 %token<token> KW_IF "if"
104 %token<token> KW_ELSE "else"
105 %token<token> KW_BREAK "break"
106 %token<token> KW_IS "is"
107 %token<token> KW_AS "as"
109 %token<token> T_EQEQ "=="
110 %token<token> T_EQEQEQ "==="
111 %token<token> T_NE "!="
112 %token<token> T_LE "<="
113 %token<token> T_GE ">="
114 %token<token> T_DIVBY "/="
115 %token<token> T_MODBY "%="
116 %token<token> T_PLUSBY "+="
117 %token<token> T_MINUSBY "-="
118 %token<token> T_SHRBY ">>="
119 %token<token> T_SHLBY "<<="
120 %token<token> T_USHRBY ">>>="
121 %token<token> T_OROR "||"
122 %token<token> T_ANDAND "&&"
123 %token<token> T_COLONCOLON "::"
124 %token<token> T_MINUSMINUS "--"
125 %token<token> T_PLUSPLUS "++"
126 %token<token> T_DOTDOT ".."
127 %token<token> T_DOTDOTDOT "..."
128 %token<token> T_SHL "<<"
129 %token<token> T_USHR ">>>"
130 %token<token> T_SHR ">>"
131 %token<token> T_SEMICOLON ';'
132 %token<token> T_STAR '*'
133 %token<token> T_DOT '.'
135 %type <token> X_IDENTIFIER VARCONST
137 %type <code> CODEPIECE
138 %type <code> CODEBLOCK MAYBECODE
139 %type <token> PACKAGE_DECLARATION
140 %type <token> FUNCTION_DECLARATION
141 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
142 %type <token> CLASS_DECLARATION
143 %type <token> NAMESPACE_DECLARATION
144 %type <token> INTERFACE_DECLARATION
145 %type <code> VOIDEXPRESSION
146 %type <value> EXPRESSION NONCOMMAEXPRESSION
147 %type <value> MAYBEEXPRESSION
149 %type <value> CONSTANT
150 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
151 %type <token> USE_NAMESPACE
152 %type <code> FOR_INIT
154 %type <classinfo> MAYBETYPE
157 %type <params> PARAM_LIST
158 %type <params> MAYBE_PARAM_LIST
159 %type <token> MODIFIERS
160 %type <token> MODIFIER_LIST
161 %type <classinfo_list> IMPLEMENTS_LIST
162 %type <classinfo> EXTENDS
163 %type <classinfo_list> EXTENDS_LIST
164 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
165 %type <classinfo_list> QNAME_LIST
166 %type <classinfo> TYPE
168 //%type <token> VARIABLE
169 %type <value> VAR_READ
171 //%type <token> T_IDENTIFIER
172 %type <token> MODIFIER
173 %type <token> PACKAGE
174 %type <value> FUNCTIONCALL
175 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
177 // precedence: from low to high
178 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
193 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
195 %left prec_belowminus
210 %nonassoc T_IDENTIFIER
211 %left below_semicolon
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "new" "false" "true" "null"
226 static int yyerror(char*s)
228 syntaxerror("%s", s);
230 static token_t* concat2(token_t* t1, token_t* t2)
233 int l1 = strlen(t1->text);
234 int l2 = strlen(t2->text);
235 t->text = malloc(l1+l2+1);
236 memcpy(t->text , t1->text, l1);
237 memcpy(t->text+l1, t2->text, l2);
241 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
244 int l1 = strlen(t1->text);
245 int l2 = strlen(t2->text);
246 int l3 = strlen(t3->text);
247 t->text = malloc(l1+l2+l3+1);
248 memcpy(t->text , t1->text, l1);
249 memcpy(t->text+l1, t2->text, l2);
250 memcpy(t->text+l1+l2, t3->text, l3);
251 t->text[l1+l2+l3] = 0;
254 static char* concat3str(const char* t1, const char* t2, const char* t3)
259 char*text = malloc(l1+l2+l3+1);
260 memcpy(text , t1, l1);
261 memcpy(text+l1, t2, l2);
262 memcpy(text+l1+l2, t3, l3);
267 typedef struct _import {
271 DECLARE_LIST(import);
273 typedef struct _state {
281 /* code that needs to be executed at the start of
282 a method (like initializing local registers) */
285 import_list_t*wildcard_imports;
287 char has_own_imports;
293 code_t*cls_static_init;
304 static state_t* state = 0;
308 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
310 /* warning: list length of namespace set is undefined */
311 #define MULTINAME_LATE(m, access, package) \
312 namespace_t m##_ns = {access, package}; \
313 namespace_set_t m##_nsset; \
314 namespace_list_t m##_l;m##_l.next = 0; \
315 m##_nsset.namespaces = &m##_l; \
316 m##_nsset = m##_nsset; \
317 m##_l.namespace = &m##_ns; \
318 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
320 static state_list_t*state_stack=0;
322 static void new_state()
325 NEW(state_list_t, sl);
327 state_t*oldstate = state;
329 memcpy(s, state, sizeof(state_t)); //shallow copy
330 sl->next = state_stack;
333 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
336 s->imports = dict_new();
341 state->vars = array_new();
343 state->has_own_imports = 0;
345 static void state_has_imports()
347 state->wildcard_imports = list_clone(state->wildcard_imports);
348 state->imports = dict_clone(state->imports);
349 state->has_own_imports = 1;
352 static void old_state()
354 if(!state_stack || !state_stack->next)
355 syntaxerror("invalid nesting");
356 state_t*oldstate = state;
357 state_list_t*old = state_stack;
358 state_stack = state_stack->next;
360 state = state_stack->state;
361 /*if(state->initcode) {
362 printf("residual initcode\n");
363 code_dump(state->initcode, 0, 0, "", stdout);
365 if(oldstate->has_own_imports) {
366 list_free(oldstate->wildcard_imports);
367 dict_destroy(oldstate->imports);oldstate->imports=0;
369 state->initcode = code_append(state->initcode, oldstate->initcode);
371 void initialize_state()
375 state->file = abc_file_new();
376 state->file->flags &= ~ABCFILE_LAZY;
378 state->init = abc_initscript(state->file, 0, 0);
379 code_t*c = state->init->method->body->code;
381 c = abc_getlocal_0(c);
382 c = abc_pushscope(c);
384 /* findpropstrict doesn't just return a scope object- it
385 also makes it "active" somehow. Push local_0 on the
386 scope stack and read it back with findpropstrict, it'll
387 contain properties like "trace". Trying to find the same
388 property on a "vanilla" local_0 yields only a "undefined" */
389 //c = abc_findpropstrict(c, "[package]::trace");
391 /*c = abc_getlocal_0(c);
392 c = abc_findpropstrict(c, "[package]::trace");
394 c = abc_setlocal_1(c);
396 c = abc_pushbyte(c, 0);
397 c = abc_setlocal_2(c);
399 code_t*xx = c = abc_label(c);
400 c = abc_findpropstrict(c, "[package]::trace");
401 c = abc_pushstring(c, "prop:");
402 c = abc_hasnext2(c, 1, 2);
404 c = abc_setlocal_3(c);
405 c = abc_callpropvoid(c, "[package]::trace", 2);
406 c = abc_getlocal_3(c);
408 c = abc_iftrue(c,xx);*/
410 c = abc_findpropstrict(c, "[package]::trace");
411 c = abc_pushstring(c, "[entering global init function]");
412 c = abc_callpropvoid(c, "[package]::trace", 1);
414 state->init->method->body->code = c;
416 void* finalize_state()
418 if(state->level!=1) {
419 syntaxerror("unexpected end of file");
421 abc_method_body_t*m = state->init->method->body;
424 __ findpropstrict(m, "[package]::trace");
425 __ pushstring(m, "[leaving global init function]");
426 __ callpropvoid(m, "[package]::trace", 1);
432 static void startpackage(token_t*t)
435 syntaxerror("Packages can not be nested.");
438 char*name = t?t->text:"";
439 /*printf("entering package \"%s\"\n", name);*/
440 state->package = name;
442 static void endpackage()
444 /*printf("leaving package \"%s\"\n", state->package);*/
449 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
452 syntaxerror("inner classes now allowed");
455 char*classname = name->text;
458 classinfo_list_t*mlist=0;
459 /*printf("entering class %s\n", name->text);
460 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
462 printf(" extends: %s.%s\n", extends->package, extends->name);
463 printf(" implements (%d): ", list_length(implements));
464 for(mlist=implements;mlist;mlist=mlist->next) {
465 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
470 char public=0,internal=0,final=0,sealed=1;
471 for(t=modifiers->tokens;t;t=t->next) {
472 if(t->token->type == KW_INTERNAL) {
473 /* the programmer is being explicit-
474 being internal is the default anyway */
476 } else if(t->token->type == KW_PUBLIC) {
478 } else if(t->token->type == KW_FINAL) {
481 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
485 syntaxerror("public and internal not supported at the same time.");
487 /* create the class name, together with the proper attributes */
491 if(!public && !state->package) {
492 access = ACCESS_PRIVATE; package = current_filename;
493 } else if(!public && state->package) {
494 access = ACCESS_PACKAGEINTERNAL; package = state->package;
495 } else if(state->package) {
496 access = ACCESS_PACKAGE; package = state->package;
498 syntaxerror("public classes only allowed inside a package");
501 if(registry_findclass(package, classname)) {
502 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
505 state->clsinfo = classinfo_register(access, package, classname);
507 MULTINAME(classname2,state->clsinfo);
509 multiname_t*extends2 = sig2mname(extends);
512 state->cls_init = abc_getlocal_0(state->cls_init);
513 state->cls_init = abc_constructsuper(state->cls_init, 0);
516 state->cls = abc_class_new(state->file, &classname2, extends2);
517 if(final) abc_class_final(state->cls);
518 if(sealed) abc_class_sealed(state->cls);
519 if(interface) abc_class_interface(state->cls);
521 for(mlist=implements;mlist;mlist=mlist->next) {
522 MULTINAME(m, mlist->classinfo);
523 abc_class_add_interface(state->cls, &m);
526 /* now write the construction code for this class */
527 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
529 abc_method_body_t*m = state->init->method->body;
530 __ getglobalscope(m);
531 classinfo_t*s = extends;
536 //TODO: take a look at the current scope stack, maybe
537 // we can re-use something
542 multiname_t*s2 = sig2mname(s);
544 multiname_destroy(s2);
546 __ pushscope(m); count++;
547 m->code = m->code->prev->prev; // invert
549 /* continue appending after last op end */
550 while(m->code && m->code->next) m->code = m->code->next;
552 /* TODO: if this is one of *our* classes, we can also
553 do a getglobalscope/getslot <nr> (which references
554 the init function's slots) */
556 __ getlex2(m, extends2);
558 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
559 stack is not the superclass */
560 __ pushscope(m);count++;
563 /* notice: we get a verify error #1107 if the top element on the scope
564 stack is not the global object */
566 __ pushscope(m);count++;
568 __ newclass(m,state->cls);
572 __ setslot(m, slotindex);
574 /* flash.display.MovieClip handling */
575 if(!globalclass && public && classinfo_equals(registry_getMovieClip(),extends)) {
576 if(state->package && state->package[0]) {
577 globalclass = concat3str(state->package, ".", classname);
579 globalclass = strdup(classname);
582 multiname_destroy(extends2);
585 static void endclass()
587 if(state->cls_init) {
588 if(!state->cls->constructor) {
589 abc_method_body_t*m = abc_class_constructor(state->cls, 0, 0);
590 m->code = code_append(m->code, state->cls_init);
591 m->code = abc_returnvoid(m->code);
593 code_t*c = state->cls->constructor->body->code;
594 c = code_append(state->cls_init, c);
595 state->cls->constructor->body->code = c;
599 if(state->cls_static_init) {
600 if(!state->cls->static_constructor) {
601 abc_method_body_t*m = abc_class_staticconstructor(state->cls, 0, 0);
602 m->code = state->cls_static_init;
604 state->cls->static_constructor->body->code =
605 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
611 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
612 params_t*params, classinfo_t*type)
616 state->function = name->text;
619 syntaxerror("not able to start another method scope");
622 multiname_t*type2 = sig2mname(type);
623 if(!strcmp(state->clsinfo->name,name->text)) {
624 state->m = abc_class_constructor(state->cls, type2, 0);
626 state->minfo = memberinfo_register(state->clsinfo, name->text, MEMBER_METHOD);
627 state->m = abc_class_method(state->cls, type2, name->text, 0);
628 // getslot on a member slot only returns "undefined", so no need
629 // to actually store these
630 //state->minfo->slot = state->m->method->trait->slot_id;
632 if(getset->type == KW_GET) {
633 state->m->method->trait->kind = TRAIT_GETTER;
635 if(getset->type == KW_SET) {
636 state->m->method->trait->kind = TRAIT_SETTER;
638 if(params->varargs) {
639 state->m->method->flags |= METHOD_NEED_REST;
643 for(p=params->list;p;p=p->next) {
644 if(params->varargs && !p->next) {
645 break; //varargs: omit last parameter in function signature
647 multiname_t*m = sig2mname(p->param->type);
648 list_append(state->m->method->parameters, m);
651 /* state->vars is initialized by state_new */
652 array_append(state->vars, "this", state->clsinfo);
653 for(p=params->list;p;p=p->next) {
654 array_append(state->vars, p->param->name, 0);
657 static void endfunction(code_t*body)
660 if(state->late_binding) {
661 c = abc_getlocal_0(c);
662 c = abc_pushscope(c);
664 c = code_append(c, state->initcode);
665 c = code_append(c, body);
667 /* append return if necessary */
668 if(!c || c->opcode != OPCODE_RETURNVOID &&
669 c->opcode != OPCODE_RETURNVALUE)
670 c = abc_returnvoid(c);
672 if(state->m->code) syntaxerror("internal error");
678 static token_t* empty_token()
686 void extend(token_t*list, token_t*add) {
687 list_append(list->tokens,add);
689 list->text = add->text;
691 void extend_s(token_t*list, char*seperator, token_t*add) {
692 list_append(list->tokens,add);
693 char*t1 = list->text;
699 list->text = malloc(l1+l2+l3+1);
700 strcpy(list->text, t1);
701 strcpy(list->text+l1, t2);
702 strcpy(list->text+l1+l2, t3);
703 list->text[l1+l2+l3]=0;
706 static int find_variable(char*name, classinfo_t**m)
708 state_list_t* s = state_stack;
710 int i = array_find(s->state->vars, name);
713 *m = array_getvalue(s->state->vars, i);
715 return i + s->state->local_var_base;
721 static int find_variable_safe(char*name, classinfo_t**m)
723 int i = find_variable(name, m);
725 syntaxerror("undefined variable: %s", name);
728 static char variable_exists(char*name)
730 return array_contains(state->vars, name);
732 static int new_variable(char*name, classinfo_t*type)
734 return array_append(state->vars, name, type) + state->local_var_base;
736 #define TEMPVARNAME "__as3_temp__"
737 static int gettempvar()
739 int i = find_variable(TEMPVARNAME, 0);
741 return new_variable(TEMPVARNAME, 0);
747 code_t* killvars(code_t*c)
750 for(t=0;t<state->vars->num;t++) {
751 classinfo_t*type = array_getvalue(state->vars, t);
752 //do this always, otherwise register types don't match
753 //in the verifier when doing nested loops
754 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
755 c = abc_kill(c, t+state->local_var_base);
761 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
766 void breakjumpsto(code_t*c, code_t*jump)
771 if(c->opcode == OPCODE___BREAK__) {
772 c->opcode = OPCODE_JUMP;
779 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
782 return registry_getanytype();
783 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
784 return registry_getanytype();
787 return registry_getanytype();
789 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
794 /*TODO: can omit this if from is zero? */
795 return abc_coerce_a(c);
797 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
798 MULTINAME(m, TYPE_UINT);
799 return abc_coerce2(c, &m);
801 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
802 MULTINAME(m, TYPE_INT);
803 return abc_coerce2(c, &m);
808 code_t*defaultvalue(code_t*c, classinfo_t*type)
810 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
811 c = abc_pushbyte(c, 0);
812 } else if(TYPE_IS_BOOLEAN(type)) {
813 c = abc_pushfalse(c);
820 char is_pushundefined(code_t*c)
822 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
825 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign)
829 [prefix code] [read instruction]
833 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
836 if(in && in->opcode == OPCODE_COERCE_A) {
837 in = code_cutlast(in);
840 syntaxerror("internal error");
842 /* chop off read instruction */
846 prefix = r->prev;r->prev = 0;
852 /* generate the write instruction, and maybe append a dup to the prefix code */
853 code_t* write = abc_nop(0);
854 if(r->opcode == OPCODE_GETPROPERTY) {
855 write->opcode = OPCODE_SETPROPERTY;
856 multiname_t*m = (multiname_t*)r->data[0];
857 write->data[0] = multiname_clone(m);
859 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
861 prefix = abc_dup(prefix); // we need the object, too
862 } else if(r->opcode == OPCODE_GETSLOT) {
863 write->opcode = OPCODE_SETSLOT;
864 write->data[0] = r->data[0];
866 prefix = abc_dup(prefix); // we need the object, too
867 } else if(r->opcode == OPCODE_GETLOCAL) {
868 write->opcode = OPCODE_SETLOCAL;
869 write->data[0] = r->data[0];
870 } else if(r->opcode == OPCODE_GETLOCAL_0) {
871 write->opcode = OPCODE_SETLOCAL_0;
872 } else if(r->opcode == OPCODE_GETLOCAL_1) {
873 write->opcode = OPCODE_SETLOCAL_1;
874 } else if(r->opcode == OPCODE_GETLOCAL_2) {
875 write->opcode = OPCODE_SETLOCAL_2;
876 } else if(r->opcode == OPCODE_GETLOCAL_3) {
877 write->opcode = OPCODE_SETLOCAL_3;
879 code_dump(r, 0, 0, "", stdout);
880 syntaxerror("illegal lvalue: can't assign a value to this expression");
886 /* read value, modify it with middle part, and write it again,
887 using prefix only once and making sure (by using a temporary
888 register) that the return value is what we just wrote */
890 c = code_append(c, prefix);
891 c = code_append(c, r);
892 c = code_append(c, middlepart);
894 c = abc_setlocal(c, temp);
895 c = code_append(c, write);
896 c = abc_getlocal(c, temp);
897 c = abc_kill(c, temp);
899 /* simpler version: overwrite the value without reading
901 c = code_append(c, prefix);
903 c = code_append(c, middlepart);
904 c = code_append(c, write);
905 c = code_append(c, r);
917 /* ------------ code blocks / statements ---------------- */
921 MAYBECODE: CODE {$$=$1;}
922 MAYBECODE: {$$=code_new();}
924 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
925 CODE: CODEPIECE {$$=$1;}
927 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
928 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
929 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
930 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
931 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
932 CODEPIECE: ';' {$$=code_new();}
933 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
934 CODEPIECE: VOIDEXPRESSION {$$=$1}
935 CODEPIECE: FOR {$$=$1}
936 CODEPIECE: WHILE {$$=$1}
937 CODEPIECE: BREAK {$$=$1}
938 CODEPIECE: RETURN {$$=$1}
939 CODEPIECE: IF {$$=$1}
940 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
941 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
943 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
944 CODEBLOCK : CODEPIECE ';' {$$=$1;}
945 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
947 /* ------------ variables --------------------------- */
949 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
950 | {$$.c=abc_pushundefined(0);
954 VAR : "const" | "var"
955 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
957 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
958 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
960 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
962 if(variable_exists($2->text))
963 syntaxerror("Variable %s already defined", $2->text);
965 if(!is_subtype_of($4.t, $3)) {
966 syntaxerror("Can't convert %s to %s", $4.t->name,
970 int index = new_variable($2->text, $3);
973 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
975 $$ = converttype($$, $4.t, $3);
976 $$ = abc_setlocal($$, index);
978 $$ = defaultvalue(0, $3);
979 $$ = abc_setlocal($$, index);
982 /* push default value for type on stack */
983 state->initcode = defaultvalue(state->initcode, $3);
984 state->initcode = abc_setlocal(state->initcode, index);
986 /* only bother to actually set this variable if its syntax is either
991 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
993 $$ = abc_coerce_a($$);
994 $$ = abc_setlocal($$, index);
1000 /* that's the default for a local register, anyway
1002 state->initcode = abc_pushundefined(state->initcode);
1003 state->initcode = abc_setlocal(state->initcode, index);
1005 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1008 /* ------------ control flow ------------------------- */
1010 MAYBEELSE: %prec prec_none {$$ = code_new();}
1011 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1012 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1014 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1015 $$ = state->initcode;state->initcode=0;
1017 $$ = code_append($$, $4.c);
1018 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1020 $$ = code_append($$, $6);
1022 myjmp = $$ = abc_jump($$, 0);
1024 myif->branch = $$ = abc_label($$);
1026 $$ = code_append($$, $7);
1027 myjmp->branch = $$ = abc_label($$);
1030 $$ = killvars($$);old_state();
1033 FOR_INIT : {$$=code_new();}
1034 FOR_INIT : VARIABLE_DECLARATION
1035 FOR_INIT : VOIDEXPRESSION
1037 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1038 $$ = state->initcode;state->initcode=0;
1040 $$ = code_append($$, $4);
1041 code_t*loopstart = $$ = abc_label($$);
1042 $$ = code_append($$, $6.c);
1043 code_t*myif = $$ = abc_iffalse($$, 0);
1044 $$ = code_append($$, $10);
1045 $$ = code_append($$, $8);
1046 $$ = abc_jump($$, loopstart);
1047 code_t*out = $$ = abc_label($$);
1048 breakjumpsto($$, out);
1051 $$ = killvars($$);old_state();
1054 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1055 $$ = state->initcode;state->initcode=0;
1057 code_t*myjmp = $$ = abc_jump($$, 0);
1058 code_t*loopstart = $$ = abc_label($$);
1059 $$ = code_append($$, $6);
1060 myjmp->branch = $$ = abc_label($$);
1061 $$ = code_append($$, $4.c);
1062 $$ = abc_iftrue($$, loopstart);
1063 code_t*out = $$ = abc_label($$);
1064 breakjumpsto($$, out);
1066 $$ = killvars($$);old_state();
1070 $$ = abc___break__(0);
1073 /* ------------ packages and imports ---------------- */
1075 X_IDENTIFIER: T_IDENTIFIER
1078 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
1079 PACKAGE: X_IDENTIFIER {$$=$1;}
1081 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1082 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
1084 IMPORT : "import" QNAME {
1087 syntaxerror("Couldn't import class\n");
1088 state_has_imports();
1089 dict_put(state->imports, c->name, c);
1092 IMPORT : "import" PACKAGE '.' '*' {
1094 i->package = $2->text;
1095 state_has_imports();
1096 list_append(state->wildcard_imports, i);
1100 /* ------------ classes and interfaces (header) -------------- */
1102 MODIFIERS : {$$=empty_token();}
1103 MODIFIERS : MODIFIER_LIST {$$=$1}
1104 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1105 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
1106 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1108 EXTENDS : {$$=registry_getobjectclass();}
1109 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1111 EXTENDS_LIST : {$$=list_new();}
1112 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1114 IMPLEMENTS_LIST : {$$=list_new();}
1115 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1117 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
1118 EXTENDS IMPLEMENTS_LIST
1119 '{' {startclass($1,$3,$4,$5, 0);}
1120 MAYBE_DECLARATION_LIST
1123 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
1125 '{' {startclass($1,$3,0,$4,1);}
1126 MAYBE_IDECLARATION_LIST
1129 /* ------------ classes and interfaces (body) -------------- */
1131 MAYBE_DECLARATION_LIST :
1132 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1133 DECLARATION_LIST : DECLARATION
1134 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1136 DECLARATION : SLOT_DECLARATION
1137 DECLARATION : FUNCTION_DECLARATION
1139 /* ------------ classes and interfaces (body, slots ) ------- */
1141 VARCONST: "var" | "const"
1142 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1144 memberinfo_t* info = memberinfo_register(state->clsinfo, $3->text, MEMBER_SLOT);
1150 t=abc_class_slot(state->cls, $3->text, &m);
1152 t=abc_class_slot(state->cls, $3->text, 0);
1154 if($2->type==KW_CONST) {
1155 t->kind= TRAIT_CONST;
1157 info->slot = t->slot_id;
1158 if($5.c && !is_pushundefined($5.c)) {
1160 c = abc_getlocal_0(c);
1161 c = code_append(c, $5.c);
1162 c = converttype(c, $5.t, $4);
1163 c = abc_setslot(c, t->slot_id);
1164 //c = abc_setproperty(c, $3->text);
1165 state->cls_init = code_append(state->cls_init, c);
1169 /* ------------ classes and interfaces (body, functions) ------- */
1171 // non-vararg version
1173 memset(&$$,0,sizeof($$));
1175 MAYBE_PARAM_LIST: PARAM_LIST {
1180 MAYBE_PARAM_LIST: "..." PARAM {
1181 memset(&$$,0,sizeof($$));
1183 list_append($$.list, $2);
1185 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1188 list_append($$.list, $4);
1192 PARAM_LIST: PARAM_LIST ',' PARAM {
1194 list_append($$.list, $3);
1197 memset(&$$,0,sizeof($$));
1198 list_append($$.list, $1);
1200 PARAM: T_IDENTIFIER ':' TYPE {
1201 $$ = malloc(sizeof(param_t));
1202 $$->name=$1->text;$$->type = $3;
1204 PARAM: T_IDENTIFIER {
1205 $$ = malloc(sizeof(param_t));
1206 $$->name=$1->text;$$->type = TYPE_ANY;
1209 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1210 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1212 if(!state->m) syntaxerror("internal error: undefined function");
1216 /* ------------- package + class ids --------------- */
1218 CLASS: T_IDENTIFIER {
1220 /* try current package */
1221 $$ = registry_findclass(state->package, $1->text);
1223 /* try explicit imports */
1224 dictentry_t* e = dict_get_slot(state->imports, $1->text);
1228 if(!strcmp(e->key, $1->text)) {
1229 $$ = (classinfo_t*)e->data;
1234 /* try package.* imports */
1235 import_list_t*l = state->wildcard_imports;
1239 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1240 $$ = registry_findclass(l->import->package, $1->text);
1244 /* try global package */
1246 $$ = registry_findclass("", $1->text);
1249 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1252 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1253 $$ = registry_findclass($1->text, $3->text);
1254 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1257 QNAME: PACKAGEANDCLASS
1261 /* ----------function calls, constructor calls ------ */
1263 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1264 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1266 MAYBE_EXPRESSION_LIST : {$$=0;}
1267 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1268 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1269 typedcode_t*t = malloc(sizeof(typedcode_t));
1271 list_append($$, t);}
1272 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1273 typedcode_t*t = malloc(sizeof(typedcode_t));
1275 list_append($$, t);}
1277 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1281 /* TODO: why do we have to *find* our own classes? */
1282 $$.c = abc_findpropstrict2($$.c, &m);
1284 typedcode_list_t*l = $3;
1287 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1291 $$.c = abc_constructprop2($$.c, &m, len);
1295 /* TODO: use abc_call (for calling local variables),
1296 abc_callstatic (for calling own methods)
1299 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1300 typedcode_list_t*l = $3;
1302 code_t*paramcode = 0;
1304 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1310 if($$.c->opcode == OPCODE_COERCE_A) {
1311 $$.c = code_cutlast($$.c);
1315 multiname_t*name = 0;
1316 if($$.c->opcode == OPCODE_GETPROPERTY) {
1317 name = multiname_clone($$.c->data[0]);
1318 } else if($$.c->opcode == OPCODE_GETSLOT) {
1319 int slot = (int)(ptroff_t)$$.c->data[0];
1320 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1321 if(t->kind!=TRAIT_METHOD) {
1322 //flash allows to assign closures to members.
1323 //syntaxerror("not a function");
1327 code_dump($$.c, 0, 0, "", stdout);
1328 syntaxerror("Object is not callable");
1331 $$.c = code_cutlast($$.c);
1332 $$.c = code_append($$.c, paramcode);
1333 //$$.c = abc_callmethod($$.c, m, len); //#1051 illegal early access binding
1334 $$.c = abc_callproperty2($$.c, name, len);
1337 if(TYPE_IS_FUNCTION($1.t) &&
1338 (f = registry_findmember($1.t, "__funcptr__"))) {
1339 $$.t = f->return_type;
1341 $$.c = abc_coerce_a($$.c);
1346 RETURN: "return" %prec prec_none {
1347 $$ = abc_returnvoid(0);
1349 RETURN: "return" EXPRESSION {
1351 $$ = abc_returnvalue($$);
1353 // ----------------------- expression types -------------------------------------
1355 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1356 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1357 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1359 $$.c = cut_last_push($$.c);
1360 $$.c = code_append($$.c,$3.c);
1363 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1365 // ----------------------- expression evaluation -------------------------------------
1368 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1370 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1374 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1375 $$.t = TYPE_BOOLEAN;
1377 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1378 $$.t = TYPE_BOOLEAN;
1380 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1381 $$.t = TYPE_BOOLEAN;
1383 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1384 $$.t = TYPE_BOOLEAN;
1386 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1387 $$.t = TYPE_BOOLEAN;
1389 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1390 $$.t = TYPE_BOOLEAN;
1392 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1393 $$.t = TYPE_BOOLEAN;
1396 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1398 $$.c = converttype($$.c, $1.t, $$.t);
1399 $$.c = abc_dup($$.c);
1400 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1401 $$.c = cut_last_push($$.c);
1402 $$.c = code_append($$.c,$3.c);
1403 $$.c = converttype($$.c, $3.t, $$.t);
1404 code_t*label = $$.c = abc_label($$.c);
1405 jmp->branch = label;
1407 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1409 $$.c = converttype($$.c, $1.t, $$.t);
1410 $$.c = abc_dup($$.c);
1411 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1412 $$.c = cut_last_push($$.c);
1413 $$.c = code_append($$.c,$3.c);
1414 $$.c = converttype($$.c, $3.t, $$.t);
1415 code_t*label = $$.c = abc_label($$.c);
1416 jmp->branch = label;
1419 E : '!' E {$$.c=$2.c;
1420 $$.c = abc_not($$.c);
1421 $$.t = TYPE_BOOLEAN;
1426 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1427 $$.t = join_types($1.t, $3.t, '+');
1429 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1430 $$.t = join_types($1.t, $3.t, '%');
1432 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1433 $$.t = join_types($1.t, $3.t, '*');
1438 E : '(' E ')' {$$=$2;}
1443 $$.c = code_append($$.c, $3.c);
1445 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1446 $$.c = abc_getproperty2($$.c, &m);
1451 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1456 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1458 $$.c = toreadwrite($1.c, c, 0);
1461 E : E "-=" E { code_t*c = $3.c;
1462 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1463 c=abc_subtract_i(c);
1467 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1469 $$.c = toreadwrite($1.c, c, 0);
1472 E : E '=' E { code_t*c = 0;
1473 c = code_append(c, $3.c);
1474 c = converttype(c, $3.t, $1.t);
1475 $$.c = toreadwrite($1.c, c, 1);
1479 // TODO: use inclocal where appropriate
1480 E : E "++" { code_t*c = 0;
1481 classinfo_t*type = $1.t;
1482 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1483 c=abc_increment_i(c);
1488 c=converttype(c, type, $1.t);
1489 $$.c = toreadwrite($1.c, c, 0);
1492 E : E "--" { code_t*c = 0;
1493 classinfo_t*type = $1.t;
1494 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1495 c=abc_increment_i(c);
1500 c=converttype(c, type, $1.t);
1501 $$.c = toreadwrite($1.c, c, 0);
1505 E : E '.' T_IDENTIFIER
1508 memberinfo_t*f = registry_findmember($$.t, $3->text);
1511 $$.c = abc_getslot($$.c, f->slot);
1513 namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
1514 multiname_t m = {QNAME, &ns, 0, $3->text};
1515 $$.c = abc_getproperty2($$.c, &m);
1517 /* determine type */
1519 if(f->kind == MEMBER_METHOD) {
1520 $$.t = TYPE_FUNCTION(f);
1525 $$.c = abc_coerce_a($$.c);
1526 $$.t = registry_getanytype();
1529 namespace_t ns = {ACCESS_PACKAGE, ""};
1530 multiname_t m = {QNAME, &ns, 0, $3->text};
1531 $$.c = abc_getproperty2($$.c, &m);
1532 $$.c = abc_coerce_a($$.c);
1533 $$.t = registry_getanytype();
1537 VAR_READ : T_IDENTIFIER {
1542 if((i = find_variable($1->text, &$$.t)) >= 0) {
1543 // $1 is a local variable
1544 $$.c = abc_getlocal($$.c, i);
1545 } else if((f = registry_findmember(state->clsinfo, $1->text))) {
1546 // $1 is a function in this class
1547 if(f->kind == MEMBER_METHOD) {
1548 $$.t = TYPE_FUNCTION(f);
1553 $$.c = abc_getlocal_0($$.c);
1554 $$.c = abc_getslot($$.c, f->slot);
1556 namespace_t ns = {state->clsinfo->access, ""};
1557 multiname_t m = {QNAME, &ns, 0, $1->text};
1558 $$.c = abc_getlocal_0($$.c);
1559 $$.c = abc_getproperty2($$.c, &m);
1562 // let the avm2 resolve $1
1563 if(strcmp($1->text,"trace"))
1564 warning("Couldn't resolve %s, doing late binding", $1->text);
1565 state->late_binding = 1;
1568 $$.c = abc_findpropstrict($$.c, $1->text);
1569 $$.c = abc_getproperty($$.c, $1->text);
1574 // ------------------------------------------------------------------------------
1577 TYPE : QNAME {$$=$1;}
1578 | '*' {$$=registry_getanytype();}
1579 | "String" {$$=registry_getstringclass();}
1580 | "int" {$$=registry_getintclass();}
1581 | "uint" {$$=registry_getuintclass();}
1582 | "Boolean" {$$=registry_getbooleanclass();}
1583 | "Number" {$$=registry_getnumberclass();}
1585 MAYBETYPE: ':' TYPE {$$=$2;}
1588 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
1589 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1592 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1593 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1594 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1596 //NAMESPACE : {$$=empty_token();}
1597 //NAMESPACE : T_IDENTIFIER {$$=$1};
1599 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1600 //MULTINAME(m, registry_getintclass());
1601 //$$.c = abc_coerce2($$.c, &m); // FIXME
1604 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1607 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1610 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1613 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1616 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1619 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1620 $$.t = TYPE_BOOLEAN;
1622 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1623 $$.t = TYPE_BOOLEAN;
1625 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1629 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1632 //VARIABLE : T_IDENTIFIER
1633 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1634 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1635 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1636 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1637 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1639 GETSET : "get" {$$=$1;}
1641 | {$$=empty_token();}
1643 IDECLARATION : VARIABLE_DECLARATION
1644 IDECLARATION : FUNCTION_DECLARATION
1646 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1647 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1649 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1650 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1653 MAYBE_IDECLARATION_LIST :
1654 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1655 IDECLARATION_LIST : IDECLARATION
1656 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1659 // 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
1660 // syntactic keywords: each get set namespace include dynamic final native override static