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