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