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