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