added stub for inner functions
[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     codeandnumber_t value_list;
55     param_t* param;
56     params_t params;
57     string_t str;
58     char*id;
59     constant_t*constant;
60     for_start_t for_start;
61     abc_exception_t *exception;
62     abc_exception_list_t *exception_list;
63     regexp_t regexp;
64 }
65
66
67 %token<id> T_IDENTIFIER
68 %token<str> T_STRING
69 %token<regexp> T_REGEXP
70 %token<token> T_EMPTY
71 %token<number_int> T_INT
72 %token<number_uint> T_UINT
73 %token<number_uint> T_BYTE
74 %token<number_uint> T_SHORT
75 %token<number_float> T_FLOAT
76
77 %token<id> T_FOR "for"
78 %token<id> T_WHILE "while"
79 %token<id> T_DO "do"
80 %token<id> T_SWITCH "switch"
81
82 %token<token> KW_IMPLEMENTS "implements"
83 %token<token> KW_NAMESPACE "namespace"
84 %token<token> KW_PACKAGE "package"
85 %token<token> KW_PROTECTED "protected"
86 %token<token> KW_PUBLIC "public"
87 %token<token> KW_PRIVATE "private"
88 %token<token> KW_USE "use"
89 %token<token> KW_INTERNAL "internal"
90 %token<token> KW_NEW "new"
91 %token<token> KW_NATIVE "native"
92 %token<token> KW_FUNCTION "function"
93 %token<token> KW_UNDEFINED "undefined"
94 %token<token> KW_CONTINUE "continue"
95 %token<token> KW_CLASS "class"
96 %token<token> KW_CONST "const"
97 %token<token> KW_CATCH "catch"
98 %token<token> KW_CASE "case"
99 %token<token> KW_SET "set"
100 %token<token> KW_VOID "void"
101 %token<token> KW_THROW "throw"
102 %token<token> KW_STATIC "static"
103 %token<token> KW_WITH "with"
104 %token<token> KW_INSTANCEOF "instanceof"
105 %token<token> KW_IMPORT "import"
106 %token<token> KW_RETURN "return"
107 %token<token> KW_TYPEOF "typeof"
108 %token<token> KW_INTERFACE "interface"
109 %token<token> KW_NULL "null"
110 %token<token> KW_VAR "var"
111 %token<token> KW_DYNAMIC "dynamic"
112 %token<token> KW_OVERRIDE "override"
113 %token<token> KW_FINAL "final"
114 %token<token> KW_EACH "each"
115 %token<token> KW_GET "get"
116 %token<token> KW_TRY "try"
117 %token<token> KW_SUPER "super"
118 %token<token> KW_EXTENDS "extends"
119 %token<token> KW_FALSE "false"
120 %token<token> KW_TRUE "true"
121 %token<token> KW_BOOLEAN "Boolean"
122 %token<token> KW_UINT "uint"
123 %token<token> KW_INT "int"
124 %token<token> KW_NUMBER "Number"
125 %token<token> KW_STRING "String"
126 %token<token> KW_DEFAULT "default"
127 %token<token> KW_DELETE "delete"
128 %token<token> KW_IF "if"
129 %token<token> KW_ELSE  "else"
130 %token<token> KW_BREAK   "break"
131 %token<token> KW_IS "is"
132 %token<token> KW_IN "in"
133 %token<token> KW_AS "as"
134
135 %token<token> T_EQEQ "=="
136 %token<token> T_EQEQEQ "==="
137 %token<token> T_NE "!="
138 %token<token> T_NEE "!=="
139 %token<token> T_LE "<="
140 %token<token> T_GE ">="
141 %token<token> T_ORBY "|=" 
142 %token<token> T_DIVBY "/=" 
143 %token<token> T_MODBY "%="
144 %token<token> T_MULBY "*="
145 %token<token> T_PLUSBY "+=" 
146 %token<token> T_MINUSBY "-="
147 %token<token> T_SHRBY ">>="
148 %token<token> T_SHLBY "<<="
149 %token<token> T_USHRBY ">>>="
150 %token<token> T_OROR "||"
151 %token<token> T_ANDAND "&&"
152 %token<token> T_COLONCOLON "::"
153 %token<token> T_MINUSMINUS "--"
154 %token<token> T_PLUSPLUS "++"
155 %token<token> T_DOTDOT ".."
156 %token<token> T_DOTDOTDOT "..."
157 %token<token> T_SHL "<<"
158 %token<token> T_USHR ">>>"
159 %token<token> T_SHR ">>"
160
161 %type <for_start> FOR_START
162 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
163 %type <token> VARCONST
164 %type <code> CODE
165 %type <code> CODEPIECE CODE_STATEMENT
166 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
167 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
168 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
169 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW 
170 %type <exception> CATCH
171 %type <exception_list> CATCH_LIST
172 %type <code> CLASS_DECLARATION
173 %type <code> NAMESPACE_DECLARATION
174 %type <code> INTERFACE_DECLARATION
175 %type <code> VOIDEXPRESSION
176 %type <value> EXPRESSION NONCOMMAEXPRESSION
177 %type <value> MAYBEEXPRESSION
178 %type <value> E DELETE
179 %type <value> CONSTANT
180 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY 
181 %type <value> INNERFUNCTION
182 %type <token> USE_NAMESPACE
183 %type <code> FOR_INIT
184 %type <code> IMPORT
185 %type <classinfo> MAYBETYPE
186 %type <token> GETSET
187 %type <param> PARAM
188 %type <params> PARAM_LIST
189 %type <params> MAYBE_PARAM_LIST
190 %type <flags> MAYBE_MODIFIERS
191 %type <flags> MODIFIER_LIST
192 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
193 %type <classinfo_list> IMPLEMENTS_LIST
194 %type <classinfo> EXTENDS
195 %type <classinfo_list> EXTENDS_LIST
196 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
197 %type <classinfo_list> QNAME_LIST
198 %type <classinfo> TYPE
199 //%type <token> VARIABLE
200 %type <value> VAR_READ
201 %type <value> NEW
202 //%type <token> T_IDENTIFIER
203 %type <token> MODIFIER
204 %type <value> FUNCTIONCALL
205 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
206
207 // precedence: from low to high
208
209 %left prec_none
210
211 %left below_semicolon
212 %left ';'
213 %left ','
214 %nonassoc below_assignment // for ?:, contrary to spec
215 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
216 %right '?' ':'
217 %left "||"
218 %left "&&"
219 %left '|'
220 %left '^'
221 %nonassoc '&'
222 %nonassoc "==" "!=" "===" "!=="
223 %nonassoc "is" "as" "in"
224 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
225 %left "<<" ">>" ">>>" 
226 %left below_minus
227 %left '-' '+'
228 %left '/' '*' '%'
229 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
230 %left "--" "++" 
231 %nonassoc below_curly
232 %left '[' ']' '{' "new" '.' ".." "::"
233 %nonassoc T_IDENTIFIER
234 %left above_identifier
235 %left below_else
236 %nonassoc "else"
237 %left '('
238
239 // needed for "return" precedence:
240 %nonassoc T_STRING T_REGEXP
241 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
242 %nonassoc "false" "true" "null" "undefined" "super" "function"
243 %nonassoc above_function
244
245
246      
247 %{
248
249 static int yyerror(char*s)
250 {
251    syntaxerror("%s", s); 
252 }
253
254 static char* concat2(const char* t1, const char* t2)
255 {
256     int l1 = strlen(t1);
257     int l2 = strlen(t2);
258     char*text = malloc(l1+l2+1);
259     memcpy(text   , t1, l1);
260     memcpy(text+l1, t2, l2);
261     text[l1+l2] = 0;
262     return text;
263 }
264 static char* concat3(const char* t1, const char* t2, const char* t3)
265 {
266     int l1 = strlen(t1);
267     int l2 = strlen(t2);
268     int l3 = strlen(t3);
269     char*text = malloc(l1+l2+l3+1);
270     memcpy(text   , t1, l1);
271     memcpy(text+l1, t2, l2);
272     memcpy(text+l1+l2, t3, l3);
273     text[l1+l2+l3] = 0;
274     return text;
275 }
276
277 typedef struct _import {
278     char*package;
279 } import_t;
280
281 DECLARE_LIST(import);
282
283 typedef struct _classstate {
284     /* class data */
285     classinfo_t*info;
286     abc_class_t*abc;
287     code_t*init;
288     code_t*static_init;
289     char has_constructor;
290 } classstate_t;
291
292 typedef struct _methodstate {
293     /* method data */
294     memberinfo_t*info;
295     char late_binding;
296     char is_constructor;
297     char has_super;
298     char is_global;
299     abc_exception_list_t*exceptions;
300 } methodstate_t;
301
302 typedef struct _state {
303     struct _state*old;
304     int level;
305     
306     char*package;     
307     import_list_t*wildcard_imports;
308     dict_t*imports;
309     char has_own_imports;
310   
311     classstate_t*cls;   
312     methodstate_t*method;
313
314     char*exception_name;
315     
316     dict_t*vars;
317 } state_t;
318
319 typedef struct _global {
320     abc_file_t*file;
321     abc_script_t*init;
322
323     int variable_count;
324 } global_t;
325
326 static global_t*global = 0;
327 static state_t* state = 0;
328
329 DECLARE_LIST(state);
330
331 #define MULTINAME(m,x) \
332     multiname_t m;\
333     namespace_t m##_ns;\
334     registry_fill_multiname(&m, &m##_ns, x);
335                     
336 #define MEMBER_MULTINAME(m,f,n) \
337     multiname_t m;\
338     namespace_t m##_ns;\
339     if(f) { \
340         m##_ns = flags2namespace(f->flags, ""); \
341         m.type = QNAME; \
342         m.ns = &m##_ns; \
343         m.namespace_set = 0; \
344         m.name = f->name; \
345     } else { \
346         m.type = MULTINAME; \
347         m.ns =0; \
348         m.namespace_set = &nopackage_namespace_set; \
349         m.name = n; \
350     }
351
352 /* warning: list length of namespace set is undefined */
353 #define MULTINAME_LATE(m, access, package) \
354     namespace_t m##_ns = {access, package}; \
355     namespace_set_t m##_nsset; \
356     namespace_list_t m##_l;m##_l.next = 0; \
357     m##_nsset.namespaces = &m##_l; \
358     m##_nsset = m##_nsset; \
359     m##_l.namespace = &m##_ns; \
360     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
361
362 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
363 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
364 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
365 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
366 static namespace_list_t nl4 = {&ns4,0};
367 static namespace_list_t nl3 = {&ns3,&nl4};
368 static namespace_list_t nl2 = {&ns2,&nl3};
369 static namespace_list_t nl1 = {&ns1,&nl2};
370 static namespace_set_t nopackage_namespace_set = {&nl1};
371
372 static void new_state()
373 {
374     NEW(state_t, s);
375     state_t*oldstate = state;
376     if(state)
377         memcpy(s, state, sizeof(state_t)); //shallow copy
378     if(!s->imports) {
379         s->imports = dict_new();
380     }
381     state = s;
382     state->level++;
383     state->has_own_imports = 0;    
384     state->vars = dict_new(); 
385     state->old = oldstate;
386 }
387 static void state_has_imports()
388 {
389     state->wildcard_imports = list_clone(state->wildcard_imports);
390     state->imports = dict_clone(state->imports);
391     state->has_own_imports = 1;
392 }
393
394 static void state_destroy(state_t*state)
395 {
396     if(state->has_own_imports) {
397         list_free(state->wildcard_imports);
398         dict_destroy(state->imports);state->imports=0;
399     }
400     if(state->imports && (!state->old || state->old->imports!=state->imports)) {
401         dict_destroy(state->imports);state->imports=0;
402     }
403     if(state->vars) {
404         int t;
405         for(t=0;t<state->vars->hashsize;t++) {
406             dictentry_t*e =state->vars->slots[t];
407             while(e) {
408                 free(e->data);e->data=0;
409                 e = e->next;
410             }
411         }
412         dict_destroy(state->vars);state->vars=0;
413     }
414     
415     free(state);
416 }
417
418 static void old_state()
419 {
420     if(!state || !state->old)
421         syntaxerror("invalid nesting");
422     state_t*leaving = state;
423     
424     state = state->old;
425     state_destroy(leaving);
426 }
427
428 void initialize_parser()
429 {
430     global = rfx_calloc(sizeof(global_t));
431     global->file = abc_file_new();
432     global->file->flags &= ~ABCFILE_LAZY;
433     global->variable_count = 1;
434     global->init = abc_initscript(global->file);
435     code_t*c = global->init->method->body->code;
436     c = abc_getlocal_0(c);
437     c = abc_pushscope(c);
438     /*c = abc_findpropstrict(c, "[package]::trace");
439     c = abc_pushstring(c, "[entering global init function]");
440     c = abc_callpropvoid(c, "[package]::trace", 1);*/
441     global->init->method->body->code = c;
442 }
443
444 void initialize_file(char*filename)
445 {
446     new_state();
447     state->package = filename;
448 }
449 void finish_file()
450 {
451     if(!state || state->level!=1) {
452         syntaxerror("unexpected end of file");
453     }
454     state_destroy(state);state=0;
455 }
456
457 void* finish_parser()
458 {
459     code_t*c = global->init->method->body->code;
460     /*c = abc_findpropstrict(c, "[package]::trace");
461       c = abc_pushstring(c, "[leaving global init function]");
462       c = abc_callpropvoid(c, "[package]::trace", 1);*/
463     c = abc_returnvoid(c);
464     global->init->method->body->code = c;
465     return global->file;
466 }
467
468
469 static void xx_scopetest() 
470 {
471     /* findpropstrict doesn't just return a scope object- it
472        also makes it "active" somehow. Push local_0 on the
473        scope stack and read it back with findpropstrict, it'll
474        contain properties like "trace". Trying to find the same
475        property on a "vanilla" local_0 yields only a "undefined" */
476     //c = abc_findpropstrict(c, "[package]::trace");
477     
478     /*c = abc_getlocal_0(c);
479     c = abc_findpropstrict(c, "[package]::trace");
480     c = abc_coerce_a(c);
481     c = abc_setlocal_1(c);
482
483     c = abc_pushbyte(c, 0);
484     c = abc_setlocal_2(c);
485    
486     code_t*xx = c = abc_label(c);
487     c = abc_findpropstrict(c, "[package]::trace");
488     c = abc_pushstring(c, "prop:");
489     c = abc_hasnext2(c, 1, 2);
490     c = abc_dup(c);
491     c = abc_setlocal_3(c);
492     c = abc_callpropvoid(c, "[package]::trace", 2);
493     c = abc_getlocal_3(c);
494     c = abc_kill(c, 3);
495     c = abc_iftrue(c,xx);*/
496 }
497
498
499 typedef struct _variable {
500     int index;
501     classinfo_t*type;
502     char init;
503 } variable_t;
504
505 static variable_t* find_variable(char*name)
506 {
507     state_t* s = state;
508     while(s) {
509         variable_t*v = 0;
510         if(s->method)
511             v = dict_lookup(s->vars, name);
512         if(v) {
513             return v;
514         }
515         s = s->old;
516     }
517     return 0;
518
519 static variable_t* find_variable_safe(char*name)
520 {
521     variable_t* v = find_variable(name);
522     if(!v)
523         syntaxerror("undefined variable: %s", name);
524     return v;
525 }
526 static char variable_exists(char*name) 
527 {
528     return dict_lookup(state->vars, name)!=0;
529 }
530 code_t*defaultvalue(code_t*c, classinfo_t*type);
531 static int new_variable(char*name, classinfo_t*type, char init)
532 {
533     NEW(variable_t, v);
534     v->index = global->variable_count;
535     v->type = type;
536     v->init = init;
537     
538     dict_put(state->vars, name, v);
539
540     return global->variable_count++;
541 }
542 #define TEMPVARNAME "__as3_temp__"
543 static int gettempvar()
544 {
545     variable_t*v = find_variable(TEMPVARNAME);
546     if(v) 
547         return v->index;
548     return new_variable(TEMPVARNAME, 0, 0);
549 }
550
551 code_t* var_block(code_t*body) 
552 {
553     code_t*c = 0;
554     code_t*k = 0;
555     int t;
556     int num=0;
557     for(t=0;t<state->vars->hashsize;t++) {
558         dictentry_t*e = state->vars->slots[t];
559         while(e) {
560             variable_t*v = (variable_t*)e->data;
561             if(v->type && v->init) {
562                 c = defaultvalue(c, v->type);
563                 c = abc_setlocal(c, v->index);
564                 k = abc_kill(k, v->index); 
565                 num++;
566             }
567             e = e->next;
568         }
569     }
570
571     if(k) {
572         code_t*x = body;
573         while(x) {
574             if(x->opcode== OPCODE___BREAK__ ||
575                x->opcode== OPCODE___CONTINUE__) {
576                /* link kill code before break/continue */
577                 code_t*e = code_dup(k);
578                 code_t*s = code_start(e);
579                 s->prev = x->prev;
580                 if(x->prev) {
581                     x->prev->next = s;
582                 }
583                 e->next = x;
584                 x->prev = e;
585             }
586             x = x->prev;
587         }
588     }
589     
590     c = code_append(c, body);
591     c = code_append(c, k);
592     return c;
593 }
594
595 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
596 {
597     c = code_append(c, header);
598     c = code_append(c, var_block(body));
599     /* append return if necessary */
600     if(!c || c->opcode != OPCODE_RETURNVOID && 
601              c->opcode != OPCODE_RETURNVALUE) {
602         c = abc_returnvoid(c);
603     }
604     return c;
605 }
606
607
608 static void startpackage(char*name)
609 {
610     new_state();
611     /*printf("entering package \"%s\"\n", name);*/
612     state->package = strdup(name);
613     global->variable_count = 1;
614 }
615 static void endpackage()
616 {
617     /*printf("leaving package \"%s\"\n", state->package);*/
618
619     //used e.g. in classinfo_register:
620     //free(state->package);state->package=0;
621
622     old_state();
623 }
624
625 char*as3_globalclass=0;
626 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
627 {
628     if(state->cls) {
629         syntaxerror("inner classes now allowed"); 
630     }
631     new_state();
632     global->variable_count = 1;
633     state->cls = rfx_calloc(sizeof(classstate_t));
634     state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
635
636     token_list_t*t=0;
637     classinfo_list_t*mlist=0;
638
639     if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
640         syntaxerror("invalid modifier(s)");
641
642     if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
643         syntaxerror("public and internal not supported at the same time.");
644
645     /* create the class name, together with the proper attributes */
646     int access=0;
647     char*package=0;
648
649     if(!(flags&FLAG_PUBLIC) && !state->package) {
650         access = ACCESS_PRIVATE; package = current_filename;
651     } else if(!(flags&FLAG_PUBLIC) && state->package) {
652         access = ACCESS_PACKAGEINTERNAL; package = state->package;
653     } else if(state->package) {
654         access = ACCESS_PACKAGE; package = state->package;
655     } else {
656         syntaxerror("public classes only allowed inside a package");
657     }
658
659     if(registry_findclass(package, classname)) {
660         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
661     }
662    
663
664     /* build info struct */
665     int num_interfaces = (list_length(implements));
666     state->cls->info = classinfo_register(access, package, classname, num_interfaces);
667     state->cls->info->superclass = extends?extends:TYPE_OBJECT;
668     int pos = 0;
669     classinfo_list_t*l = implements;
670     for(l=implements;l;l=l->next) {
671         state->cls->info->interfaces[pos++] = l->classinfo;
672     }
673     
674     multiname_t*extends2 = sig2mname(extends);
675
676     MULTINAME(classname2,state->cls->info);
677
678     /*if(extends) {
679         state->cls_init = abc_getlocal_0(state->cls_init);
680         state->cls_init = abc_constructsuper(state->cls_init, 0);
681     }*/
682
683     state->cls->abc = abc_class_new(global->file, &classname2, extends2);
684     if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
685     if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
686     if(interface) {
687         state->cls->info->flags |= CLASS_INTERFACE;
688         abc_class_interface(state->cls->abc);
689     }
690
691     abc_class_protectedNS(state->cls->abc, classname);
692
693     for(mlist=implements;mlist;mlist=mlist->next) {
694         MULTINAME(m, mlist->classinfo);
695         abc_class_add_interface(state->cls->abc, &m);
696     }
697
698     /* now write the construction code for this class */
699     int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
700
701     abc_method_body_t*m = global->init->method->body;
702     __ getglobalscope(m);
703     classinfo_t*s = extends;
704
705     int count=0;
706     
707     while(s) {
708         //TODO: take a look at the current scope stack, maybe 
709         //      we can re-use something
710         s = s->superclass;
711         if(!s) 
712         break;
713        
714         multiname_t*s2 = sig2mname(s);
715         __ getlex2(m, s2);
716         multiname_destroy(s2);
717
718         __ pushscope(m); count++;
719         m->code = m->code->prev->prev; // invert
720     }
721     /* continue appending after last op end */
722     while(m->code && m->code->next) m->code = m->code->next; 
723
724     /* TODO: if this is one of *our* classes, we can also 
725              do a getglobalscope/getslot <nr> (which references
726              the init function's slots) */
727     if(extends2) {
728         __ getlex2(m, extends2);
729         __ dup(m);
730         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
731            stack is not the superclass */
732         __ pushscope(m);count++;
733     } else {
734         __ pushnull(m);
735         /* notice: we get a verify error #1107 if the top element on the scope 
736            stack is not the global object */
737         __ getlocal_0(m);
738         __ pushscope(m);count++;
739     }
740     __ newclass(m,state->cls->abc);
741     while(count--) {
742         __ popscope(m);
743     }
744     __ setslot(m, slotindex);
745
746     /* flash.display.MovieClip handling */
747     if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
748         if(state->package && state->package[0]) {
749             as3_globalclass = concat3(state->package, ".", classname);
750         } else {
751             as3_globalclass = strdup(classname);
752         }
753     }
754     multiname_destroy(extends2);
755 }
756
757 static void endclass()
758 {
759     if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
760         code_t*c = 0;
761         c = abc_getlocal_0(c);
762         c = abc_constructsuper(c, 0);
763         state->cls->init = code_append(state->cls->init, c);
764     }
765     if(!state->method->late_binding) {
766         // class initialization code uses late binding
767         code_t*c = 0;
768         c = abc_getlocal_0(c);
769         c = abc_pushscope(c);
770         state->cls->static_init = code_append(c, state->cls->static_init);
771     }
772
773     if(state->cls->init) {
774         abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
775         m->body->code = wrap_function(0, state->cls->init, m->body->code);
776     }
777     if(state->cls->static_init) {
778         abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
779         m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
780     }
781
782     free(state->cls);state->cls=0;
783     free(state->method);state->method=0;
784     old_state();
785 }
786
787 void check_code_for_break(code_t*c)
788 {
789     while(c) {
790         if(c->opcode == OPCODE___BREAK__) {
791             char*name = string_cstr(c->data[0]);
792             syntaxerror("Unresolved \"break %s\"", name);
793         }
794         if(c->opcode == OPCODE___CONTINUE__) {
795             char*name = string_cstr(c->data[0]);
796             syntaxerror("Unresolved \"continue %s\"", name);
797         }
798         c=c->prev;
799     }
800 }
801
802
803 static void check_constant_against_type(classinfo_t*t, constant_t*c)
804 {
805 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
806    if(TYPE_IS_NUMBER(t)) {
807         xassert(c->type == CONSTANT_FLOAT
808              || c->type == CONSTANT_INT
809              || c->type == CONSTANT_UINT);
810    } else if(TYPE_IS_UINT(t)) {
811         xassert(c->type == CONSTANT_UINT ||
812                (c->type == CONSTANT_INT && c->i>0));
813    } else if(TYPE_IS_INT(t)) {
814         xassert(c->type == CONSTANT_INT);
815    } else if(TYPE_IS_BOOLEAN(t)) {
816         xassert(c->type == CONSTANT_TRUE
817              || c->type == CONSTANT_FALSE);
818    }
819 }
820
821
822 static int flags2access(int flags)
823 {
824     int access = 0;
825     if(flags&FLAG_PUBLIC)  {
826         if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
827             syntaxerror("invalid combination of access levels");
828         access = ACCESS_PACKAGE;
829     } else if(flags&FLAG_PRIVATE) {
830         if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
831             syntaxerror("invalid combination of access levels");
832         access = ACCESS_PRIVATE;
833     } else if(flags&FLAG_PROTECTED) {
834         if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL)) 
835             syntaxerror("invalid combination of access levels");
836         access = ACCESS_PROTECTED;
837     } else {
838         access = ACCESS_PACKAGEINTERNAL;
839     }
840     return access;
841 }
842
843
844 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
845 {
846     memberinfo_t*minfo = 0;
847     if(!state->cls) {
848         //package method
849         minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
850         minfo->return_type = return_type;
851     } else if(getset != KW_GET && getset != KW_SET) {
852         //class method
853         if((minfo = registry_findmember(state->cls->info, name, 0))) {
854             if(minfo->parent == state->cls->info) {
855                 syntaxerror("class already contains a member/method called '%s'", name);
856             } else if(!minfo->parent) {
857                 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
858             } else {
859                 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
860                     syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
861             }
862         }
863         minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
864         minfo->return_type = return_type;
865         // getslot on a member slot only returns "undefined", so no need
866         // to actually store these
867         //state->minfo->slot = state->method->abc->method->trait->slot_id;
868     } else {
869         //class getter/setter
870         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
871         classinfo_t*type=0;
872         if(getset == KW_GET)
873             type = return_type;
874         else if(params->list)
875             type = params->list->param->type;
876         // not sure wether to look into superclasses here, too
877         if((minfo=registry_findmember(state->cls->info, name, 0))) {
878             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
879                 syntaxerror("class already contains a member or method called '%s'", name);
880             if(minfo->kind & gs)
881                 syntaxerror("getter/setter for '%s' already defined", name);
882             /* make a setter or getter into a getset */
883             minfo->kind |= gs;
884             if(!minfo->type) 
885                 minfo->type = type;
886             else
887                 if(type && minfo->type != type)
888                     syntaxerror("different type in getter and setter");
889         } else {
890             minfo = memberinfo_register(state->cls->info, name, gs);
891             minfo->type = type;
892         }
893         /* can't assign a slot as getter and setter might have different slots */
894         //minfo->slot = slot;
895     }
896     if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
897     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
898     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
899     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
900     if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
901     if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
902     return minfo;
903 }
904
905 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
906                           params_t*params, classinfo_t*return_type)
907 {
908     if(state->method && state->method->info) {
909         syntaxerror("not able to start another method scope");
910     }
911     new_state();
912     global->variable_count = 0;
913     state->method = rfx_calloc(sizeof(methodstate_t));
914     state->method->has_super = 0;
915
916     if(state->cls) {
917         state->method->is_constructor = !strcmp(state->cls->info->name,name);
918         state->cls->has_constructor |= state->method->is_constructor;
919         
920         new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
921     } else {
922         state->method->is_global = 1;
923         state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
924
925         new_variable("globalscope", 0, 0);
926     }
927
928     /* state->vars is initialized by state_new */
929
930     param_list_t*p=0;
931     for(p=params->list;p;p=p->next) {
932         new_variable(p->param->name, p->param->type, 0);
933     }
934     if(state->method->is_constructor)
935         name = "__as3_constructor__";
936     state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
937 }
938
939 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
940                           params_t*params, classinfo_t*return_type, code_t*body)
941 {
942     abc_method_t*f = 0;
943
944     multiname_t*type2 = sig2mname(return_type);
945     int slot = 0;
946     if(state->method->is_constructor) {
947         f = abc_class_getconstructor(state->cls->abc, type2);
948     } else if(!state->method->is_global) {
949         namespace_t mname_ns = flags2namespace(flags, "");
950         multiname_t mname = {QNAME, &mname_ns, 0, name};
951
952         if(flags&FLAG_STATIC)
953             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
954         else
955             f = abc_class_method(state->cls->abc, type2, &mname);
956         slot = f->trait->slot_id;
957     } else {
958         namespace_t mname_ns = flags2namespace(flags, state->package);
959         multiname_t mname = {QNAME, &mname_ns, 0, name};
960
961         f = abc_method_new(global->file, type2, 1);
962         trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
963         //abc_code_t*c = global->init->method->body->code;
964     }
965     //flash doesn't seem to allow us to access function slots
966     //state->method->info->slot = slot;
967
968     if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
969     if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
970     if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
971     if(params->varargs) f->flags |= METHOD_NEED_REST;
972
973     char opt=0;
974     param_list_t*p=0;
975     for(p=params->list;p;p=p->next) {
976         if(params->varargs && !p->next) {
977             break; //varargs: omit last parameter in function signature
978         }
979         multiname_t*m = sig2mname(p->param->type);
980         list_append(f->parameters, m);
981         if(p->param->value) {
982             check_constant_against_type(p->param->type, p->param->value);
983             opt=1;list_append(f->optional_parameters, p->param->value);
984         } else if(opt) {
985             syntaxerror("non-optional parameter not allowed after optional parameters");
986         }
987     }
988     check_code_for_break(body);
989
990     if(f->body) {
991         f->body->code = body;
992         f->body->exceptions = state->method->exceptions;
993     } else { //interface
994         if(body)
995             syntaxerror("interface methods can't have a method body");
996     }
997        
998     free(state->method);state->method=0;
999     old_state();
1000 }
1001
1002
1003
1004 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1005 {
1006     return 1; // FIXME
1007 }
1008
1009 void breakjumpsto(code_t*c, char*name, code_t*jump) 
1010 {
1011     while(c) {
1012         if(c->opcode == OPCODE___BREAK__) {
1013             string_t*name2 = c->data[0];
1014             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1015                 c->opcode = OPCODE_JUMP;
1016                 c->branch = jump;
1017             }
1018         }
1019         c=c->prev;
1020     }
1021 }
1022 void continuejumpsto(code_t*c, char*name, code_t*jump) 
1023 {
1024     while(c) {
1025         if(c->opcode == OPCODE___CONTINUE__) {
1026             string_t*name2 = c->data[0];
1027             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1028                 c->opcode = OPCODE_JUMP;
1029                 c->branch = jump;
1030             }
1031         }
1032         c = c->prev;
1033     }
1034 }
1035
1036 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1037 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1038 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1039
1040 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1041 {
1042     if(!type1 || !type2) 
1043         return registry_getanytype();
1044     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1045         return registry_getanytype();
1046
1047     if(op=='+') {
1048         if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1049             return TYPE_NUMBER;
1050         } else {
1051             return TYPE_ANY;
1052         }
1053     }
1054
1055     if(type1 == type2)
1056         return type1;
1057     return registry_getanytype();
1058 }
1059 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1060 {
1061     if(from==to)
1062         return c;
1063     if(!to) {
1064         return abc_coerce_a(c);
1065     }
1066     MULTINAME(m, to);
1067     if(!from) {
1068         // cast an "any" type to a specific type. subject to
1069         // runtime exceptions
1070         return abc_coerce2(c, &m);
1071     }
1072     
1073     if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1074        (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1075         // allow conversion between number types
1076         return abc_coerce2(c, &m);
1077     }
1078     //printf("%s.%s\n", from.package, from.name);
1079     //printf("%s.%s\n", to.package, to.name);
1080
1081     classinfo_t*supertype = from;
1082     while(supertype) {
1083         if(supertype == to) {
1084              // target type is one of from's superclasses
1085              return abc_coerce2(c, &m);
1086         }
1087         int t=0;
1088         while(supertype->interfaces[t]) {
1089             if(supertype->interfaces[t]==to) {
1090                 // target type is one of from's interfaces
1091                 return abc_coerce2(c, &m);
1092             }
1093             t++;
1094         }
1095         supertype = supertype->superclass;
1096     }
1097     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1098         return c;
1099     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1100         return c;
1101     syntaxerror("can't convert type %s to %s", from->name, to->name);
1102 }
1103
1104 code_t*defaultvalue(code_t*c, classinfo_t*type)
1105 {
1106     if(TYPE_IS_INT(type)) {
1107        c = abc_pushbyte(c, 0);
1108     } else if(TYPE_IS_UINT(type)) {
1109        c = abc_pushuint(c, 0);
1110     } else if(TYPE_IS_FLOAT(type)) {
1111        c = abc_pushnan(c);
1112     } else if(TYPE_IS_BOOLEAN(type)) {
1113        c = abc_pushfalse(c);
1114     } else if(!type) {
1115        //c = abc_pushundefined(c);
1116     } else {
1117        c = abc_pushnull(c);
1118        MULTINAME(m, type);
1119        c = abc_coerce2(c, &m);
1120     }
1121     return c;
1122 }
1123
1124 char is_pushundefined(code_t*c)
1125 {
1126     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1127 }
1128
1129 void parserassert(int b)
1130 {
1131     if(!b) syntaxerror("internal error: assertion failed");
1132 }
1133
1134 static classinfo_t* find_class(char*name)
1135 {
1136     classinfo_t*c=0;
1137
1138     c = registry_findclass(state->package, name);
1139     if(c) return c;
1140
1141     /* try explicit imports */
1142     dictentry_t* e = dict_get_slot(state->imports, name);
1143     if(c) return c;
1144     while(e) {
1145         if(!strcmp(e->key, name)) {
1146             c = (classinfo_t*)e->data;
1147             if(c) return c;
1148         }
1149         e = e->next;
1150     }
1151
1152     /* try package.* imports */
1153     import_list_t*l = state->wildcard_imports;
1154     while(l) {
1155         //printf("does package %s contain a class %s?\n", l->import->package, name);
1156         c = registry_findclass(l->import->package, name);
1157         if(c) return c;
1158         l = l->next;
1159     }
1160
1161     /* try global package */
1162     c = registry_findclass("", name);
1163     if(c) return c;
1164    
1165     /* try local "filename" package */
1166     c = registry_findclass(current_filename, name);
1167     if(c) return c;
1168
1169     return 0;
1170 }
1171
1172 static char is_getlocal(code_t*c)
1173 {
1174     if(!c || c->prev || c->next)
1175         return 0;
1176     return(c->opcode == OPCODE_GETLOCAL
1177         || c->opcode == OPCODE_GETLOCAL_0
1178         || c->opcode == OPCODE_GETLOCAL_1
1179         || c->opcode == OPCODE_GETLOCAL_2
1180         || c->opcode == OPCODE_GETLOCAL_3);
1181 }
1182 static int getlocalnr(code_t*c)
1183 {
1184     if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1185     else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1186     else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1187     else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1188     else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1189     else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1190 }
1191
1192 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1193 {
1194     /* converts this:
1195
1196        [prefix code] [read instruction]
1197
1198        to this:
1199
1200        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1201     */
1202     
1203     if(in && in->opcode == OPCODE_COERCE_A) {
1204         in = code_cutlast(in);
1205     }
1206     if(in->next)
1207         syntaxerror("internal error");
1208
1209     /* chop off read instruction */
1210     code_t*prefix = in;
1211     code_t*r = in;
1212     if(r->prev) {
1213         prefix = r->prev;r->prev = 0;
1214         prefix->next=0;
1215     } else {
1216         prefix = 0;
1217     }
1218
1219     char use_temp_var = readbefore;
1220
1221     /* generate the write instruction, and maybe append a dup to the prefix code */
1222     code_t* write = abc_nop(0);
1223     if(r->opcode == OPCODE_GETPROPERTY) {
1224         write->opcode = OPCODE_SETPROPERTY;
1225         multiname_t*m = (multiname_t*)r->data[0];
1226         write->data[0] = multiname_clone(m);
1227         if(m->type == QNAME || m->type == MULTINAME) {
1228             if(!justassign) {
1229                 prefix = abc_dup(prefix); // we need the object, too
1230             }
1231             use_temp_var = 1;
1232         } else if(m->type == MULTINAMEL) {
1233             if(!justassign) {
1234                 /* dupping two values on the stack requires 5 operations and one register- 
1235                    couldn't adobe just have given us a dup2? */
1236                 int temp = gettempvar();
1237                 prefix = abc_setlocal(prefix, temp);
1238                 prefix = abc_dup(prefix);
1239                 prefix = abc_getlocal(prefix, temp);
1240                 prefix = abc_swap(prefix);
1241                 prefix = abc_getlocal(prefix, temp);
1242                 if(!use_temp_var);
1243                     prefix = abc_kill(prefix, temp);
1244             }
1245             use_temp_var = 1;
1246         } else {
1247             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1248         }
1249     } else if(r->opcode == OPCODE_GETSLOT) {
1250         write->opcode = OPCODE_SETSLOT;
1251         write->data[0] = r->data[0];
1252         if(!justassign) {
1253             prefix = abc_dup(prefix); // we need the object, too
1254         }
1255         use_temp_var = 1;
1256     } else if(r->opcode == OPCODE_GETLOCAL) { 
1257         write->opcode = OPCODE_SETLOCAL;
1258         write->data[0] = r->data[0];
1259     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1260         write->opcode = OPCODE_SETLOCAL_0;
1261     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1262         write->opcode = OPCODE_SETLOCAL_1;
1263     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1264         write->opcode = OPCODE_SETLOCAL_2;
1265     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1266         write->opcode = OPCODE_SETLOCAL_3;
1267     } else {
1268         code_dump(r, 0, 0, "", stdout);
1269         syntaxerror("illegal lvalue: can't assign a value to this expression");
1270     }
1271     code_t* c = 0;
1272     
1273     int temp = -1;
1274     if(!justassign) {
1275         if(use_temp_var) {
1276             /* with getproperty/getslot, we have to be extra careful not
1277                to execute the read code twice, as it might have side-effects
1278                (e.g. if the property is in fact a setter/getter combination)
1279
1280                So read the value, modify it, and write it again,
1281                using prefix only once and making sure (by using a temporary
1282                register) that the return value is what we just wrote */
1283             temp = gettempvar();
1284             c = code_append(c, prefix);
1285             c = code_append(c, r);
1286             if(readbefore) {
1287                 c = abc_dup(c);
1288                 c = abc_setlocal(c, temp);
1289             }
1290             c = code_append(c, middlepart);
1291             if(!readbefore) {
1292                 c = abc_dup(c);
1293                 c = abc_setlocal(c, temp);
1294             }
1295             c = code_append(c, write);
1296             c = abc_getlocal(c, temp);
1297             c = abc_kill(c, temp);
1298         } else {
1299             /* if we're allowed to execute the read code twice *and*
1300                the middlepart doesn't modify the code, things are easier.
1301             */
1302             code_t* r2 = code_dup(r);
1303             //c = code_append(c, prefix);
1304             parserassert(!prefix);
1305             c = code_append(c, r);
1306             c = code_append(c, middlepart);
1307             c = code_append(c, write);
1308             c = code_append(c, r2);
1309         }
1310     } else {
1311         /* even smaller version: overwrite the value without reading
1312            it out first */
1313         if(!use_temp_var) {
1314             if(prefix) {
1315                 c = code_append(c, prefix);
1316                 c = abc_dup(c);
1317             }
1318             c = code_append(c, middlepart);
1319             c = code_append(c, write);
1320             c = code_append(c, r);
1321         } else {
1322             temp = gettempvar();
1323             if(prefix) {
1324                 c = code_append(c, prefix);
1325             }
1326             c = code_append(c, middlepart);
1327             c = abc_dup(c);
1328             c = abc_setlocal(c, temp);
1329             c = code_append(c, write);
1330             c = abc_getlocal(c, temp);
1331             c = abc_kill(c, temp);
1332         }
1333     }
1334
1335     return c;
1336 }
1337
1338
1339 %}
1340
1341
1342 %%
1343
1344 /* ------------ code blocks / statements ---------------- */
1345
1346 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1347
1348 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST 
1349 PROGRAM_CODE_LIST: PROGRAM_CODE 
1350                  | PROGRAM_CODE_LIST PROGRAM_CODE
1351
1352 PROGRAM_CODE: PACKAGE_DECLARATION 
1353             | INTERFACE_DECLARATION 
1354             | CLASS_DECLARATION
1355             | FUNCTION_DECLARATION
1356             | SLOT_DECLARATION
1357             | PACKAGE_INITCODE
1358             | ';'
1359
1360 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1361 INPACKAGE_CODE_LIST: INPACKAGE_CODE 
1362                    | INPACKAGE_CODE_LIST INPACKAGE_CODE
1363
1364 INPACKAGE_CODE: INTERFACE_DECLARATION 
1365               | CLASS_DECLARATION
1366               | FUNCTION_DECLARATION
1367               | SLOT_DECLARATION
1368               | PACKAGE_INITCODE
1369               | ';'
1370
1371 MAYBECODE: CODE {$$=$1;}
1372 MAYBECODE: {$$=code_new();}
1373
1374 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1375 CODE: CODEPIECE {$$=$1;}
1376
1377 // code which also may appear outside a method
1378 CODE_STATEMENT: IMPORT 
1379 CODE_STATEMENT: FOR 
1380 CODE_STATEMENT: FOR_IN 
1381 CODE_STATEMENT: WHILE 
1382 CODE_STATEMENT: DO_WHILE 
1383 CODE_STATEMENT: SWITCH 
1384 CODE_STATEMENT: IF
1385 CODE_STATEMENT: WITH
1386 CODE_STATEMENT: TRY
1387 CODE_STATEMENT: VOIDEXPRESSION 
1388
1389 // code which may appear anywhere
1390 CODEPIECE: ';' {$$=0;}
1391 CODEPIECE: CODE_STATEMENT
1392 CODEPIECE: VARIABLE_DECLARATION
1393 CODEPIECE: BREAK
1394 CODEPIECE: CONTINUE
1395 CODEPIECE: RETURN
1396 CODEPIECE: THROW
1397
1398 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1399 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=0;}
1400
1401 CODEBLOCK :  '{' CODE '}' {$$=$2;}
1402 CODEBLOCK :  '{' '}'      {$$=0;}
1403 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1404 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1405
1406 /* ------------ package init code ------------------- */
1407
1408 PACKAGE_INITCODE: CODE_STATEMENT {
1409     if($1) as3_warning("code ignored");
1410 }
1411
1412 /* ------------ variables --------------------------- */
1413
1414 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1415                 |                {$$.c=abc_pushundefined(0);
1416                                   $$.t=TYPE_ANY;
1417                                  }
1418
1419 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1420 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1421
1422 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1423 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1424
1425 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1426 {
1427     if(variable_exists($1))
1428         syntaxerror("Variable %s already defined", $1);
1429    
1430     if(!is_subtype_of($3.t, $2)) {
1431         syntaxerror("Can't convert %s to %s", $3.t->name, 
1432                                               $2->name);
1433     }
1434
1435     int index = new_variable($1, $2, 1);
1436     
1437     if($2) {
1438         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1439             $$ = $3.c;
1440             $$ = converttype($$, $3.t, $2);
1441             $$ = abc_setlocal($$, index);
1442         } else {
1443             $$ = defaultvalue(0, $2);
1444             $$ = abc_setlocal($$, index);
1445         }
1446     } else {
1447         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1448             $$ = $3.c;
1449             $$ = abc_coerce_a($$);
1450             $$ = abc_setlocal($$, index);
1451         } else {
1452             $$ = code_new();
1453         }
1454     }
1455     
1456     /* that's the default for a local register, anyway
1457         else {
1458         state->method->initcode = abc_pushundefined(state->method->initcode);
1459         state->method->initcode = abc_setlocal(state->method->initcode, index);
1460     }*/
1461     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1462 }
1463
1464 /* ------------ control flow ------------------------- */
1465
1466 MAYBEELSE:  %prec below_else {$$ = code_new();}
1467 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1468 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1469
1470 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1471      
1472     $$ = code_new();
1473     $$ = code_append($$, $4.c);
1474     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1475    
1476     $$ = code_append($$, $6);
1477     if($7) {
1478         myjmp = $$ = abc_jump($$, 0);
1479     }
1480     myif->branch = $$ = abc_nop($$);
1481     if($7) {
1482         $$ = code_append($$, $7);
1483         myjmp->branch = $$ = abc_nop($$);
1484     }
1485     $$ = var_block($$);
1486     old_state();
1487 }
1488
1489 FOR_INIT : {$$=code_new();}
1490 FOR_INIT : VARIABLE_DECLARATION
1491 FOR_INIT : VOIDEXPRESSION
1492
1493 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1494 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1495     $$=$2;new_variable($2,$3,1);
1496 }
1497 FOR_IN_INIT : T_IDENTIFIER {
1498     $$=$1;
1499 }
1500
1501 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1502 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1503
1504 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1505     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1506     $$ = code_new();
1507     $$ = code_append($$, $2);
1508     code_t*loopstart = $$ = abc_label($$);
1509     $$ = code_append($$, $4.c);
1510     code_t*myif = $$ = abc_iffalse($$, 0);
1511     $$ = code_append($$, $8);
1512     code_t*cont = $$ = abc_nop($$);
1513     $$ = code_append($$, $6);
1514     $$ = abc_jump($$, loopstart);
1515     code_t*out = $$ = abc_nop($$);
1516     breakjumpsto($$, $1.name, out);
1517     continuejumpsto($$, $1.name, cont);
1518     myif->branch = out;
1519
1520     $$ = var_block($$);
1521     old_state();
1522 }
1523
1524 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1525     variable_t*var = find_variable($2);
1526     char*tmp1name = concat2($2, "__tmp1__");
1527     int it = new_variable(tmp1name, TYPE_INT, 0);
1528     char*tmp2name = concat2($2, "__array__");
1529     int array = new_variable(tmp1name, 0, 0);
1530
1531     $$ = code_new();
1532     $$ = code_append($$, $4.c);
1533     $$ = abc_coerce_a($$);
1534     $$ = abc_setlocal($$, array);
1535     $$ = abc_pushbyte($$, 0);
1536     $$ = abc_setlocal($$, it);
1537
1538     code_t*loopstart = $$ = abc_label($$);
1539     
1540     $$ = abc_hasnext2($$, array, it);
1541     code_t*myif = $$ = abc_iffalse($$, 0);
1542     $$ = abc_getlocal($$, array);
1543     $$ = abc_getlocal($$, it);
1544     if(!$1.each)
1545         $$ = abc_nextname($$);
1546     else
1547         $$ = abc_nextvalue($$);
1548     $$ = converttype($$, 0, var->type);
1549     $$ = abc_setlocal($$, var->index);
1550
1551     $$ = code_append($$, $6);
1552     $$ = abc_jump($$, loopstart);
1553     
1554     code_t*out = $$ = abc_nop($$);
1555     breakjumpsto($$, $1.name, out);
1556     continuejumpsto($$, $1.name, loopstart);
1557     
1558     myif->branch = out;
1559
1560     $$ = var_block($$);
1561     old_state();
1562
1563     free(tmp1name);
1564     free(tmp2name);
1565 }
1566
1567 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1568
1569     $$ = code_new();
1570
1571     code_t*myjmp = $$ = abc_jump($$, 0);
1572     code_t*loopstart = $$ = abc_label($$);
1573     $$ = code_append($$, $6);
1574     code_t*cont = $$ = abc_nop($$);
1575     myjmp->branch = cont;
1576     $$ = code_append($$, $4.c);
1577     $$ = abc_iftrue($$, loopstart);
1578     code_t*out = $$ = abc_nop($$);
1579     breakjumpsto($$, $1, out);
1580     continuejumpsto($$, $1, cont);
1581
1582     $$ = var_block($$);
1583     old_state();
1584 }
1585
1586 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1587     $$ = code_new();
1588     code_t*loopstart = $$ = abc_label($$);
1589     $$ = code_append($$, $3);
1590     code_t*cont = $$ = abc_nop($$);
1591     $$ = code_append($$, $6.c);
1592     $$ = abc_iftrue($$, loopstart);
1593     code_t*out = $$ = abc_nop($$);
1594     breakjumpsto($$, $1, out);
1595     continuejumpsto($$, $1, cont);
1596     
1597     $$ = var_block($$);
1598     old_state();
1599 }
1600
1601 BREAK : "break" %prec prec_none {
1602     $$ = abc___break__(0, "");
1603 }
1604 BREAK : "break" T_IDENTIFIER {
1605     $$ = abc___break__(0, $2);
1606 }
1607 CONTINUE : "continue" %prec prec_none {
1608     $$ = abc___continue__(0, "");
1609 }
1610 CONTINUE : "continue" T_IDENTIFIER {
1611     $$ = abc___continue__(0, $2);
1612 }
1613
1614 MAYBE_CASE_LIST :           {$$=0;}
1615 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1616 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
1617 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1618 CASE_LIST: CASE             {$$=$1}
1619 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
1620
1621 CASE: "case" E ':' MAYBECODE {
1622     $$ = abc_dup(0);
1623     $$ = code_append($$, $2.c);
1624     code_t*j = $$ = abc_ifne($$, 0);
1625     $$ = code_append($$, $4);
1626     if($$->opcode != OPCODE___BREAK__) {
1627         $$ = abc___fallthrough__($$, "");
1628     }
1629     code_t*e = $$ = abc_nop($$);
1630     j->branch = e;
1631 }
1632 DEFAULT: "default" ':' MAYBECODE {
1633     $$ = $3;
1634 }
1635 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1636     $$=$4.c;
1637     $$ = code_append($$, $7);
1638     code_t*out = $$ = abc_pop($$);
1639     breakjumpsto($$, $1, out);
1640     
1641     code_t*c = $$,*lastblock=0;
1642     while(c) {
1643         if(c->opcode == OPCODE_IFNE) {
1644             if(!c->next) syntaxerror("internal error in fallthrough handling");
1645             lastblock=c->next;
1646         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1647             if(lastblock) {
1648                 c->opcode = OPCODE_JUMP;
1649                 c->branch = lastblock;
1650             } else {
1651                 /* fall through end of switch */
1652                 c->opcode = OPCODE_NOP;
1653             }
1654         }
1655         c=c->prev;
1656     }
1657    
1658     $$ = var_block($$);
1659     old_state();
1660 }
1661
1662 /* ------------ try / catch /finally ---------------- */
1663
1664 FINALLY: "finally" '{' CODE '}'
1665 MAYBE_FINALLY: | FINALLY 
1666
1667 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
1668         '{' CODE '}' {
1669     namespace_t name_ns = {ACCESS_PACKAGE, ""};
1670     multiname_t name = {QNAME, &name_ns, 0, $3};
1671     
1672     NEW(abc_exception_t, e)
1673     e->exc_type = sig2mname($4);
1674     e->var_name = multiname_clone(&name);
1675     $$ = e;
1676
1677     code_t*c = 0;
1678     int i = find_variable_safe($3)->index;
1679     e->target = c = abc_setlocal(0, i);
1680     c = code_append(c, $8);
1681     c = abc_kill(c, i);
1682
1683     c = var_block(c);
1684     old_state();
1685     
1686 }
1687
1688 CATCH_LIST: CATCH {$$=list_new();list_append($$,$1);}
1689 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$,$2);}
1690
1691 TRY : "try" '{' {new_state();} CODE '}' CATCH_LIST MAYBE_FINALLY {
1692     code_t*start = code_start($4);
1693     $$=$4;
1694
1695     code_t*out = abc_nop(0);
1696     code_t*jmp = $$ = abc_jump($$, out);
1697
1698     abc_exception_list_t*l = $6;
1699     while(l) {
1700         abc_exception_t*e = l->abc_exception;
1701         e->from = start;
1702         e->to = jmp;
1703         $$ = code_append($$, e->target);
1704         $$ = abc_jump($$, out);
1705         l = l->next;
1706     }
1707     $$ = code_append($$, out);
1708     jmp->branch = out;
1709         
1710     list_concat(state->method->exceptions, $6);
1711    
1712     $$ = var_block($$);
1713     old_state();
1714 }
1715
1716 /* ------------ throw ------------------------------- */
1717
1718 THROW : "throw" EXPRESSION {
1719     $$=$2.c;
1720     $$=abc_throw($$);
1721 }
1722 THROW : "throw" %prec prec_none {
1723     if(!state->exception_name)
1724         syntaxerror("re-throw only possible within a catch block");
1725     variable_t*v = find_variable(state->exception_name);
1726     $$=code_new();
1727     $$=abc_getlocal($$, v->index);
1728     $$=abc_throw($$);
1729 }
1730
1731 /* ------------ with -------------------------------- */
1732
1733 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
1734      $$ = $3.c;
1735      $$ = abc_pushscope($$);
1736      $$ = code_append($$, $5);
1737      $$ = abc_popscope($$);
1738 }
1739
1740 /* ------------ packages and imports ---------------- */
1741
1742 X_IDENTIFIER: T_IDENTIFIER
1743             | "package" {$$="package";}
1744
1745 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1746 PACKAGE: X_IDENTIFIER             {$$=strdup($1);}
1747
1748 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1749 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBE_INPACKAGE_CODE_LIST '}' {endpackage();$$=0;}
1750
1751 IMPORT : "import" QNAME {
1752        classinfo_t*c = $2;
1753        if(!c) 
1754             syntaxerror("Couldn't import class\n");
1755        state_has_imports();
1756        dict_put(state->imports, c->name, c);
1757        $$=0;
1758 }
1759 IMPORT : "import" PACKAGE '.' '*' {
1760        NEW(import_t,i);
1761        i->package = $2;
1762        state_has_imports();
1763        list_append(state->wildcard_imports, i);
1764        $$=0;
1765 }
1766
1767 /* ------------ classes and interfaces (header) -------------- */
1768
1769 MAYBE_MODIFIERS : %prec above_function {$$=0;}
1770 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1771 MODIFIER_LIST : MODIFIER               {$$=$1;}
1772 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1773
1774 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1775          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1776          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1777          | KW_STATIC {$$=FLAG_STATIC;}
1778          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1779          | KW_FINAL {$$=FLAG_FINAL;}
1780          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1781          | KW_NATIVE {$$=FLAG_NATIVE;}
1782          | KW_INTERNAL {$$=FLAG_PACKAGEINTERNAL;}
1783
1784 EXTENDS : {$$=registry_getobjectclass();}
1785 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1786
1787 EXTENDS_LIST : {$$=list_new();}
1788 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1789
1790 IMPLEMENTS_LIST : {$$=list_new();}
1791 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1792
1793 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1794                               EXTENDS IMPLEMENTS_LIST 
1795                               '{' {startclass($1,$3,$4,$5, 0);} 
1796                               MAYBE_CLASS_BODY 
1797                               '}' {endclass();$$=0;}
1798
1799 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1800                               EXTENDS_LIST 
1801                               '{' {startclass($1,$3,0,$4,1);}
1802                               MAYBE_INTERFACE_BODY 
1803                               '}' {endclass();$$=0;}
1804
1805 /* ------------ classes and interfaces (body) -------------- */
1806
1807 MAYBE_CLASS_BODY : 
1808 MAYBE_CLASS_BODY : CLASS_BODY
1809 CLASS_BODY : CLASS_BODY_ITEM
1810 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
1811 CLASS_BODY_ITEM : ';'
1812 CLASS_BODY_ITEM : SLOT_DECLARATION
1813 CLASS_BODY_ITEM : FUNCTION_DECLARATION
1814
1815 CLASS_BODY_ITEM : CODE_STATEMENT {
1816     code_t*c = state->cls->static_init;
1817     c = code_append(c, $1);  
1818     state->cls->static_init = c;
1819 }
1820
1821 MAYBE_INTERFACE_BODY : 
1822 MAYBE_INTERFACE_BODY : INTERFACE_BODY
1823 INTERFACE_BODY : IDECLARATION
1824 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
1825 IDECLARATION : ';'
1826 IDECLARATION : "var" T_IDENTIFIER {
1827     syntaxerror("variable declarations not allowed in interfaces");
1828 }
1829 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1830     $1 |= FLAG_PUBLIC;
1831     if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
1832         syntaxerror("invalid method modifiers: interface methods always need to be public");
1833     }
1834     startfunction(0,$1,$3,$4,&$6,$8);
1835     endfunction(0,$1,$3,$4,&$6,$8, 0);
1836 }
1837
1838 /* ------------ classes and interfaces (body, slots ) ------- */
1839
1840 VARCONST: "var" | "const"
1841
1842 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1843     int flags = $1;
1844     memberinfo_t* info = state->cls?
1845             memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
1846             memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
1847
1848     info->type = $4;
1849     info->flags = flags;
1850
1851     /* slot name */
1852     namespace_t mname_ns = {flags2access(flags), ""};
1853     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1854   
1855     trait_list_t**traits;
1856     code_t**code;
1857     if(!state->cls) {
1858         // global variable
1859         traits = &global->init->traits;
1860         code = &global->init->method->body->code;
1861     } else if(flags&FLAG_STATIC) {
1862         // static variable
1863         traits = &state->cls->abc->static_traits;
1864         code = &state->cls->static_init;
1865     } else {
1866         // instance variable
1867         traits = &state->cls->abc->traits;
1868         code = &state->cls->init;
1869     }
1870     
1871     trait_t*t=0;
1872     if($4) {
1873         MULTINAME(m, $4);
1874         t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
1875     } else {
1876         t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
1877     }
1878     info->slot = t->slot_id;
1879     
1880     /* initalization code (if needed) */
1881     code_t*c = 0;
1882     if($5.c && !is_pushundefined($5.c)) {
1883         c = abc_getlocal_0(c);
1884         c = code_append(c, $5.c);
1885         c = converttype(c, $5.t, $4);
1886         c = abc_setslot(c, t->slot_id);
1887     }
1888
1889     *code = code_append(*code, c);
1890
1891     if($2==KW_CONST) {
1892         t->kind= TRAIT_CONST;
1893     }
1894
1895     $$=0;
1896 }
1897
1898 /* ------------ constants -------------------------------------- */
1899
1900 MAYBESTATICCONSTANT: {$$=0;}
1901 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1902
1903 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1904 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1905 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1906 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1907 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1908 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1909 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1910 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1911 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1912
1913 /* ------------ classes and interfaces (body, functions) ------- */
1914
1915 // non-vararg version
1916 MAYBE_PARAM_LIST: {
1917     memset(&$$,0,sizeof($$));
1918 }
1919 MAYBE_PARAM_LIST: PARAM_LIST {
1920     $$=$1;
1921 }
1922
1923 // vararg version
1924 MAYBE_PARAM_LIST: "..." PARAM {
1925     memset(&$$,0,sizeof($$));
1926     $$.varargs=1;
1927     list_append($$.list, $2);
1928 }
1929 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1930     $$ =$1;
1931     $$.varargs=1;
1932     list_append($$.list, $4);
1933 }
1934
1935 // non empty
1936 PARAM_LIST: PARAM_LIST ',' PARAM {
1937     $$ = $1;
1938     list_append($$.list, $3);
1939 }
1940 PARAM_LIST: PARAM {
1941     memset(&$$,0,sizeof($$));
1942     list_append($$.list, $1);
1943 }
1944
1945 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1946      $$ = malloc(sizeof(param_t));
1947      $$->name=$1;
1948      $$->type = $3;
1949      $$->value = $4;
1950 }
1951 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1952      $$ = malloc(sizeof(param_t));
1953      $$->name=$1;
1954      $$->type = TYPE_ANY;
1955      $$->value = $2;
1956 }
1957 GETSET : "get" {$$=$1;}
1958        | "set" {$$=$1;}
1959        |       {$$=0;}
1960
1961 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1962                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1963 {
1964     code_t*c = 0;
1965     if(state->method->late_binding) {
1966         c = abc_getlocal_0(c);
1967         c = abc_pushscope(c);
1968     }
1969     if(state->method->is_constructor && !state->method->has_super) {
1970         // call default constructor
1971         c = abc_getlocal_0(c);
1972         c = abc_constructsuper(c, 0);
1973     }
1974     c = wrap_function(c, 0, $11);
1975     endfunction(0,$1,$3,$4,&$6,$8,c);
1976     $$=0;
1977 }
1978
1979 MAYBE_IDENTIFIER: T_IDENTIFIER
1980 MAYBE_IDENTIFIER: {$$=0;}
1981 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE '{' MAYBECODE '}'
1982 {
1983     syntaxerror("nested functions not supported yet");
1984 }
1985
1986
1987 /* ------------- package + class ids --------------- */
1988
1989 CLASS: T_IDENTIFIER {
1990
1991     /* try current package */
1992     $$ = find_class($1);
1993     if(!$$) syntaxerror("Could not find class %s\n", $1);
1994 }
1995
1996 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1997     $$ = registry_findclass($1, $3);
1998     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1999     free($1);$1=0;
2000 }
2001
2002 QNAME: PACKAGEANDCLASS
2003      | CLASS
2004
2005 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
2006 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
2007
2008 TYPE : QNAME      {$$=$1;}
2009      | '*'        {$$=registry_getanytype();}
2010      | "void"     {$$=registry_getanytype();}
2011     /*
2012      |  "String"  {$$=registry_getstringclass();}
2013      |  "int"     {$$=registry_getintclass();}
2014      |  "uint"    {$$=registry_getuintclass();}
2015      |  "Boolean" {$$=registry_getbooleanclass();}
2016      |  "Number"  {$$=registry_getnumberclass();}
2017     */
2018
2019 MAYBETYPE: ':' TYPE {$$=$2;}
2020 MAYBETYPE:          {$$=0;}
2021
2022 /* ----------function calls, delete, constructor calls ------ */
2023
2024 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
2025 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
2026
2027 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2028 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2029 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
2030                                                   $$.cc = $1.c;
2031                                                  }
2032 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2033                                                   $$.len= $1.len+1;
2034                                                   $$.cc = code_append($1.cc, $3.c);
2035                                                   }
2036
2037 NEW : "new" CLASS MAYBE_PARAM_VALUES {
2038     MULTINAME(m, $2);
2039     $$.c = code_new();
2040
2041     if($2->slot) {
2042         $$.c = abc_getglobalscope($$.c);
2043         $$.c = abc_getslot($$.c, $2->slot);
2044     } else {
2045         $$.c = abc_findpropstrict2($$.c, &m);
2046     }
2047
2048     $$.c = code_append($$.c, $3.cc);
2049
2050     if($2->slot)
2051         $$.c = abc_construct($$.c, $3.len);
2052     else
2053         $$.c = abc_constructprop2($$.c, &m, $3.len);
2054     $$.t = $2;
2055 }
2056
2057 /* TODO: use abc_call (for calling local variables),
2058          abc_callstatic (for calling own methods) 
2059          call (for closures)
2060 */
2061 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2062     
2063     $$.c = $1.c;
2064     if($$.c->opcode == OPCODE_COERCE_A) {
2065         $$.c = code_cutlast($$.c);
2066     }
2067     code_t*paramcode = $3.cc;
2068
2069     $$.t = TYPE_ANY;
2070     if($$.c->opcode == OPCODE_GETPROPERTY) {
2071         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2072         $$.c = code_cutlast($$.c);
2073         $$.c = code_append($$.c, paramcode);
2074         $$.c = abc_callproperty2($$.c, name, $3.len);
2075         multiname_destroy(name);
2076     } else if($$.c->opcode == OPCODE_GETSLOT) {
2077         int slot = (int)(ptroff_t)$$.c->data[0];
2078         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2079         if(t->kind!=TRAIT_METHOD) {
2080             //ok: flash allows to assign closures to members.
2081         }
2082         multiname_t*name = t->name;
2083         $$.c = code_cutlast($$.c);
2084         $$.c = code_append($$.c, paramcode);
2085         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2086         $$.c = abc_callproperty2($$.c, name, $3.len);
2087     } else if($$.c->opcode == OPCODE_GETSUPER) {
2088         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2089         $$.c = code_cutlast($$.c);
2090         $$.c = code_append($$.c, paramcode);
2091         $$.c = abc_callsuper2($$.c, name, $3.len);
2092         multiname_destroy(name);
2093     } else {
2094         $$.c = abc_getlocal_0($$.c);
2095         $$.c = code_append($$.c, paramcode);
2096         $$.c = abc_call($$.c, $3.len);
2097     }
2098    
2099     memberinfo_t*f = 0;
2100    
2101     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2102         $$.t = $1.t->function->return_type;
2103     } else {
2104         $$.c = abc_coerce_a($$.c);
2105         $$.t = TYPE_ANY;
2106     }
2107
2108 }
2109 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2110     if(!state->cls) syntaxerror("super() not allowed outside of a class");
2111     if(!state->method) syntaxerror("super() not allowed outside of a function");
2112     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2113
2114     $$.c = code_new();
2115     $$.c = abc_getlocal_0($$.c);
2116
2117     $$.c = code_append($$.c, $3.cc);
2118     /*
2119     this is dependent on the control path, check this somewhere else
2120     if(state->method->has_super)
2121         syntaxerror("constructor may call super() only once");
2122     */
2123     state->method->has_super = 1;
2124     $$.c = abc_constructsuper($$.c, $3.len);
2125     $$.c = abc_pushundefined($$.c);
2126     $$.t = TYPE_ANY;
2127 }
2128
2129 DELETE: "delete" E {
2130     $$.c = $2.c;
2131     if($$.c->opcode == OPCODE_COERCE_A) {
2132         $$.c = code_cutlast($$.c);
2133     }
2134     multiname_t*name = 0;
2135     if($$.c->opcode == OPCODE_GETPROPERTY) {
2136         $$.c->opcode = OPCODE_DELETEPROPERTY;
2137     } else if($$.c->opcode == OPCODE_GETSLOT) {
2138         int slot = (int)(ptroff_t)$$.c->data[0];
2139         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2140         $$.c = code_cutlast($$.c);
2141         $$.c = abc_deleteproperty2($$.c, name);
2142     } else {
2143         $$.c = abc_getlocal_0($$.c);
2144         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2145         $$.c = abc_deleteproperty2($$.c, &m);
2146     }
2147     $$.t = TYPE_BOOLEAN;
2148 }
2149
2150 RETURN: "return" %prec prec_none {
2151     $$ = abc_returnvoid(0);
2152 }
2153 RETURN: "return" EXPRESSION {
2154     $$ = $2.c;
2155     $$ = abc_returnvalue($$);
2156 }
2157
2158 // ----------------------- expression types -------------------------------------
2159
2160 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
2161 EXPRESSION : E                %prec below_minus {$$ = $1;}
2162 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2163     $$.c = $1.c;
2164     $$.c = cut_last_push($$.c);
2165     $$.c = code_append($$.c,$3.c);
2166     $$.t = $3.t;
2167 }
2168 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2169     $$=cut_last_push($1.c);
2170 }
2171
2172 // ----------------------- expression evaluation -------------------------------------
2173
2174 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2175 //V : CONSTANT                    {$$ = 0;}
2176 E : CONSTANT
2177 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2178 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2179 //V : NEW                         {$$ = $1.c;}
2180 E : NEW                         {$$ = $1;}
2181 //V : DELETE                      {$$ = $1.c;}
2182 E : DELETE                      {$$ = $1;}
2183
2184 E : T_REGEXP {
2185     $$.c = 0;
2186     namespace_t ns = {ACCESS_PACKAGE, ""};
2187     multiname_t m = {QNAME, &ns, 0, "RegExp"};
2188     if(!$1.options) {
2189         $$.c = abc_getlex2($$.c, &m);
2190         $$.c = abc_pushstring($$.c, $1.pattern);
2191         $$.c = abc_construct($$.c, 1);
2192     } else {
2193         $$.c = abc_getlex2($$.c, &m);
2194         $$.c = abc_pushstring($$.c, $1.pattern);
2195         $$.c = abc_pushstring($$.c, $1.options);
2196         $$.c = abc_construct($$.c, 2);
2197     }
2198     $$.t = TYPE_REGEXP;
2199 }
2200
2201 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2202                    //MULTINAME(m, registry_getintclass());
2203                    //$$.c = abc_coerce2($$.c, &m); // FIXME
2204                    $$.t = TYPE_INT;
2205                   }
2206 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2207                     $$.t = TYPE_INT;
2208                    }
2209 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2210                   $$.t = TYPE_INT;
2211                  }
2212 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2213                    $$.t = TYPE_UINT;
2214                   }
2215 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2216                     $$.t = TYPE_FLOAT;
2217                    }
2218 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2219                      $$.t = TYPE_STRING;
2220                     }
2221 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2222                     $$.t = TYPE_ANY;
2223                    }
2224 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2225                     $$.t = TYPE_BOOLEAN;
2226                    }
2227 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2228                      $$.t = TYPE_BOOLEAN;
2229                     }
2230 CONSTANT : "null" {$$.c = abc_pushnull(0);
2231                     $$.t = TYPE_NULL;
2232                    }
2233
2234 E : FUNCTIONCALL
2235 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2236              $$.t = TYPE_BOOLEAN;
2237             }
2238 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2239              $$.t = TYPE_BOOLEAN;
2240             }
2241 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2242               $$.t = TYPE_BOOLEAN;
2243              }
2244 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2245               $$.t = TYPE_BOOLEAN;
2246              }
2247 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2248               $$.t = TYPE_BOOLEAN;
2249              }
2250 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2251               $$.t = TYPE_BOOLEAN;
2252               }
2253 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2254               $$.t = TYPE_BOOLEAN;
2255              }
2256 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2257               $$.t = TYPE_BOOLEAN;
2258              }
2259
2260 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2261               $$.c = $1.c;
2262               $$.c = converttype($$.c, $1.t, $$.t);
2263               $$.c = abc_dup($$.c);
2264               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2265               $$.c = cut_last_push($$.c);
2266               $$.c = code_append($$.c,$3.c);
2267               $$.c = converttype($$.c, $3.t, $$.t);
2268               code_t*label = $$.c = abc_label($$.c);
2269               jmp->branch = label;
2270              }
2271 E : E "&&" E {
2272               $$.t = join_types($1.t, $3.t, 'A');
2273               /*printf("%08x:\n",$1.t);
2274               code_dump($1.c, 0, 0, "", stdout);
2275               printf("%08x:\n",$3.t);
2276               code_dump($3.c, 0, 0, "", stdout);
2277               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2278               $$.c = $1.c;
2279               $$.c = converttype($$.c, $1.t, $$.t);
2280               $$.c = abc_dup($$.c);
2281               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2282               $$.c = cut_last_push($$.c);
2283               $$.c = code_append($$.c,$3.c);
2284               $$.c = converttype($$.c, $3.t, $$.t);
2285               code_t*label = $$.c = abc_label($$.c);
2286               jmp->branch = label;              
2287              }
2288
2289 E : '!' E    {$$.c=$2.c;
2290               $$.c = abc_not($$.c);
2291               $$.t = TYPE_BOOLEAN;
2292              }
2293
2294 E : '~' E    {$$.c=$2.c;
2295               $$.c = abc_bitnot($$.c);
2296               $$.t = TYPE_INT;
2297              }
2298
2299 E : E '&' E {$$.c = code_append($1.c,$3.c);
2300              $$.c = abc_bitand($$.c);
2301              $$.t = TYPE_INT;
2302             }
2303
2304 E : E '^' E {$$.c = code_append($1.c,$3.c);
2305              $$.c = abc_bitxor($$.c);
2306              $$.t = TYPE_INT;
2307             }
2308
2309 E : E '|' E {$$.c = code_append($1.c,$3.c);
2310              $$.c = abc_bitor($$.c);
2311              $$.t = TYPE_INT;
2312             }
2313
2314 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2315              $$.c = abc_rshift($$.c);
2316              $$.t = TYPE_INT;
2317             }
2318 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2319              $$.c = abc_urshift($$.c);
2320              $$.t = TYPE_INT;
2321             }
2322 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2323              $$.c = abc_lshift($$.c);
2324              $$.t = TYPE_INT;
2325             }
2326
2327 E : E '/' E {$$.c = code_append($1.c,$3.c);
2328              $$.c = abc_divide($$.c);
2329              $$.t = TYPE_NUMBER;
2330             }
2331 E : E '%' E {$$.c = code_append($1.c,$3.c);
2332              $$.c = abc_modulo($$.c);
2333              $$.t = TYPE_NUMBER;
2334             }
2335 E : E '+' E {$$.c = code_append($1.c,$3.c);
2336              if(BOTH_INT($1.t, $3.t)) {
2337                 $$.c = abc_add_i($$.c);
2338                 $$.t = TYPE_INT;
2339              } else {
2340                 $$.c = abc_add($$.c);
2341                 $$.t = join_types($1.t,$3.t,'+');
2342              }
2343             }
2344 E : E '-' E {$$.c = code_append($1.c,$3.c);
2345              if(BOTH_INT($1.t,$3.t)) {
2346                 $$.c = abc_subtract_i($$.c);
2347                 $$.t = TYPE_INT;
2348              } else {
2349                 $$.c = abc_subtract($$.c);
2350                 $$.t = TYPE_NUMBER;
2351              }
2352             }
2353 E : E '*' E {$$.c = code_append($1.c,$3.c);
2354              if(BOTH_INT($1.t,$3.t)) {
2355                 $$.c = abc_multiply_i($$.c);
2356                 $$.t = TYPE_INT;
2357              } else {
2358                 $$.c = abc_multiply($$.c);
2359                 $$.t = TYPE_NUMBER;
2360              }
2361             }
2362
2363 E : E "in" E {$$.c = code_append($1.c,$3.c);
2364               $$.c = abc_in($$.c);
2365               $$.t = TYPE_BOOLEAN;
2366              }
2367
2368 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2369               if(use_astype && TYPE_IS_CLASS($3.t)) {
2370                 MULTINAME(m,$3.t->cls);
2371                 $$.c = abc_astype2($1.c, &m);
2372                 $$.t = $3.t->cls;
2373               } else {
2374                 $$.c = code_append($1.c, $3.c);
2375                 $$.c = abc_astypelate($$.c);
2376                 $$.t = TYPE_ANY;
2377               }
2378              }
2379
2380 E : E "instanceof" E 
2381              {$$.c = code_append($1.c, $3.c);
2382               $$.c = abc_instanceof($$.c);
2383               $$.t = TYPE_BOOLEAN;
2384              }
2385
2386 E : E "is" E {$$.c = code_append($1.c, $3.c);
2387               $$.c = abc_istypelate($$.c);
2388               $$.t = TYPE_BOOLEAN;
2389              }
2390
2391 E : "typeof" '(' E ')' {
2392               $$.c = $3.c;
2393               $$.c = abc_typeof($$.c);
2394               $$.t = TYPE_STRING;
2395              }
2396
2397 E : "void" E {
2398               $$.c = cut_last_push($2.c);
2399               $$.c = abc_pushundefined($$.c);
2400               $$.t = TYPE_ANY;
2401              }
2402
2403 E : "void" { $$.c = abc_pushundefined(0);
2404              $$.t = TYPE_ANY;
2405            }
2406
2407 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2408
2409 E : '-' E {
2410   $$=$2;
2411   if(IS_INT($2.t)) {
2412    $$.c=abc_negate_i($$.c);
2413    $$.t = TYPE_INT;
2414   } else {
2415    $$.c=abc_negate($$.c);
2416    $$.t = TYPE_NUMBER;
2417   }
2418 }
2419
2420 E : E '[' E ']' {
2421   $$.c = $1.c;
2422   $$.c = code_append($$.c, $3.c);
2423  
2424   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2425   $$.c = abc_getproperty2($$.c, &m);
2426   $$.t = 0; // array elements have unknown type
2427 }
2428
2429 E : '[' MAYBE_EXPRESSION_LIST ']' {
2430     $$.c = code_new();
2431     $$.c = code_append($$.c, $2.cc);
2432     $$.c = abc_newarray($$.c, $2.len);
2433     $$.t = registry_getarrayclass();
2434 }
2435
2436 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2437 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2438
2439 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2440     $$.cc = 0;
2441     $$.cc = code_append($$.cc, $1.c);
2442     $$.cc = code_append($$.cc, $3.c);
2443     $$.len = 2;
2444 }
2445 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2446     $$.cc = $1.cc;
2447     $$.len = $1.len+2;
2448     $$.cc = code_append($$.cc, $3.c);
2449     $$.cc = code_append($$.cc, $5.c);
2450 }
2451 //MAYBECOMMA: ','
2452 //MAYBECOMMA:
2453
2454 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2455     $$.c = code_new();
2456     $$.c = code_append($$.c, $2.cc);
2457     $$.c = abc_newobject($$.c, $2.len/2);
2458     $$.t = registry_getobjectclass();
2459 }
2460
2461 E : E "*=" E { 
2462                code_t*c = $3.c;
2463                if(BOTH_INT($1.t,$3.t)) {
2464                 c=abc_multiply_i(c);
2465                } else {
2466                 c=abc_multiply(c);
2467                }
2468                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2469                $$.c = toreadwrite($1.c, c, 0, 0);
2470                $$.t = $1.t;
2471               }
2472
2473 E : E "%=" E { 
2474                code_t*c = abc_modulo($3.c);
2475                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2476                $$.c = toreadwrite($1.c, c, 0, 0);
2477                $$.t = $1.t;
2478               }
2479 E : E "<<=" E { 
2480                code_t*c = abc_lshift($3.c);
2481                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2482                $$.c = toreadwrite($1.c, c, 0, 0);
2483                $$.t = $1.t;
2484               }
2485 E : E ">>=" E { 
2486                code_t*c = abc_rshift($3.c);
2487                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2488                $$.c = toreadwrite($1.c, c, 0, 0);
2489                $$.t = $1.t;
2490               }
2491 E : E ">>>=" E { 
2492                code_t*c = abc_urshift($3.c);
2493                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2494                $$.c = toreadwrite($1.c, c, 0, 0);
2495                $$.t = $1.t;
2496               }
2497 E : E "/=" E { 
2498                code_t*c = abc_divide($3.c);
2499                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2500                $$.c = toreadwrite($1.c, c, 0, 0);
2501                $$.t = $1.t;
2502               }
2503 E : E "|=" E { 
2504                code_t*c = abc_bitor($3.c);
2505                c=converttype(c, TYPE_INT, $1.t);
2506                $$.c = toreadwrite($1.c, c, 0, 0);
2507                $$.t = $1.t;
2508               }
2509 E : E "+=" E { 
2510                code_t*c = $3.c;
2511
2512                if(TYPE_IS_INT($1.t)) {
2513                 c=abc_add_i(c);
2514                } else {
2515                 c=abc_add(c);
2516                 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2517                }
2518                
2519                $$.c = toreadwrite($1.c, c, 0, 0);
2520                $$.t = $1.t;
2521               }
2522 E : E "-=" E { code_t*c = $3.c; 
2523                if(TYPE_IS_INT($1.t)) {
2524                 c=abc_subtract_i(c);
2525                } else {
2526                 c=abc_subtract(c);
2527                 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2528                }
2529                
2530                $$.c = toreadwrite($1.c, c, 0, 0);
2531                $$.t = $1.t;
2532              }
2533 E : E '=' E { code_t*c = 0;
2534               c = code_append(c, $3.c);
2535               c = converttype(c, $3.t, $1.t);
2536               $$.c = toreadwrite($1.c, c, 1, 0);
2537               $$.t = $1.t;
2538             }
2539
2540 E : E '?' E ':' E %prec below_assignment { 
2541               $$.t = join_types($3.t,$5.t,'?');
2542               $$.c = $1.c;
2543               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2544               $$.c = code_append($$.c, $3.c);
2545               $$.c = converttype($$.c, $3.t, $$.t);
2546               code_t*j2 = $$.c = abc_jump($$.c, 0);
2547               $$.c = j1->branch = abc_label($$.c);
2548               $$.c = code_append($$.c, $5.c);
2549               $$.c = converttype($$.c, $3.t, $$.t);
2550               $$.c = j2->branch = abc_label($$.c);
2551             }
2552
2553 E : E "++" { code_t*c = 0;
2554              classinfo_t*type = $1.t;
2555              if(is_getlocal($1.c) && TYPE_IS_INT($1.t) || TYPE_IS_NUMBER($1.t)) {
2556                  int nr = getlocalnr($1.c);
2557                  code_free($1.c);$1.c=0;
2558                  if(TYPE_IS_INT($1.t)) {
2559                     $$.c = abc_getlocal(0, nr);
2560                     $$.c = abc_inclocal_i($$.c, nr);
2561                  } else if(TYPE_IS_NUMBER($1.t)) {
2562                     $$.c = abc_getlocal(0, nr);
2563                     $$.c = abc_inclocal($$.c, nr);
2564                  } else syntaxerror("internal error");
2565              } else {
2566                  if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2567                      c=abc_increment_i(c);
2568                      type = TYPE_INT;
2569                  } else {
2570                      c=abc_increment(c);
2571                      type = TYPE_NUMBER;
2572                  }
2573                  c=converttype(c, type, $1.t);
2574                  $$.c = toreadwrite($1.c, c, 0, 1);
2575                  $$.t = $1.t;
2576              }
2577            }
2578
2579 // TODO: use inclocal, like with ++
2580 E : E "--" { code_t*c = 0;
2581              classinfo_t*type = $1.t;
2582              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2583                  c=abc_decrement_i(c);
2584                  type = TYPE_INT;
2585              } else {
2586                  c=abc_decrement(c);
2587                  type = TYPE_NUMBER;
2588              }
2589              c=converttype(c, type, $1.t);
2590              $$.c = toreadwrite($1.c, c, 0, 1);
2591              $$.t = $1.t;
2592             }
2593
2594 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2595              classinfo_t*type = $2.t;
2596              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2597                  c=abc_increment_i(c);
2598                  type = TYPE_INT;
2599              } else {
2600                  c=abc_increment(c);
2601                  type = TYPE_NUMBER;
2602              }
2603              c=converttype(c, type, $2.t);
2604              $$.c = toreadwrite($2.c, c, 0, 0);
2605              $$.t = $2.t;
2606            }
2607
2608 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2609              classinfo_t*type = $2.t;
2610              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2611                  c=abc_decrement_i(c);
2612                  type = TYPE_INT;
2613              } else {
2614                  c=abc_decrement(c);
2615                  type = TYPE_NUMBER;
2616              }
2617              c=converttype(c, type, $2.t);
2618              $$.c = toreadwrite($2.c, c, 0, 0);
2619              $$.t = $2.t;
2620            }
2621
2622 E : "super" '.' T_IDENTIFIER 
2623            { if(!state->cls->info)
2624                   syntaxerror("super keyword not allowed outside a class");
2625               classinfo_t*t = state->cls->info->superclass;
2626               if(!t) t = TYPE_OBJECT;
2627
2628               memberinfo_t*f = registry_findmember(t, $3, 1);
2629               namespace_t ns = flags2namespace(f->flags, "");
2630               MEMBER_MULTINAME(m, f, $3);
2631               $$.c = 0;
2632               $$.c = abc_getlocal_0($$.c);
2633               $$.c = abc_getsuper2($$.c, &m);
2634               $$.t = memberinfo_gettype(f);
2635            }
2636
2637 E : E '.' T_IDENTIFIER
2638             {$$.c = $1.c;
2639              classinfo_t*t = $1.t;
2640              char is_static = 0;
2641              if(TYPE_IS_CLASS(t) && t->cls) {
2642                  t = t->cls;
2643                  is_static = 1;
2644              }
2645              if(t) {
2646                  memberinfo_t*f = registry_findmember(t, $3, 1);
2647                  char noslot = 0;
2648                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2649                     noslot=1;
2650                  if(f && f->slot && !noslot) {
2651                      $$.c = abc_getslot($$.c, f->slot);
2652                  } else {
2653                      MEMBER_MULTINAME(m, f, $3);
2654                      $$.c = abc_getproperty2($$.c, &m);
2655                  }
2656                  /* determine type */
2657                  $$.t = memberinfo_gettype(f);
2658                  if(!$$.t)
2659                     $$.c = abc_coerce_a($$.c);
2660              } else {
2661                  /* when resolving a property on an unknown type, we do know the
2662                     name of the property (and don't seem to need the package), but
2663                     we need to make avm2 try out all access modes */
2664                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2665                  $$.c = abc_getproperty2($$.c, &m);
2666                  $$.c = abc_coerce_a($$.c);
2667                  $$.t = registry_getanytype();
2668              }
2669             }
2670
2671 VAR_READ : T_IDENTIFIER {
2672     $$.t = 0;
2673     $$.c = 0;
2674     classinfo_t*a = 0;
2675     memberinfo_t*f = 0;
2676
2677     variable_t*v;
2678     /* look at variables */
2679     if((v = find_variable($1))) {
2680         // $1 is a local variable
2681         $$.c = abc_getlocal($$.c, v->index);
2682         $$.t = v->type;
2683
2684     /* look at current class' members */
2685     } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2686         // $1 is a function in this class
2687         int var_is_static = (f->flags&FLAG_STATIC);
2688         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2689         if(var_is_static != i_am_static) {
2690             /* there doesn't seem to be any "static" way to access
2691                static properties of a class */
2692             state->method->late_binding = 1;
2693             $$.t = f->type;
2694             namespace_t ns = {flags2access(f->flags), ""};
2695             multiname_t m = {QNAME, &ns, 0, $1};
2696             $$.c = abc_findpropstrict2($$.c, &m);
2697             $$.c = abc_getproperty2($$.c, &m);
2698         } else {
2699             if(f->slot>0) {
2700                 $$.c = abc_getlocal_0($$.c);
2701                 $$.c = abc_getslot($$.c, f->slot);
2702             } else {
2703                 namespace_t ns = {flags2access(f->flags), ""};
2704                 multiname_t m = {QNAME, &ns, 0, $1};
2705                 $$.c = abc_getlocal_0($$.c);
2706                 $$.c = abc_getproperty2($$.c, &m);
2707             }
2708         }
2709         if(f->kind == MEMBER_METHOD) {
2710             $$.t = TYPE_FUNCTION(f);
2711         } else {
2712             $$.t = f->type;
2713         }
2714     
2715     /* look at actual classes, in the current package and imported */
2716     } else if((a = find_class($1))) {
2717         if(a->flags & FLAG_METHOD) {
2718             MULTINAME(m, a);
2719             $$.c = abc_findpropstrict2($$.c, &m);
2720             $$.c = abc_getproperty2($$.c, &m);
2721             if(a->function->kind == MEMBER_METHOD) {
2722                 $$.t = TYPE_FUNCTION(a->function);
2723             } else {
2724                 $$.t = a->function->type;
2725             }
2726         } else {
2727             if(a->slot) {
2728                 $$.c = abc_getglobalscope($$.c);
2729                 $$.c = abc_getslot($$.c, a->slot);
2730             } else {
2731                 MULTINAME(m, a);
2732                 $$.c = abc_getlex2($$.c, &m);
2733             }
2734             $$.t = TYPE_CLASS(a);
2735         }
2736
2737     /* unknown object, let the avm2 resolve it */
2738     } else {
2739         if(strcmp($1,"trace"))
2740             as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
2741         state->method->late_binding = 1;
2742                 
2743         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2744
2745         $$.t = 0;
2746         $$.c = abc_findpropstrict2($$.c, &m);
2747         $$.c = abc_getproperty2($$.c, &m);
2748     }
2749 }
2750
2751 //TODO: 
2752 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2753 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2754 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2755
2756 // ----------------- namespaces -------------------------------------------------
2757
2758 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
2759 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
2760 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
2761
2762 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}
2763