extended error messages
[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     syntaxerror("can't convert type %s%s%s to %s%s%s", 
1367         from->package, from->package?".":"", from->name, 
1368         to->package, to->package?".":"", to->name);
1369     return 0; // make gcc happy
1370 }
1371
1372 code_t*defaultvalue(code_t*c, classinfo_t*type)
1373 {
1374     if(TYPE_IS_INT(type)) {
1375        c = abc_pushbyte(c, 0);
1376     } else if(TYPE_IS_UINT(type)) {
1377        c = abc_pushuint(c, 0);
1378     } else if(TYPE_IS_FLOAT(type)) {
1379        c = abc_pushnan(c);
1380     } else if(TYPE_IS_BOOLEAN(type)) {
1381        c = abc_pushfalse(c);
1382     } else if(!type) {
1383        //c = abc_pushundefined(c);
1384     } else {
1385        c = abc_pushnull(c);
1386        MULTINAME(m, type);
1387        c = abc_coerce2(c, &m);
1388     }
1389     return c;
1390 }
1391
1392 char is_pushundefined(code_t*c)
1393 {
1394     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1395 }
1396
1397 static slotinfo_t* find_class(char*name)
1398 {
1399     slotinfo_t*c=0;
1400
1401     c = registry_find(state->package, name);
1402     if(c) return c;
1403
1404     /* try explicit imports */
1405     dictentry_t* e = dict_get_slot(state->imports, name);
1406     if(c) return c;
1407     while(e) {
1408         if(!strcmp(e->key, name)) {
1409             c = (slotinfo_t*)e->data;
1410             if(c) return c;
1411         }
1412         e = e->next;
1413     }
1414
1415     /* try package.* imports */
1416     import_list_t*l = state->wildcard_imports;
1417     while(l) {
1418         //printf("does package %s contain a class %s?\n", l->import->package, name);
1419         c = registry_find(l->import->package, name);
1420         if(c) return c;
1421         l = l->next;
1422     }
1423
1424     /* try global package */
1425     c = registry_find("", name);
1426     if(c) return c;
1427   
1428     /* try local "filename" package */
1429     c = registry_find(internal_filename_package, name);
1430     if(c) return c;
1431
1432     return 0;
1433 }
1434
1435 static char is_getlocal(code_t*c)
1436 {
1437     if(!c || c->prev || c->next)
1438         return 0;
1439     return(c->opcode == OPCODE_GETLOCAL
1440         || c->opcode == OPCODE_GETLOCAL_0
1441         || c->opcode == OPCODE_GETLOCAL_1
1442         || c->opcode == OPCODE_GETLOCAL_2
1443         || c->opcode == OPCODE_GETLOCAL_3);
1444 }
1445 static int getlocalnr(code_t*c)
1446 {
1447     if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1448     else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1449     else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1450     else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1451     else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1452     else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1453     return 0;
1454 }
1455
1456 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1457 {
1458     /* converts this:
1459
1460        [prefix code] [read instruction]
1461
1462        to this:
1463
1464        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1465     */
1466     if(in && in->opcode == OPCODE_COERCE_A) {
1467         in = code_cutlast(in);
1468     }
1469     if(in->next)
1470         syntaxerror("internal error");
1471
1472     /* chop off read instruction */
1473     code_t*prefix = in;
1474     code_t*r = in;
1475     if(r->prev) {
1476         prefix = r->prev;r->prev = 0;
1477         prefix->next=0;
1478     } else {
1479         prefix = 0;
1480     }
1481
1482     char use_temp_var = readbefore;
1483
1484     /* generate the write instruction, and maybe append a dup to the prefix code */
1485     code_t* write = abc_nop(0);
1486     if(r->opcode == OPCODE_GETPROPERTY) {
1487         write->opcode = OPCODE_SETPROPERTY;
1488         multiname_t*m = (multiname_t*)r->data[0];
1489         write->data[0] = multiname_clone(m);
1490         if(m->type == QNAME || m->type == MULTINAME) {
1491             if(!justassign) {
1492                 prefix = abc_dup(prefix); // we need the object, too
1493             }
1494             use_temp_var = 1;
1495         } else if(m->type == MULTINAMEL) {
1496             if(!justassign) {
1497                 /* dupping two values on the stack requires 5 operations and one register- 
1498                    couldn't adobe just have given us a dup2? */
1499                 int temp = gettempvar();
1500                 prefix = abc_setlocal(prefix, temp);
1501                 prefix = abc_dup(prefix);
1502                 prefix = abc_getlocal(prefix, temp);
1503                 prefix = abc_swap(prefix);
1504                 prefix = abc_getlocal(prefix, temp);
1505                 if(!use_temp_var);
1506                     prefix = abc_kill(prefix, temp);
1507             }
1508             use_temp_var = 1;
1509         } else {
1510             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1511         }
1512     } else if(r->opcode == OPCODE_GETSLOT) {
1513         write->opcode = OPCODE_SETSLOT;
1514         write->data[0] = r->data[0];
1515         if(!justassign) {
1516             prefix = abc_dup(prefix); // we need the object, too
1517         }
1518         use_temp_var = 1;
1519     } else if(r->opcode == OPCODE_GETLOCAL) { 
1520         write->opcode = OPCODE_SETLOCAL;
1521         write->data[0] = r->data[0];
1522     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1523         write->opcode = OPCODE_SETLOCAL_0;
1524     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1525         write->opcode = OPCODE_SETLOCAL_1;
1526     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1527         write->opcode = OPCODE_SETLOCAL_2;
1528     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1529         write->opcode = OPCODE_SETLOCAL_3;
1530     } else {
1531         code_dump(r);
1532         syntaxerror("illegal lvalue: can't assign a value to this expression");
1533     }
1534     code_t* c = 0;
1535     
1536     int temp = -1;
1537     if(!justassign) {
1538         if(use_temp_var) {
1539             /* with getproperty/getslot, we have to be extra careful not
1540                to execute the read code twice, as it might have side-effects
1541                (e.g. if the property is in fact a setter/getter combination)
1542
1543                So read the value, modify it, and write it again,
1544                using prefix only once and making sure (by using a temporary
1545                register) that the return value is what we just wrote */
1546             temp = gettempvar();
1547             c = code_append(c, prefix);
1548             c = code_append(c, r);
1549             if(readbefore) {
1550                 c = abc_dup(c);
1551                 c = abc_setlocal(c, temp);
1552             }
1553             c = code_append(c, middlepart);
1554             if(!readbefore) {
1555                 c = abc_dup(c);
1556                 c = abc_setlocal(c, temp);
1557             }
1558             c = code_append(c, write);
1559             c = abc_getlocal(c, temp);
1560             c = abc_kill(c, temp);
1561         } else {
1562             /* if we're allowed to execute the read code twice *and*
1563                the middlepart doesn't modify the code, things are easier.
1564             */
1565             code_t* r2 = code_dup(r);
1566             //c = code_append(c, prefix);
1567             parserassert(!prefix);
1568             c = code_append(c, r);
1569             c = code_append(c, middlepart);
1570             c = code_append(c, write);
1571             c = code_append(c, r2);
1572         }
1573     } else {
1574         /* even smaller version: overwrite the value without reading
1575            it out first */
1576         if(!use_temp_var) {
1577             if(prefix) {
1578                 c = code_append(c, prefix);
1579                 c = abc_dup(c);
1580             }
1581             c = code_append(c, middlepart);
1582             c = code_append(c, write);
1583             c = code_append(c, r);
1584         } else {
1585             code_free(r);r=0;
1586             temp = gettempvar();
1587             if(prefix) {
1588                 c = code_append(c, prefix);
1589             }
1590             c = code_append(c, middlepart);
1591             c = abc_dup(c);
1592             c = abc_setlocal(c, temp);
1593             c = code_append(c, write);
1594             c = abc_getlocal(c, temp);
1595             c = abc_kill(c, temp);
1596         }
1597     }
1598     return c;
1599 }
1600
1601 char is_break_or_jump(code_t*c)
1602 {
1603     if(!c)
1604         return 0;
1605     if(c->opcode == OPCODE_JUMP ||
1606        c->opcode == OPCODE___BREAK__ ||
1607        c->opcode == OPCODE___CONTINUE__ ||
1608        c->opcode == OPCODE_THROW ||
1609        c->opcode == OPCODE_RETURNVOID ||
1610        c->opcode == OPCODE_RETURNVALUE) {
1611        return 1;
1612     }
1613     return 0;
1614 }
1615
1616
1617 #define IS_FINALLY_TARGET(op) \
1618         ((op) == OPCODE___CONTINUE__ || \
1619          (op) == OPCODE___BREAK__ || \
1620          (op) == OPCODE_RETURNVOID || \
1621          (op) == OPCODE_RETURNVALUE || \
1622          (op) == OPCODE___RETHROW__)
1623
1624 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1625 {
1626 #define NEED_EXTRA_STACK_ARG
1627     code_t*finally_label = abc_nop(0);
1628     NEW(lookupswitch_t, l);
1629     //_lookupswitch
1630
1631     code_t*i = c;
1632     int count=0;
1633     while(i) {
1634         code_t*prev = i->prev;
1635         if(IS_FINALLY_TARGET(i->opcode)) {
1636            code_t*p = prev;
1637            char needvalue=0;
1638            if(i->opcode == OPCODE___RETHROW__ ||
1639               i->opcode == OPCODE_RETURNVALUE) {
1640                if(i->opcode == OPCODE___RETHROW__)
1641                  i->opcode = OPCODE_THROW;
1642                needvalue=1;
1643                p = abc_coerce_a(p);
1644                p = abc_setlocal(p, tempvar);
1645            }
1646            p = abc_pushbyte(p, count++);
1647            p = abc_jump(p, finally_label);
1648            code_t*target = p = abc_label(p);
1649 #ifdef NEED_EXTRA_STACK_ARG
1650            p = abc_pop(p);
1651 #endif
1652            if(needvalue) {
1653                p = abc_getlocal(p, tempvar);
1654            }
1655
1656            p->next = i;i->prev = p;
1657            list_append(l->targets, target);
1658         }
1659         i = prev;
1660     }
1661
1662     code_t*j,*f;
1663     c = abc_pushbyte(c, -1);
1664     c = code_append(c, finally_label);
1665     c = code_append(c, finally);
1666
1667 #ifdef NEED_EXTRA_STACK_ARG
1668     c = abc_dup(c);
1669 #endif
1670     c = abc_lookupswitch(c, l);
1671     c = l->def = abc_label(c);
1672 #ifdef NEED_EXTRA_STACK_ARG
1673     c = abc_pop(c);
1674 #endif
1675
1676     return c;
1677 }
1678
1679 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1680 {
1681     code_t*i = c;
1682     while(i) {
1683         code_t*prev = i->prev;
1684         if(IS_FINALLY_TARGET(i->opcode)) {
1685            if(i->opcode == OPCODE___RETHROW__)
1686                 i->opcode = OPCODE_THROW;
1687            code_t*end = code_dup(finally);
1688            code_t*start = code_start(end);
1689            if(prev) prev->next = start;
1690            start->prev = prev;
1691            i->prev = end;
1692            end->next = i;
1693         }
1694         i = prev;
1695     }
1696     return code_append(c, finally);
1697 }
1698
1699 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1700 {
1701     if(!finally)
1702         return c;
1703     code_t*i = c;
1704     char cantdup=0;
1705     int num_insertion_points=0;
1706     while(i) {
1707         if(IS_FINALLY_TARGET(i->opcode))
1708             num_insertion_points++;
1709         i = i->prev;
1710     }
1711     i = finally;
1712     int code_size=0;
1713     while(i) {
1714         code_size++;
1715         if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1716             cantdup=1;
1717         }
1718         i = i->prev;
1719     }
1720     int simple_version_cost = (1+num_insertion_points)*code_size;
1721     int lookup_version_cost = 4*num_insertion_points + 5;
1722
1723     if(cantdup || simple_version_cost > lookup_version_cost) {
1724         printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1725         return insert_finally_lookup(c, finally, tempvar);
1726     } else {
1727         printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1728         return insert_finally_simple(c, finally, tempvar);
1729     }
1730 }
1731
1732 #define PASS1 }} if(as3_pass == 1) {{
1733 #define PASS1END }} if(as3_pass == 2) {{
1734 #define PASS2 }} if(as3_pass == 2) {{
1735 #define PASS12 }} {{
1736 #define PASS12END }} if(as3_pass == 2) {{
1737
1738 %}
1739
1740 %%
1741
1742 /* ------------ code blocks / statements ---------------- */
1743
1744 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1745
1746 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST 
1747 PROGRAM_CODE_LIST: PROGRAM_CODE 
1748                  | PROGRAM_CODE_LIST PROGRAM_CODE
1749
1750 PROGRAM_CODE: PACKAGE_DECLARATION 
1751             | INTERFACE_DECLARATION 
1752             | CLASS_DECLARATION
1753             | FUNCTION_DECLARATION
1754             | SLOT_DECLARATION
1755             | PACKAGE_INITCODE
1756             | CONDITIONAL_COMPILATION '{' MAYBE_PROGRAM_CODE_LIST '}' // conditional compilation
1757             | ';'
1758
1759 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1760 INPACKAGE_CODE_LIST: INPACKAGE_CODE 
1761                    | INPACKAGE_CODE_LIST INPACKAGE_CODE
1762
1763 INPACKAGE_CODE: INTERFACE_DECLARATION 
1764               | CLASS_DECLARATION
1765               | FUNCTION_DECLARATION
1766               | SLOT_DECLARATION
1767               | PACKAGE_INITCODE
1768               | CONDITIONAL_COMPILATION '{' MAYBE_INPACKAGE_CODE_LIST '}' // conditional compilation
1769               | ';'
1770
1771 MAYBECODE: CODE {$$=$1;}
1772 MAYBECODE: {$$=code_new();}
1773
1774 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1775 CODE: CODEPIECE {$$=$1;}
1776
1777 // code which also may appear outside a method
1778 CODE_STATEMENT: IMPORT 
1779 CODE_STATEMENT: FOR 
1780 CODE_STATEMENT: FOR_IN 
1781 CODE_STATEMENT: WHILE 
1782 CODE_STATEMENT: DO_WHILE 
1783 CODE_STATEMENT: SWITCH 
1784 CODE_STATEMENT: IF
1785 CODE_STATEMENT: WITH
1786 CODE_STATEMENT: TRY
1787 CODE_STATEMENT: VOIDEXPRESSION 
1788 CODE_STATEMENT: USE_NAMESPACE
1789 CODE_STATEMENT: '{' CODE '}' {$$=$2;}
1790 CODE_STATEMENT: '{' '}' {$$=0;}
1791
1792 // code which may appear anywhere
1793 CODEPIECE: ';' {$$=0;}
1794 CODEPIECE: CODE_STATEMENT
1795 CODEPIECE: VARIABLE_DECLARATION
1796 CODEPIECE: BREAK
1797 CODEPIECE: CONTINUE
1798 CODEPIECE: RETURN
1799 CODEPIECE: THROW
1800 CODEPIECE: CONDITIONAL_COMPILATION '{' CODE '}' {$$=$3;}
1801
1802 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1803
1804 //CODEBLOCK :  '{' CODE '}' {$$=$2;}
1805 //CODEBLOCK :  '{' '}'      {$$=0;}
1806 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1807 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1808
1809 /* ------------ package init code ------------------- */
1810
1811 PACKAGE_INITCODE: CODE_STATEMENT {
1812     code_t**cc = &global->init->method->body->code;
1813     *cc = code_append(*cc, $1);
1814 }
1815
1816 /* ------------ conditional compilation ------------- */
1817
1818 CONDITIONAL_COMPILATION: T_IDENTIFIER "::" T_IDENTIFIER 
1819
1820 /* ------------ variables --------------------------- */
1821
1822 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1823                 |                {$$.c=abc_pushundefined(0);
1824                                   $$.t=TYPE_ANY;
1825                                  }
1826
1827 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1828 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1829
1830 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1831 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1832
1833 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1834 {
1835     if(variable_exists($1))
1836         syntaxerror("Variable %s already defined", $1);
1837    
1838     if(!is_subtype_of($3.t, $2)) {
1839         syntaxerror("Can't convert %s to %s", $3.t->name, 
1840                                               $2->name);
1841     }
1842
1843     int index = new_variable($1, $2, 1);
1844     
1845     if($2) {
1846         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1847             $$ = $3.c;
1848             $$ = converttype($$, $3.t, $2);
1849             $$ = abc_setlocal($$, index);
1850         } else {
1851             code_free($3.c);
1852             $$ = defaultvalue(0, $2);
1853             $$ = abc_setlocal($$, index);
1854         }
1855     } else {
1856         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1857             $$ = $3.c;
1858             $$ = abc_coerce_a($$);
1859             $$ = abc_setlocal($$, index);
1860         } else {
1861             code_free($3.c);
1862             $$ = code_new();
1863         }
1864     }
1865     
1866     /* that's the default for a local register, anyway
1867         else {
1868         state->method->initcode = abc_pushundefined(state->method->initcode);
1869         state->method->initcode = abc_setlocal(state->method->initcode, index);
1870     }*/
1871     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1872 }
1873
1874 /* ------------ control flow ------------------------- */
1875
1876 MAYBEELSE:  %prec below_else {$$ = code_new();}
1877 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1878 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1879
1880 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1881      
1882     $$ = code_new();
1883     $$ = code_append($$, $4.c);
1884     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1885    
1886     $$ = code_append($$, $6);
1887     if($7) {
1888         myjmp = $$ = abc_jump($$, 0);
1889     }
1890     myif->branch = $$ = abc_nop($$);
1891     if($7) {
1892         $$ = code_append($$, $7);
1893         myjmp->branch = $$ = abc_nop($$);
1894     }
1895     $$ = var_block($$);
1896     old_state();
1897 }
1898
1899 FOR_INIT : {$$=code_new();}
1900 FOR_INIT : VARIABLE_DECLARATION
1901 FOR_INIT : VOIDEXPRESSION
1902
1903 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1904 //       (I don't see any easy way to revolve this conflict otherwise, as we
1905 //        can't touch VAR_READ without upsetting the precedence about "return")
1906 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1907     $$=$2;new_variable($2,$3,1);
1908 }
1909 FOR_IN_INIT : T_IDENTIFIER {
1910     $$=$1;
1911 }
1912
1913 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1914 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1915
1916 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1917     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1918     $$ = code_new();
1919     $$ = code_append($$, $2);
1920     code_t*loopstart = $$ = abc_label($$);
1921     $$ = code_append($$, $4.c);
1922     code_t*myif = $$ = abc_iffalse($$, 0);
1923     $$ = code_append($$, $8);
1924     code_t*cont = $$ = abc_nop($$);
1925     $$ = code_append($$, $6);
1926     $$ = abc_jump($$, loopstart);
1927     code_t*out = $$ = abc_nop($$);
1928     breakjumpsto($$, $1.name, out);
1929     continuejumpsto($$, $1.name, cont);
1930     myif->branch = out;
1931
1932     $$ = var_block($$);
1933     old_state();
1934 }
1935
1936 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1937     variable_t*var = find_variable($2);
1938     char*tmp1name = concat2($2, "__tmp1__");
1939     int it = new_variable(tmp1name, TYPE_INT, 0);
1940     char*tmp2name = concat2($2, "__array__");
1941     int array = new_variable(tmp1name, 0, 0);
1942
1943     $$ = code_new();
1944     $$ = code_append($$, $4.c);
1945     $$ = abc_coerce_a($$);
1946     $$ = abc_setlocal($$, array);
1947     $$ = abc_pushbyte($$, 0);
1948     $$ = abc_setlocal($$, it);
1949
1950     code_t*loopstart = $$ = abc_label($$);
1951     
1952     $$ = abc_hasnext2($$, array, it);
1953     code_t*myif = $$ = abc_iffalse($$, 0);
1954     $$ = abc_getlocal($$, array);
1955     $$ = abc_getlocal($$, it);
1956     if(!$1.each)
1957         $$ = abc_nextname($$);
1958     else
1959         $$ = abc_nextvalue($$);
1960     $$ = converttype($$, 0, var->type);
1961     $$ = abc_setlocal($$, var->index);
1962
1963     $$ = code_append($$, $6);
1964     $$ = abc_jump($$, loopstart);
1965     
1966     code_t*out = $$ = abc_nop($$);
1967     breakjumpsto($$, $1.name, out);
1968     continuejumpsto($$, $1.name, loopstart);
1969     
1970     myif->branch = out;
1971
1972     $$ = var_block($$);
1973     old_state();
1974
1975     free(tmp1name);
1976     free(tmp2name);
1977 }
1978
1979 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1980
1981     $$ = code_new();
1982
1983     code_t*myjmp = $$ = abc_jump($$, 0);
1984     code_t*loopstart = $$ = abc_label($$);
1985     $$ = code_append($$, $6);
1986     code_t*cont = $$ = abc_nop($$);
1987     myjmp->branch = cont;
1988     $$ = code_append($$, $4.c);
1989     $$ = abc_iftrue($$, loopstart);
1990     code_t*out = $$ = abc_nop($$);
1991     breakjumpsto($$, $1, out);
1992     continuejumpsto($$, $1, cont);
1993
1994     $$ = var_block($$);
1995     old_state();
1996 }
1997
1998 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1999     $$ = code_new();
2000     code_t*loopstart = $$ = abc_label($$);
2001     $$ = code_append($$, $3);
2002     code_t*cont = $$ = abc_nop($$);
2003     $$ = code_append($$, $6.c);
2004     $$ = abc_iftrue($$, loopstart);
2005     code_t*out = $$ = abc_nop($$);
2006     breakjumpsto($$, $1, out);
2007     continuejumpsto($$, $1, cont);
2008     
2009     $$ = var_block($$);
2010     old_state();
2011 }
2012
2013 BREAK : "break" %prec prec_none {
2014     $$ = abc___break__(0, "");
2015 }
2016 BREAK : "break" T_IDENTIFIER {
2017     $$ = abc___break__(0, $2);
2018 }
2019 CONTINUE : "continue" %prec prec_none {
2020     $$ = abc___continue__(0, "");
2021 }
2022 CONTINUE : "continue" T_IDENTIFIER {
2023     $$ = abc___continue__(0, $2);
2024 }
2025
2026 MAYBE_CASE_LIST :           {$$=0;}
2027 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
2028 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
2029 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
2030 CASE_LIST: CASE             {$$=$1;}
2031 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
2032
2033 CASE: "case" E ':' MAYBECODE {
2034     $$ = abc_dup(0);
2035     $$ = code_append($$, $2.c);
2036     code_t*j = $$ = abc_ifne($$, 0);
2037     $$ = code_append($$, $4);
2038     if($$->opcode != OPCODE___BREAK__) {
2039         $$ = abc___fallthrough__($$, "");
2040     }
2041     code_t*e = $$ = abc_nop($$);
2042     j->branch = e;
2043 }
2044 DEFAULT: "default" ':' MAYBECODE {
2045     $$ = $3;
2046 }
2047 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
2048     $$=$4.c;
2049     $$ = code_append($$, $7);
2050     code_t*out = $$ = abc_pop($$);
2051     breakjumpsto($$, $1, out);
2052     
2053     code_t*c = $$,*lastblock=0;
2054     while(c) {
2055         if(c->opcode == OPCODE_IFNE) {
2056             if(!c->next) syntaxerror("internal error in fallthrough handling");
2057             lastblock=c->next;
2058         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
2059             if(lastblock) {
2060                 c->opcode = OPCODE_JUMP;
2061                 c->branch = lastblock;
2062             } else {
2063                 /* fall through end of switch */
2064                 c->opcode = OPCODE_NOP;
2065             }
2066         }
2067         c=c->prev;
2068     }
2069    
2070     $$ = var_block($$);
2071     old_state();
2072 }
2073
2074 /* ------------ try / catch /finally ---------------- */
2075
2076 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
2077         '{' MAYBECODE '}' {
2078     namespace_t name_ns = {ACCESS_PACKAGE, ""};
2079     multiname_t name = {QNAME, &name_ns, 0, $3};
2080     
2081     NEW(abc_exception_t, e)
2082     e->exc_type = sig2mname($4);
2083     e->var_name = multiname_clone(&name);
2084     $$ = e;
2085
2086     code_t*c = 0;
2087     int i = find_variable_safe($3)->index;
2088     e->target = c = abc_nop(0);
2089     c = abc_setlocal(c, i);
2090     c = code_append(c, $8);
2091     c = abc_kill(c, i);
2092
2093     c = var_block(c);
2094     old_state();
2095 }
2096 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
2097     $4 = var_block($4);
2098     if(!$4) {
2099         $$=0;
2100         old_state();
2101     } else {
2102         NEW(abc_exception_t, e)
2103         e->exc_type = 0; //all exceptions
2104         e->var_name = 0; //no name
2105         e->target = 0;
2106         e->to = abc_nop(0);
2107         e->to = code_append(e->to, $4);
2108         old_state();
2109         $$ = e;
2110     }
2111 }
2112
2113 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
2114 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
2115 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
2116 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
2117     $$ = $1;
2118     $$.finally = 0;
2119     if($2) {
2120         list_append($$.l,$2);
2121         $$.finally = $2->to;$2->to=0;
2122     }
2123 }
2124 CATCH_FINALLY_LIST: FINALLY {
2125     $$.l=list_new();
2126     $$.finally = 0;
2127     if($1) {
2128         list_append($$.l,$1);
2129         $$.finally = $1->to;$1->to=0;
2130     }
2131 }
2132
2133 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
2134     code_t*out = abc_nop(0);
2135
2136     code_t*start = abc_nop(0);
2137     $$ = code_append(start, $4);
2138     if(!is_break_or_jump($4)) {
2139         $$ = abc_jump($$, out);
2140     }
2141     code_t*end = $$ = abc_nop($$);
2142   
2143     int tmp;
2144     if($6.finally)
2145         tmp = new_variable("__finally__", 0, 0);
2146     
2147     abc_exception_list_t*l = $6.l;
2148     int count=0;
2149     while(l) {
2150         abc_exception_t*e = l->abc_exception;
2151         if(e->var_name) {
2152             $$ = code_append($$, e->target);
2153             $$ = abc_jump($$, out);
2154         } else {
2155             parserassert((ptroff_t)$6.finally);
2156             // finally block
2157             e->target = $$ = abc_nop($$);
2158             $$ = abc___rethrow__($$);
2159         }
2160         
2161         e->from = start;
2162         e->to = end;
2163
2164         l = l->next;
2165     }
2166     $$ = code_append($$, out);
2167
2168     $$ = insert_finally($$, $6.finally, tmp);
2169         
2170     list_concat(state->method->exceptions, $6.l);
2171    
2172     $$ = var_block($$);
2173     old_state();
2174 }
2175
2176 /* ------------ throw ------------------------------- */
2177
2178 THROW : "throw" EXPRESSION {
2179     $$=$2.c;
2180     $$=abc_throw($$);
2181 }
2182 THROW : "throw" %prec prec_none {
2183     if(!state->exception_name)
2184         syntaxerror("re-throw only possible within a catch block");
2185     variable_t*v = find_variable(state->exception_name);
2186     $$=code_new();
2187     $$=abc_getlocal($$, v->index);
2188     $$=abc_throw($$);
2189 }
2190
2191 /* ------------ with -------------------------------- */
2192
2193 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
2194      $$ = $3.c;
2195      $$ = abc_pushscope($$);
2196      $$ = code_append($$, $5);
2197      $$ = abc_popscope($$);
2198 }
2199
2200 /* ------------ packages and imports ---------------- */
2201
2202 X_IDENTIFIER: T_IDENTIFIER
2203             | "package" {PASS12 $$="package";}
2204
2205 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2206 PACKAGE: X_IDENTIFIER             {PASS12 $$=strdup($1);}
2207
2208 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2209                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2210 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} 
2211                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2212
2213 IMPORT : "import" PACKAGEANDCLASS {
2214        PASS1 
2215        if(!registry_find($2->package, $2->name)) {
2216            as3_schedule_class($2->package, $2->name);
2217        }
2218
2219        PASS2
2220        classinfo_t*c = $2;
2221        if(!c) 
2222             syntaxerror("Couldn't import class\n");
2223        state_has_imports();
2224        dict_put(state->imports, c->name, c);
2225        $$=0;
2226 }
2227 IMPORT : "import" PACKAGE '.' '*' {
2228        PASS1 
2229        if(strncmp("flash.", $2, 6)) {
2230            as3_schedule_package($2);
2231        }
2232
2233        PASS2
2234        NEW(import_t,i);
2235        i->package = $2;
2236        state_has_imports();
2237        list_append(state->wildcard_imports, i);
2238        $$=0;
2239 }
2240
2241 /* ------------ classes and interfaces (header) -------------- */
2242
2243 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
2244 MAYBE_MODIFIERS : MODIFIER_LIST        {PASS12 $$=$1;}
2245 MODIFIER_LIST : MODIFIER               {PASS12 $$=$1;}
2246 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
2247
2248 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
2249          | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
2250          | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
2251          | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2252          | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2253          | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2254          | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2255          | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2256          | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2257          | T_NAMESPACE {PASS12 $$=FLAG_NAMESPACE;}
2258
2259 EXTENDS : {$$=registry_getobjectclass();}
2260 EXTENDS : KW_EXTENDS CLASS_SPEC {$$=$2;}
2261
2262 EXTENDS_LIST : {PASS12 $$=list_new();}
2263 EXTENDS_LIST : KW_EXTENDS CLASS_SPEC_LIST {PASS12 $$=$2;}
2264
2265 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2266 IMPLEMENTS_LIST : KW_IMPLEMENTS CLASS_SPEC_LIST {PASS12 $$=$2;}
2267
2268 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
2269                               EXTENDS IMPLEMENTS_LIST 
2270                               '{' {PASS12 startclass($1,$3,$4,$5);} 
2271                               MAYBE_CLASS_BODY 
2272                               '}' {PASS12 endclass();$$=0;}
2273
2274 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
2275                               EXTENDS_LIST 
2276                               '{' {PASS12 startclass($1|FLAG_INTERFACE,$3,0,$4);}
2277                               MAYBE_INTERFACE_BODY 
2278                               '}' {PASS12 endclass();$$=0;}
2279
2280 /* ------------ classes and interfaces (body) -------------- */
2281
2282 MAYBE_CLASS_BODY : 
2283 MAYBE_CLASS_BODY : CLASS_BODY
2284 CLASS_BODY : CLASS_BODY_ITEM
2285 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2286 CLASS_BODY_ITEM : ';'
2287 CLASS_BODY_ITEM : CONDITIONAL_COMPILATION '{' MAYBE_CLASS_BODY '}'
2288 CLASS_BODY_ITEM : SLOT_DECLARATION
2289 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2290
2291 CLASS_BODY_ITEM : CODE_STATEMENT {
2292     code_t*c = state->cls->static_init->header;
2293     c = code_append(c, $1);  
2294     state->cls->static_init->header = c;
2295 }
2296
2297 MAYBE_INTERFACE_BODY : 
2298 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2299 INTERFACE_BODY : IDECLARATION
2300 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2301 IDECLARATION : ';'
2302 IDECLARATION : "var" T_IDENTIFIER {
2303     syntaxerror("variable declarations not allowed in interfaces");
2304 }
2305 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2306     PASS12
2307     $1 |= FLAG_PUBLIC;
2308     if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2309         syntaxerror("invalid method modifiers: interface methods always need to be public");
2310     }
2311     startfunction(0,$1,$3,$4,&$6,$8);
2312     endfunction(0,$1,$3,$4,&$6,$8, 0);
2313     list_deep_free($6.list);
2314 }
2315
2316 /* ------------ classes and interfaces (body, slots ) ------- */
2317
2318 VARCONST: "var" | "const"
2319
2320 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER {setstaticfunction($1);} MAYBETYPE MAYBEEXPRESSION {
2321     int flags = $1;
2322     U8 access = flags2access($1);
2323
2324     varinfo_t* info = 0;
2325     if(state->cls) {
2326         memberinfo_t*i = registry_findmember(state->cls->info, $3, 1);
2327         if(i) {
2328             check_override(i, flags);
2329         }
2330         info = varinfo_register_onclass(state->cls->info, access, $3);
2331     } else {
2332         slotinfo_t*i = registry_find(state->package, $3);
2333         if(i) {
2334             syntaxerror("package %s already contains '%s'", state->package, $3);
2335         }
2336         info = varinfo_register_global(access, state->package, $3);
2337     }
2338
2339     info->type = $5;
2340     info->flags = flags;
2341
2342     /* slot name */
2343     namespace_t mname_ns = {access, ""};
2344     multiname_t mname = {QNAME, &mname_ns, 0, $3};
2345   
2346     trait_list_t**traits;
2347     code_t**code;
2348     if(!state->cls) {
2349         // global variable
2350         mname_ns.name = state->package;
2351         traits = &global->init->traits;
2352         code = &global->init->method->body->code;
2353     } else if(flags&FLAG_STATIC) {
2354         // static variable
2355         traits = &state->cls->abc->static_traits;
2356         code = &state->cls->static_init->header;
2357     } else {
2358         // instance variable
2359         traits = &state->cls->abc->traits;
2360         code = &state->cls->init->header;
2361     }
2362     
2363     trait_t*t=0;
2364     if($5) {
2365         MULTINAME(m, $5);
2366         t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2367     } else {
2368         t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2369     }
2370     info->slot = t->slot_id;
2371     
2372     /* initalization code (if needed) */
2373     code_t*c = 0;
2374     if($6.c && !is_pushundefined($6.c)) {
2375         c = abc_getlocal_0(c);
2376         c = code_append(c, $6.c);
2377         c = converttype(c, $6.t, $5);
2378         c = abc_setslot(c, t->slot_id);
2379     }
2380
2381     *code = code_append(*code, c);
2382
2383     if($2==KW_CONST) {
2384         t->kind= TRAIT_CONST;
2385     }
2386
2387     $$=0;
2388     setstaticfunction(0);
2389 }
2390
2391 /* ------------ constants -------------------------------------- */
2392
2393 MAYBESTATICCONSTANT: {$$=0;}
2394 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2395
2396 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2397 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2398 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2399 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2400 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);free((char*)$1.str);}
2401 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2402 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2403 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2404 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2405 STATICCONSTANT : T_IDENTIFIER {
2406     // TODO
2407     as3_warning("Couldn't resolve %s", $1);
2408     $$ = constant_new_null($1);
2409 }
2410
2411 /* ------------ classes and interfaces (body, functions) ------- */
2412
2413 // non-vararg version
2414 MAYBE_PARAM_LIST: {
2415     PASS12
2416     memset(&$$,0,sizeof($$));
2417 }
2418 MAYBE_PARAM_LIST: PARAM_LIST {
2419     PASS12
2420     $$=$1;
2421 }
2422
2423 // vararg version
2424 MAYBE_PARAM_LIST: "..." PARAM {
2425     PASS12
2426     memset(&$$,0,sizeof($$));
2427     $$.varargs=1;
2428     list_append($$.list, $2);
2429 }
2430 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2431     PASS12
2432     $$ =$1;
2433     $$.varargs=1;
2434     list_append($$.list, $4);
2435 }
2436
2437 // non empty
2438 PARAM_LIST: PARAM_LIST ',' PARAM {
2439     PASS12
2440     $$ = $1;
2441     list_append($$.list, $3);
2442 }
2443 PARAM_LIST: PARAM {
2444     PASS12
2445     memset(&$$,0,sizeof($$));
2446     list_append($$.list, $1);
2447 }
2448
2449 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2450      PASS1 $$=0;
2451      PASS2
2452      $$ = malloc(sizeof(param_t));
2453      $$->name=$1;
2454      $$->type = $3;
2455      $$->value = $4;
2456 }
2457 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
2458      PASS1 $$=0;
2459      PASS2
2460      $$ = malloc(sizeof(param_t));
2461      $$->name=$1;
2462      $$->type = TYPE_ANY;
2463      $$->value = $2;
2464 }
2465 GETSET : "get" {$$=$1;}
2466        | "set" {$$=$1;}
2467        |       {$$=0;}
2468
2469 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
2470                       MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}' 
2471 {
2472     PASS1 old_state();list_deep_free($6.list);
2473     PASS2
2474     if(!state->method->info) syntaxerror("internal error");
2475     
2476     code_t*c = method_header(state->method);
2477     c = wrap_function(c, 0, $11);
2478
2479     endfunction(0,$1,$3,$4,&$6,$8,c);
2480     list_deep_free($6.list);
2481     $$=0;
2482 }
2483
2484 MAYBE_IDENTIFIER: T_IDENTIFIER
2485 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2486 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE 
2487                '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2488 {
2489     PASS1 old_state();list_deep_free($4.list);
2490     PASS2
2491     methodinfo_t*f = state->method->info;
2492     if(!f || !f->kind) syntaxerror("internal error");
2493     
2494     code_t*c = method_header(state->method);
2495     c = wrap_function(c, 0, $9);
2496
2497     int index = state->method->var_index;
2498     endfunction(0,0,0,$2,&$4,$6,c);
2499     list_deep_free($4.list);
2500     
2501     $$.c = abc_getlocal(0, index);
2502     $$.t = TYPE_FUNCTION(f);
2503 }
2504
2505
2506 /* ------------- package + class ids --------------- */
2507
2508 CLASS: T_IDENTIFIER {
2509     PASS1 $$=0;
2510     PASS2
2511     /* try current package */
2512     slotinfo_t*s = find_class($1);
2513     if(!s) syntaxerror("Could not find class/method %s\n", $1);
2514     $$ = (classinfo_t*)s;
2515 }
2516
2517 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2518     PASS1 static classinfo_t c;
2519           memset(&c, 0, sizeof(c));
2520           c.package = $1;
2521           c.name = $3;
2522           $$=&c;
2523     PASS2
2524     slotinfo_t*s = registry_find($1, $3);
2525     if(!s) syntaxerror("Couldn't find class/method %s.%s\n", $1, $3);
2526     free($1);$1=0;
2527     $$ = (classinfo_t*)s;
2528 }
2529
2530 CLASS_SPEC: PACKAGEANDCLASS
2531           | CLASS
2532
2533 CLASS_SPEC_LIST : CLASS_SPEC {PASS12 $$=list_new();list_append($$, $1);}
2534 CLASS_SPEC_LIST : CLASS_SPEC_LIST ',' CLASS_SPEC {PASS12 $$=$1;list_append($$,$3);}
2535
2536 TYPE : CLASS_SPEC {$$=$1;}
2537      | '*'        {$$=registry_getanytype();}
2538      | "void"     {$$=registry_getanytype();}
2539     /*
2540      |  "String"  {$$=registry_getstringclass();}
2541      |  "int"     {$$=registry_getintclass();}
2542      |  "uint"    {$$=registry_getuintclass();}
2543      |  "Boolean" {$$=registry_getbooleanclass();}
2544      |  "Number"  {$$=registry_getnumberclass();}
2545     */
2546
2547 MAYBETYPE: ':' TYPE {$$=$2;}
2548 MAYBETYPE:          {$$=0;}
2549
2550 /* ----------function calls, delete, constructor calls ------ */
2551
2552 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
2553 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2554
2555 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2556 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2557 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA
2558
2559 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
2560                                                   $$.cc = $1.c;
2561                                                  }
2562
2563 EXPRESSION_LIST_AND_COMMA: EXPRESSION_LIST ',' {$$ = $1;}
2564 EXPRESSION_LIST : EXPRESSION_LIST_AND_COMMA NONCOMMAEXPRESSION {
2565                                                   $$.len= $1.len+1;
2566                                                   $$.cc = code_append($1.cc, $2.c);
2567                                                   }
2568                
2569 XX : %prec new2
2570 NEW : "new" E XX MAYBE_PARAM_VALUES {
2571     $$.c = $2.c;
2572     if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2573     
2574     code_t*paramcode = $4.cc;
2575     if($$.c->opcode == OPCODE_GETPROPERTY) {
2576         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2577         $$.c = code_cutlast($$.c);
2578         $$.c = code_append($$.c, paramcode);
2579         $$.c = abc_constructprop2($$.c, name, $4.len);
2580         multiname_destroy(name);
2581     } else if($$.c->opcode == OPCODE_GETSLOT) {
2582         int slot = (int)(ptroff_t)$$.c->data[0];
2583         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2584         multiname_t*name = t->name;
2585         $$.c = code_cutlast($$.c);
2586         $$.c = code_append($$.c, paramcode);
2587         $$.c = abc_constructprop2($$.c, name, $4.len);
2588     } else {
2589         $$.c = code_append($$.c, paramcode);
2590         $$.c = abc_construct($$.c, $4.len);
2591     }
2592    
2593     $$.t = TYPE_ANY;
2594     if(TYPE_IS_CLASS($2.t) && $2.t->data) {
2595         $$.t = $2.t->data;
2596     } else {
2597         $$.c = abc_coerce_a($$.c);
2598         $$.t = TYPE_ANY;
2599     }
2600 }
2601
2602 /* TODO: use abc_call (for calling local variables),
2603          abc_callstatic (for calling own methods) 
2604          call (for closures)
2605 */
2606 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2607     
2608     $$.c = $1.c;
2609     if($$.c->opcode == OPCODE_COERCE_A) {
2610         $$.c = code_cutlast($$.c);
2611     }
2612     code_t*paramcode = $3.cc;
2613
2614     $$.t = TYPE_ANY;
2615     if($$.c->opcode == OPCODE_GETPROPERTY) {
2616         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2617         $$.c = code_cutlast($$.c);
2618         $$.c = code_append($$.c, paramcode);
2619         $$.c = abc_callproperty2($$.c, name, $3.len);
2620         multiname_destroy(name);
2621     } else if($$.c->opcode == OPCODE_GETSLOT) {
2622         int slot = (int)(ptroff_t)$$.c->data[0];
2623         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2624         if(t->kind!=TRAIT_METHOD) {
2625             //ok: flash allows to assign closures to members.
2626         }
2627         multiname_t*name = t->name;
2628         $$.c = code_cutlast($$.c);
2629         $$.c = code_append($$.c, paramcode);
2630         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2631         $$.c = abc_callproperty2($$.c, name, $3.len);
2632     } else if($$.c->opcode == OPCODE_GETSUPER) {
2633         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2634         $$.c = code_cutlast($$.c);
2635         $$.c = code_append($$.c, paramcode);
2636         $$.c = abc_callsuper2($$.c, name, $3.len);
2637         multiname_destroy(name);
2638     } else {
2639         $$.c = abc_getglobalscope($$.c);
2640         $$.c = code_append($$.c, paramcode);
2641         $$.c = abc_call($$.c, $3.len);
2642     }
2643    
2644     if(TYPE_IS_FUNCTION($1.t) && $1.t->data) {
2645         $$.t = ((methodinfo_t*)($1.t->data))->return_type;
2646     } else {
2647         $$.c = abc_coerce_a($$.c);
2648         $$.t = TYPE_ANY;
2649     }
2650 }
2651
2652 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2653     if(!state->cls) syntaxerror("super() not allowed outside of a class");
2654     if(!state->method) syntaxerror("super() not allowed outside of a function");
2655     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2656
2657     $$.c = code_new();
2658     $$.c = abc_getlocal_0($$.c);
2659
2660     $$.c = code_append($$.c, $3.cc);
2661     /*
2662     this is dependent on the control path, check this somewhere else
2663     if(state->method->has_super)
2664         syntaxerror("constructor may call super() only once");
2665     */
2666     state->method->has_super = 1;
2667
2668     $$.c = abc_constructsuper($$.c, $3.len);
2669     $$.c = abc_pushundefined($$.c);
2670     $$.t = TYPE_ANY;
2671 }
2672
2673 DELETE: "delete" E {
2674     $$.c = $2.c;
2675     if($$.c->opcode == OPCODE_COERCE_A) {
2676         $$.c = code_cutlast($$.c);
2677     }
2678     multiname_t*name = 0;
2679     if($$.c->opcode == OPCODE_GETPROPERTY) {
2680         $$.c->opcode = OPCODE_DELETEPROPERTY;
2681     } else if($$.c->opcode == OPCODE_GETSLOT) {
2682         int slot = (int)(ptroff_t)$$.c->data[0];
2683         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2684         $$.c = code_cutlast($$.c);
2685         $$.c = abc_deleteproperty2($$.c, name);
2686     } else {
2687         $$.c = abc_getlocal_0($$.c);
2688         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2689         $$.c = abc_deleteproperty2($$.c, &m);
2690     }
2691     $$.t = TYPE_BOOLEAN;
2692 }
2693
2694 RETURN: "return" %prec prec_none {
2695     $$ = abc_returnvoid(0);
2696 }
2697 RETURN: "return" EXPRESSION {
2698     $$ = $2.c;
2699     $$ = abc_returnvalue($$);
2700 }
2701
2702 // ----------------------- expression types -------------------------------------
2703
2704 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
2705 EXPRESSION : E                %prec below_minus {$$ = $1;}
2706 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2707     $$.c = $1.c;
2708     $$.c = cut_last_push($$.c);
2709     $$.c = code_append($$.c,$3.c);
2710     $$.t = $3.t;
2711 }
2712 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2713     $$=cut_last_push($1.c);
2714 }
2715
2716 // ----------------------- expression evaluation -------------------------------------
2717
2718 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2719 //V : CONSTANT                    {$$ = 0;}
2720 E : CONSTANT
2721 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2722 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2723 //V : NEW                         {$$ = $1.c;}
2724 E : NEW                         {$$ = $1;}
2725 //V : DELETE                      {$$ = $1.c;}
2726 E : DELETE                      {$$ = $1;}
2727
2728 E : FUNCTIONCALL
2729
2730 E : T_REGEXP {
2731     $$.c = 0;
2732     namespace_t ns = {ACCESS_PACKAGE, ""};
2733     multiname_t m = {QNAME, &ns, 0, "RegExp"};
2734     if(!$1.options) {
2735         $$.c = abc_getlex2($$.c, &m);
2736         $$.c = abc_pushstring($$.c, $1.pattern);
2737         $$.c = abc_construct($$.c, 1);
2738     } else {
2739         $$.c = abc_getlex2($$.c, &m);
2740         $$.c = abc_pushstring($$.c, $1.pattern);
2741         $$.c = abc_pushstring($$.c, $1.options);
2742         $$.c = abc_construct($$.c, 2);
2743     }
2744     $$.t = TYPE_REGEXP;
2745 }
2746
2747 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2748                    //MULTINAME(m, registry_getintclass());
2749                    //$$.c = abc_coerce2($$.c, &m); // FIXME
2750                    $$.t = TYPE_INT;
2751                   }
2752 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2753                     $$.t = TYPE_INT;
2754                    }
2755 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2756                   $$.t = TYPE_INT;
2757                  }
2758 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2759                    $$.t = TYPE_UINT;
2760                   }
2761 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2762                     $$.t = TYPE_FLOAT;
2763                    }
2764 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);free((char*)$1.str);
2765                      $$.t = TYPE_STRING;
2766                     }
2767 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2768                     $$.t = TYPE_ANY;
2769                    }
2770 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2771                     $$.t = TYPE_BOOLEAN;
2772                    }
2773 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2774                      $$.t = TYPE_BOOLEAN;
2775                     }
2776 CONSTANT : "null" {$$.c = abc_pushnull(0);
2777                     $$.t = TYPE_NULL;
2778                    }
2779
2780 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2781              $$.t = TYPE_BOOLEAN;
2782             }
2783 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2784              $$.t = TYPE_BOOLEAN;
2785             }
2786 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2787               $$.t = TYPE_BOOLEAN;
2788              }
2789 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2790               $$.t = TYPE_BOOLEAN;
2791              }
2792 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2793               $$.t = TYPE_BOOLEAN;
2794              }
2795 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2796               $$.t = TYPE_BOOLEAN;
2797               }
2798 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2799               $$.t = TYPE_BOOLEAN;
2800              }
2801 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2802               $$.t = TYPE_BOOLEAN;
2803              }
2804
2805 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2806               $$.c = $1.c;
2807               $$.c = converttype($$.c, $1.t, $$.t);
2808               $$.c = abc_dup($$.c);
2809               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2810               $$.c = cut_last_push($$.c);
2811               $$.c = code_append($$.c,$3.c);
2812               $$.c = converttype($$.c, $3.t, $$.t);
2813               code_t*label = $$.c = abc_label($$.c);
2814               jmp->branch = label;
2815              }
2816 E : E "&&" E {
2817               $$.t = join_types($1.t, $3.t, 'A');
2818               /*printf("%08x:\n",$1.t);
2819               code_dump($1.c, 0, 0, "", stdout);
2820               printf("%08x:\n",$3.t);
2821               code_dump($3.c, 0, 0, "", stdout);
2822               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2823               $$.c = $1.c;
2824               $$.c = converttype($$.c, $1.t, $$.t);
2825               $$.c = abc_dup($$.c);
2826               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2827               $$.c = cut_last_push($$.c);
2828               $$.c = code_append($$.c,$3.c);
2829               $$.c = converttype($$.c, $3.t, $$.t);
2830               code_t*label = $$.c = abc_label($$.c);
2831               jmp->branch = label;              
2832              }
2833
2834 E : '!' E    {$$.c=$2.c;
2835               $$.c = abc_not($$.c);
2836               $$.t = TYPE_BOOLEAN;
2837              }
2838
2839 E : '~' E    {$$.c=$2.c;
2840               $$.c = abc_bitnot($$.c);
2841               $$.t = TYPE_INT;
2842              }
2843
2844 E : E '&' E {$$.c = code_append($1.c,$3.c);
2845              $$.c = abc_bitand($$.c);
2846              $$.t = TYPE_INT;
2847             }
2848
2849 E : E '^' E {$$.c = code_append($1.c,$3.c);
2850              $$.c = abc_bitxor($$.c);
2851              $$.t = TYPE_INT;
2852             }
2853
2854 E : E '|' E {$$.c = code_append($1.c,$3.c);
2855              $$.c = abc_bitor($$.c);
2856              $$.t = TYPE_INT;
2857             }
2858
2859 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2860              $$.c = abc_rshift($$.c);
2861              $$.t = TYPE_INT;
2862             }
2863 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2864              $$.c = abc_urshift($$.c);
2865              $$.t = TYPE_INT;
2866             }
2867 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2868              $$.c = abc_lshift($$.c);
2869              $$.t = TYPE_INT;
2870             }
2871
2872 E : E '/' E {$$.c = code_append($1.c,$3.c);
2873              $$.c = abc_divide($$.c);
2874              $$.t = TYPE_NUMBER;
2875             }
2876 E : E '%' E {$$.c = code_append($1.c,$3.c);
2877              $$.c = abc_modulo($$.c);
2878              $$.t = TYPE_NUMBER;
2879             }
2880 E : E '+' E {$$.c = code_append($1.c,$3.c);
2881              if(BOTH_INT($1.t, $3.t)) {
2882                 $$.c = abc_add_i($$.c);
2883                 $$.t = TYPE_INT;
2884              } else {
2885                 $$.c = abc_add($$.c);
2886                 $$.t = join_types($1.t,$3.t,'+');
2887              }
2888             }
2889 E : E '-' E {$$.c = code_append($1.c,$3.c);
2890              if(BOTH_INT($1.t,$3.t)) {
2891                 $$.c = abc_subtract_i($$.c);
2892                 $$.t = TYPE_INT;
2893              } else {
2894                 $$.c = abc_subtract($$.c);
2895                 $$.t = TYPE_NUMBER;
2896              }
2897             }
2898 E : E '*' E {$$.c = code_append($1.c,$3.c);
2899              if(BOTH_INT($1.t,$3.t)) {
2900                 $$.c = abc_multiply_i($$.c);
2901                 $$.t = TYPE_INT;
2902              } else {
2903                 $$.c = abc_multiply($$.c);
2904                 $$.t = TYPE_NUMBER;
2905              }
2906             }
2907
2908 E : E "in" E {$$.c = code_append($1.c,$3.c);
2909               $$.c = abc_in($$.c);
2910               $$.t = TYPE_BOOLEAN;
2911              }
2912
2913 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2914               if(use_astype && TYPE_IS_CLASS($3.t) && $3.t->data) {
2915                 MULTINAME(m, (classinfo_t*)($3.t->data));
2916                 $$.c = abc_astype2($1.c, &m);
2917                 $$.t = $3.t->data;
2918               } else {
2919                 $$.c = code_append($1.c, $3.c);
2920                 $$.c = abc_astypelate($$.c);
2921                 $$.t = TYPE_ANY;
2922               }
2923              }
2924
2925 E : E "instanceof" E 
2926              {$$.c = code_append($1.c, $3.c);
2927               $$.c = abc_instanceof($$.c);
2928               $$.t = TYPE_BOOLEAN;
2929              }
2930
2931 E : E "is" E {$$.c = code_append($1.c, $3.c);
2932               $$.c = abc_istypelate($$.c);
2933               $$.t = TYPE_BOOLEAN;
2934              }
2935
2936 E : "typeof" '(' E ')' {
2937               $$.c = $3.c;
2938               $$.c = abc_typeof($$.c);
2939               $$.t = TYPE_STRING;
2940              }
2941
2942 E : "void" E {
2943               $$.c = cut_last_push($2.c);
2944               $$.c = abc_pushundefined($$.c);
2945               $$.t = TYPE_ANY;
2946              }
2947
2948 E : "void" { $$.c = abc_pushundefined(0);
2949              $$.t = TYPE_ANY;
2950            }
2951
2952 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2953
2954 E : '-' E {
2955   $$=$2;
2956   if(IS_INT($2.t)) {
2957    $$.c=abc_negate_i($$.c);
2958    $$.t = TYPE_INT;
2959   } else {
2960    $$.c=abc_negate($$.c);
2961    $$.t = TYPE_NUMBER;
2962   }
2963 }
2964
2965 E : E '[' E ']' {
2966   $$.c = $1.c;
2967   $$.c = code_append($$.c, $3.c);
2968
2969   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2970   $$.c = abc_getproperty2($$.c, &m);
2971   $$.t = 0; // array elements have unknown type
2972 }
2973
2974 E : '[' MAYBE_EXPRESSION_LIST ']' {
2975     $$.c = code_new();
2976     $$.c = code_append($$.c, $2.cc);
2977     $$.c = abc_newarray($$.c, $2.len);
2978     $$.t = registry_getarrayclass();
2979 }
2980
2981 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2982 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2983
2984 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2985     $$.cc = 0;
2986     $$.cc = code_append($$.cc, $1.c);
2987     $$.cc = code_append($$.cc, $3.c);
2988     $$.len = 2;
2989 }
2990 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2991     $$.cc = $1.cc;
2992     $$.len = $1.len+2;
2993     $$.cc = code_append($$.cc, $3.c);
2994     $$.cc = code_append($$.cc, $5.c);
2995 }
2996 //MAYBECOMMA: ','
2997 //MAYBECOMMA:
2998
2999 E : "{ (dictionary)" MAYBE_EXPRPAIR_LIST '}' {
3000     $$.c = code_new();
3001     $$.c = code_append($$.c, $2.cc);
3002     $$.c = abc_newobject($$.c, $2.len/2);
3003     $$.t = registry_getobjectclass();
3004 }
3005
3006 E : E "*=" E { 
3007                code_t*c = $3.c;
3008                if(BOTH_INT($1.t,$3.t)) {
3009                 c=abc_multiply_i(c);
3010                } else {
3011                 c=abc_multiply(c);
3012                }
3013                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
3014                $$.c = toreadwrite($1.c, c, 0, 0);
3015                $$.t = $1.t;
3016               }
3017
3018 E : E "%=" E { 
3019                code_t*c = abc_modulo($3.c);
3020                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
3021                $$.c = toreadwrite($1.c, c, 0, 0);
3022                $$.t = $1.t;
3023               }
3024 E : E "<<=" E { 
3025                code_t*c = abc_lshift($3.c);
3026                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
3027                $$.c = toreadwrite($1.c, c, 0, 0);
3028                $$.t = $1.t;
3029               }
3030 E : E ">>=" E { 
3031                code_t*c = abc_rshift($3.c);
3032                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
3033                $$.c = toreadwrite($1.c, c, 0, 0);
3034                $$.t = $1.t;
3035               }
3036 E : E ">>>=" E { 
3037                code_t*c = abc_urshift($3.c);
3038                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
3039                $$.c = toreadwrite($1.c, c, 0, 0);
3040                $$.t = $1.t;
3041               }
3042 E : E "/=" E { 
3043                code_t*c = abc_divide($3.c);
3044                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
3045                $$.c = toreadwrite($1.c, c, 0, 0);
3046                $$.t = $1.t;
3047               }
3048 E : E "|=" E { 
3049                code_t*c = abc_bitor($3.c);
3050                c=converttype(c, TYPE_INT, $1.t);
3051                $$.c = toreadwrite($1.c, c, 0, 0);
3052                $$.t = $1.t;
3053               }
3054 E : E "^=" E { 
3055                code_t*c = abc_bitxor($3.c);
3056                c=converttype(c, TYPE_INT, $1.t);
3057                $$.c = toreadwrite($1.c, c, 0, 0);
3058                $$.t = $1.t;
3059               }
3060 E : E "+=" E { 
3061                code_t*c = $3.c;
3062
3063                if(TYPE_IS_INT($1.t)) {
3064                 c=abc_add_i(c);
3065                } else {
3066                 c=abc_add(c);
3067                 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
3068                }
3069                
3070                $$.c = toreadwrite($1.c, c, 0, 0);
3071                $$.t = $1.t;
3072               }
3073 E : E "-=" E { code_t*c = $3.c; 
3074                if(TYPE_IS_INT($1.t)) {
3075                 c=abc_subtract_i(c);
3076                } else {
3077                 c=abc_subtract(c);
3078                 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
3079                }
3080                
3081                $$.c = toreadwrite($1.c, c, 0, 0);
3082                $$.t = $1.t;
3083              }
3084 E : E '=' E { code_t*c = 0;
3085               c = code_append(c, $3.c);
3086               c = converttype(c, $3.t, $1.t);
3087               $$.c = toreadwrite($1.c, c, 1, 0);
3088               $$.t = $1.t;
3089             }
3090
3091 E : E '?' E ':' E %prec below_assignment { 
3092               $$.t = join_types($3.t,$5.t,'?');
3093               $$.c = $1.c;
3094               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
3095               $$.c = code_append($$.c, $3.c);
3096               $$.c = converttype($$.c, $3.t, $$.t);
3097               code_t*j2 = $$.c = abc_jump($$.c, 0);
3098               $$.c = j1->branch = abc_label($$.c);
3099               $$.c = code_append($$.c, $5.c);
3100               $$.c = converttype($$.c, $3.t, $$.t);
3101               $$.c = j2->branch = abc_label($$.c);
3102             }
3103
3104 E : E "++" { code_t*c = 0;
3105              classinfo_t*type = $1.t;
3106              if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
3107                  int nr = getlocalnr($1.c);
3108                  code_free($1.c);$1.c=0;
3109                  if(TYPE_IS_INT($1.t)) {
3110                     $$.c = abc_getlocal(0, nr);
3111                     $$.c = abc_inclocal_i($$.c, nr);
3112                  } else if(TYPE_IS_NUMBER($1.t)) {
3113                     $$.c = abc_getlocal(0, nr);
3114                     $$.c = abc_inclocal($$.c, nr);
3115                  } else syntaxerror("internal error");
3116              } else {
3117                  if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3118                      c=abc_increment_i(c);
3119                      type = TYPE_INT;
3120                  } else {
3121                      c=abc_increment(c);
3122                      type = TYPE_NUMBER;
3123                  }
3124                  c=converttype(c, type, $1.t);
3125                  $$.c = toreadwrite($1.c, c, 0, 1);
3126                  $$.t = $1.t;
3127              }
3128            }
3129
3130 // TODO: use inclocal, like with ++
3131 E : E "--" { code_t*c = 0;
3132              classinfo_t*type = $1.t;
3133              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3134                  c=abc_decrement_i(c);
3135                  type = TYPE_INT;
3136              } else {
3137                  c=abc_decrement(c);
3138                  type = TYPE_NUMBER;
3139              }
3140              c=converttype(c, type, $1.t);
3141              $$.c = toreadwrite($1.c, c, 0, 1);
3142              $$.t = $1.t;
3143             }
3144
3145 E : "++" %prec plusplus_prefix E { code_t*c = 0;
3146              classinfo_t*type = $2.t;
3147              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3148                  c=abc_increment_i(c);
3149                  type = TYPE_INT;
3150              } else {
3151                  c=abc_increment(c);
3152                  type = TYPE_NUMBER;
3153              }
3154              c=converttype(c, type, $2.t);
3155              $$.c = toreadwrite($2.c, c, 0, 0);
3156              $$.t = $2.t;
3157            }
3158
3159 E : "--" %prec minusminus_prefix E { code_t*c = 0;
3160              classinfo_t*type = $2.t;
3161              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
3162                  c=abc_decrement_i(c);
3163                  type = TYPE_INT;
3164              } else {
3165                  c=abc_decrement(c);
3166                  type = TYPE_NUMBER;
3167              }
3168              c=converttype(c, type, $2.t);
3169              $$.c = toreadwrite($2.c, c, 0, 0);
3170              $$.t = $2.t;
3171            }
3172
3173 E : "super" '.' T_IDENTIFIER 
3174            { if(!state->cls->info)
3175                   syntaxerror("super keyword not allowed outside a class");
3176               classinfo_t*t = state->cls->info->superclass;
3177               if(!t) t = TYPE_OBJECT;
3178
3179               memberinfo_t*f = registry_findmember(t, $3, 1);
3180               namespace_t ns = {f->access, ""};
3181               MEMBER_MULTINAME(m, f, $3);
3182               $$.c = 0;
3183               $$.c = abc_getlocal_0($$.c);
3184               $$.c = abc_getsuper2($$.c, &m);
3185               $$.t = slotinfo_gettype((slotinfo_t*)f);
3186            }
3187
3188 E : '@' T_IDENTIFIER {
3189               // attribute TODO
3190               $$.c = abc_pushundefined(0);
3191               $$.t = 0;
3192               as3_warning("ignored @ operator");
3193            }
3194
3195 E : E '.' '@' T_IDENTIFIER {
3196               // child attribute  TODO
3197               $$.c = abc_pushundefined(0);
3198               $$.t = 0;
3199               as3_warning("ignored .@ operator");
3200            }
3201
3202 E : E '.' T_IDENTIFIER "::" T_IDENTIFIER {
3203               // namespace declaration TODO
3204               $$.c = abc_pushundefined(0);
3205               $$.t = 0;
3206               as3_warning("ignored :: operator");
3207            }
3208
3209 E : E ".." T_IDENTIFIER {
3210               // descendants TODO
3211               $$.c = abc_pushundefined(0);
3212               $$.t = 0;
3213               as3_warning("ignored .. operator");
3214            }
3215
3216 E : E '.' '(' E ')' {
3217               // filter TODO
3218               $$.c = abc_pushundefined(0);
3219               $$.t = 0;
3220               as3_warning("ignored .() operator");
3221            }
3222
3223 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3224
3225
3226
3227 E : E '.' T_IDENTIFIER
3228             {$$.c = $1.c;
3229              classinfo_t*t = $1.t;
3230              char is_static = 0;
3231              if(TYPE_IS_CLASS(t) && t->data) {
3232                  t = t->data;
3233                  is_static = 1;
3234              }
3235              if(t) {
3236                  memberinfo_t*f = registry_findmember(t, $3, 1);
3237                  char noslot = 0;
3238                  if(f && !is_static != !(f->flags&FLAG_STATIC))
3239                     noslot=1;
3240                  if(f && f->slot && !noslot) {
3241                      $$.c = abc_getslot($$.c, f->slot);
3242                  } else {
3243                      MEMBER_MULTINAME(m, f, $3);
3244                      $$.c = abc_getproperty2($$.c, &m);
3245                  }
3246                  /* determine type */
3247                  $$.t = slotinfo_gettype((slotinfo_t*)f);
3248                  if(!$$.t)
3249                     $$.c = abc_coerce_a($$.c);
3250              } else {
3251                  /* when resolving a property on an unknown type, we do know the
3252                     name of the property (and don't seem to need the package), but
3253                     we need to make avm2 try out all access modes */
3254                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3255                  $$.c = abc_getproperty2($$.c, &m);
3256                  $$.c = abc_coerce_a($$.c);
3257                  $$.t = registry_getanytype();
3258              }
3259             }
3260
3261 VAR_READ : T_IDENTIFIER {
3262     $$.t = 0;
3263     $$.c = 0;
3264     slotinfo_t*a = 0;
3265     memberinfo_t*f = 0;
3266
3267     variable_t*v;
3268     /* look at variables */
3269     if((v = find_variable($1))) {
3270         // $1 is a local variable
3271         $$.c = abc_getlocal($$.c, v->index);
3272         $$.t = v->type;
3273         break;
3274     }
3275
3276     int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3277
3278     /* look at current class' members */
3279     if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
3280         (f->flags&FLAG_STATIC) >= i_am_static) {
3281         // $1 is a function in this class
3282         int var_is_static = (f->flags&FLAG_STATIC);
3283
3284         if(f->kind == INFOTYPE_METHOD) {
3285             $$.t = TYPE_FUNCTION(f);
3286         } else {
3287             $$.t = f->type;
3288         }
3289         if(var_is_static && !i_am_static) {
3290         /* access to a static member from a non-static location.
3291            do this via findpropstrict:
3292            there doesn't seem to be any non-lookup way to access
3293            static properties of a class */
3294             state->method->late_binding = 1;
3295             $$.t = f->type;
3296             namespace_t ns = {f->access, ""};
3297             multiname_t m = {QNAME, &ns, 0, $1};
3298             $$.c = abc_findpropstrict2($$.c, &m);
3299             $$.c = abc_getproperty2($$.c, &m);
3300             break;
3301         } else if(f->slot>0) {
3302             $$.c = abc_getlocal_0($$.c);
3303             $$.c = abc_getslot($$.c, f->slot);
3304             break;
3305         } else {
3306             namespace_t ns = {f->access, ""};
3307             multiname_t m = {QNAME, &ns, 0, $1};
3308             $$.c = abc_getlocal_0($$.c);
3309             $$.c = abc_getproperty2($$.c, &m);
3310             break;
3311         }
3312     } 
3313     
3314     /* look at actual classes, in the current package and imported */
3315     if((a = find_class($1))) {
3316         if(a->access == ACCESS_PACKAGEINTERNAL &&
3317            strcmp(a->package, state->package) &&
3318            strcmp(a->package, internal_filename_package)
3319            )
3320            syntaxerror("Can't access internal %s %s in package '%s' from package '%s'",
3321                 infotypename(a),$1, a->package, state->package);
3322
3323         if(a->kind != INFOTYPE_CLASS) {
3324             MULTINAME(m, a);
3325             $$.c = abc_findpropstrict2($$.c, &m);
3326             $$.c = abc_getproperty2($$.c, &m);
3327             if(a->kind == INFOTYPE_METHOD) {
3328                 methodinfo_t*f = (methodinfo_t*)a;
3329                 $$.t = TYPE_FUNCTION(f);
3330             } else {
3331                 varinfo_t*v = (varinfo_t*)a;
3332                 $$.t = v->type;
3333             }
3334         } else {
3335             classinfo_t*c = (classinfo_t*)a;
3336             if(c->slot) {
3337                 $$.c = abc_getglobalscope($$.c);
3338                 $$.c = abc_getslot($$.c, c->slot);
3339             } else {
3340                 MULTINAME(m, c);
3341                 $$.c = abc_getlex2($$.c, &m);
3342             }
3343             $$.t = TYPE_CLASS(c);
3344         }
3345         break;
3346     }
3347
3348     /* unknown object, let the avm2 resolve it */
3349     if(1) {
3350         as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3351         state->method->late_binding = 1;
3352                 
3353         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3354
3355         $$.t = 0;
3356         $$.c = abc_findpropstrict2($$.c, &m);
3357         $$.c = abc_getproperty2($$.c, &m);
3358     }
3359 }
3360
3361 // ----------------- namespaces -------------------------------------------------
3362
3363 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3364 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3365 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3366
3367 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {
3368     PASS12
3369     tokenizer_register_namespace($3);
3370     $$=0;
3371 }
3372