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
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_MULBY "*="
118 %token<token> T_PLUSBY "+="
119 %token<token> T_MINUSBY "-="
120 %token<token> T_SHRBY ">>="
121 %token<token> T_SHLBY "<<="
122 %token<token> T_USHRBY ">>>="
123 %token<token> T_OROR "||"
124 %token<token> T_ANDAND "&&"
125 %token<token> T_COLONCOLON "::"
126 %token<token> T_MINUSMINUS "--"
127 %token<token> T_PLUSPLUS "++"
128 %token<token> T_DOTDOT ".."
129 %token<token> T_DOTDOTDOT "..."
130 %token<token> T_SHL "<<"
131 %token<token> T_USHR ">>>"
132 %token<token> T_SHR ">>"
133 %token<token> T_SEMICOLON ';'
134 %token<token> T_STAR '*'
135 %token<token> T_DOT '.'
137 %type <token> X_IDENTIFIER VARCONST
139 %type <code> CODEPIECE
140 %type <code> CODEBLOCK MAYBECODE
141 %type <token> PACKAGE_DECLARATION
142 %type <token> FUNCTION_DECLARATION
143 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
144 %type <token> CLASS_DECLARATION
145 %type <token> NAMESPACE_DECLARATION
146 %type <token> INTERFACE_DECLARATION
147 %type <code> VOIDEXPRESSION
148 %type <value> EXPRESSION NONCOMMAEXPRESSION
149 %type <value> MAYBEEXPRESSION
151 %type <value> CONSTANT
152 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
153 %type <token> USE_NAMESPACE
154 %type <code> FOR_INIT
156 %type <classinfo> MAYBETYPE
159 %type <params> PARAM_LIST
160 %type <params> MAYBE_PARAM_LIST
161 %type <token> MODIFIERS
162 %type <token> MODIFIER_LIST
163 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
164 %type <classinfo_list> IMPLEMENTS_LIST
165 %type <classinfo> EXTENDS
166 %type <classinfo_list> EXTENDS_LIST
167 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
168 %type <classinfo_list> QNAME_LIST
169 %type <classinfo> TYPE
171 //%type <token> VARIABLE
172 %type <value> VAR_READ
174 //%type <token> T_IDENTIFIER
175 %type <token> MODIFIER
176 %type <token> PACKAGE
177 %type <value> FUNCTIONCALL
178 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
180 // precedence: from low to high
181 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
185 %right '=' "/=" "%=" "*=" "+=" "-=" ">>=" "<<=" ">>>="
191 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
193 %left prec_belowminus
208 %nonassoc T_IDENTIFIER
209 %left below_semicolon
214 // needed for "return" precedence:
215 %nonassoc T_STRING T_REGEXP
216 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
217 %nonassoc "new" "false" "true" "null"
224 static int yyerror(char*s)
226 syntaxerror("%s", s);
228 static token_t* concat2(token_t* t1, token_t* t2)
231 int l1 = strlen(t1->text);
232 int l2 = strlen(t2->text);
233 t->text = malloc(l1+l2+1);
234 memcpy(t->text , t1->text, l1);
235 memcpy(t->text+l1, t2->text, l2);
239 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
242 int l1 = strlen(t1->text);
243 int l2 = strlen(t2->text);
244 int l3 = strlen(t3->text);
245 t->text = malloc(l1+l2+l3+1);
246 memcpy(t->text , t1->text, l1);
247 memcpy(t->text+l1, t2->text, l2);
248 memcpy(t->text+l1+l2, t3->text, l3);
249 t->text[l1+l2+l3] = 0;
252 static char* concat3str(const char* t1, const char* t2, const char* t3)
257 char*text = malloc(l1+l2+l3+1);
258 memcpy(text , t1, l1);
259 memcpy(text+l1, t2, l2);
260 memcpy(text+l1+l2, t3, l3);
265 typedef struct _import {
269 DECLARE_LIST(import);
271 typedef struct _state {
279 /* code that needs to be executed at the start of
280 a method (like initializing local registers) */
283 import_list_t*wildcard_imports;
285 char has_own_imports;
291 code_t*cls_static_init;
301 typedef struct _global {
305 static global_t*global = 0;
306 static state_t* state = 0;
310 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
312 /* warning: list length of namespace set is undefined */
313 #define MULTINAME_LATE(m, access, package) \
314 namespace_t m##_ns = {access, package}; \
315 namespace_set_t m##_nsset; \
316 namespace_list_t m##_l;m##_l.next = 0; \
317 m##_nsset.namespaces = &m##_l; \
318 m##_nsset = m##_nsset; \
319 m##_l.namespace = &m##_ns; \
320 multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
322 static state_list_t*state_stack=0;
324 static void init_globals()
326 global = rfx_calloc(sizeof(global_t));
329 static void new_state()
332 NEW(state_list_t, sl);
334 state_t*oldstate = state;
336 memcpy(s, state, sizeof(state_t)); //shallow copy
337 sl->next = state_stack;
340 s->imports = dict_new();
345 state->vars = dict_new();
347 state->has_own_imports = 0;
349 static void state_has_imports()
351 state->wildcard_imports = list_clone(state->wildcard_imports);
352 state->imports = dict_clone(state->imports);
353 state->has_own_imports = 1;
356 static void old_state()
358 if(!state_stack || !state_stack->next)
359 syntaxerror("invalid nesting");
360 state_t*oldstate = state;
361 state_list_t*old = state_stack;
362 state_stack = state_stack->next;
364 state = state_stack->state;
365 /*if(state->initcode) {
366 printf("residual initcode\n");
367 code_dump(state->initcode, 0, 0, "", stdout);
369 if(oldstate->has_own_imports) {
370 list_free(oldstate->wildcard_imports);
371 dict_destroy(oldstate->imports);oldstate->imports=0;
373 state->initcode = code_append(state->initcode, oldstate->initcode);
375 void initialize_state()
380 state->file = abc_file_new();
381 state->file->flags &= ~ABCFILE_LAZY;
383 state->init = abc_initscript(state->file, 0, 0);
384 code_t*c = state->init->method->body->code;
386 c = abc_getlocal_0(c);
387 c = abc_pushscope(c);
389 /* findpropstrict doesn't just return a scope object- it
390 also makes it "active" somehow. Push local_0 on the
391 scope stack and read it back with findpropstrict, it'll
392 contain properties like "trace". Trying to find the same
393 property on a "vanilla" local_0 yields only a "undefined" */
394 //c = abc_findpropstrict(c, "[package]::trace");
396 /*c = abc_getlocal_0(c);
397 c = abc_findpropstrict(c, "[package]::trace");
399 c = abc_setlocal_1(c);
401 c = abc_pushbyte(c, 0);
402 c = abc_setlocal_2(c);
404 code_t*xx = c = abc_label(c);
405 c = abc_findpropstrict(c, "[package]::trace");
406 c = abc_pushstring(c, "prop:");
407 c = abc_hasnext2(c, 1, 2);
409 c = abc_setlocal_3(c);
410 c = abc_callpropvoid(c, "[package]::trace", 2);
411 c = abc_getlocal_3(c);
413 c = abc_iftrue(c,xx);*/
415 c = abc_findpropstrict(c, "[package]::trace");
416 c = abc_pushstring(c, "[entering global init function]");
417 c = abc_callpropvoid(c, "[package]::trace", 1);
419 state->init->method->body->code = c;
421 void* finalize_state()
423 if(state->level!=1) {
424 syntaxerror("unexpected end of file");
426 abc_method_body_t*m = state->init->method->body;
429 __ findpropstrict(m, "[package]::trace");
430 __ pushstring(m, "[leaving global init function]");
431 __ callpropvoid(m, "[package]::trace", 1);
437 static void startpackage(token_t*t)
440 syntaxerror("Packages can not be nested.");
443 char*name = t?t->text:"";
444 /*printf("entering package \"%s\"\n", name);*/
445 state->package = name;
447 static void endpackage()
449 /*printf("leaving package \"%s\"\n", state->package);*/
454 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
457 syntaxerror("inner classes now allowed");
460 char*classname = name->text;
463 classinfo_list_t*mlist=0;
464 /*printf("entering class %s\n", name->text);
465 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
467 printf(" extends: %s.%s\n", extends->package, extends->name);
468 printf(" implements (%d): ", list_length(implements));
469 for(mlist=implements;mlist;mlist=mlist->next) {
470 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
475 char public=0,internal=0,final=0,sealed=1;
476 for(t=modifiers->tokens;t;t=t->next) {
477 if(t->token->type == KW_INTERNAL) {
478 /* the programmer is being explicit-
479 being internal is the default anyway */
481 } else if(t->token->type == KW_PUBLIC) {
483 } else if(t->token->type == KW_FINAL) {
486 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
490 syntaxerror("public and internal not supported at the same time.");
492 /* create the class name, together with the proper attributes */
496 if(!public && !state->package) {
497 access = ACCESS_PRIVATE; package = current_filename;
498 } else if(!public && state->package) {
499 access = ACCESS_PACKAGEINTERNAL; package = state->package;
500 } else if(state->package) {
501 access = ACCESS_PACKAGE; package = state->package;
503 syntaxerror("public classes only allowed inside a package");
506 if(registry_findclass(package, classname)) {
507 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
510 state->clsinfo = classinfo_register(access, package, classname);
512 MULTINAME(classname2,state->clsinfo);
514 multiname_t*extends2 = sig2mname(extends);
517 state->cls_init = abc_getlocal_0(state->cls_init);
518 state->cls_init = abc_constructsuper(state->cls_init, 0);
521 state->cls = abc_class_new(state->file, &classname2, extends2);
522 if(final) abc_class_final(state->cls);
523 if(sealed) abc_class_sealed(state->cls);
524 if(interface) abc_class_interface(state->cls);
526 for(mlist=implements;mlist;mlist=mlist->next) {
527 MULTINAME(m, mlist->classinfo);
528 abc_class_add_interface(state->cls, &m);
531 /* now write the construction code for this class */
532 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
534 abc_method_body_t*m = state->init->method->body;
535 __ getglobalscope(m);
536 classinfo_t*s = extends;
541 //TODO: take a look at the current scope stack, maybe
542 // we can re-use something
547 multiname_t*s2 = sig2mname(s);
549 multiname_destroy(s2);
551 __ pushscope(m); count++;
552 m->code = m->code->prev->prev; // invert
554 /* continue appending after last op end */
555 while(m->code && m->code->next) m->code = m->code->next;
557 /* TODO: if this is one of *our* classes, we can also
558 do a getglobalscope/getslot <nr> (which references
559 the init function's slots) */
561 __ getlex2(m, extends2);
563 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
564 stack is not the superclass */
565 __ pushscope(m);count++;
568 /* notice: we get a verify error #1107 if the top element on the scope
569 stack is not the global object */
571 __ pushscope(m);count++;
573 __ newclass(m,state->cls);
577 __ setslot(m, slotindex);
579 /* flash.display.MovieClip handling */
580 if(!globalclass && public && classinfo_equals(registry_getMovieClip(),extends)) {
581 if(state->package && state->package[0]) {
582 globalclass = concat3str(state->package, ".", classname);
584 globalclass = strdup(classname);
587 multiname_destroy(extends2);
590 static void endclass()
592 if(state->cls_init) {
593 if(!state->cls->constructor) {
594 abc_method_body_t*m = abc_class_constructor(state->cls, 0, 0);
595 m->code = code_append(m->code, state->cls_init);
596 m->code = abc_returnvoid(m->code);
598 code_t*c = state->cls->constructor->body->code;
599 c = code_append(state->cls_init, c);
600 state->cls->constructor->body->code = c;
604 if(state->cls_static_init) {
605 if(!state->cls->static_constructor) {
606 abc_method_body_t*m = abc_class_staticconstructor(state->cls, 0, 0);
607 m->code = state->cls_static_init;
609 state->cls->static_constructor->body->code =
610 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
617 static token_t* empty_token()
625 void extend(token_t*list, token_t*add) {
626 list_append(list->tokens,add);
628 list->text = add->text;
630 void extend_s(token_t*list, char*seperator, token_t*add) {
631 list_append(list->tokens,add);
632 char*t1 = list->text;
638 list->text = malloc(l1+l2+l3+1);
639 strcpy(list->text, t1);
640 strcpy(list->text+l1, t2);
641 strcpy(list->text+l1+l2, t3);
642 list->text[l1+l2+l3]=0;
645 typedef struct _variable {
650 static int find_variable(char*name, classinfo_t**m)
652 state_list_t* s = state_stack;
654 variable_t*v = dict_lookup(s->state->vars, name);
665 static int find_variable_safe(char*name, classinfo_t**m)
667 int i = find_variable(name, m);
669 syntaxerror("undefined variable: %s", name);
672 static char variable_exists(char*name)
674 return dict_lookup(state->vars, name)!=0;
676 static int new_variable(char*name, classinfo_t*type)
679 v->index = global->variable_count;
681 dict_put(state->vars, name, v);
682 return global->variable_count++;
684 #define TEMPVARNAME "__as3_temp__"
685 static int gettempvar()
687 int i = find_variable(TEMPVARNAME, 0);
689 return new_variable(TEMPVARNAME, 0);
695 code_t* killvars(code_t*c)
698 for(t=0;t<state->vars->hashsize;t++) {
699 dictentry_t*e =state->vars->slots[t];
701 variable_t*v = (variable_t*)e->data;
702 //do this always, otherwise register types don't match
703 //in the verifier when doing nested loops
704 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
705 c = abc_kill(c, v->index);
713 static void check_constant_against_type(classinfo_t*t, constant_t*c)
715 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
716 if(TYPE_IS_NUMBER(t)) {
717 xassert(c->type == CONSTANT_FLOAT
718 || c->type == CONSTANT_INT
719 || c->type == CONSTANT_UINT);
720 } else if(TYPE_IS_UINT(t)) {
721 xassert(c->type == CONSTANT_UINT ||
722 (c->type == CONSTANT_INT && c->i>0));
723 } else if(TYPE_IS_INT(t)) {
724 xassert(c->type == CONSTANT_INT);
725 } else if(TYPE_IS_BOOLEAN(t)) {
726 xassert(c->type == CONSTANT_TRUE
727 || c->type == CONSTANT_FALSE);
731 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
732 params_t*params, classinfo_t*type)
736 global->variable_count = 0;
737 state->function = name->text;
740 syntaxerror("not able to start another method scope");
743 multiname_t*type2 = sig2mname(type);
744 if(!strcmp(state->clsinfo->name,name->text)) {
745 state->m = abc_class_constructor(state->cls, type2, 0);
747 state->minfo = memberinfo_register(state->clsinfo, name->text, MEMBER_METHOD);
748 state->minfo->return_type = type;
749 state->m = abc_class_method(state->cls, type2, name->text, 0);
750 // getslot on a member slot only returns "undefined", so no need
751 // to actually store these
752 //state->minfo->slot = state->m->method->trait->slot_id;
754 if(getset->type == KW_GET) {
755 state->m->method->trait->kind = TRAIT_GETTER;
757 if(getset->type == KW_SET) {
758 state->m->method->trait->kind = TRAIT_SETTER;
760 if(params->varargs) {
761 state->m->method->flags |= METHOD_NEED_REST;
766 for(p=params->list;p;p=p->next) {
767 if(params->varargs && !p->next) {
768 break; //varargs: omit last parameter in function signature
770 multiname_t*m = sig2mname(p->param->type);
771 list_append(state->m->method->parameters, m);
772 if(p->param->value) {
773 check_constant_against_type(p->param->type, p->param->value);
774 opt=1;list_append(state->m->method->optional_parameters, p->param->value);
776 syntaxerror("non-optional parameter not allowed after optional parameters");
780 /* state->vars is initialized by state_new */
781 if(new_variable("this", state->clsinfo)!=0) syntaxerror("Internal error");
783 for(p=params->list;p;p=p->next) {
784 new_variable(p->param->name, p->param->type);
787 static void endfunction(code_t*body)
790 if(state->late_binding) {
791 c = abc_getlocal_0(c);
792 c = abc_pushscope(c);
794 c = code_append(c, state->initcode);
795 c = code_append(c, body);
797 /* append return if necessary */
798 if(!c || c->opcode != OPCODE_RETURNVOID &&
799 c->opcode != OPCODE_RETURNVALUE)
800 c = abc_returnvoid(c);
802 if(state->m->code) syntaxerror("internal error");
809 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
814 void breakjumpsto(code_t*c, code_t*jump)
819 if(c->opcode == OPCODE___BREAK__) {
820 c->opcode = OPCODE_JUMP;
827 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
830 return registry_getanytype();
831 if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
832 return registry_getanytype();
835 return registry_getanytype();
837 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
842 /*TODO: can omit this if from is zero? */
843 return abc_coerce_a(c);
845 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
846 MULTINAME(m, TYPE_UINT);
847 return abc_coerce2(c, &m);
849 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
850 MULTINAME(m, TYPE_INT);
851 return abc_coerce2(c, &m);
856 code_t*defaultvalue(code_t*c, classinfo_t*type)
858 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
859 c = abc_pushbyte(c, 0);
860 } else if(TYPE_IS_BOOLEAN(type)) {
861 c = abc_pushfalse(c);
868 char is_pushundefined(code_t*c)
870 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
873 void parserassert(int b)
875 if(!b) syntaxerror("internal error: assertion failed");
878 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
882 [prefix code] [read instruction]
886 [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
889 if(in && in->opcode == OPCODE_COERCE_A) {
890 in = code_cutlast(in);
893 syntaxerror("internal error");
895 /* chop off read instruction */
899 prefix = r->prev;r->prev = 0;
905 char use_temp_var = readbefore;
907 /* generate the write instruction, and maybe append a dup to the prefix code */
908 code_t* write = abc_nop(0);
909 if(r->opcode == OPCODE_GETPROPERTY) {
910 write->opcode = OPCODE_SETPROPERTY;
911 multiname_t*m = (multiname_t*)r->data[0];
912 write->data[0] = multiname_clone(m);
914 syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
917 prefix = abc_dup(prefix); // we need the object, too
919 } else if(r->opcode == OPCODE_GETSLOT) {
920 write->opcode = OPCODE_SETSLOT;
921 write->data[0] = r->data[0];
924 prefix = abc_dup(prefix); // we need the object, too
926 } else if(r->opcode == OPCODE_GETLOCAL) {
927 write->opcode = OPCODE_SETLOCAL;
928 write->data[0] = r->data[0];
929 } else if(r->opcode == OPCODE_GETLOCAL_0) {
930 write->opcode = OPCODE_SETLOCAL_0;
931 } else if(r->opcode == OPCODE_GETLOCAL_1) {
932 write->opcode = OPCODE_SETLOCAL_1;
933 } else if(r->opcode == OPCODE_GETLOCAL_2) {
934 write->opcode = OPCODE_SETLOCAL_2;
935 } else if(r->opcode == OPCODE_GETLOCAL_3) {
936 write->opcode = OPCODE_SETLOCAL_3;
938 code_dump(r, 0, 0, "", stdout);
939 syntaxerror("illegal lvalue: can't assign a value to this expression");
946 /* with getproperty/getslot, we have to be extra careful not
947 to execute the read code twice, as it might have side-effects
948 (e.g. if the property is in fact a setter/getter combination)
950 So read the value, modify it, and write it again,
951 using prefix only once and making sure (by using a temporary
952 register) that the return value is what we just wrote */
954 c = code_append(c, prefix);
955 c = code_append(c, r);
958 c = abc_setlocal(c, temp);
960 c = code_append(c, middlepart);
963 c = abc_setlocal(c, temp);
965 c = code_append(c, write);
966 c = abc_getlocal(c, temp);
967 c = abc_kill(c, temp);
969 /* if we're allowed to execute the read code twice *and*
970 the middlepart doesn't modify the code, things are easier.
972 code_t* r2 = code_dup(r);
973 //c = code_append(c, prefix);
974 parserassert(!prefix);
975 c = code_append(c, r);
976 c = code_append(c, middlepart);
977 c = code_append(c, write);
978 c = code_append(c, r2);
981 /* even smaller version: overwrite the value without reading
984 c = code_append(c, prefix);
987 c = code_append(c, middlepart);
988 c = code_append(c, write);
989 c = code_append(c, r);
1001 /* ------------ code blocks / statements ---------------- */
1005 MAYBECODE: CODE {$$=$1;}
1006 MAYBECODE: {$$=code_new();}
1008 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1009 CODE: CODEPIECE {$$=$1;}
1011 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
1012 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
1013 CODEPIECE: FUNCTION_DECLARATION {$$=code_new();/*enters a scope*/}
1014 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1015 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
1016 CODEPIECE: ';' {$$=code_new();}
1017 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
1018 CODEPIECE: VOIDEXPRESSION {$$=$1}
1019 CODEPIECE: FOR {$$=$1}
1020 CODEPIECE: WHILE {$$=$1}
1021 CODEPIECE: BREAK {$$=$1}
1022 CODEPIECE: RETURN {$$=$1}
1023 CODEPIECE: IF {$$=$1}
1024 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1025 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
1027 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
1028 CODEBLOCK : CODEPIECE ';' {$$=$1;}
1029 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
1031 /* ------------ variables --------------------------- */
1033 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1034 | {$$.c=abc_pushundefined(0);
1038 VAR : "const" | "var"
1039 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1041 VARIABLE_LIST: ONE_VARIABLE {$$ = $1;}
1042 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1044 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1046 if(variable_exists($2->text))
1047 syntaxerror("Variable %s already defined", $2->text);
1049 if(!is_subtype_of($4.t, $3)) {
1050 syntaxerror("Can't convert %s to %s", $4.t->name,
1054 int index = new_variable($2->text, $3);
1057 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1059 $$ = converttype($$, $4.t, $3);
1060 $$ = abc_setlocal($$, index);
1062 $$ = defaultvalue(0, $3);
1063 $$ = abc_setlocal($$, index);
1066 /* if this is a typed variable:
1067 push default value for type on stack */
1069 state->initcode = defaultvalue(state->initcode, $3);
1070 state->initcode = abc_setlocal(state->initcode, index);
1073 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1075 $$ = abc_coerce_a($$);
1076 $$ = abc_setlocal($$, index);
1082 /* that's the default for a local register, anyway
1084 state->initcode = abc_pushundefined(state->initcode);
1085 state->initcode = abc_setlocal(state->initcode, index);
1087 //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1090 /* ------------ control flow ------------------------- */
1092 MAYBEELSE: %prec prec_none {$$ = code_new();}
1093 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1094 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1096 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1097 $$ = state->initcode;state->initcode=0;
1099 $$ = code_append($$, $4.c);
1100 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1102 $$ = code_append($$, $6);
1104 myjmp = $$ = abc_jump($$, 0);
1106 myif->branch = $$ = abc_label($$);
1108 $$ = code_append($$, $7);
1109 myjmp->branch = $$ = abc_label($$);
1112 $$ = killvars($$);old_state();
1115 FOR_INIT : {$$=code_new();}
1116 FOR_INIT : VARIABLE_DECLARATION
1117 FOR_INIT : VOIDEXPRESSION
1119 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1120 $$ = state->initcode;state->initcode=0;
1122 $$ = code_append($$, $4);
1123 code_t*loopstart = $$ = abc_label($$);
1124 $$ = code_append($$, $6.c);
1125 code_t*myif = $$ = abc_iffalse($$, 0);
1126 $$ = code_append($$, $10);
1127 $$ = code_append($$, $8);
1128 $$ = abc_jump($$, loopstart);
1129 code_t*out = $$ = abc_label($$);
1130 breakjumpsto($$, out);
1133 $$ = killvars($$);old_state();
1136 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1137 $$ = state->initcode;state->initcode=0;
1139 code_t*myjmp = $$ = abc_jump($$, 0);
1140 code_t*loopstart = $$ = abc_label($$);
1141 $$ = code_append($$, $6);
1142 myjmp->branch = $$ = abc_label($$);
1143 $$ = code_append($$, $4.c);
1144 $$ = abc_iftrue($$, loopstart);
1145 code_t*out = $$ = abc_label($$);
1146 breakjumpsto($$, out);
1148 $$ = killvars($$);old_state();
1152 $$ = abc___break__(0);
1155 /* ------------ packages and imports ---------------- */
1157 X_IDENTIFIER: T_IDENTIFIER
1160 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
1161 PACKAGE: X_IDENTIFIER {$$=$1;}
1163 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1164 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
1166 IMPORT : "import" QNAME {
1169 syntaxerror("Couldn't import class\n");
1170 state_has_imports();
1171 dict_put(state->imports, c->name, c);
1174 IMPORT : "import" PACKAGE '.' '*' {
1176 i->package = $2->text;
1177 state_has_imports();
1178 list_append(state->wildcard_imports, i);
1182 /* ------------ classes and interfaces (header) -------------- */
1184 MODIFIERS : {$$=empty_token();}
1185 MODIFIERS : MODIFIER_LIST {$$=$1}
1186 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1187 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
1188 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1190 EXTENDS : {$$=registry_getobjectclass();}
1191 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1193 EXTENDS_LIST : {$$=list_new();}
1194 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1196 IMPLEMENTS_LIST : {$$=list_new();}
1197 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1199 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
1200 EXTENDS IMPLEMENTS_LIST
1201 '{' {startclass($1,$3,$4,$5, 0);}
1202 MAYBE_DECLARATION_LIST
1205 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
1207 '{' {startclass($1,$3,0,$4,1);}
1208 MAYBE_IDECLARATION_LIST
1211 /* ------------ classes and interfaces (body) -------------- */
1213 MAYBE_DECLARATION_LIST :
1214 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1215 DECLARATION_LIST : DECLARATION
1216 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1218 DECLARATION : SLOT_DECLARATION
1219 DECLARATION : FUNCTION_DECLARATION
1221 /* ------------ classes and interfaces (body, slots ) ------- */
1223 VARCONST: "var" | "const"
1224 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1226 memberinfo_t* info = memberinfo_register(state->clsinfo, $3->text, MEMBER_SLOT);
1232 t=abc_class_slot(state->cls, $3->text, &m);
1234 t=abc_class_slot(state->cls, $3->text, 0);
1236 if($2->type==KW_CONST) {
1237 t->kind= TRAIT_CONST;
1239 info->slot = t->slot_id;
1240 if($5.c && !is_pushundefined($5.c)) {
1242 c = abc_getlocal_0(c);
1243 c = code_append(c, $5.c);
1244 c = converttype(c, $5.t, $4);
1245 c = abc_setslot(c, t->slot_id);
1246 //c = abc_setproperty(c, $3->text);
1247 state->cls_init = code_append(state->cls_init, c);
1251 /* ------------ constants -------------------------------------- */
1253 MAYBESTATICCONSTANT: {$$=0;}
1254 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1256 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1257 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1258 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1259 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1260 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1261 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1262 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1263 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1264 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1266 /* ------------ classes and interfaces (body, functions) ------- */
1268 // non-vararg version
1270 memset(&$$,0,sizeof($$));
1272 MAYBE_PARAM_LIST: PARAM_LIST {
1277 MAYBE_PARAM_LIST: "..." PARAM {
1278 memset(&$$,0,sizeof($$));
1280 list_append($$.list, $2);
1282 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1285 list_append($$.list, $4);
1289 PARAM_LIST: PARAM_LIST ',' PARAM {
1291 list_append($$.list, $3);
1294 memset(&$$,0,sizeof($$));
1295 list_append($$.list, $1);
1297 PARAM: T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1298 $$ = malloc(sizeof(param_t));
1303 PARAM: T_IDENTIFIER MAYBESTATICCONSTANT {
1304 $$ = malloc(sizeof(param_t));
1306 $$->type = TYPE_ANY;
1310 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1311 MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}'
1313 if(!state->m) syntaxerror("internal error: undefined function");
1317 /* ------------- package + class ids --------------- */
1319 CLASS: T_IDENTIFIER {
1321 /* try current package */
1322 $$ = registry_findclass(state->package, $1->text);
1324 /* try explicit imports */
1325 dictentry_t* e = dict_get_slot(state->imports, $1->text);
1329 if(!strcmp(e->key, $1->text)) {
1330 $$ = (classinfo_t*)e->data;
1335 /* try package.* imports */
1336 import_list_t*l = state->wildcard_imports;
1340 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1341 $$ = registry_findclass(l->import->package, $1->text);
1345 /* try global package */
1347 $$ = registry_findclass("", $1->text);
1350 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1353 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1354 $$ = registry_findclass($1->text, $3->text);
1355 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1358 QNAME: PACKAGEANDCLASS
1362 /* ----------function calls, constructor calls ------ */
1364 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1365 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1367 MAYBE_EXPRESSION_LIST : {$$=0;}
1368 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1369 EXPRESSION_LIST : NONCOMMAEXPRESSION {$$=list_new();
1370 typedcode_t*t = malloc(sizeof(typedcode_t));
1372 list_append($$, t);}
1373 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1374 typedcode_t*t = malloc(sizeof(typedcode_t));
1376 list_append($$, t);}
1378 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1382 /* TODO: why do we have to *find* our own classes? */
1383 $$.c = abc_findpropstrict2($$.c, &m);
1385 typedcode_list_t*l = $3;
1388 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1392 $$.c = abc_constructprop2($$.c, &m, len);
1396 /* TODO: use abc_call (for calling local variables),
1397 abc_callstatic (for calling own methods)
1400 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1401 typedcode_list_t*l = $3;
1403 code_t*paramcode = 0;
1405 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1411 if($$.c->opcode == OPCODE_COERCE_A) {
1412 $$.c = code_cutlast($$.c);
1416 multiname_t*name = 0;
1417 if($$.c->opcode == OPCODE_GETPROPERTY) {
1418 name = multiname_clone($$.c->data[0]);
1419 $$.c = code_cutlast($$.c);
1420 $$.c = code_append($$.c, paramcode);
1421 $$.c = abc_callproperty2($$.c, name, len);
1422 } else if($$.c->opcode == OPCODE_GETSLOT) {
1423 int slot = (int)(ptroff_t)$$.c->data[0];
1424 trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1425 if(t->kind!=TRAIT_METHOD) {
1426 //flash allows to assign closures to members.
1427 //syntaxerror("not a function");
1430 $$.c = code_cutlast($$.c);
1431 $$.c = code_append($$.c, paramcode);
1432 //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1433 $$.c = abc_callproperty2($$.c, name, len);
1435 $$.c = abc_getlocal_0($$.c);
1436 $$.c = code_append($$.c, paramcode);
1437 $$.c = abc_call($$.c, len);
1442 if(TYPE_IS_FUNCTION($1.t) &&
1443 (f = registry_findmember($1.t, "call"))) {
1444 $$.t = f->return_type;
1446 $$.c = abc_coerce_a($$.c);
1451 RETURN: "return" %prec prec_none {
1452 $$ = abc_returnvoid(0);
1454 RETURN: "return" EXPRESSION {
1456 $$ = abc_returnvalue($$);
1458 // ----------------------- expression types -------------------------------------
1460 NONCOMMAEXPRESSION : E %prec prec_belowminus {$$=$1;}
1461 EXPRESSION : E %prec prec_belowminus {$$ = $1;}
1462 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1464 $$.c = cut_last_push($$.c);
1465 $$.c = code_append($$.c,$3.c);
1468 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1470 // ----------------------- expression evaluation -------------------------------------
1473 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1475 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1479 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1480 $$.t = TYPE_BOOLEAN;
1482 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1483 $$.t = TYPE_BOOLEAN;
1485 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1486 $$.t = TYPE_BOOLEAN;
1488 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1489 $$.t = TYPE_BOOLEAN;
1491 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1492 $$.t = TYPE_BOOLEAN;
1494 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1495 $$.t = TYPE_BOOLEAN;
1497 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1498 $$.t = TYPE_BOOLEAN;
1501 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1503 $$.c = converttype($$.c, $1.t, $$.t);
1504 $$.c = abc_dup($$.c);
1505 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1506 $$.c = cut_last_push($$.c);
1507 $$.c = code_append($$.c,$3.c);
1508 $$.c = converttype($$.c, $3.t, $$.t);
1509 code_t*label = $$.c = abc_label($$.c);
1510 jmp->branch = label;
1513 $$.t = join_types($1.t, $3.t, 'A');
1514 /*printf("%08x:\n",$1.t);
1515 code_dump($1.c, 0, 0, "", stdout);
1516 printf("%08x:\n",$3.t);
1517 code_dump($3.c, 0, 0, "", stdout);
1518 printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1520 $$.c = converttype($$.c, $1.t, $$.t);
1521 $$.c = abc_dup($$.c);
1522 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1523 $$.c = cut_last_push($$.c);
1524 $$.c = code_append($$.c,$3.c);
1525 $$.c = converttype($$.c, $3.t, $$.t);
1526 code_t*label = $$.c = abc_label($$.c);
1527 jmp->branch = label;
1530 E : '!' E {$$.c=$2.c;
1531 $$.c = abc_not($$.c);
1532 $$.t = TYPE_BOOLEAN;
1537 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1538 $$.t = join_types($1.t, $3.t, '+');
1540 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1541 $$.t = join_types($1.t, $3.t, '%');
1543 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1544 $$.t = join_types($1.t, $3.t, '*');
1549 E : '(' E ')' {$$=$2;}
1554 $$.c = code_append($$.c, $3.c);
1556 MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1557 $$.c = abc_getproperty2($$.c, &m);
1562 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1563 c=abc_multiply_i(c);
1567 c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1568 $$.c = toreadwrite($1.c, c, 0, 0);
1572 code_t*c = abc_modulo($3.c);
1573 c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1574 $$.c = toreadwrite($1.c, c, 0, 0);
1578 code_t*c = abc_lshift($3.c);
1579 c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1580 $$.c = toreadwrite($1.c, c, 0, 0);
1584 code_t*c = abc_rshift($3.c);
1585 c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1586 $$.c = toreadwrite($1.c, c, 0, 0);
1590 code_t*c = abc_urshift($3.c);
1591 c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1592 $$.c = toreadwrite($1.c, c, 0, 0);
1596 code_t*c = abc_divide($3.c);
1597 c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1598 $$.c = toreadwrite($1.c, c, 0, 0);
1603 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1608 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1610 $$.c = toreadwrite($1.c, c, 0, 0);
1613 E : E "-=" E { code_t*c = $3.c;
1614 if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1615 c=abc_subtract_i(c);
1619 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1621 $$.c = toreadwrite($1.c, c, 0, 0);
1624 E : E '=' E { code_t*c = 0;
1625 c = code_append(c, $3.c);
1626 c = converttype(c, $3.t, $1.t);
1627 $$.c = toreadwrite($1.c, c, 1, 0);
1631 // TODO: use inclocal where appropriate
1632 E : E "++" { code_t*c = 0;
1633 classinfo_t*type = $1.t;
1634 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1635 c=abc_increment_i(c);
1640 c=converttype(c, type, $1.t);
1641 $$.c = toreadwrite($1.c, c, 0, 1);
1644 E : E "--" { code_t*c = 0;
1645 classinfo_t*type = $1.t;
1646 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1647 c=abc_decrement_i(c);
1652 c=converttype(c, type, $1.t);
1653 $$.c = toreadwrite($1.c, c, 0, 1);
1657 E : "++" E { code_t*c = 0;
1658 classinfo_t*type = $2.t;
1659 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1660 c=abc_increment_i(c);
1665 c=converttype(c, type, $2.t);
1666 $$.c = toreadwrite($2.c, c, 0, 0);
1670 E : "--" E { code_t*c = 0;
1671 classinfo_t*type = $2.t;
1672 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1673 c=abc_decrement_i(c);
1678 c=converttype(c, type, $2.t);
1679 $$.c = toreadwrite($2.c, c, 0, 0);
1683 E : E '.' T_IDENTIFIER
1686 memberinfo_t*f = registry_findmember($$.t, $3->text);
1689 $$.c = abc_getslot($$.c, f->slot);
1691 namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
1692 multiname_t m = {QNAME, &ns, 0, $3->text};
1693 $$.c = abc_getproperty2($$.c, &m);
1695 /* determine type */
1697 if(f->kind == MEMBER_METHOD) {
1698 $$.t = TYPE_FUNCTION(f);
1703 $$.c = abc_coerce_a($$.c);
1704 $$.t = registry_getanytype();
1707 namespace_t ns = {ACCESS_PACKAGE, ""};
1708 multiname_t m = {QNAME, &ns, 0, $3->text};
1709 $$.c = abc_getproperty2($$.c, &m);
1710 $$.c = abc_coerce_a($$.c);
1711 $$.t = registry_getanytype();
1715 VAR_READ : T_IDENTIFIER {
1720 if((i = find_variable($1->text, &$$.t)) >= 0) {
1721 // $1 is a local variable
1722 $$.c = abc_getlocal($$.c, i);
1723 } else if((f = registry_findmember(state->clsinfo, $1->text))) {
1724 // $1 is a function in this class
1725 if(f->kind == MEMBER_METHOD) {
1726 $$.t = TYPE_FUNCTION(f);
1731 $$.c = abc_getlocal_0($$.c);
1732 $$.c = abc_getslot($$.c, f->slot);
1734 namespace_t ns = {state->clsinfo->access, ""};
1735 multiname_t m = {QNAME, &ns, 0, $1->text};
1736 $$.c = abc_getlocal_0($$.c);
1737 $$.c = abc_getproperty2($$.c, &m);
1740 // let the avm2 resolve $1
1741 if(strcmp($1->text,"trace"))
1742 warning("Couldn't resolve %s, doing late binding", $1->text);
1743 state->late_binding = 1;
1746 $$.c = abc_findpropstrict($$.c, $1->text);
1747 $$.c = abc_getproperty($$.c, $1->text);
1752 // ------------------------------------------------------------------------------
1755 TYPE : QNAME {$$=$1;}
1756 | '*' {$$=registry_getanytype();}
1757 | "String" {$$=registry_getstringclass();}
1758 | "int" {$$=registry_getintclass();}
1759 | "uint" {$$=registry_getuintclass();}
1760 | "Boolean" {$$=registry_getbooleanclass();}
1761 | "Number" {$$=registry_getnumberclass();}
1763 MAYBETYPE: ':' TYPE {$$=$2;}
1766 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
1767 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1770 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1771 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1772 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1774 //NAMESPACE : {$$=empty_token();}
1775 //NAMESPACE : T_IDENTIFIER {$$=$1};
1777 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1778 //MULTINAME(m, registry_getintclass());
1779 //$$.c = abc_coerce2($$.c, &m); // FIXME
1782 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1785 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1788 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1791 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1794 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1797 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1798 $$.t = TYPE_BOOLEAN;
1800 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1801 $$.t = TYPE_BOOLEAN;
1803 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1807 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1810 //VARIABLE : T_IDENTIFIER
1811 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1812 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1813 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1814 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1815 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1817 GETSET : "get" {$$=$1;}
1819 | {$$=empty_token();}
1821 IDECLARATION : VARIABLE_DECLARATION
1822 IDECLARATION : FUNCTION_DECLARATION
1824 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1825 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1827 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1828 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1831 MAYBE_IDECLARATION_LIST :
1832 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1833 IDECLARATION_LIST : IDECLARATION
1834 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1837 // 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
1838 // syntactic keywords: each get set namespace include dynamic final native override static