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