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