implemented arrays
[swftools.git] / lib / as3 / parser.y
1 /* parser.lex
2
3    Routines for compiling Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
9  
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.
14
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.
19
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 */
23 %{
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
27 #include "abc.h"
28 #include "pool.h"
29 #include "files.h"
30 #include "tokenizer.h"
31 #include "registry.h"
32 #include "code.h"
33 #include "opcodes.h"
34
35 %}
36
37 //%glr-parser
38 //%expect-rr 1
39 %error-verbose
40
41 %union tokenunion {
42     enum yytokentype token;
43     int flags;
44
45     classinfo_t*classinfo;
46     classinfo_list_t*classinfo_list;
47
48     int number_int;
49     unsigned int number_uint;
50     double number_float;
51     code_t*code;
52     typedcode_t value;
53     typedcode_list_t*value_list;
54     param_t* param;
55     params_t params;
56     string_t str;
57     char*id;
58     constant_t*constant;
59 }
60
61
62 %token<id> T_IDENTIFIER
63 %token<str> T_STRING
64 %token<token> T_REGEXP
65 %token<token> T_EMPTY
66 %token<number_int> T_INT
67 %token<number_uint> T_UINT
68 %token<number_uint> T_BYTE
69 %token<number_uint> T_SHORT
70 %token<number_float> T_FLOAT
71
72 %token<token> KW_IMPLEMENTS
73 %token<token> KW_NAMESPACE "namespace"
74 %token<token> KW_PACKAGE "package"
75 %token<token> KW_PROTECTED
76 %token<token> KW_PUBLIC
77 %token<token> KW_PRIVATE
78 %token<token> KW_USE "use"
79 %token<token> KW_INTERNAL
80 %token<token> KW_NEW "new"
81 %token<token> KW_NATIVE
82 %token<token> KW_FUNCTION "function"
83 %token<token> KW_UNDEFINED "undefined"
84 %token<token> KW_FOR "for"
85 %token<token> KW_CLASS "class"
86 %token<token> KW_CONST "const"
87 %token<token> KW_SET "set"
88 %token<token> KW_VOID "void"
89 %token<token> KW_STATIC
90 %token<token> KW_INSTANCEOF "instanceof"
91 %token<token> KW_IMPORT "import"
92 %token<token> KW_RETURN "return"
93 %token<token> KW_TYPEOF "typeof"
94 %token<token> KW_INTERFACE "interface"
95 %token<token> KW_NULL "null"
96 %token<token> KW_VAR "var"
97 %token<token> KW_DYNAMIC
98 %token<token> KW_OVERRIDE
99 %token<token> KW_FINAL
100 %token<token> KW_GET "get"
101 %token<token> KW_SUPER "super"
102 %token<token> KW_EXTENDS
103 %token<token> KW_FALSE "false"
104 %token<token> KW_TRUE "true"
105 %token<token> KW_BOOLEAN "Boolean"
106 %token<token> KW_UINT "uint"
107 %token<token> KW_INT "int"
108 %token<token> KW_WHILE "while"
109 %token<token> KW_NUMBER "Number"
110 %token<token> KW_STRING "String"
111 %token<token> KW_DELETE "delete"
112 %token<token> KW_IF "if"
113 %token<token> KW_ELSE  "else"
114 %token<token> KW_BREAK   "break"
115 %token<token> KW_IS "is"
116 %token<token> KW_AS "as"
117
118 %token<token> T_EQEQ "=="
119 %token<token> T_EQEQEQ "==="
120 %token<token> T_NE "!="
121 %token<token> T_NEE "!=="
122 %token<token> T_LE "<="
123 %token<token> T_GE ">="
124 %token<token> T_DIVBY "/=" 
125 %token<token> T_MODBY "%="
126 %token<token> T_MULBY "*="
127 %token<token> T_PLUSBY "+=" 
128 %token<token> T_MINUSBY "-="
129 %token<token> T_SHRBY ">>="
130 %token<token> T_SHLBY "<<="
131 %token<token> T_USHRBY ">>>="
132 %token<token> T_OROR "||"
133 %token<token> T_ANDAND "&&"
134 %token<token> T_COLONCOLON "::"
135 %token<token> T_MINUSMINUS "--"
136 %token<token> T_PLUSPLUS "++"
137 %token<token> T_DOTDOT ".."
138 %token<token> T_DOTDOTDOT "..."
139 %token<token> T_SHL "<<"
140 %token<token> T_USHR ">>>"
141 %token<token> T_SHR ">>"
142
143 %type <id> X_IDENTIFIER PACKAGE
144 %type <token> VARCONST
145 %type <code> CODE
146 %type <code> CODEPIECE
147 %type <code> CODEBLOCK MAYBECODE
148 %type <token> PACKAGE_DECLARATION
149 %type <token> FUNCTION_DECLARATION
150 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
151 %type <token> CLASS_DECLARATION
152 %type <token> NAMESPACE_DECLARATION
153 %type <token> INTERFACE_DECLARATION
154 %type <code> VOIDEXPRESSION
155 %type <value> EXPRESSION NONCOMMAEXPRESSION
156 %type <value> MAYBEEXPRESSION
157 %type <value> E DELETE
158 %type <value> CONSTANT
159 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
160 %type <token> USE_NAMESPACE
161 %type <code> FOR_INIT
162 %type <token> IMPORT
163 %type <classinfo> MAYBETYPE
164 %type <token> GETSET
165 %type <param> PARAM
166 %type <params> PARAM_LIST
167 %type <params> MAYBE_PARAM_LIST
168 %type <flags> MAYBE_MODIFIERS
169 %type <flags> MODIFIER_LIST
170 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
171 %type <classinfo_list> IMPLEMENTS_LIST
172 %type <classinfo> EXTENDS
173 %type <classinfo_list> EXTENDS_LIST
174 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
175 %type <classinfo_list> QNAME_LIST
176 %type <classinfo> TYPE
177 %type <token> VAR
178 //%type <token> VARIABLE
179 %type <value> VAR_READ
180 %type <value> NEW
181 //%type <token> T_IDENTIFIER
182 %type <token> MODIFIER
183 %type <value> FUNCTIONCALL
184 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
185
186 // precedence: from low to high
187
188 %left prec_none
189
190 %left below_semicolon
191 %left ';'
192 %left ','
193 %nonassoc below_assignment // for ?:, contrary to spec
194 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
195 %right '?' ':'
196 %left "||"
197 %left "&&"
198 %nonassoc '|'
199 %nonassoc '^'
200 %nonassoc '&'
201 %nonassoc "==" "!=" "===" "!=="
202 %nonassoc "is" "as"
203 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
204 %left "<<" ">>" ">>>" 
205 %left below_minus
206 %left '-' '+'
207 %left '/' '*' '%'
208 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
209 %left "--" "++" 
210 %left '[' ']' '{' "new" '.' ".." "::"
211 %nonassoc T_IDENTIFIER
212 %left below_else
213 %nonassoc "else"
214 %left '('
215
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 "false" "true" "null" "undefined" "super"
220
221      
222 %{
223
224 static int yyerror(char*s)
225 {
226    syntaxerror("%s", s); 
227 }
228 static char* concat3str(const char* t1, const char* t2, const char* t3)
229 {
230     int l1 = strlen(t1);
231     int l2 = strlen(t2);
232     int l3 = strlen(t3);
233     char*text = malloc(l1+l2+l3+1);
234     memcpy(text   , t1, l1);
235     memcpy(text+l1, t2, l2);
236     memcpy(text+l1+l2, t3, l3);
237     text[l1+l2+l3] = 0;
238     return text;
239 }
240
241 typedef struct _import {
242     char*package;
243 } import_t;
244
245 DECLARE_LIST(import);
246
247 typedef struct _classstate {
248     /* class data */
249     classinfo_t*info;
250     abc_class_t*abc;
251     code_t*init;
252     code_t*static_init;
253     char has_constructor;
254 } classstate_t;
255
256 typedef struct _methodstate {
257     /* method data */
258     memberinfo_t*info;
259     char late_binding;
260     /* code that needs to be executed at the start of
261        a method (like initializing local registers) */
262     code_t*initcode;
263     char is_constructor;
264     char has_super;
265 } methodstate_t;
266
267 typedef struct _state {
268     int level;
269
270     char*package;     
271     import_list_t*wildcard_imports;
272     dict_t*imports;
273     char has_own_imports;
274   
275     classstate_t*cls;   
276     methodstate_t*method;
277     
278     dict_t*vars;
279 } state_t;
280
281 typedef struct _global {
282     abc_file_t*file;
283     abc_script_t*init;
284
285     int variable_count;
286 } global_t;
287
288 static global_t*global = 0;
289 static state_t* state = 0;
290
291 DECLARE_LIST(state);
292
293 #define MULTINAME(m,x) \
294     multiname_t m;\
295     namespace_t m##_ns;\
296     registry_fill_multiname(&m, &m##_ns, x);
297                     
298 #define MEMBER_MULTINAME(m,f,n) \
299     multiname_t m;\
300     namespace_t m##_ns;\
301     if(f) { \
302         m##_ns.access = flags2access(f->flags); \
303         m##_ns.name = ""; \
304         m.type = QNAME; \
305         m.ns = &m##_ns; \
306         m.namespace_set = 0; \
307         m.name = f->name; \
308     } else { \
309         m.type = MULTINAME; \
310         m.ns =0; \
311         m.namespace_set = &nopackage_namespace_set; \
312         m.name = n; \
313     }
314
315 /* warning: list length of namespace set is undefined */
316 #define MULTINAME_LATE(m, access, package) \
317     namespace_t m##_ns = {access, package}; \
318     namespace_set_t m##_nsset; \
319     namespace_list_t m##_l;m##_l.next = 0; \
320     m##_nsset.namespaces = &m##_l; \
321     m##_nsset = m##_nsset; \
322     m##_l.namespace = &m##_ns; \
323     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
324
325 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
326 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
327 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
328 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
329 static namespace_list_t nl4 = {&ns4,0};
330 static namespace_list_t nl3 = {&ns3,&nl4};
331 static namespace_list_t nl2 = {&ns2,&nl3};
332 static namespace_list_t nl1 = {&ns1,&nl2};
333 static namespace_set_t nopackage_namespace_set = {&nl1};
334
335 static state_list_t*state_stack=0;
336     
337 static void init_globals()
338 {
339     global = rfx_calloc(sizeof(global_t));
340 }
341
342 static void new_state()
343 {
344     NEW(state_t, s);
345     NEW(state_list_t, sl);
346
347     state_t*oldstate = state;
348     if(state)
349         memcpy(s, state, sizeof(state_t)); //shallow copy
350     sl->next = state_stack;
351     sl->state = s;
352     if(!s->imports) {
353         s->imports = dict_new();
354     }
355     state_stack = sl;
356     state = s;
357     state->level++;
358     state->has_own_imports = 0;    
359     state->vars = dict_new();
360 }
361 static void state_has_imports()
362 {
363     state->wildcard_imports = list_clone(state->wildcard_imports);
364     state->imports = dict_clone(state->imports);
365     state->has_own_imports = 1;
366 }
367
368 static void old_state()
369 {
370     if(!state_stack || !state_stack->next)
371         syntaxerror("invalid nesting");
372     state_t*oldstate = state;
373     state_list_t*old = state_stack;
374     state_stack = state_stack->next;
375     free(old);
376     state = state_stack->state;
377     /*if(state->method->initcode) {
378         printf("residual initcode\n");
379         code_dump(state->method->initcode, 0, 0, "", stdout);
380     }*/
381     if(oldstate->has_own_imports) {
382         list_free(oldstate->wildcard_imports);
383         dict_destroy(oldstate->imports);oldstate->imports=0;
384     }
385 }
386 void initialize_state()
387 {
388     init_globals();
389     new_state();
390
391     global->file = abc_file_new();
392     global->file->flags &= ~ABCFILE_LAZY;
393     
394     global->init = abc_initscript(global->file, 0);
395     code_t*c = global->init->method->body->code;
396
397     c = abc_getlocal_0(c);
398     c = abc_pushscope(c);
399   
400     /* findpropstrict doesn't just return a scope object- it
401        also makes it "active" somehow. Push local_0 on the
402        scope stack and read it back with findpropstrict, it'll
403        contain properties like "trace". Trying to find the same
404        property on a "vanilla" local_0 yields only a "undefined" */
405     //c = abc_findpropstrict(c, "[package]::trace");
406     
407     /*c = abc_getlocal_0(c);
408     c = abc_findpropstrict(c, "[package]::trace");
409     c = abc_coerce_a(c);
410     c = abc_setlocal_1(c);
411
412     c = abc_pushbyte(c, 0);
413     c = abc_setlocal_2(c);
414    
415     code_t*xx = c = abc_label(c);
416     c = abc_findpropstrict(c, "[package]::trace");
417     c = abc_pushstring(c, "prop:");
418     c = abc_hasnext2(c, 1, 2);
419     c = abc_dup(c);
420     c = abc_setlocal_3(c);
421     c = abc_callpropvoid(c, "[package]::trace", 2);
422     c = abc_getlocal_3(c);
423     c = abc_kill(c, 3);
424     c = abc_iftrue(c,xx);*/
425
426     c = abc_findpropstrict(c, "[package]::trace");
427     c = abc_pushstring(c, "[entering global init function]");
428     c = abc_callpropvoid(c, "[package]::trace", 1);
429     
430     global->init->method->body->code = c;
431 }
432 void* finalize_state()
433 {
434     if(state->level!=1) {
435         syntaxerror("unexpected end of file");
436     }
437     abc_method_body_t*m = global->init->method->body;
438     //__ popscope(m);
439     
440     __ findpropstrict(m, "[package]::trace");
441     __ pushstring(m, "[leaving global init function]");
442     __ callpropvoid(m, "[package]::trace", 1);
443     __ returnvoid(m);
444     return global->file;
445 }
446
447
448 static void startpackage(char*name)
449 {
450     if(state->package) {
451         syntaxerror("Packages can not be nested."); 
452     } 
453     new_state();
454     /*printf("entering package \"%s\"\n", name);*/
455     state->package = name;
456 }
457 static void endpackage()
458 {
459     /*printf("leaving package \"%s\"\n", state->package);*/
460     old_state();
461 }
462
463 char*globalclass=0;
464 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
465 {
466     if(state->cls) {
467         syntaxerror("inner classes now allowed"); 
468     }
469     new_state();
470     state->cls = rfx_calloc(sizeof(classstate_t));
471
472     token_list_t*t=0;
473     classinfo_list_t*mlist=0;
474     /*printf("entering class %s\n", name);
475     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
476     if(extends) 
477         printf("  extends: %s.%s\n", extends->package, extends->name);
478     printf("  implements (%d): ", list_length(implements));
479     for(mlist=implements;mlist;mlist=mlist->next)  {
480         printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
481     }
482     printf("\n");
483     */
484
485     if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
486         syntaxerror("invalid modifier(s)");
487
488     if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
489         syntaxerror("public and internal not supported at the same time.");
490
491     /* create the class name, together with the proper attributes */
492     int access=0;
493     char*package=0;
494
495     if(!(flags&FLAG_PUBLIC) && !state->package) {
496         access = ACCESS_PRIVATE; package = current_filename;
497     } else if(!(flags&FLAG_PUBLIC) && state->package) {
498         access = ACCESS_PACKAGEINTERNAL; package = state->package;
499     } else if(state->package) {
500         access = ACCESS_PACKAGE; package = state->package;
501     } else {
502         syntaxerror("public classes only allowed inside a package");
503     }
504
505     if(registry_findclass(package, classname)) {
506         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
507     }
508    
509
510     /* build info struct */
511     int num_interfaces = (list_length(implements));
512     state->cls->info = classinfo_register(access, package, classname, num_interfaces);
513     state->cls->info->superclass = extends?extends:TYPE_OBJECT;
514     int pos = 0;
515     classinfo_list_t*l = implements;
516     for(l=implements;l;l=l->next) {
517         state->cls->info->interfaces[pos++] = l->classinfo;
518     }
519     
520     multiname_t*extends2 = sig2mname(extends);
521
522     MULTINAME(classname2,state->cls->info);
523
524     /*if(extends) {
525         state->cls_init = abc_getlocal_0(state->cls_init);
526         state->cls_init = abc_constructsuper(state->cls_init, 0);
527     }*/
528
529     state->cls->abc = abc_class_new(global->file, &classname2, extends2);
530     if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
531     if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
532     if(interface) {
533         state->cls->info->flags |= CLASS_INTERFACE;
534         abc_class_interface(state->cls->abc);
535     }
536
537     abc_class_protectedNS(state->cls->abc, classname);
538
539     for(mlist=implements;mlist;mlist=mlist->next) {
540         MULTINAME(m, mlist->classinfo);
541         abc_class_add_interface(state->cls->abc, &m);
542     }
543
544     /* now write the construction code for this class */
545     int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
546
547     abc_method_body_t*m = global->init->method->body;
548     __ getglobalscope(m);
549     classinfo_t*s = extends;
550
551     int count=0;
552     
553     while(s) {
554         //TODO: take a look at the current scope stack, maybe 
555         //      we can re-use something
556         s = s->superclass;
557         if(!s) 
558         break;
559        
560         multiname_t*s2 = sig2mname(s);
561         __ getlex2(m, s2);
562         multiname_destroy(s2);
563
564         __ pushscope(m); count++;
565         m->code = m->code->prev->prev; // invert
566     }
567     /* continue appending after last op end */
568     while(m->code && m->code->next) m->code = m->code->next; 
569
570     /* TODO: if this is one of *our* classes, we can also 
571              do a getglobalscope/getslot <nr> (which references
572              the init function's slots) */
573     if(extends2) {
574         __ getlex2(m, extends2);
575         __ dup(m);
576         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
577            stack is not the superclass */
578         __ pushscope(m);count++;
579     } else {
580         __ pushnull(m);
581         /* notice: we get a verify error #1107 if the top element on the scope 
582            stack is not the global object */
583         __ getlocal_0(m);
584         __ pushscope(m);count++;
585     }
586     __ newclass(m,state->cls->abc);
587     while(count--) {
588         __ popscope(m);
589     }
590     __ setslot(m, slotindex);
591
592     /* flash.display.MovieClip handling */
593     if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
594         if(state->package && state->package[0]) {
595             globalclass = concat3str(state->package, ".", classname);
596         } else {
597             globalclass = strdup(classname);
598         }
599     }
600     multiname_destroy(extends2);
601 }
602
603 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
604 {
605     c = code_append(c, initcode);
606     c = code_append(c, body);
607     /* append return if necessary */
608     if(!c || c->opcode != OPCODE_RETURNVOID && 
609              c->opcode != OPCODE_RETURNVALUE) {
610         c = abc_returnvoid(c);
611     }
612     return c;
613 }
614
615 static void endclass()
616 {
617     if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
618         code_t*c = 0;
619         c = abc_getlocal_0(c);
620         c = abc_constructsuper(c, 0);
621         state->cls->init = code_append(state->cls->init, c);
622     }
623
624     if(state->cls->init) {
625         abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
626         m->body->code = wrap_function(0, state->cls->init, m->body->code);
627     }
628     if(state->cls->static_init) {
629         abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
630         m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
631     } else {
632         // handy for scope testing 
633         /*code_t*c = 0;
634         c = abc_pop(c);
635         c = abc_pop(c);
636         abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
637     }
638
639     old_state();
640 }
641
642 typedef struct _variable {
643     int index;
644     classinfo_t*type;
645 } variable_t;
646
647 static int find_variable(char*name, classinfo_t**m)
648 {
649     state_list_t* s = state_stack;
650     while(s) {
651         variable_t*v = 0;
652         if(s->state->method)
653             v = dict_lookup(s->state->vars, name);
654         if(v) {
655             if(m) {
656                 *m = v->type;
657             }
658             return v->index;
659         }
660         s = s->next;
661     }
662     return -1;
663
664 static int find_variable_safe(char*name, classinfo_t**m)
665 {
666     int i = find_variable(name, m);
667     if(i<0)
668         syntaxerror("undefined variable: %s", name);
669     return i;
670 }
671 static char variable_exists(char*name) 
672 {
673     return dict_lookup(state->vars, name)!=0;
674 }
675 static int new_variable(char*name, classinfo_t*type)
676 {
677     NEW(variable_t, v);
678     v->index = global->variable_count;
679     v->type = type;
680     dict_put(state->vars, name, v);
681     return global->variable_count++;
682 }
683 #define TEMPVARNAME "__as3_temp__"
684 static int gettempvar()
685 {
686     int i = find_variable(TEMPVARNAME, 0);
687     if(i<0) {
688         i = new_variable(TEMPVARNAME, 0);
689     }
690     return i;
691 }
692
693 code_t* killvars(code_t*c) 
694 {
695     int t;
696     for(t=0;t<state->vars->hashsize;t++) {
697         dictentry_t*e =state->vars->slots[t];
698         while(e) {
699             variable_t*v = (variable_t*)e->data;
700             //do this always, otherwise register types don't match
701             //in the verifier when doing nested loops
702             //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
703             c = abc_kill(c, v->index);
704             e = e->next;
705         }
706     }
707     return c;
708 }
709
710
711 static void check_constant_against_type(classinfo_t*t, constant_t*c)
712 {
713 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
714    if(TYPE_IS_NUMBER(t)) {
715         xassert(c->type == CONSTANT_FLOAT
716              || c->type == CONSTANT_INT
717              || c->type == CONSTANT_UINT);
718    } else if(TYPE_IS_UINT(t)) {
719         xassert(c->type == CONSTANT_UINT ||
720                (c->type == CONSTANT_INT && c->i>0));
721    } else if(TYPE_IS_INT(t)) {
722         xassert(c->type == CONSTANT_INT);
723    } else if(TYPE_IS_BOOLEAN(t)) {
724         xassert(c->type == CONSTANT_TRUE
725              || c->type == CONSTANT_FALSE);
726    }
727 }
728
729 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
730 {
731     memberinfo_t*minfo = 0;
732     if(getset != KW_GET && getset != KW_SET) {
733         if(registry_findmember(state->cls->info, name)) {
734             syntaxerror("class already contains a member/method called '%s'", name);
735         }
736         minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
737         minfo->return_type = return_type;
738         // getslot on a member slot only returns "undefined", so no need
739         // to actually store these
740         //state->minfo->slot = state->method->abc->method->trait->slot_id;
741     } else {
742         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
743         classinfo_t*type=0;
744         if(getset == KW_GET)
745             type = return_type;
746         else if(params->list)
747             type = params->list->param->type;
748         if((minfo=registry_findmember(state->cls->info, name))) {
749             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
750                 syntaxerror("class already contains a member or method called '%s'", name);
751             if(minfo->kind & gs)
752                 syntaxerror("getter/setter for '%s' already defined", name);
753             /* make a setter or getter into a getset */
754             minfo->kind |= gs;
755             if(!minfo->type) 
756                 minfo->type = type;
757             else
758                 if(type && minfo->type != type)
759                     syntaxerror("different type in getter and setter");
760         } else {
761             minfo = memberinfo_register(state->cls->info, name, gs);
762             minfo->type = type;
763         }
764         /* can't assign a slot as getter and setter might have different slots */
765         //minfo->slot = slot;
766     }
767     if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
768     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
769     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
770     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
771     if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
772     return minfo;
773 }
774
775 static int flags2access(int flags)
776 {
777     int access = 0;
778     if(flags&FLAG_PUBLIC)  {
779         if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
780         access = ACCESS_PACKAGE;
781     } else if(flags&FLAG_PRIVATE) {
782         if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
783         access = ACCESS_PRIVATE;
784     } else if(flags&FLAG_PROTECTED) {
785         if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
786         access = ACCESS_PROTECTED;
787     } else {
788         access = ACCESS_PACKAGEINTERNAL;
789     }
790     return access;
791 }
792
793 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
794                           params_t*params, classinfo_t*return_type)
795 {
796     if(state->method) {
797         syntaxerror("not able to start another method scope");
798     }
799     new_state();
800     state->method = rfx_calloc(sizeof(methodstate_t));
801     state->method->initcode = 0;
802     state->method->is_constructor = !strcmp(state->cls->info->name,name);
803     state->method->has_super = 0;
804     
805     state->cls->has_constructor |= state->method->is_constructor;
806
807     global->variable_count = 0;
808
809     /* state->vars is initialized by state_new */
810     if(new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info)!=0) syntaxerror("Internal error");
811     param_list_t*p=0;
812     for(p=params->list;p;p=p->next) {
813         new_variable(p->param->name, p->param->type);
814     }
815     if(state->method->is_constructor)
816         name = "__as3_constructor__";
817     state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
818 }
819
820 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
821                           params_t*params, classinfo_t*return_type, code_t*body)
822 {
823     namespace_t mname_ns = {flags2access(flags), ""};
824     multiname_t mname = {QNAME, &mname_ns, 0, name};
825
826     abc_method_t*f = 0;
827
828     multiname_t*type2 = sig2mname(return_type);
829     int slot = 0;
830     if(state->method->is_constructor) {
831         f = abc_class_getconstructor(state->cls->abc, type2);
832     } else {
833         if(flags&FLAG_STATIC)
834             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
835         else
836             f = abc_class_method(state->cls->abc, type2, &mname);
837         slot = f->trait->slot_id;
838     }
839     //flash doesn't seem to allow us to access function slots
840     //state->method->info->slot = slot;
841
842     if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
843     if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
844     if(params->varargs) f->flags |= METHOD_NEED_REST;
845
846     char opt=0;
847     param_list_t*p=0;
848     for(p=params->list;p;p=p->next) {
849         if(params->varargs && !p->next) {
850             break; //varargs: omit last parameter in function signature
851         }
852         multiname_t*m = sig2mname(p->param->type);
853         list_append(f->parameters, m);
854         if(p->param->value) {
855             check_constant_against_type(p->param->type, p->param->value);
856             opt=1;list_append(f->optional_parameters, p->param->value);
857         } else if(opt) {
858             syntaxerror("non-optional parameter not allowed after optional parameters");
859         }
860     }
861     f->body->code = body;
862         
863     old_state();
864 }
865
866
867
868 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
869 {
870     return 1; // FIXME
871 }
872
873 void breakjumpsto(code_t*c, code_t*jump) 
874 {
875     while(c->prev) 
876         c=c->prev;
877     while(c) {
878         if(c->opcode == OPCODE___BREAK__) {
879             c->opcode = OPCODE_JUMP;
880             c->branch = jump;
881         }
882         c = c->next;
883     }
884 }
885
886 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
887 {
888     if(!type1 || !type2) 
889         return registry_getanytype();
890     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
891         return registry_getanytype();
892     if(type1 == type2)
893         return type1;
894     return registry_getanytype();
895 }
896 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
897 {
898     if(from==to)
899         return c;
900     if(!to) {
901         return abc_coerce_a(c);
902     }
903     MULTINAME(m, to);
904     if(!from) {
905         // cast an "any" type to a specific type. subject to
906         // runtime exceptions
907         return abc_coerce2(c, &m);
908     }
909     
910     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
911         return abc_coerce2(c, &m);
912     }
913     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
914         return abc_coerce2(c, &m);
915     }
916     /* these are subject to overflow */
917     if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
918         return abc_coerce2(c, &m);
919     }
920     if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
921         return abc_coerce2(c, &m);
922     }
923
924     classinfo_t*supertype = from;
925     while(supertype) {
926         if(supertype == to) {
927              // target type is one of from's superclasses
928              return abc_coerce2(c, &m);
929         }
930         int t=0;
931         while(supertype->interfaces[t]) {
932             if(supertype->interfaces[t]==to) {
933                 // to type is one of from's interfaces
934                 return abc_coerce2(c, &m);
935             }
936             t++;
937         }
938         supertype = supertype->superclass;
939     }
940     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
941         return c;
942     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
943         return c;
944     syntaxerror("can't convert type %s to %s", from->name, to->name);
945 }
946
947 code_t*defaultvalue(code_t*c, classinfo_t*type)
948 {
949     if(TYPE_IS_INT(type)) {
950        c = abc_pushbyte(c, 0);
951     } else if(TYPE_IS_UINT(type)) {
952        c = abc_pushuint(c, 0);
953     } else if(TYPE_IS_FLOAT(type)) {
954        c = abc_pushnan(c);
955     } else if(TYPE_IS_BOOLEAN(type)) {
956        c = abc_pushfalse(c);
957     } else {
958        c = abc_pushnull(c);
959     }
960     return c;
961 }
962
963 char is_pushundefined(code_t*c)
964 {
965     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
966 }
967
968 void parserassert(int b)
969 {
970     if(!b) syntaxerror("internal error: assertion failed");
971 }
972
973 static classinfo_t* find_class(char*name)
974 {
975     classinfo_t*c=0;
976
977     c = registry_findclass(state->package, name);
978
979     /* try explicit imports */
980     dictentry_t* e = dict_get_slot(state->imports, name);
981     while(e) {
982         if(c)
983             break;
984         if(!strcmp(e->key, name)) {
985             c = (classinfo_t*)e->data;
986         }
987         e = e->next;
988     }
989
990     /* try package.* imports */
991     import_list_t*l = state->wildcard_imports;
992     while(l) {
993         if(c)
994             break;
995         //printf("does package %s contain a class %s?\n", l->import->package, name);
996         c = registry_findclass(l->import->package, name);
997         l = l->next;
998     }
999
1000     /* try global package */
1001     if(!c) {
1002         c = registry_findclass("", name);
1003     }
1004     return c;
1005 }
1006
1007 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1008 {
1009     /* converts this:
1010
1011        [prefix code] [read instruction]
1012
1013        to this:
1014
1015        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1016     */
1017     
1018     if(in && in->opcode == OPCODE_COERCE_A) {
1019         in = code_cutlast(in);
1020     }
1021     if(in->next)
1022         syntaxerror("internal error");
1023
1024     /* chop off read instruction */
1025     code_t*prefix = in;
1026     code_t*r = in;
1027     if(r->prev) {
1028         prefix = r->prev;r->prev = 0;
1029         prefix->next=0;
1030     } else {
1031         prefix = 0;
1032     }
1033
1034     char use_temp_var = readbefore;
1035
1036     /* generate the write instruction, and maybe append a dup to the prefix code */
1037     code_t* write = abc_nop(0);
1038     if(r->opcode == OPCODE_GETPROPERTY) {
1039         write->opcode = OPCODE_SETPROPERTY;
1040         multiname_t*m = (multiname_t*)r->data[0];
1041         write->data[0] = multiname_clone(m);
1042         if(m->type == QNAME || m->type == MULTINAME) {
1043             if(!justassign) {
1044                 prefix = abc_dup(prefix); // we need the object, too
1045             }
1046             use_temp_var = 1;
1047         } else if(m->type == MULTINAMEL) {
1048             if(!justassign) {
1049                 /* dupping two values on the stack requires 5 operations and one register- 
1050                    couldn't adobe just have given us a dup2? */
1051                 int temp = gettempvar();
1052                 prefix = abc_setlocal(prefix, temp);
1053                 prefix = abc_dup(prefix);
1054                 prefix = abc_getlocal(prefix, temp);
1055                 prefix = abc_swap(prefix);
1056                 prefix = abc_getlocal(prefix, temp);
1057             }
1058             use_temp_var = 1;
1059         } else {
1060             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1061         }
1062     } else if(r->opcode == OPCODE_GETSLOT) {
1063         write->opcode = OPCODE_SETSLOT;
1064         write->data[0] = r->data[0];
1065         if(!justassign) {
1066             prefix = abc_dup(prefix); // we need the object, too
1067         }
1068         use_temp_var = 1;
1069     } else if(r->opcode == OPCODE_GETLOCAL) { 
1070         write->opcode = OPCODE_SETLOCAL;
1071         write->data[0] = r->data[0];
1072     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1073         write->opcode = OPCODE_SETLOCAL_0;
1074     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1075         write->opcode = OPCODE_SETLOCAL_1;
1076     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1077         write->opcode = OPCODE_SETLOCAL_2;
1078     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1079         write->opcode = OPCODE_SETLOCAL_3;
1080     } else {
1081         code_dump(r, 0, 0, "", stdout);
1082         syntaxerror("illegal lvalue: can't assign a value to this expression");
1083     }
1084     code_t* c = 0;
1085     
1086     int temp = -1;
1087     if(!justassign) {
1088         if(use_temp_var) {
1089             /* with getproperty/getslot, we have to be extra careful not
1090                to execute the read code twice, as it might have side-effects
1091                (e.g. if the property is in fact a setter/getter combination)
1092
1093                So read the value, modify it, and write it again,
1094                using prefix only once and making sure (by using a temporary
1095                register) that the return value is what we just wrote */
1096             temp = gettempvar();
1097             c = code_append(c, prefix);
1098             c = code_append(c, r);
1099             if(readbefore) {
1100                 c = abc_dup(c);
1101                 c = abc_setlocal(c, temp);
1102             }
1103             c = code_append(c, middlepart);
1104             if(!readbefore) {
1105                 c = abc_dup(c);
1106                 c = abc_setlocal(c, temp);
1107             }
1108             c = code_append(c, write);
1109             c = abc_getlocal(c, temp);
1110             c = abc_kill(c, temp);
1111         } else {
1112             /* if we're allowed to execute the read code twice *and*
1113                the middlepart doesn't modify the code, things are easier.
1114             */
1115             code_t* r2 = code_dup(r);
1116             //c = code_append(c, prefix);
1117             parserassert(!prefix);
1118             c = code_append(c, r);
1119             c = code_append(c, middlepart);
1120             c = code_append(c, write);
1121             c = code_append(c, r2);
1122         }
1123     } else {
1124         /* even smaller version: overwrite the value without reading
1125            it out first */
1126         if(!use_temp_var) {
1127             if(prefix) {
1128                 c = code_append(c, prefix);
1129                 c = abc_dup(c);
1130             }
1131             c = code_append(c, middlepart);
1132             c = code_append(c, write);
1133             c = code_append(c, r);
1134         } else {
1135             temp = gettempvar();
1136             if(prefix) {
1137                 c = code_append(c, prefix);
1138                 c = abc_dup(c);
1139             }
1140             c = code_append(c, middlepart);
1141             c = abc_dup(c);
1142             c = abc_setlocal(c, temp);
1143             c = code_append(c, write);
1144             c = abc_getlocal(c, temp);
1145         }
1146     }
1147
1148     return c;
1149 }
1150
1151 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1152 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1153
1154 %}
1155
1156
1157 %%
1158
1159 /* ------------ code blocks / statements ---------------- */
1160
1161 PROGRAM: MAYBECODE
1162
1163 MAYBECODE: CODE {$$=$1;/*TODO: do something with this code if we're not in a function*/}
1164 MAYBECODE:      {$$=code_new();}
1165
1166 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1167 CODE: CODEPIECE {$$=$1;}
1168
1169 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1170 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1171 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1172 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1173 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1174 CODEPIECE: ';'                   {$$=code_new();}
1175 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1176 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1177 CODEPIECE: FOR                   {$$=$1}
1178 CODEPIECE: WHILE                 {$$=$1}
1179 CODEPIECE: BREAK                 {$$=$1}
1180 CODEPIECE: RETURN                {$$=$1}
1181 CODEPIECE: IF                    {$$=$1}
1182 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1183 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1184
1185 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
1186 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1187 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1188
1189 /* ------------ variables --------------------------- */
1190
1191 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1192                 |                {$$.c=abc_pushundefined(0);
1193                                   $$.t=TYPE_ANY;
1194                                  }
1195
1196 VAR : "const" | "var"
1197 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1198
1199 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1200 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1201
1202 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1203 {
1204     if(variable_exists($2))
1205         syntaxerror("Variable %s already defined", $2);
1206    
1207     if(!is_subtype_of($4.t, $3)) {
1208         syntaxerror("Can't convert %s to %s", $4.t->name, 
1209                                               $3->name);
1210     }
1211
1212     int index = new_variable($2, $3);
1213     
1214     if($3) {
1215         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1216             $$ = $4.c;
1217             $$ = converttype($$, $4.t, $3);
1218             $$ = abc_setlocal($$, index);
1219         } else {
1220             $$ = defaultvalue(0, $3);
1221             $$ = abc_setlocal($$, index);
1222         }
1223
1224         /* if this is a typed variable:
1225            push default value for type on stack */
1226         if($3) {
1227             state->method->initcode = defaultvalue(state->method->initcode, $3);
1228             state->method->initcode = abc_setlocal(state->method->initcode, index);
1229         }
1230     } else {
1231         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1232             $$ = $4.c;
1233             $$ = abc_coerce_a($$);
1234             $$ = abc_setlocal($$, index);
1235         } else {
1236             $$ = code_new();
1237         }
1238     }
1239     
1240     /* that's the default for a local register, anyway
1241         else {
1242         state->method->initcode = abc_pushundefined(state->method->initcode);
1243         state->method->initcode = abc_setlocal(state->method->initcode, index);
1244     }*/
1245     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1246 }
1247
1248 /* ------------ control flow ------------------------- */
1249
1250 MAYBEELSE:  %prec below_else {$$ = code_new();}
1251 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1252 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1253
1254 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1255     $$ = code_new();
1256     $$ = code_append($$, $4.c);
1257     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1258    
1259     $$ = code_append($$, $6);
1260     if($7) {
1261         myjmp = $$ = abc_jump($$, 0);
1262     }
1263     myif->branch = $$ = abc_nop($$);
1264     if($7) {
1265         $$ = code_append($$, $7);
1266         myjmp->branch = $$ = abc_nop($$);
1267     }
1268     
1269     $$ = killvars($$);old_state();
1270 }
1271
1272 FOR_INIT : {$$=code_new();}
1273 FOR_INIT : VARIABLE_DECLARATION
1274 FOR_INIT : VOIDEXPRESSION
1275
1276 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1277     $$ = code_new();
1278     $$ = code_append($$, $4);
1279     code_t*loopstart = $$ = abc_label($$);
1280     $$ = code_append($$, $6.c);
1281     code_t*myif = $$ = abc_iffalse($$, 0);
1282     $$ = code_append($$, $10);
1283     $$ = code_append($$, $8);
1284     $$ = abc_jump($$, loopstart);
1285     code_t*out = $$ = abc_nop($$);
1286     breakjumpsto($$, out);
1287     myif->branch = out;
1288
1289     $$ = killvars($$);old_state();
1290 }
1291
1292 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1293     $$ = code_new();
1294
1295     code_t*myjmp = $$ = abc_jump($$, 0);
1296     code_t*loopstart = $$ = abc_label($$);
1297     $$ = code_append($$, $6);
1298     myjmp->branch = $$ = abc_nop($$);
1299     $$ = code_append($$, $4.c);
1300     $$ = abc_iftrue($$, loopstart);
1301     code_t*out = $$ = abc_nop($$);
1302     breakjumpsto($$, out);
1303
1304     $$ = killvars($$);old_state();
1305 }
1306
1307 BREAK : "break" {
1308     $$ = abc___break__(0);
1309 }
1310
1311 /* ------------ packages and imports ---------------- */
1312
1313 X_IDENTIFIER: T_IDENTIFIER
1314             | "package" {$$="package";}
1315
1316 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1317 PACKAGE: X_IDENTIFIER             {$$=$1;}
1318
1319 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1320 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1321
1322 IMPORT : "import" QNAME {
1323        classinfo_t*c = $2;
1324        if(!c) 
1325             syntaxerror("Couldn't import class\n");
1326        state_has_imports();
1327        dict_put(state->imports, c->name, c);
1328        $$=0;
1329 }
1330 IMPORT : "import" PACKAGE '.' '*' {
1331        NEW(import_t,i);
1332        i->package = $2;
1333        state_has_imports();
1334        list_append(state->wildcard_imports, i);
1335        $$=0;
1336 }
1337
1338 /* ------------ classes and interfaces (header) -------------- */
1339
1340 MAYBE_MODIFIERS : {$$=0;}
1341 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1342 MODIFIER_LIST : MODIFIER               {$$=$1;}
1343 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1344
1345 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1346          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1347          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1348          | KW_STATIC {$$=FLAG_STATIC;}
1349          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1350          | KW_FINAL {$$=FLAG_FINAL;}
1351          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1352          | KW_NATIVE {$$=FLAG_NATIVE;}
1353          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1354
1355 EXTENDS : {$$=registry_getobjectclass();}
1356 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1357
1358 EXTENDS_LIST : {$$=list_new();}
1359 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1360
1361 IMPLEMENTS_LIST : {$$=list_new();}
1362 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1363
1364 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1365                               EXTENDS IMPLEMENTS_LIST 
1366                               '{' {startclass($1,$3,$4,$5, 0);} 
1367                               MAYBE_DECLARATION_LIST 
1368                               '}' {endclass();}
1369
1370 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1371                               EXTENDS_LIST 
1372                               '{' {startclass($1,$3,0,$4,1);}
1373                               MAYBE_IDECLARATION_LIST 
1374                               '}' {endclass();}
1375
1376 /* ------------ classes and interfaces (body) -------------- */
1377
1378 MAYBE_DECLARATION_LIST : 
1379 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1380 DECLARATION_LIST : DECLARATION
1381 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1382 DECLARATION : ';'
1383 DECLARATION : SLOT_DECLARATION
1384 DECLARATION : FUNCTION_DECLARATION
1385
1386 MAYBE_IDECLARATION_LIST : 
1387 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1388 IDECLARATION_LIST : IDECLARATION
1389 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1390 IDECLARATION : ';'
1391 IDECLARATION : "var" T_IDENTIFIER {
1392     syntaxerror("variable declarations not allowed in interfaces");
1393 }
1394 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1395     $1 |= FLAG_PUBLIC;
1396     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1397         syntaxerror("invalid method modifiers: interface methods always need to be public");
1398     }
1399     startfunction(0,$1,$3,$4,&$6,$8);
1400     endfunction(0,$1,$3,$4,&$6,$8, 0);
1401 }
1402
1403 /* ------------ classes and interfaces (body, slots ) ------- */
1404
1405 VARCONST: "var" | "const"
1406
1407 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1408     int flags = $1;
1409     memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1410     info->type = $4;
1411     info->flags = flags;
1412     trait_t*t=0;
1413
1414     namespace_t mname_ns = {flags2access(flags), ""};
1415     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1416
1417     if(!(flags&FLAG_STATIC)) {
1418         if($4) {
1419             MULTINAME(m, $4);
1420             t=abc_class_slot(state->cls->abc, &mname, &m);
1421         } else {
1422             t=abc_class_slot(state->cls->abc, &mname, 0);
1423         }
1424         info->slot = t->slot_id;
1425     } else {
1426         if($4) {
1427             MULTINAME(m, $4);
1428             t=abc_class_staticslot(state->cls->abc, &mname, &m);
1429         } else {
1430             t=abc_class_staticslot(state->cls->abc, &mname, 0);
1431         }
1432         info->slot = t->slot_id;
1433     }
1434     if($5.c && !is_pushundefined($5.c)) {
1435         code_t*c = 0;
1436         c = abc_getlocal_0(c);
1437         c = code_append(c, $5.c);
1438         c = converttype(c, $5.t, $4);
1439         c = abc_setslot(c, t->slot_id);
1440         if(!(flags&FLAG_STATIC))
1441             state->cls->init = code_append(state->cls->init, c);
1442         else
1443             state->cls->static_init = code_append(state->cls->static_init, c);
1444     }
1445     if($2==KW_CONST) {
1446         t->kind= TRAIT_CONST;
1447     }
1448 }
1449
1450 /* ------------ constants -------------------------------------- */
1451
1452 MAYBESTATICCONSTANT: {$$=0;}
1453 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1454
1455 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1456 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1457 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1458 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1459 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1460 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1461 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1462 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1463 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1464
1465 /* ------------ classes and interfaces (body, functions) ------- */
1466
1467 // non-vararg version
1468 MAYBE_PARAM_LIST: {
1469     memset(&$$,0,sizeof($$));
1470 }
1471 MAYBE_PARAM_LIST: PARAM_LIST {
1472     $$=$1;
1473 }
1474
1475 // vararg version
1476 MAYBE_PARAM_LIST: "..." PARAM {
1477     memset(&$$,0,sizeof($$));
1478     $$.varargs=1;
1479     list_append($$.list, $2);
1480 }
1481 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1482     $$ =$1;
1483     $$.varargs=1;
1484     list_append($$.list, $4);
1485 }
1486
1487 // non empty
1488 PARAM_LIST: PARAM_LIST ',' PARAM {
1489     $$ = $1;
1490     list_append($$.list, $3);
1491 }
1492 PARAM_LIST: PARAM {
1493     memset(&$$,0,sizeof($$));
1494     list_append($$.list, $1);
1495 }
1496
1497 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1498      $$ = malloc(sizeof(param_t));
1499      $$->name=$1;
1500      $$->type = $3;
1501      $$->value = $4;
1502 }
1503 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1504      $$ = malloc(sizeof(param_t));
1505      $$->name=$1;
1506      $$->type = TYPE_ANY;
1507      $$->value = $2;
1508 }
1509 GETSET : "get" {$$=$1;}
1510        | "set" {$$=$1;}
1511        |       {$$=0;}
1512
1513 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1514                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1515 {
1516     code_t*c = 0;
1517     if(state->method->late_binding) {
1518         c = abc_getlocal_0(c);
1519         c = abc_pushscope(c);
1520     }
1521     if(state->method->is_constructor && !state->method->has_super) {
1522         // call default constructor
1523         c = abc_getlocal_0(c);
1524         c = abc_constructsuper(c, 0);
1525     }
1526     c = wrap_function(c, state->method->initcode, $11);
1527     endfunction(0,$1,$3,$4,&$6,$8,c);
1528 }
1529
1530 /* ------------- package + class ids --------------- */
1531
1532 CLASS: T_IDENTIFIER {
1533
1534     /* try current package */
1535     $$ = find_class($1);
1536     if(!$$) syntaxerror("Could not find class %s\n", $1);
1537 }
1538
1539 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1540     $$ = registry_findclass($1, $3);
1541     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1542 }
1543
1544 QNAME: PACKAGEANDCLASS
1545      | CLASS
1546
1547 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1548 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1549
1550 TYPE : QNAME      {$$=$1;}
1551      | '*'        {$$=registry_getanytype();}
1552     /*
1553      |  "String"  {$$=registry_getstringclass();}
1554      |  "int"     {$$=registry_getintclass();}
1555      |  "uint"    {$$=registry_getuintclass();}
1556      |  "Boolean" {$$=registry_getbooleanclass();}
1557      |  "Number"  {$$=registry_getnumberclass();}
1558     */
1559
1560 MAYBETYPE: ':' TYPE {$$=$2;}
1561 MAYBETYPE:          {$$=0;}
1562
1563 /* ----------function calls, delete, constructor calls ------ */
1564
1565 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1566 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1567
1568 MAYBE_EXPRESSION_LIST : {$$=0;}
1569 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1570 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1571                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1572                                                   *t = $1;
1573                                                   list_append($$, t);}
1574 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1575                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1576                                                   *t = $3;
1577                                                   list_append($$, t);}
1578
1579 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1580     MULTINAME(m, $2);
1581     $$.c = code_new();
1582
1583     if($2->slot) {
1584         $$.c = abc_getglobalscope($$.c);
1585         $$.c = abc_getslot($$.c, $2->slot);
1586     } else {
1587         $$.c = abc_findpropstrict2($$.c, &m);
1588     }
1589
1590     typedcode_list_t*l = $3;
1591     int len = 0;
1592     while(l) {
1593         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1594         l = l->next;
1595         len ++;
1596     }
1597     if($2->slot)
1598         $$.c = abc_construct($$.c, len);
1599     else
1600         $$.c = abc_constructprop2($$.c, &m, len);
1601     $$.t = $2;
1602 }
1603
1604 /* TODO: use abc_call (for calling local variables),
1605          abc_callstatic (for calling own methods) 
1606          call (for closures)
1607 */
1608 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1609     typedcode_list_t*l = $3;
1610     int len = 0;
1611     code_t*paramcode = 0;
1612     while(l) {
1613         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1614         l = l->next;
1615         len ++;
1616     }
1617        
1618     $$.c = $1.c;
1619     if($$.c->opcode == OPCODE_COERCE_A) {
1620         $$.c = code_cutlast($$.c);
1621     }
1622
1623     $$.t = TYPE_ANY;
1624     multiname_t*name = 0;
1625     if($$.c->opcode == OPCODE_GETPROPERTY) {
1626         name = multiname_clone($$.c->data[0]);
1627         $$.c = code_cutlast($$.c);
1628         $$.c = code_append($$.c, paramcode);
1629         $$.c = abc_callproperty2($$.c, name, len);
1630     } else if($$.c->opcode == OPCODE_GETSLOT) {
1631         int slot = (int)(ptroff_t)$$.c->data[0];
1632         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1633         if(t->kind!=TRAIT_METHOD) {
1634             //ok: flash allows to assign closures to members.
1635         }
1636         name = t->name;
1637         $$.c = code_cutlast($$.c);
1638         $$.c = code_append($$.c, paramcode);
1639         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1640         $$.c = abc_callproperty2($$.c, name, len);
1641     } else if($$.c->opcode == OPCODE_GETSUPER) {
1642         name = multiname_clone($$.c->data[0]);
1643         $$.c = code_cutlast($$.c);
1644         $$.c = code_append($$.c, paramcode);
1645         $$.c = abc_callsuper2($$.c, name, len);
1646     } else {
1647         $$.c = abc_getlocal_0($$.c);
1648         $$.c = code_append($$.c, paramcode);
1649         $$.c = abc_call($$.c, len);
1650     }
1651    
1652     memberinfo_t*f = 0;
1653    
1654     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1655         $$.t = $1.t->function->return_type;
1656     } else {
1657         $$.c = abc_coerce_a($$.c);
1658         $$.t = TYPE_ANY;
1659     }
1660 }
1661 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1662     if(!state->cls) syntaxerror("super() not allowed outside of a class");
1663     if(!state->method) syntaxerror("super() not allowed outside of a function");
1664     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1665
1666     $$.c = code_new();
1667     $$.c = abc_getlocal_0($$.c);
1668     typedcode_list_t*l = 0;
1669     int len = 0;
1670     for(l=$3;l;l=l->next) {
1671         $$.c = code_append($$.c, l->typedcode->c);len++;
1672     }
1673     /*
1674     this is dependent on the control path, check this somewhere else
1675     if(state->method->has_super)
1676         syntaxerror("constructor may call super() only once");
1677     */
1678     state->method->has_super = 1;
1679     $$.c = abc_constructsuper($$.c, len);
1680     $$.c = abc_pushundefined($$.c);
1681     $$.t = TYPE_ANY;
1682 }
1683
1684 DELETE: "delete" E {
1685     $$.c = $2.c;
1686     if($$.c->opcode == OPCODE_COERCE_A) {
1687         $$.c = code_cutlast($$.c);
1688     }
1689     multiname_t*name = 0;
1690     if($$.c->opcode == OPCODE_GETPROPERTY) {
1691         $$.c->opcode = OPCODE_DELETEPROPERTY;
1692     } else if($$.c->opcode == OPCODE_GETSLOT) {
1693         int slot = (int)(ptroff_t)$$.c->data[0];
1694         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1695         $$.c = code_cutlast($$.c);
1696         $$.c = abc_deleteproperty2($$.c, name);
1697     } else {
1698         $$.c = abc_getlocal_0($$.c);
1699         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1700         $$.c = abc_deleteproperty2($$.c, &m);
1701     }
1702     $$.t = TYPE_BOOLEAN;
1703 }
1704
1705 RETURN: "return" %prec prec_none {
1706     $$ = abc_returnvoid(0);
1707 }
1708 RETURN: "return" EXPRESSION {
1709     $$ = $2.c;
1710     $$ = abc_returnvalue($$);
1711 }
1712
1713 // ----------------------- expression types -------------------------------------
1714
1715 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
1716 EXPRESSION : E                %prec below_minus {$$ = $1;}
1717 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1718     $$.c = $1.c;
1719     $$.c = cut_last_push($$.c);
1720     $$.c = code_append($$.c,$3.c);
1721     $$.t = $3.t;
1722 }
1723 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1724     $$=cut_last_push($1.c);
1725 }
1726
1727 // ----------------------- expression evaluation -------------------------------------
1728
1729 E : CONSTANT
1730 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1731 E : NEW                         {$$ = $1;}
1732 E : DELETE                      {$$ = $1;}
1733 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1734                                  $$.t = TYPE_ANY;
1735                                 }
1736
1737 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1738                    //MULTINAME(m, registry_getintclass());
1739                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1740                    $$.t = TYPE_INT;
1741                   }
1742 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1743                     $$.t = TYPE_INT;
1744                    }
1745 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1746                   $$.t = TYPE_INT;
1747                  }
1748 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1749                    $$.t = TYPE_UINT;
1750                   }
1751 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1752                     $$.t = TYPE_FLOAT;
1753                    }
1754 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1755                      $$.t = TYPE_STRING;
1756                     }
1757 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1758                     $$.t = TYPE_ANY;
1759                    }
1760 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1761                     $$.t = TYPE_BOOLEAN;
1762                    }
1763 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1764                      $$.t = TYPE_BOOLEAN;
1765                     }
1766 CONSTANT : "null" {$$.c = abc_pushnull(0);
1767                     $$.t = TYPE_NULL;
1768                    }
1769
1770 E : FUNCTIONCALL
1771 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1772              $$.t = TYPE_BOOLEAN;
1773             }
1774 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1775              $$.t = TYPE_BOOLEAN;
1776             }
1777 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1778               $$.t = TYPE_BOOLEAN;
1779              }
1780 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1781               $$.t = TYPE_BOOLEAN;
1782              }
1783 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1784               $$.t = TYPE_BOOLEAN;
1785              }
1786 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1787               $$.t = TYPE_BOOLEAN;
1788               }
1789 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
1790               $$.t = TYPE_BOOLEAN;
1791              }
1792 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1793               $$.t = TYPE_BOOLEAN;
1794              }
1795
1796 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1797               $$.c = $1.c;
1798               $$.c = converttype($$.c, $1.t, $$.t);
1799               $$.c = abc_dup($$.c);
1800               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1801               $$.c = cut_last_push($$.c);
1802               $$.c = code_append($$.c,$3.c);
1803               $$.c = converttype($$.c, $3.t, $$.t);
1804               code_t*label = $$.c = abc_label($$.c);
1805               jmp->branch = label;
1806              }
1807 E : E "&&" E {
1808               $$.t = join_types($1.t, $3.t, 'A');
1809               /*printf("%08x:\n",$1.t);
1810               code_dump($1.c, 0, 0, "", stdout);
1811               printf("%08x:\n",$3.t);
1812               code_dump($3.c, 0, 0, "", stdout);
1813               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1814               $$.c = $1.c;
1815               $$.c = converttype($$.c, $1.t, $$.t);
1816               $$.c = abc_dup($$.c);
1817               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1818               $$.c = cut_last_push($$.c);
1819               $$.c = code_append($$.c,$3.c);
1820               $$.c = converttype($$.c, $3.t, $$.t);
1821               code_t*label = $$.c = abc_label($$.c);
1822               jmp->branch = label;              
1823              }
1824
1825 E : '!' E    {$$.c=$2.c;
1826               $$.c = abc_not($$.c);
1827               $$.t = TYPE_BOOLEAN;
1828              }
1829
1830 E : '~' E    {$$.c=$2.c;
1831               $$.c = abc_bitnot($$.c);
1832               $$.t = TYPE_INT;
1833              }
1834
1835 E : E '&' E {$$.c = code_append($1.c,$3.c);
1836              $$.c = abc_bitand($$.c);
1837              $$.t = TYPE_INT;
1838             }
1839
1840 E : E '^' E {$$.c = code_append($1.c,$3.c);
1841              $$.c = abc_bitxor($$.c);
1842              $$.t = TYPE_INT;
1843             }
1844
1845 E : E '|' E {$$.c = code_append($1.c,$3.c);
1846              $$.c = abc_bitor($$.c);
1847              $$.t = TYPE_INT;
1848             }
1849
1850 E : E '-' E {$$.c = code_append($1.c,$3.c);
1851              if(BOTH_INT($1,$3)) {
1852                 $$.c = abc_subtract_i($$.c);
1853                 $$.t = TYPE_INT;
1854              } else {
1855                 $$.c = abc_subtract($$.c);
1856                 $$.t = TYPE_NUMBER;
1857              }
1858             }
1859 E : E ">>" E {$$.c = code_append($1.c,$3.c);
1860              $$.c = abc_rshift($$.c);
1861              $$.t = TYPE_INT;
1862             }
1863 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
1864              $$.c = abc_urshift($$.c);
1865              $$.t = TYPE_INT;
1866             }
1867 E : E "<<" E {$$.c = code_append($1.c,$3.c);
1868              $$.c = abc_lshift($$.c);
1869              $$.t = TYPE_INT;
1870             }
1871
1872 E : E '/' E {$$.c = code_append($1.c,$3.c);
1873              $$.c = abc_divide($$.c);
1874              $$.t = TYPE_NUMBER;
1875             }
1876 E : E '+' E {$$.c = code_append($1.c,$3.c);
1877              $$.c = abc_add($$.c);
1878              $$.t = TYPE_NUMBER;
1879             }
1880 E : E '%' E {$$.c = code_append($1.c,$3.c);
1881              $$.c = abc_modulo($$.c);
1882              $$.t = TYPE_NUMBER;
1883             }
1884 E : E '*' E {$$.c = code_append($1.c,$3.c);
1885              if(BOTH_INT($1,$3)) {
1886                 $$.c = abc_multiply_i($$.c);
1887                 $$.t = TYPE_INT;
1888              } else {
1889                 $$.c = abc_multiply($$.c);
1890                 $$.t = TYPE_NUMBER;
1891              }
1892             }
1893
1894 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
1895               if(use_astype && TYPE_IS_CLASS($3.t)) {
1896                 MULTINAME(m,$3.t->cls);
1897                 $$.c = abc_astype2($1.c, &m);
1898                 $$.t = $3.t->cls;
1899               } else {
1900                 $$.c = code_append($1.c, $3.c);
1901                 $$.c = abc_astypelate($$.c);
1902                 $$.t = TYPE_ANY;
1903               }
1904              }
1905
1906 E : E "instanceof" E 
1907              {$$.c = code_append($1.c, $3.c);
1908               $$.c = abc_instanceof($$.c);
1909               $$.t = TYPE_BOOLEAN;
1910              }
1911
1912 E : E "is" E {$$.c = code_append($1.c, $3.c);
1913               $$.c = abc_istypelate($$.c);
1914               $$.t = TYPE_BOOLEAN;
1915              }
1916
1917 E : "typeof" '(' E ')' {
1918               $$.c = $3.c;
1919               $$.c = abc_typeof($$.c);
1920               $$.t = TYPE_STRING;
1921              }
1922
1923 E : "void" E {
1924               $$.c = cut_last_push($2.c);
1925               $$.c = abc_pushundefined($$.c);
1926               $$.t = TYPE_ANY;
1927              }
1928
1929 E : "void" { $$.c = abc_pushundefined(0);
1930              $$.t = TYPE_ANY;
1931            }
1932
1933 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
1934
1935 E : '-' E {
1936   $$=$2;
1937   if(IS_INT($2)) {
1938    $$.c=abc_negate_i($$.c);
1939    $$.t = TYPE_INT;
1940   } else {
1941    $$.c=abc_negate($$.c);
1942    $$.t = TYPE_NUMBER;
1943   }
1944 }
1945
1946 E : E '[' E ']' {
1947   $$.c = $1.c;
1948   $$.c = code_append($$.c, $3.c);
1949  
1950   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1951   $$.c = abc_getproperty2($$.c, &m);
1952   $$.t = 0; // array elements have unknown type
1953 }
1954
1955 E : '[' MAYBE_EXPRESSION_LIST ']' {
1956     $$.c = code_new();
1957     typedcode_list_t*l = 0;
1958     int len = 0;
1959     for(l=$2;l;l=l->next) {
1960         $$.c = code_append($$.c, l->typedcode->c);len++;
1961     }
1962     $$.c = abc_newarray($$.c, len);
1963     $$.t = registry_getarrayclass();
1964 }
1965
1966 E : E "*=" E { 
1967                code_t*c = $3.c;
1968                if(BOTH_INT($1,$3)) {
1969                 c=abc_multiply_i(c);
1970                } else {
1971                 c=abc_multiply(c);
1972                }
1973                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1974                $$.c = toreadwrite($1.c, c, 0, 0);
1975                $$.t = $1.t;
1976               }
1977
1978 E : E "%=" E { 
1979                code_t*c = abc_modulo($3.c);
1980                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1981                $$.c = toreadwrite($1.c, c, 0, 0);
1982                $$.t = $1.t;
1983               }
1984 E : E "<<=" E { 
1985                code_t*c = abc_lshift($3.c);
1986                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1987                $$.c = toreadwrite($1.c, c, 0, 0);
1988                $$.t = $1.t;
1989               }
1990 E : E ">>=" E { 
1991                code_t*c = abc_rshift($3.c);
1992                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1993                $$.c = toreadwrite($1.c, c, 0, 0);
1994                $$.t = $1.t;
1995               }
1996 E : E ">>>=" E { 
1997                code_t*c = abc_urshift($3.c);
1998                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1999                $$.c = toreadwrite($1.c, c, 0, 0);
2000                $$.t = $1.t;
2001               }
2002 E : E "/=" E { 
2003                code_t*c = abc_divide($3.c);
2004                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2005                $$.c = toreadwrite($1.c, c, 0, 0);
2006                $$.t = $1.t;
2007               }
2008 E : E "+=" E { 
2009                code_t*c = $3.c;
2010                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2011                 c=abc_add_i(c);
2012                } else {
2013                 c=abc_add(c);
2014                }
2015                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2016                
2017                $$.c = toreadwrite($1.c, c, 0, 0);
2018                $$.t = $1.t;
2019               }
2020 E : E "-=" E { code_t*c = $3.c; 
2021                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2022                 c=abc_subtract_i(c);
2023                } else {
2024                 c=abc_subtract(c);
2025                }
2026                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2027                
2028                $$.c = toreadwrite($1.c, c, 0, 0);
2029                $$.t = $1.t;
2030              }
2031 E : E '=' E { code_t*c = 0;
2032               c = code_append(c, $3.c);
2033               c = converttype(c, $3.t, $1.t);
2034               $$.c = toreadwrite($1.c, c, 1, 0);
2035               $$.t = $1.t;
2036             }
2037
2038 E : E '?' E ':' E %prec below_assignment { 
2039               $$.c = $1.c;
2040               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2041               $$.c = code_append($$.c, $3.c);
2042               code_t*j2 = $$.c = abc_jump($$.c, 0);
2043               $$.c = j1->branch = abc_label($$.c);
2044               $$.c = code_append($$.c, $5.c);
2045               $$.c = j2->branch = abc_label($$.c);
2046               $$.t = join_types($3.t,$5.t,'?');
2047             }
2048
2049 // TODO: use inclocal where appropriate
2050 E : E "++" { code_t*c = 0;
2051              classinfo_t*type = $1.t;
2052              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2053                  c=abc_increment_i(c);
2054                  type = TYPE_INT;
2055              } else {
2056                  c=abc_increment(c);
2057                  type = TYPE_NUMBER;
2058              }
2059              c=converttype(c, type, $1.t);
2060              $$.c = toreadwrite($1.c, c, 0, 1);
2061              $$.t = $1.t;
2062            }
2063 E : E "--" { code_t*c = 0;
2064              classinfo_t*type = $1.t;
2065              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2066                  c=abc_decrement_i(c);
2067                  type = TYPE_INT;
2068              } else {
2069                  c=abc_decrement(c);
2070                  type = TYPE_NUMBER;
2071              }
2072              c=converttype(c, type, $1.t);
2073              $$.c = toreadwrite($1.c, c, 0, 1);
2074              $$.t = $1.t;
2075             }
2076
2077 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2078              classinfo_t*type = $2.t;
2079              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2080                  c=abc_increment_i(c);
2081                  type = TYPE_INT;
2082              } else {
2083                  c=abc_increment(c);
2084                  type = TYPE_NUMBER;
2085              }
2086              c=converttype(c, type, $2.t);
2087              $$.c = toreadwrite($2.c, c, 0, 0);
2088              $$.t = $2.t;
2089            }
2090
2091 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2092              classinfo_t*type = $2.t;
2093              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2094                  c=abc_decrement_i(c);
2095                  type = TYPE_INT;
2096              } else {
2097                  c=abc_decrement(c);
2098                  type = TYPE_NUMBER;
2099              }
2100              c=converttype(c, type, $2.t);
2101              $$.c = toreadwrite($2.c, c, 0, 0);
2102              $$.t = $2.t;
2103            }
2104
2105 E : "super" '.' T_IDENTIFIER 
2106            { if(!state->cls->info)
2107                   syntaxerror("super keyword not allowed outside a class");
2108               classinfo_t*t = state->cls->info->superclass;
2109               if(!t) t = TYPE_OBJECT;
2110
2111               memberinfo_t*f = registry_findmember(t, $3);
2112               namespace_t ns = {flags2access(f->flags), ""};
2113               MEMBER_MULTINAME(m, f, $3);
2114               $$.c = 0;
2115               $$.c = abc_getlocal_0($$.c);
2116               $$.c = abc_getsuper2($$.c, &m);
2117               $$.t = memberinfo_gettype(f);
2118            }
2119
2120 E : E '.' T_IDENTIFIER
2121             {$$.c = $1.c;
2122              classinfo_t*t = $1.t;
2123              char is_static = 0;
2124              if(TYPE_IS_CLASS(t) && t->cls) {
2125                  t = t->cls;
2126                  is_static = 1;
2127              }
2128              if(t) {
2129                  memberinfo_t*f = registry_findmember(t, $3);
2130                  char noslot = 0;
2131                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2132                     noslot=1;
2133                  if(f && f->slot && !noslot) {
2134                      $$.c = abc_getslot($$.c, f->slot);
2135                  } else {
2136                      MEMBER_MULTINAME(m, f, $3);
2137                      $$.c = abc_getproperty2($$.c, &m);
2138                  }
2139                  /* determine type */
2140                  $$.t = memberinfo_gettype(f);
2141                  if(!$$.t)
2142                     $$.c = abc_coerce_a($$.c);
2143              } else {
2144                  /* when resolving a property on an unknown type, we do know the
2145                     name of the property (and don't seem to need the package), but
2146                     we need to make avm2 try out all access modes */
2147                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2148                  $$.c = abc_getproperty2($$.c, &m);
2149                  $$.c = abc_coerce_a($$.c);
2150                  $$.t = registry_getanytype();
2151              }
2152             }
2153
2154 VAR_READ : T_IDENTIFIER {
2155     $$.t = 0;
2156     $$.c = 0;
2157     int i;
2158     classinfo_t*a = 0;
2159     memberinfo_t*f = 0;
2160
2161     /* look at variables */
2162     if((i = find_variable($1, &$$.t)) >= 0) {
2163         // $1 is a local variable
2164         $$.c = abc_getlocal($$.c, i);
2165
2166     /* look at current class' members */
2167     } else if((f = registry_findmember(state->cls->info, $1))) {
2168         // $1 is a function in this class
2169         int var_is_static = (f->flags&FLAG_STATIC);
2170         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2171         if(var_is_static != i_am_static) {
2172             /* there doesn't seem to be any "static" way to access
2173                static properties of a class */
2174             state->method->late_binding = 1;
2175             $$.t = f->type;
2176             namespace_t ns = {flags2access(f->flags), ""};
2177             multiname_t m = {QNAME, &ns, 0, $1};
2178             $$.c = abc_findpropstrict2($$.c, &m);
2179             $$.c = abc_getproperty2($$.c, &m);
2180         } else {
2181             if(f->slot>0) {
2182                 $$.c = abc_getlocal_0($$.c);
2183                 $$.c = abc_getslot($$.c, f->slot);
2184             } else {
2185                 namespace_t ns = {flags2access(f->flags), ""};
2186                 multiname_t m = {QNAME, &ns, 0, $1};
2187                 $$.c = abc_getlocal_0($$.c);
2188                 $$.c = abc_getproperty2($$.c, &m);
2189             }
2190         }
2191         if(f->kind == MEMBER_METHOD) {
2192             $$.t = TYPE_FUNCTION(f);
2193         } else {
2194             $$.t = f->type;
2195         }
2196     
2197     /* look at classes in the current package and imported classes */
2198     } else if((a = find_class($1))) {
2199         if(a->flags & FLAG_METHOD) {
2200             MULTINAME(m, a);
2201             $$.c = abc_findpropstrict2($$.c, &m);
2202             $$.c = abc_getproperty2($$.c, &m);
2203             $$.t = TYPE_FUNCTION(a->function);
2204         } else {
2205             if(a->slot) {
2206                 $$.c = abc_getglobalscope($$.c);
2207                 $$.c = abc_getslot($$.c, a->slot);
2208             } else {
2209                 MULTINAME(m, a);
2210                 $$.c = abc_getlex2($$.c, &m);
2211             }
2212             $$.t = TYPE_CLASS(a);
2213         }
2214
2215     /* unknown object, let the avm2 resolve it */
2216     } else {
2217         if(strcmp($1,"trace"))
2218             warning("Couldn't resolve '%s', doing late binding", $1);
2219         state->method->late_binding = 1;
2220                 
2221         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2222
2223         $$.t = 0;
2224         $$.c = abc_findpropstrict2($$.c, &m);
2225         $$.c = abc_getproperty2($$.c, &m);
2226     }
2227 }
2228
2229 //TODO: 
2230 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2231 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2232 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2233
2234 // ----------------- namespaces -------------------------------------------------
2235
2236 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2237 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2238 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2239
2240 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
2241