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