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