fixed bug in variable allocation
[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
35 %}
36
37 //%glr-parser
38 //%expect-rr 1
39 %error-verbose
40
41 %union tokenunion {
42     enum yytokentype token;
43     int flags;
44
45     classinfo_t*classinfo;
46     classinfo_list_t*classinfo_list;
47
48     int number_int;
49     unsigned int number_uint;
50     double number_float;
51     code_t*code;
52     typedcode_t value;
53     //typedcode_list_t*value_list;
54     codeandnumber_t value_list;
55     param_t* param;
56     params_t params;
57     string_t str;
58     char*id;
59     constant_t*constant;
60     for_start_t for_start;
61 }
62
63
64 %token<id> T_IDENTIFIER
65 %token<str> T_STRING
66 %token<token> T_REGEXP
67 %token<token> T_EMPTY
68 %token<number_int> T_INT
69 %token<number_uint> T_UINT
70 %token<number_uint> T_BYTE
71 %token<number_uint> T_SHORT
72 %token<number_float> T_FLOAT
73
74 %token<id> T_FOR "for"
75 %token<id> T_WHILE "while"
76 %token<id> T_DO "do"
77 %token<id> T_SWITCH "switch"
78
79 %token<token> KW_IMPLEMENTS
80 %token<token> KW_NAMESPACE "namespace"
81 %token<token> KW_PACKAGE "package"
82 %token<token> KW_PROTECTED
83 %token<token> KW_PUBLIC
84 %token<token> KW_PRIVATE
85 %token<token> KW_USE "use"
86 %token<token> KW_INTERNAL
87 %token<token> KW_NEW "new"
88 %token<token> KW_NATIVE
89 %token<token> KW_FUNCTION "function"
90 %token<token> KW_UNDEFINED "undefined"
91 %token<token> KW_CONTINUE "continue"
92 %token<token> KW_CLASS "class"
93 %token<token> KW_CONST "const"
94 %token<token> KW_CATCH "catch"
95 %token<token> KW_CASE "case"
96 %token<token> KW_SET "set"
97 %token<token> KW_VOID "void"
98 %token<token> KW_STATIC
99 %token<token> KW_INSTANCEOF "instanceof"
100 %token<token> KW_IMPORT "import"
101 %token<token> KW_RETURN "return"
102 %token<token> KW_TYPEOF "typeof"
103 %token<token> KW_INTERFACE "interface"
104 %token<token> KW_NULL "null"
105 %token<token> KW_VAR "var"
106 %token<token> KW_DYNAMIC "dynamic"
107 %token<token> KW_OVERRIDE
108 %token<token> KW_FINAL
109 %token<token> KW_EACH "each"
110 %token<token> KW_GET "get"
111 %token<token> KW_TRY "try"
112 %token<token> KW_SUPER "super"
113 %token<token> KW_EXTENDS
114 %token<token> KW_FALSE "false"
115 %token<token> KW_TRUE "true"
116 %token<token> KW_BOOLEAN "Boolean"
117 %token<token> KW_UINT "uint"
118 %token<token> KW_INT "int"
119 %token<token> KW_NUMBER "Number"
120 %token<token> KW_STRING "String"
121 %token<token> KW_DEFAULT "default"
122 %token<token> KW_DELETE "delete"
123 %token<token> KW_IF "if"
124 %token<token> KW_ELSE  "else"
125 %token<token> KW_BREAK   "break"
126 %token<token> KW_IS "is"
127 %token<token> KW_IN "in"
128 %token<token> KW_AS "as"
129
130 %token<token> T_EQEQ "=="
131 %token<token> T_EQEQEQ "==="
132 %token<token> T_NE "!="
133 %token<token> T_NEE "!=="
134 %token<token> T_LE "<="
135 %token<token> T_GE ">="
136 %token<token> T_DIVBY "/=" 
137 %token<token> T_MODBY "%="
138 %token<token> T_MULBY "*="
139 %token<token> T_PLUSBY "+=" 
140 %token<token> T_MINUSBY "-="
141 %token<token> T_SHRBY ">>="
142 %token<token> T_SHLBY "<<="
143 %token<token> T_USHRBY ">>>="
144 %token<token> T_OROR "||"
145 %token<token> T_ANDAND "&&"
146 %token<token> T_COLONCOLON "::"
147 %token<token> T_MINUSMINUS "--"
148 %token<token> T_PLUSPLUS "++"
149 %token<token> T_DOTDOT ".."
150 %token<token> T_DOTDOTDOT "..."
151 %token<token> T_SHL "<<"
152 %token<token> T_USHR ">>>"
153 %token<token> T_SHR ">>"
154
155 %type <for_start> FOR_START
156 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT
157 %type <token> VARCONST
158 %type <code> CODE
159 %type <code> CODEPIECE
160 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH
161 %type <token> PACKAGE_DECLARATION
162 %type <token> FUNCTION_DECLARATION
163 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
164 %type <token> CLASS_DECLARATION
165 %type <token> NAMESPACE_DECLARATION
166 %type <token> INTERFACE_DECLARATION
167 %type <code> VOIDEXPRESSION
168 %type <value> EXPRESSION NONCOMMAEXPRESSION
169 %type <value> MAYBEEXPRESSION
170 %type <value> E DELETE
171 %type <value> CONSTANT
172 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE
173 %type <token> USE_NAMESPACE
174 %type <code> FOR_INIT
175 %type <token> IMPORT
176 %type <classinfo> MAYBETYPE
177 %type <token> GETSET
178 %type <param> PARAM
179 %type <params> PARAM_LIST
180 %type <params> MAYBE_PARAM_LIST
181 %type <flags> MAYBE_MODIFIERS
182 %type <flags> MODIFIER_LIST
183 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
184 %type <classinfo_list> IMPLEMENTS_LIST
185 %type <classinfo> EXTENDS
186 %type <classinfo_list> EXTENDS_LIST
187 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
188 %type <classinfo_list> QNAME_LIST
189 %type <classinfo> TYPE
190 //%type <token> VARIABLE
191 %type <value> VAR_READ
192 %type <value> NEW
193 //%type <token> T_IDENTIFIER
194 %type <token> MODIFIER
195 %type <value> FUNCTIONCALL
196 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
197
198 // precedence: from low to high
199
200 %left prec_none
201
202 %left below_semicolon
203 %left ';'
204 %left ','
205 %nonassoc below_assignment // for ?:, contrary to spec
206 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
207 %right '?' ':'
208 %left "||"
209 %left "&&"
210 %nonassoc '|'
211 %nonassoc '^'
212 %nonassoc '&'
213 %nonassoc "==" "!=" "===" "!=="
214 %nonassoc "is" "as" "in"
215 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
216 %left "<<" ">>" ">>>" 
217 %left below_minus
218 %left '-' '+'
219 %left '/' '*' '%'
220 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
221 %left "--" "++" 
222 %nonassoc below_curly
223 %left '[' ']' '{' "new" '.' ".." "::"
224 %nonassoc T_IDENTIFIER
225 %left above_identifier
226 %left below_else
227 %nonassoc "else"
228 %left '('
229
230 // needed for "return" precedence:
231 %nonassoc T_STRING T_REGEXP
232 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
233 %nonassoc "false" "true" "null" "undefined" "super"
234
235
236      
237 %{
238
239 static int yyerror(char*s)
240 {
241    syntaxerror("%s", s); 
242 }
243
244 static char* concat2(const char* t1, const char* t2)
245 {
246     int l1 = strlen(t1);
247     int l2 = strlen(t2);
248     char*text = malloc(l1+l2+1);
249     memcpy(text   , t1, l1);
250     memcpy(text+l1, t2, l2);
251     text[l1+l2] = 0;
252     return text;
253 }
254 static char* concat3(const char* t1, const char* t2, const char* t3)
255 {
256     int l1 = strlen(t1);
257     int l2 = strlen(t2);
258     int l3 = strlen(t3);
259     char*text = malloc(l1+l2+l3+1);
260     memcpy(text   , t1, l1);
261     memcpy(text+l1, t2, l2);
262     memcpy(text+l1+l2, t3, l3);
263     text[l1+l2+l3] = 0;
264     return text;
265 }
266
267 typedef struct _import {
268     char*package;
269 } import_t;
270
271 DECLARE_LIST(import);
272
273 typedef struct _classstate {
274     /* class data */
275     classinfo_t*info;
276     abc_class_t*abc;
277     code_t*init;
278     code_t*static_init;
279     char has_constructor;
280 } classstate_t;
281
282 typedef struct _methodstate {
283     /* method data */
284     memberinfo_t*info;
285     char late_binding;
286     /* code that needs to be executed at the start of
287        a method (like initializing local registers) */
288     code_t*initcode;
289     char is_constructor;
290     char has_super;
291     char is_global;
292 } methodstate_t;
293
294 typedef struct _state {
295     struct _state*old;
296     int level;
297
298     char*package;     
299     import_list_t*wildcard_imports;
300     dict_t*imports;
301     char has_own_imports;
302   
303     classstate_t*cls;   
304     methodstate_t*method;
305     
306     dict_t*vars;
307 } state_t;
308
309 typedef struct _global {
310     abc_file_t*file;
311     abc_script_t*init;
312
313     int variable_count;
314 } global_t;
315
316 static global_t*global = 0;
317 static state_t* state = 0;
318
319 DECLARE_LIST(state);
320
321 #define MULTINAME(m,x) \
322     multiname_t m;\
323     namespace_t m##_ns;\
324     registry_fill_multiname(&m, &m##_ns, x);
325                     
326 #define MEMBER_MULTINAME(m,f,n) \
327     multiname_t m;\
328     namespace_t m##_ns;\
329     if(f) { \
330         m##_ns.access = flags2access(f->flags); \
331         m##_ns.name = ""; \
332         m.type = QNAME; \
333         m.ns = &m##_ns; \
334         m.namespace_set = 0; \
335         m.name = f->name; \
336     } else { \
337         m.type = MULTINAME; \
338         m.ns =0; \
339         m.namespace_set = &nopackage_namespace_set; \
340         m.name = n; \
341     }
342
343 /* warning: list length of namespace set is undefined */
344 #define MULTINAME_LATE(m, access, package) \
345     namespace_t m##_ns = {access, package}; \
346     namespace_set_t m##_nsset; \
347     namespace_list_t m##_l;m##_l.next = 0; \
348     m##_nsset.namespaces = &m##_l; \
349     m##_nsset = m##_nsset; \
350     m##_l.namespace = &m##_ns; \
351     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
352
353 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
354 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
355 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
356 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
357 static namespace_list_t nl4 = {&ns4,0};
358 static namespace_list_t nl3 = {&ns3,&nl4};
359 static namespace_list_t nl2 = {&ns2,&nl3};
360 static namespace_list_t nl1 = {&ns1,&nl2};
361 static namespace_set_t nopackage_namespace_set = {&nl1};
362
363 static void init_globals()
364 {
365     global = rfx_calloc(sizeof(global_t));
366 }
367
368 static void new_state()
369 {
370     NEW(state_t, s);
371     state_t*oldstate = state;
372     if(state)
373         memcpy(s, state, sizeof(state_t)); //shallow copy
374     if(!s->imports) {
375         s->imports = dict_new();
376     }
377     state = s;
378     state->level++;
379     state->has_own_imports = 0;    
380     state->vars = dict_new();
381     state->old = oldstate;
382 }
383 static void state_has_imports()
384 {
385     state->wildcard_imports = list_clone(state->wildcard_imports);
386     state->imports = dict_clone(state->imports);
387     state->has_own_imports = 1;
388 }
389
390 static void state_destroy(state_t*state)
391 {
392     if(state->has_own_imports) {
393         list_free(state->wildcard_imports);
394         dict_destroy(state->imports);state->imports=0;
395     }
396     if(state->imports && (!state->old || state->old->imports!=state->imports)) {
397         dict_destroy(state->imports);state->imports=0;
398     }
399     if(state->vars) {
400         int t;
401         for(t=0;t<state->vars->hashsize;t++) {
402             dictentry_t*e =state->vars->slots[t];
403             while(e) {
404                 free(e->data);e->data=0;
405                 e = e->next;
406             }
407         }
408         dict_destroy(state->vars);state->vars=0;
409     }
410     
411     free(state);
412 }
413
414 static void old_state()
415 {
416     if(!state || !state->old)
417         syntaxerror("invalid nesting");
418     state_t*leaving = state;
419     state = state->old;
420     /*if(state->method->initcode) {
421         printf("residual initcode\n");
422         code_dump(state->method->initcode, 0, 0, "", stdout);
423     }*/
424     state_destroy(leaving);
425 }
426 void initialize_state()
427 {
428     init_globals();
429     new_state();
430
431     global->file = abc_file_new();
432     global->file->flags &= ~ABCFILE_LAZY;
433     
434     global->init = abc_initscript(global->file, 0);
435     code_t*c = global->init->method->body->code;
436
437     c = abc_getlocal_0(c);
438     c = abc_pushscope(c);
439   
440     /* findpropstrict doesn't just return a scope object- it
441        also makes it "active" somehow. Push local_0 on the
442        scope stack and read it back with findpropstrict, it'll
443        contain properties like "trace". Trying to find the same
444        property on a "vanilla" local_0 yields only a "undefined" */
445     //c = abc_findpropstrict(c, "[package]::trace");
446     
447     /*c = abc_getlocal_0(c);
448     c = abc_findpropstrict(c, "[package]::trace");
449     c = abc_coerce_a(c);
450     c = abc_setlocal_1(c);
451
452     c = abc_pushbyte(c, 0);
453     c = abc_setlocal_2(c);
454    
455     code_t*xx = c = abc_label(c);
456     c = abc_findpropstrict(c, "[package]::trace");
457     c = abc_pushstring(c, "prop:");
458     c = abc_hasnext2(c, 1, 2);
459     c = abc_dup(c);
460     c = abc_setlocal_3(c);
461     c = abc_callpropvoid(c, "[package]::trace", 2);
462     c = abc_getlocal_3(c);
463     c = abc_kill(c, 3);
464     c = abc_iftrue(c,xx);*/
465
466     c = abc_findpropstrict(c, "[package]::trace");
467     c = abc_pushstring(c, "[entering global init function]");
468     c = abc_callpropvoid(c, "[package]::trace", 1);
469     
470     global->init->method->body->code = c;
471 }
472 void* finalize_state()
473 {
474     if(state->level!=1) {
475         syntaxerror("unexpected end of file");
476     }
477     abc_method_body_t*m = global->init->method->body;
478     //__ popscope(m);
479     
480     __ findpropstrict(m, "[package]::trace");
481     __ pushstring(m, "[leaving global init function]");
482     __ callpropvoid(m, "[package]::trace", 1);
483     __ returnvoid(m);
484
485     state_destroy(state);
486
487     return global->file;
488 }
489
490
491 static void startpackage(char*name)
492 {
493     if(state->package) {
494         syntaxerror("Packages can not be nested."); 
495     } 
496     new_state();
497     /*printf("entering package \"%s\"\n", name);*/
498     state->package = strdup(name);
499 }
500 static void endpackage()
501 {
502     /*printf("leaving package \"%s\"\n", state->package);*/
503
504     //used e.g. in classinfo_register:
505     //free(state->package);state->package=0;
506
507     old_state();
508 }
509
510 char*globalclass=0;
511 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
512 {
513     if(state->cls) {
514         syntaxerror("inner classes now allowed"); 
515     }
516     new_state();
517     state->cls = rfx_calloc(sizeof(classstate_t));
518
519     token_list_t*t=0;
520     classinfo_list_t*mlist=0;
521     /*printf("entering class %s\n", name);
522     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
523     if(extends) 
524         printf("  extends: %s.%s\n", extends->package, extends->name);
525     printf("  implements (%d): ", list_length(implements));
526     for(mlist=implements;mlist;mlist=mlist->next)  {
527         printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
528     }
529     printf("\n");
530     */
531
532     if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
533         syntaxerror("invalid modifier(s)");
534
535     if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
536         syntaxerror("public and internal not supported at the same time.");
537
538     /* create the class name, together with the proper attributes */
539     int access=0;
540     char*package=0;
541
542     if(!(flags&FLAG_PUBLIC) && !state->package) {
543         access = ACCESS_PRIVATE; package = current_filename;
544     } else if(!(flags&FLAG_PUBLIC) && state->package) {
545         access = ACCESS_PACKAGEINTERNAL; package = state->package;
546     } else if(state->package) {
547         access = ACCESS_PACKAGE; package = state->package;
548     } else {
549         syntaxerror("public classes only allowed inside a package");
550     }
551
552     if(registry_findclass(package, classname)) {
553         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
554     }
555    
556
557     /* build info struct */
558     int num_interfaces = (list_length(implements));
559     state->cls->info = classinfo_register(access, package, classname, num_interfaces);
560     state->cls->info->superclass = extends?extends:TYPE_OBJECT;
561     int pos = 0;
562     classinfo_list_t*l = implements;
563     for(l=implements;l;l=l->next) {
564         state->cls->info->interfaces[pos++] = l->classinfo;
565     }
566     
567     multiname_t*extends2 = sig2mname(extends);
568
569     MULTINAME(classname2,state->cls->info);
570
571     /*if(extends) {
572         state->cls_init = abc_getlocal_0(state->cls_init);
573         state->cls_init = abc_constructsuper(state->cls_init, 0);
574     }*/
575
576     state->cls->abc = abc_class_new(global->file, &classname2, extends2);
577     if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
578     if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
579     if(interface) {
580         state->cls->info->flags |= CLASS_INTERFACE;
581         abc_class_interface(state->cls->abc);
582     }
583
584     abc_class_protectedNS(state->cls->abc, classname);
585
586     for(mlist=implements;mlist;mlist=mlist->next) {
587         MULTINAME(m, mlist->classinfo);
588         abc_class_add_interface(state->cls->abc, &m);
589     }
590
591     /* now write the construction code for this class */
592     int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
593
594     abc_method_body_t*m = global->init->method->body;
595     __ getglobalscope(m);
596     classinfo_t*s = extends;
597
598     int count=0;
599     
600     while(s) {
601         //TODO: take a look at the current scope stack, maybe 
602         //      we can re-use something
603         s = s->superclass;
604         if(!s) 
605         break;
606        
607         multiname_t*s2 = sig2mname(s);
608         __ getlex2(m, s2);
609         multiname_destroy(s2);
610
611         __ pushscope(m); count++;
612         m->code = m->code->prev->prev; // invert
613     }
614     /* continue appending after last op end */
615     while(m->code && m->code->next) m->code = m->code->next; 
616
617     /* TODO: if this is one of *our* classes, we can also 
618              do a getglobalscope/getslot <nr> (which references
619              the init function's slots) */
620     if(extends2) {
621         __ getlex2(m, extends2);
622         __ dup(m);
623         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
624            stack is not the superclass */
625         __ pushscope(m);count++;
626     } else {
627         __ pushnull(m);
628         /* notice: we get a verify error #1107 if the top element on the scope 
629            stack is not the global object */
630         __ getlocal_0(m);
631         __ pushscope(m);count++;
632     }
633     __ newclass(m,state->cls->abc);
634     while(count--) {
635         __ popscope(m);
636     }
637     __ setslot(m, slotindex);
638
639     /* flash.display.MovieClip handling */
640     if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
641         if(state->package && state->package[0]) {
642             globalclass = concat3(state->package, ".", classname);
643         } else {
644             globalclass = strdup(classname);
645         }
646     }
647     multiname_destroy(extends2);
648 }
649
650 static code_t* wrap_function(code_t*c,code_t*initcode, code_t*body)
651 {
652     c = code_append(c, initcode);
653     c = code_append(c, body);
654     /* append return if necessary */
655     if(!c || c->opcode != OPCODE_RETURNVOID && 
656              c->opcode != OPCODE_RETURNVALUE) {
657         c = abc_returnvoid(c);
658     }
659     return c;
660 }
661
662 static void endclass()
663 {
664     if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
665         code_t*c = 0;
666         c = abc_getlocal_0(c);
667         c = abc_constructsuper(c, 0);
668         state->cls->init = code_append(state->cls->init, c);
669     }
670
671     if(state->cls->init) {
672         abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
673         m->body->code = wrap_function(0, state->cls->init, m->body->code);
674     }
675     if(state->cls->static_init) {
676         abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
677         m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
678     } else {
679         // handy for scope testing 
680         /*code_t*c = 0;
681         c = abc_pop(c);
682         c = abc_pop(c);
683         abc_class_getstaticconstructor(state->cls->abc,0)->body->code = c;*/
684     }
685
686     free(state->cls);state->cls=0;
687     old_state();
688 }
689
690 typedef struct _variable {
691     int index;
692     classinfo_t*type;
693 } variable_t;
694
695 static variable_t* find_variable(char*name)
696 {
697     state_t* s = state;
698     while(s) {
699         variable_t*v = 0;
700         if(s->method)
701             v = dict_lookup(s->vars, name);
702         if(v) {
703             return v;
704         }
705         s = s->old;
706     }
707     return 0;
708
709 static variable_t* find_variable_safe(char*name)
710 {
711     variable_t* v = find_variable(name);
712     if(!v)
713         syntaxerror("undefined variable: %s", name);
714     return v;
715 }
716 static char variable_exists(char*name) 
717 {
718     return dict_lookup(state->vars, name)!=0;
719 }
720 code_t*defaultvalue(code_t*c, classinfo_t*type);
721 static int new_variable(char*name, classinfo_t*type, char init)
722 {
723     NEW(variable_t, v);
724     v->index = global->variable_count;
725     v->type = type;
726     dict_put(state->vars, name, v);
727
728     if(init && state->method && type) {
729         /* if this is a typed variable:
730            push default value for type on stack at the very beginning of the
731            method, so that it always has that type regardless of the control
732            path */
733         state->method->initcode = defaultvalue(state->method->initcode, type);
734         state->method->initcode = abc_setlocal(state->method->initcode, v->index);
735     }
736     return global->variable_count++;
737 }
738 #define TEMPVARNAME "__as3_temp__"
739 static int gettempvar()
740 {
741     variable_t*v = find_variable(TEMPVARNAME);
742     if(v) 
743         return v->index;
744     return new_variable(TEMPVARNAME, 0, 0);
745 }
746
747 code_t* killvars(code_t*c) 
748 {
749     int t;
750     for(t=0;t<state->vars->hashsize;t++) {
751         dictentry_t*e =state->vars->slots[t];
752         while(e) {
753             variable_t*v = (variable_t*)e->data;
754             //do this always, otherwise register types don't match
755             //in the verifier when doing nested loops
756             //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
757             c = abc_kill(c, v->index); 
758             e = e->next;
759         }
760     }
761     return c;
762 }
763
764 void check_code_for_break(code_t*c)
765 {
766     while(c) {
767         if(c->opcode == OPCODE___BREAK__) {
768             char*name = string_cstr(c->data[0]);
769             syntaxerror("Unresolved \"break %s\"", name);
770         }
771         if(c->opcode == OPCODE___CONTINUE__) {
772             char*name = string_cstr(c->data[0]);
773             syntaxerror("Unresolved \"continue %s\"", name);
774         }
775         c=c->prev;
776     }
777 }
778
779
780 static void check_constant_against_type(classinfo_t*t, constant_t*c)
781 {
782 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
783    if(TYPE_IS_NUMBER(t)) {
784         xassert(c->type == CONSTANT_FLOAT
785              || c->type == CONSTANT_INT
786              || c->type == CONSTANT_UINT);
787    } else if(TYPE_IS_UINT(t)) {
788         xassert(c->type == CONSTANT_UINT ||
789                (c->type == CONSTANT_INT && c->i>0));
790    } else if(TYPE_IS_INT(t)) {
791         xassert(c->type == CONSTANT_INT);
792    } else if(TYPE_IS_BOOLEAN(t)) {
793         xassert(c->type == CONSTANT_TRUE
794              || c->type == CONSTANT_FALSE);
795    }
796 }
797
798 static int flags2access(int flags)
799 {
800     int access = 0;
801     if(flags&FLAG_PUBLIC)  {
802         if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
803         access = ACCESS_PACKAGE;
804     } else if(flags&FLAG_PRIVATE) {
805         if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
806         access = ACCESS_PRIVATE;
807     } else if(flags&FLAG_PROTECTED) {
808         if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
809         access = ACCESS_PROTECTED;
810     } else {
811         access = ACCESS_PACKAGEINTERNAL;
812     }
813     return access;
814 }
815
816 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
817 {
818     memberinfo_t*minfo = 0;
819     if(!state->cls) {
820         //package method
821         minfo = rfx_calloc(sizeof(memberinfo_t));
822         classinfo_t*c = classinfo_register(flags2access(flags), state->package, name, 0);
823         c->flags |= FLAG_METHOD;
824         c->function = minfo;
825         minfo->kind = MEMBER_METHOD;
826         minfo->name = name;
827         minfo->flags = FLAG_STATIC;
828         minfo->return_type = return_type;
829     } else if(getset != KW_GET && getset != KW_SET) {
830         //class method
831         if((minfo = registry_findmember(state->cls->info, name, 0))) {
832             if(minfo->parent == state->cls->info) {
833                 syntaxerror("class already contains a member/method called '%s'", name);
834             } else if(!minfo->parent) {
835                 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
836             } else {
837                 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
838                     syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
839             }
840         }
841         minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
842         minfo->return_type = return_type;
843         // getslot on a member slot only returns "undefined", so no need
844         // to actually store these
845         //state->minfo->slot = state->method->abc->method->trait->slot_id;
846     } else {
847         //class getter/setter
848         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
849         classinfo_t*type=0;
850         if(getset == KW_GET)
851             type = return_type;
852         else if(params->list)
853             type = params->list->param->type;
854         // not sure wether to look into superclasses here, too
855         if((minfo=registry_findmember(state->cls->info, name, 0))) {
856             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
857                 syntaxerror("class already contains a member or method called '%s'", name);
858             if(minfo->kind & gs)
859                 syntaxerror("getter/setter for '%s' already defined", name);
860             /* make a setter or getter into a getset */
861             minfo->kind |= gs;
862             if(!minfo->type) 
863                 minfo->type = type;
864             else
865                 if(type && minfo->type != type)
866                     syntaxerror("different type in getter and setter");
867         } else {
868             minfo = memberinfo_register(state->cls->info, name, gs);
869             minfo->type = type;
870         }
871         /* can't assign a slot as getter and setter might have different slots */
872         //minfo->slot = slot;
873     }
874     if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
875     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
876     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
877     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
878     if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
879     if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
880     return minfo;
881 }
882
883 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
884                           params_t*params, classinfo_t*return_type)
885 {
886     if(state->method) {
887         syntaxerror("not able to start another method scope");
888     }
889     new_state();
890     global->variable_count = 0;
891     state->method = rfx_calloc(sizeof(methodstate_t));
892     state->method->initcode = 0;
893     state->method->has_super = 0;
894     if(state->cls) {
895         state->method->is_constructor = !strcmp(state->cls->info->name,name);
896         state->cls->has_constructor |= state->method->is_constructor;
897         
898         new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
899     } else {
900         state->method->is_global = 1;
901         state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
902
903         new_variable("globalscope", 0, 0);
904     }
905
906     /* state->vars is initialized by state_new */
907
908     param_list_t*p=0;
909     for(p=params->list;p;p=p->next) {
910         new_variable(p->param->name, p->param->type, 0);
911     }
912     if(state->method->is_constructor)
913         name = "__as3_constructor__";
914     state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
915 }
916
917 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
918                           params_t*params, classinfo_t*return_type, code_t*body)
919 {
920     abc_method_t*f = 0;
921
922     multiname_t*type2 = sig2mname(return_type);
923     int slot = 0;
924     if(state->method->is_constructor) {
925         f = abc_class_getconstructor(state->cls->abc, type2);
926     } else if(!state->method->is_global) {
927         namespace_t mname_ns = {flags2access(flags), ""};
928         multiname_t mname = {QNAME, &mname_ns, 0, name};
929
930         if(flags&FLAG_STATIC)
931             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
932         else
933             f = abc_class_method(state->cls->abc, type2, &mname);
934         slot = f->trait->slot_id;
935     } else {
936         namespace_t mname_ns = {flags2access(flags), state->package};
937         multiname_t mname = {QNAME, &mname_ns, 0, name};
938
939         f = abc_method_new(global->file, type2, 1);
940         trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
941         //abc_code_t*c = global->init->method->body->code;
942     }
943     //flash doesn't seem to allow us to access function slots
944     //state->method->info->slot = slot;
945
946     if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
947     if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
948     if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
949     if(params->varargs) f->flags |= METHOD_NEED_REST;
950
951     char opt=0;
952     param_list_t*p=0;
953     for(p=params->list;p;p=p->next) {
954         if(params->varargs && !p->next) {
955             break; //varargs: omit last parameter in function signature
956         }
957         multiname_t*m = sig2mname(p->param->type);
958         list_append(f->parameters, m);
959         if(p->param->value) {
960             check_constant_against_type(p->param->type, p->param->value);
961             opt=1;list_append(f->optional_parameters, p->param->value);
962         } else if(opt) {
963             syntaxerror("non-optional parameter not allowed after optional parameters");
964         }
965     }
966     check_code_for_break(body);
967
968     if(f->body)
969         f->body->code = body;
970     else //interface
971         if(body)
972             syntaxerror("interface methods can't have a method body");
973        
974     free(state->method);state->method=0;
975     old_state();
976 }
977
978
979
980 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
981 {
982     return 1; // FIXME
983 }
984
985 void breakjumpsto(code_t*c, char*name, code_t*jump) 
986 {
987     while(c) {
988         if(c->opcode == OPCODE___BREAK__) {
989             string_t*name2 = c->data[0];
990             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
991                 c->opcode = OPCODE_JUMP;
992                 c->branch = jump;
993             }
994         }
995         c=c->prev;
996     }
997 }
998 void continuejumpsto(code_t*c, char*name, code_t*jump) 
999 {
1000     while(c) {
1001         if(c->opcode == OPCODE___CONTINUE__) {
1002             string_t*name2 = c->data[0];
1003             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1004                 c->opcode = OPCODE_JUMP;
1005                 c->branch = jump;
1006             }
1007         }
1008         c = c->prev;
1009     }
1010 }
1011
1012 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1013 {
1014     if(!type1 || !type2) 
1015         return registry_getanytype();
1016     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1017         return registry_getanytype();
1018     if(type1 == type2)
1019         return type1;
1020     return registry_getanytype();
1021 }
1022 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1023 {
1024     if(from==to)
1025         return c;
1026     if(!to) {
1027         return abc_coerce_a(c);
1028     }
1029     MULTINAME(m, to);
1030     if(!from) {
1031         // cast an "any" type to a specific type. subject to
1032         // runtime exceptions
1033         return abc_coerce2(c, &m);
1034     }
1035     
1036     if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1037        (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1038         // allow conversion between number types
1039         return abc_coerce2(c, &m);
1040     }
1041     //printf("%s.%s\n", from.package, from.name);
1042     //printf("%s.%s\n", to.package, to.name);
1043
1044     classinfo_t*supertype = from;
1045     while(supertype) {
1046         if(supertype == to) {
1047              // target type is one of from's superclasses
1048              return abc_coerce2(c, &m);
1049         }
1050         int t=0;
1051         while(supertype->interfaces[t]) {
1052             if(supertype->interfaces[t]==to) {
1053                 // target type is one of from's interfaces
1054                 return abc_coerce2(c, &m);
1055             }
1056             t++;
1057         }
1058         supertype = supertype->superclass;
1059     }
1060     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1061         return c;
1062     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1063         return c;
1064     syntaxerror("can't convert type %s to %s", from->name, to->name);
1065 }
1066
1067 code_t*defaultvalue(code_t*c, classinfo_t*type)
1068 {
1069     if(TYPE_IS_INT(type)) {
1070        c = abc_pushbyte(c, 0);
1071     } else if(TYPE_IS_UINT(type)) {
1072        c = abc_pushuint(c, 0);
1073     } else if(TYPE_IS_FLOAT(type)) {
1074        c = abc_pushnan(c);
1075     } else if(TYPE_IS_BOOLEAN(type)) {
1076        c = abc_pushfalse(c);
1077     } else {
1078        c = abc_pushnull(c);
1079     }
1080     return c;
1081 }
1082
1083 char is_pushundefined(code_t*c)
1084 {
1085     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1086 }
1087
1088 void parserassert(int b)
1089 {
1090     if(!b) syntaxerror("internal error: assertion failed");
1091 }
1092
1093 static classinfo_t* find_class(char*name)
1094 {
1095     classinfo_t*c=0;
1096
1097     c = registry_findclass(state->package, name);
1098
1099     /* try explicit imports */
1100     dictentry_t* e = dict_get_slot(state->imports, name);
1101     while(e) {
1102         if(c)
1103             break;
1104         if(!strcmp(e->key, name)) {
1105             c = (classinfo_t*)e->data;
1106         }
1107         e = e->next;
1108     }
1109
1110     /* try package.* imports */
1111     import_list_t*l = state->wildcard_imports;
1112     while(l) {
1113         if(c)
1114             break;
1115         //printf("does package %s contain a class %s?\n", l->import->package, name);
1116         c = registry_findclass(l->import->package, name);
1117         l = l->next;
1118     }
1119
1120     /* try global package */
1121     if(!c) {
1122         c = registry_findclass("", name);
1123     }
1124     return c;
1125 }
1126
1127 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1128 {
1129     /* converts this:
1130
1131        [prefix code] [read instruction]
1132
1133        to this:
1134
1135        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1136     */
1137     
1138     if(in && in->opcode == OPCODE_COERCE_A) {
1139         in = code_cutlast(in);
1140     }
1141     if(in->next)
1142         syntaxerror("internal error");
1143
1144     /* chop off read instruction */
1145     code_t*prefix = in;
1146     code_t*r = in;
1147     if(r->prev) {
1148         prefix = r->prev;r->prev = 0;
1149         prefix->next=0;
1150     } else {
1151         prefix = 0;
1152     }
1153
1154     char use_temp_var = readbefore;
1155
1156     /* generate the write instruction, and maybe append a dup to the prefix code */
1157     code_t* write = abc_nop(0);
1158     if(r->opcode == OPCODE_GETPROPERTY) {
1159         write->opcode = OPCODE_SETPROPERTY;
1160         multiname_t*m = (multiname_t*)r->data[0];
1161         write->data[0] = multiname_clone(m);
1162         if(m->type == QNAME || m->type == MULTINAME) {
1163             if(!justassign) {
1164                 prefix = abc_dup(prefix); // we need the object, too
1165             }
1166             use_temp_var = 1;
1167         } else if(m->type == MULTINAMEL) {
1168             if(!justassign) {
1169                 /* dupping two values on the stack requires 5 operations and one register- 
1170                    couldn't adobe just have given us a dup2? */
1171                 int temp = gettempvar();
1172                 prefix = abc_setlocal(prefix, temp);
1173                 prefix = abc_dup(prefix);
1174                 prefix = abc_getlocal(prefix, temp);
1175                 prefix = abc_swap(prefix);
1176                 prefix = abc_getlocal(prefix, temp);
1177                 if(!use_temp_var);
1178                     prefix = abc_kill(prefix, temp);
1179             }
1180             use_temp_var = 1;
1181         } else {
1182             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1183         }
1184     } else if(r->opcode == OPCODE_GETSLOT) {
1185         write->opcode = OPCODE_SETSLOT;
1186         write->data[0] = r->data[0];
1187         if(!justassign) {
1188             prefix = abc_dup(prefix); // we need the object, too
1189         }
1190         use_temp_var = 1;
1191     } else if(r->opcode == OPCODE_GETLOCAL) { 
1192         write->opcode = OPCODE_SETLOCAL;
1193         write->data[0] = r->data[0];
1194     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1195         write->opcode = OPCODE_SETLOCAL_0;
1196     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1197         write->opcode = OPCODE_SETLOCAL_1;
1198     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1199         write->opcode = OPCODE_SETLOCAL_2;
1200     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1201         write->opcode = OPCODE_SETLOCAL_3;
1202     } else {
1203         code_dump(r, 0, 0, "", stdout);
1204         syntaxerror("illegal lvalue: can't assign a value to this expression");
1205     }
1206     code_t* c = 0;
1207     
1208     int temp = -1;
1209     if(!justassign) {
1210         if(use_temp_var) {
1211             /* with getproperty/getslot, we have to be extra careful not
1212                to execute the read code twice, as it might have side-effects
1213                (e.g. if the property is in fact a setter/getter combination)
1214
1215                So read the value, modify it, and write it again,
1216                using prefix only once and making sure (by using a temporary
1217                register) that the return value is what we just wrote */
1218             temp = gettempvar();
1219             c = code_append(c, prefix);
1220             c = code_append(c, r);
1221             if(readbefore) {
1222                 c = abc_dup(c);
1223                 c = abc_setlocal(c, temp);
1224             }
1225             c = code_append(c, middlepart);
1226             if(!readbefore) {
1227                 c = abc_dup(c);
1228                 c = abc_setlocal(c, temp);
1229             }
1230             c = code_append(c, write);
1231             c = abc_getlocal(c, temp);
1232             c = abc_kill(c, temp);
1233         } else {
1234             /* if we're allowed to execute the read code twice *and*
1235                the middlepart doesn't modify the code, things are easier.
1236             */
1237             code_t* r2 = code_dup(r);
1238             //c = code_append(c, prefix);
1239             parserassert(!prefix);
1240             c = code_append(c, r);
1241             c = code_append(c, middlepart);
1242             c = code_append(c, write);
1243             c = code_append(c, r2);
1244         }
1245     } else {
1246         /* even smaller version: overwrite the value without reading
1247            it out first */
1248         if(!use_temp_var) {
1249             if(prefix) {
1250                 c = code_append(c, prefix);
1251                 c = abc_dup(c);
1252             }
1253             c = code_append(c, middlepart);
1254             c = code_append(c, write);
1255             c = code_append(c, r);
1256         } else {
1257             temp = gettempvar();
1258             if(prefix) {
1259                 c = code_append(c, prefix);
1260             }
1261             c = code_append(c, middlepart);
1262             c = abc_dup(c);
1263             c = abc_setlocal(c, temp);
1264             c = code_append(c, write);
1265             c = abc_getlocal(c, temp);
1266             c = abc_kill(c, temp);
1267         }
1268     }
1269
1270     return c;
1271 }
1272
1273 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1274 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1275
1276 %}
1277
1278
1279 %%
1280
1281 /* ------------ code blocks / statements ---------------- */
1282
1283 PROGRAM: MAYBECODE {
1284     /* todo: do something with this code if we're outside a function */
1285     if($1)
1286         warning("ignored code");
1287 }
1288
1289 MAYBECODE: CODE {$$=$1;}
1290 MAYBECODE: {$$=code_new();}
1291
1292 CODE: CODE CODEPIECE {
1293     $$=code_append($1,$2);
1294 }
1295 CODE: CODEPIECE {
1296     $$=$1;
1297 }
1298
1299 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1300 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1301 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1302 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1303 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1304 CODEPIECE: ';'                   {$$=code_new();}
1305 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1306 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1307 CODEPIECE: FOR                   {$$=$1}
1308 CODEPIECE: FOR_IN                {$$=$1}
1309 CODEPIECE: WHILE                 {$$=$1}
1310 CODEPIECE: DO_WHILE              {$$=$1}
1311 CODEPIECE: SWITCH                {$$=$1}
1312 CODEPIECE: BREAK                 {$$=$1}
1313 CODEPIECE: CONTINUE              {$$=$1}
1314 CODEPIECE: RETURN                {$$=$1}
1315 CODEPIECE: IF                    {$$=$1}
1316 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1317 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1318
1319 CODEBLOCK :  '{' CODE '}' {$$=$2;}
1320 CODEBLOCK :  '{' '}'      {$$=0;}
1321 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1322 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1323
1324 /* ------------ variables --------------------------- */
1325
1326 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1327                 |                {$$.c=abc_pushundefined(0);
1328                                   $$.t=TYPE_ANY;
1329                                  }
1330
1331 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1332 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1333
1334 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1335 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1336
1337 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1338 {
1339     if(variable_exists($1))
1340         syntaxerror("Variable %s already defined", $1);
1341    
1342     if(!is_subtype_of($3.t, $2)) {
1343         syntaxerror("Can't convert %s to %s", $3.t->name, 
1344                                               $2->name);
1345     }
1346
1347     int index = new_variable($1, $2, 1);
1348     
1349     if($2) {
1350         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1351             $$ = $3.c;
1352             $$ = converttype($$, $3.t, $2);
1353             $$ = abc_setlocal($$, index);
1354         } else {
1355             $$ = defaultvalue(0, $2);
1356             $$ = abc_setlocal($$, index);
1357         }
1358     } else {
1359         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1360             $$ = $3.c;
1361             $$ = abc_coerce_a($$);
1362             $$ = abc_setlocal($$, index);
1363         } else {
1364             $$ = code_new();
1365         }
1366     }
1367     
1368     /* that's the default for a local register, anyway
1369         else {
1370         state->method->initcode = abc_pushundefined(state->method->initcode);
1371         state->method->initcode = abc_setlocal(state->method->initcode, index);
1372     }*/
1373     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1374 }
1375
1376 /* ------------ control flow ------------------------- */
1377
1378 MAYBEELSE:  %prec below_else {$$ = code_new();}
1379 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1380 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1381
1382 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1383     $$ = code_new();
1384     $$ = code_append($$, $4.c);
1385     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1386    
1387     $$ = code_append($$, $6);
1388     if($7) {
1389         myjmp = $$ = abc_jump($$, 0);
1390     }
1391     myif->branch = $$ = abc_nop($$);
1392     if($7) {
1393         $$ = code_append($$, $7);
1394         myjmp->branch = $$ = abc_nop($$);
1395     }
1396     
1397     $$ = killvars($$);old_state();
1398 }
1399
1400 FOR_INIT : {$$=code_new();}
1401 FOR_INIT : VARIABLE_DECLARATION
1402 FOR_INIT : VOIDEXPRESSION
1403 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1404     $$=$2;new_variable($2,$3,1);
1405 }
1406 FOR_IN_INIT : T_IDENTIFIER {
1407     $$=$1;
1408 }
1409
1410 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1411 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1412
1413 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1414     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1415     $$ = code_new();
1416     $$ = code_append($$, $2);
1417     code_t*loopstart = $$ = abc_label($$);
1418     $$ = code_append($$, $4.c);
1419     code_t*myif = $$ = abc_iffalse($$, 0);
1420     $$ = code_append($$, $8);
1421     code_t*cont = $$ = abc_nop($$);
1422     $$ = code_append($$, $6);
1423     $$ = abc_jump($$, loopstart);
1424     code_t*out = $$ = abc_nop($$);
1425     breakjumpsto($$, $1.name, out);
1426     continuejumpsto($$, $1.name, cont);
1427     myif->branch = out;
1428
1429     $$ = killvars($$);old_state();
1430 }
1431
1432 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1433     variable_t*var = find_variable($2);
1434     char*tmp1name = concat2($2, "__tmp1__");
1435     int it = new_variable(tmp1name, TYPE_INT, 0);
1436     char*tmp2name = concat2($2, "__array__");
1437     int array = new_variable(tmp1name, 0, 0);
1438
1439     $$ = code_new();
1440     $$ = code_append($$, $4.c);
1441     $$ = abc_coerce_a($$);
1442     $$ = abc_setlocal($$, array);
1443     $$ = abc_pushbyte($$, 0);
1444     $$ = abc_setlocal($$, it);
1445
1446     code_t*loopstart = $$ = abc_label($$);
1447     
1448     $$ = abc_hasnext2($$, array, it);
1449     code_t*myif = $$ = abc_iffalse($$, 0);
1450     $$ = abc_getlocal($$, array);
1451     $$ = abc_getlocal($$, it);
1452     if(!$1.each)
1453         $$ = abc_nextname($$);
1454     else
1455         $$ = abc_nextvalue($$);
1456     $$ = converttype($$, 0, var->type);
1457     $$ = abc_setlocal($$, var->index);
1458
1459     $$ = code_append($$, $6);
1460     $$ = abc_jump($$, loopstart);
1461     
1462     code_t*out = $$ = abc_nop($$);
1463     breakjumpsto($$, $1.name, out);
1464     continuejumpsto($$, $1.name, loopstart);
1465     
1466     $$ = killvars($$);
1467     
1468     myif->branch = out;
1469
1470     old_state();
1471     free(tmp1name);
1472     free(tmp2name);
1473 }
1474
1475 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1476     $$ = code_new();
1477
1478     code_t*myjmp = $$ = abc_jump($$, 0);
1479     code_t*loopstart = $$ = abc_label($$);
1480     $$ = code_append($$, $6);
1481     code_t*cont = $$ = abc_nop($$);
1482     myjmp->branch = cont;
1483     $$ = code_append($$, $4.c);
1484     $$ = abc_iftrue($$, loopstart);
1485     code_t*out = $$ = abc_nop($$);
1486     breakjumpsto($$, $1, out);
1487     continuejumpsto($$, $1, cont);
1488
1489     $$ = killvars($$);
1490     old_state();
1491 }
1492
1493 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1494     $$ = code_new();
1495     code_t*loopstart = $$ = abc_label($$);
1496     $$ = code_append($$, $3);
1497     code_t*cont = $$ = abc_nop($$);
1498     $$ = code_append($$, $6.c);
1499     $$ = abc_iftrue($$, loopstart);
1500     code_t*out = $$ = abc_nop($$);
1501     breakjumpsto($$, $1, out);
1502     continuejumpsto($$, $1, cont);
1503     $$ = killvars($$);
1504     old_state();
1505 }
1506
1507 BREAK : "break" %prec prec_none {
1508     $$ = abc___break__(0, "");
1509 }
1510 BREAK : "break" T_IDENTIFIER {
1511     $$ = abc___break__(0, $2);
1512 }
1513 CONTINUE : "continue" %prec prec_none {
1514     $$ = abc___continue__(0, "");
1515 }
1516 CONTINUE : "continue" T_IDENTIFIER {
1517     $$ = abc___continue__(0, $2);
1518 }
1519
1520 MAYBE_CASE_LIST :           {$$=0;}
1521 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1522 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
1523 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1524 CASE_LIST: CASE             {$$=$1}
1525 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
1526
1527 CASE: "case" E ':' MAYBECODE {
1528     $$ = abc_dup(0);
1529     $$ = code_append($$, $2.c);
1530     code_t*j = $$ = abc_ifne($$, 0);
1531     $$ = code_append($$, $4);
1532     if($$->opcode != OPCODE___BREAK__) {
1533         $$ = abc___fallthrough__($$, "");
1534     }
1535     code_t*e = $$ = abc_nop($$);
1536     j->branch = e;
1537 }
1538 DEFAULT: "default" ':' MAYBECODE {
1539     $$ = $3;
1540 }
1541 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1542     $$=$4.c;
1543     $$ = code_append($$, $7);
1544     code_t*out = $$ = abc_pop($$);
1545     breakjumpsto($$, $1, out);
1546     
1547     code_t*c = $$,*lastblock=0;
1548     while(c) {
1549         if(c->opcode == OPCODE_IFNE) {
1550             if(!c->next) syntaxerror("internal error in fallthrough handling");
1551             lastblock=c->next;
1552         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1553             if(lastblock) {
1554                 c->opcode = OPCODE_JUMP;
1555                 c->branch = lastblock;
1556             } else {
1557                 /* fall through end of switch */
1558                 c->opcode = OPCODE_NOP;
1559             }
1560         }
1561         c=c->prev;
1562     }
1563     old_state();
1564 }
1565
1566 /* ------------ packages and imports ---------------- */
1567
1568 X_IDENTIFIER: T_IDENTIFIER
1569             | "package" {$$="package";}
1570
1571 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1572 PACKAGE: X_IDENTIFIER             {$$=strdup($1);}
1573
1574 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
1575 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1576
1577 IMPORT : "import" QNAME {
1578        classinfo_t*c = $2;
1579        if(!c) 
1580             syntaxerror("Couldn't import class\n");
1581        state_has_imports();
1582        dict_put(state->imports, c->name, c);
1583        $$=0;
1584 }
1585 IMPORT : "import" PACKAGE '.' '*' {
1586        NEW(import_t,i);
1587        i->package = $2;
1588        state_has_imports();
1589        list_append(state->wildcard_imports, i);
1590        $$=0;
1591 }
1592
1593 /* ------------ classes and interfaces (header) -------------- */
1594
1595 MAYBE_MODIFIERS : {$$=0;}
1596 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1597 MODIFIER_LIST : MODIFIER               {$$=$1;}
1598 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1599
1600 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1601          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1602          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1603          | KW_STATIC {$$=FLAG_STATIC;}
1604          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1605          | KW_FINAL {$$=FLAG_FINAL;}
1606          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1607          | KW_NATIVE {$$=FLAG_NATIVE;}
1608          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1609
1610 EXTENDS : {$$=registry_getobjectclass();}
1611 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1612
1613 EXTENDS_LIST : {$$=list_new();}
1614 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1615
1616 IMPLEMENTS_LIST : {$$=list_new();}
1617 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1618
1619 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1620                               EXTENDS IMPLEMENTS_LIST 
1621                               '{' {startclass($1,$3,$4,$5, 0);} 
1622                               MAYBE_DECLARATION_LIST 
1623                               '}' {endclass();}
1624
1625 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1626                               EXTENDS_LIST 
1627                               '{' {startclass($1,$3,0,$4,1);}
1628                               MAYBE_IDECLARATION_LIST 
1629                               '}' {endclass();}
1630
1631 /* ------------ classes and interfaces (body) -------------- */
1632
1633 MAYBE_DECLARATION_LIST : 
1634 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1635 DECLARATION_LIST : DECLARATION
1636 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1637 DECLARATION : ';'
1638 DECLARATION : SLOT_DECLARATION
1639 DECLARATION : FUNCTION_DECLARATION
1640
1641 MAYBE_IDECLARATION_LIST : 
1642 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1643 IDECLARATION_LIST : IDECLARATION
1644 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1645 IDECLARATION : ';'
1646 IDECLARATION : "var" T_IDENTIFIER {
1647     syntaxerror("variable declarations not allowed in interfaces");
1648 }
1649 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1650     $1 |= FLAG_PUBLIC;
1651     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1652         syntaxerror("invalid method modifiers: interface methods always need to be public");
1653     }
1654     startfunction(0,$1,$3,$4,&$6,$8);
1655     endfunction(0,$1,$3,$4,&$6,$8, 0);
1656 }
1657
1658 /* ------------ classes and interfaces (body, slots ) ------- */
1659
1660 VARCONST: "var" | "const"
1661
1662 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1663     int flags = $1;
1664     memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1665     info->type = $4;
1666     info->flags = flags;
1667     trait_t*t=0;
1668
1669     namespace_t mname_ns = {flags2access(flags), ""};
1670     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1671
1672     if(!(flags&FLAG_STATIC)) {
1673         if($4) {
1674             MULTINAME(m, $4);
1675             t=abc_class_slot(state->cls->abc, &mname, &m);
1676         } else {
1677             t=abc_class_slot(state->cls->abc, &mname, 0);
1678         }
1679         info->slot = t->slot_id;
1680     } else {
1681         if($4) {
1682             MULTINAME(m, $4);
1683             t=abc_class_staticslot(state->cls->abc, &mname, &m);
1684         } else {
1685             t=abc_class_staticslot(state->cls->abc, &mname, 0);
1686         }
1687         info->slot = t->slot_id;
1688     }
1689     if($5.c && !is_pushundefined($5.c)) {
1690         code_t*c = 0;
1691         c = abc_getlocal_0(c);
1692         c = code_append(c, $5.c);
1693         c = converttype(c, $5.t, $4);
1694         c = abc_setslot(c, t->slot_id);
1695         if(!(flags&FLAG_STATIC))
1696             state->cls->init = code_append(state->cls->init, c);
1697         else
1698             state->cls->static_init = code_append(state->cls->static_init, c);
1699     }
1700     if($2==KW_CONST) {
1701         t->kind= TRAIT_CONST;
1702     }
1703 }
1704
1705 /* ------------ constants -------------------------------------- */
1706
1707 MAYBESTATICCONSTANT: {$$=0;}
1708 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1709
1710 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1711 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1712 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1713 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1714 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1715 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1716 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1717 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1718 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1719
1720 /* ------------ classes and interfaces (body, functions) ------- */
1721
1722 // non-vararg version
1723 MAYBE_PARAM_LIST: {
1724     memset(&$$,0,sizeof($$));
1725 }
1726 MAYBE_PARAM_LIST: PARAM_LIST {
1727     $$=$1;
1728 }
1729
1730 // vararg version
1731 MAYBE_PARAM_LIST: "..." PARAM {
1732     memset(&$$,0,sizeof($$));
1733     $$.varargs=1;
1734     list_append($$.list, $2);
1735 }
1736 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1737     $$ =$1;
1738     $$.varargs=1;
1739     list_append($$.list, $4);
1740 }
1741
1742 // non empty
1743 PARAM_LIST: PARAM_LIST ',' PARAM {
1744     $$ = $1;
1745     list_append($$.list, $3);
1746 }
1747 PARAM_LIST: PARAM {
1748     memset(&$$,0,sizeof($$));
1749     list_append($$.list, $1);
1750 }
1751
1752 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1753      $$ = malloc(sizeof(param_t));
1754      $$->name=$1;
1755      $$->type = $3;
1756      $$->value = $4;
1757 }
1758 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1759      $$ = malloc(sizeof(param_t));
1760      $$->name=$1;
1761      $$->type = TYPE_ANY;
1762      $$->value = $2;
1763 }
1764 GETSET : "get" {$$=$1;}
1765        | "set" {$$=$1;}
1766        |       {$$=0;}
1767
1768 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1769                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1770 {
1771     code_t*c = 0;
1772     if(state->method->late_binding) {
1773         c = abc_getlocal_0(c);
1774         c = abc_pushscope(c);
1775     }
1776     if(state->method->is_constructor && !state->method->has_super) {
1777         // call default constructor
1778         c = abc_getlocal_0(c);
1779         c = abc_constructsuper(c, 0);
1780     }
1781     c = wrap_function(c, state->method->initcode, $11);
1782     endfunction(0,$1,$3,$4,&$6,$8,c);
1783 }
1784
1785 /* ------------- package + class ids --------------- */
1786
1787 CLASS: T_IDENTIFIER {
1788
1789     /* try current package */
1790     $$ = find_class($1);
1791     if(!$$) syntaxerror("Could not find class %s\n", $1);
1792 }
1793
1794 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1795     $$ = registry_findclass($1, $3);
1796     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1797     free($1);$1=0;
1798 }
1799
1800 QNAME: PACKAGEANDCLASS
1801      | CLASS
1802
1803 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1804 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1805
1806 TYPE : QNAME      {$$=$1;}
1807      | '*'        {$$=registry_getanytype();}
1808      | "void"     {$$=registry_getanytype();}
1809     /*
1810      |  "String"  {$$=registry_getstringclass();}
1811      |  "int"     {$$=registry_getintclass();}
1812      |  "uint"    {$$=registry_getuintclass();}
1813      |  "Boolean" {$$=registry_getbooleanclass();}
1814      |  "Number"  {$$=registry_getnumberclass();}
1815     */
1816
1817 MAYBETYPE: ':' TYPE {$$=$2;}
1818 MAYBETYPE:          {$$=0;}
1819
1820 /* ----------function calls, delete, constructor calls ------ */
1821
1822 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
1823 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1824
1825 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1826 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1827 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
1828                                                   $$.cc = $1.c;
1829                                                  }
1830 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1831                                                   $$.len= $1.len+1;
1832                                                   $$.cc = code_append($1.cc, $3.c);
1833                                                   }
1834
1835 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1836     MULTINAME(m, $2);
1837     $$.c = code_new();
1838
1839     if($2->slot) {
1840         $$.c = abc_getglobalscope($$.c);
1841         $$.c = abc_getslot($$.c, $2->slot);
1842     } else {
1843         $$.c = abc_findpropstrict2($$.c, &m);
1844     }
1845
1846     $$.c = code_append($$.c, $3.cc);
1847
1848     if($2->slot)
1849         $$.c = abc_construct($$.c, $3.len);
1850     else
1851         $$.c = abc_constructprop2($$.c, &m, $3.len);
1852     $$.t = $2;
1853 }
1854
1855 /* TODO: use abc_call (for calling local variables),
1856          abc_callstatic (for calling own methods) 
1857          call (for closures)
1858 */
1859 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1860     
1861     $$.c = $1.c;
1862     if($$.c->opcode == OPCODE_COERCE_A) {
1863         $$.c = code_cutlast($$.c);
1864     }
1865     code_t*paramcode = $3.cc;
1866
1867     $$.t = TYPE_ANY;
1868     if($$.c->opcode == OPCODE_GETPROPERTY) {
1869         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1870         $$.c = code_cutlast($$.c);
1871         $$.c = code_append($$.c, paramcode);
1872         $$.c = abc_callproperty2($$.c, name, $3.len);
1873         multiname_destroy(name);
1874     } else if($$.c->opcode == OPCODE_GETSLOT) {
1875         int slot = (int)(ptroff_t)$$.c->data[0];
1876         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1877         if(t->kind!=TRAIT_METHOD) {
1878             //ok: flash allows to assign closures to members.
1879         }
1880         multiname_t*name = t->name;
1881         $$.c = code_cutlast($$.c);
1882         $$.c = code_append($$.c, paramcode);
1883         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1884         $$.c = abc_callproperty2($$.c, name, $3.len);
1885     } else if($$.c->opcode == OPCODE_GETSUPER) {
1886         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1887         $$.c = code_cutlast($$.c);
1888         $$.c = code_append($$.c, paramcode);
1889         $$.c = abc_callsuper2($$.c, name, $3.len);
1890         multiname_destroy(name);
1891     } else {
1892         $$.c = abc_getlocal_0($$.c);
1893         $$.c = code_append($$.c, paramcode);
1894         $$.c = abc_call($$.c, $3.len);
1895     }
1896    
1897     memberinfo_t*f = 0;
1898    
1899     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1900         $$.t = $1.t->function->return_type;
1901     } else {
1902         $$.c = abc_coerce_a($$.c);
1903         $$.t = TYPE_ANY;
1904     }
1905
1906 }
1907 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1908     if(!state->cls) syntaxerror("super() not allowed outside of a class");
1909     if(!state->method) syntaxerror("super() not allowed outside of a function");
1910     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1911
1912     $$.c = code_new();
1913     $$.c = abc_getlocal_0($$.c);
1914
1915     $$.c = code_append($$.c, $3.cc);
1916     /*
1917     this is dependent on the control path, check this somewhere else
1918     if(state->method->has_super)
1919         syntaxerror("constructor may call super() only once");
1920     */
1921     state->method->has_super = 1;
1922     $$.c = abc_constructsuper($$.c, $3.len);
1923     $$.c = abc_pushundefined($$.c);
1924     $$.t = TYPE_ANY;
1925 }
1926
1927 DELETE: "delete" E {
1928     $$.c = $2.c;
1929     if($$.c->opcode == OPCODE_COERCE_A) {
1930         $$.c = code_cutlast($$.c);
1931     }
1932     multiname_t*name = 0;
1933     if($$.c->opcode == OPCODE_GETPROPERTY) {
1934         $$.c->opcode = OPCODE_DELETEPROPERTY;
1935     } else if($$.c->opcode == OPCODE_GETSLOT) {
1936         int slot = (int)(ptroff_t)$$.c->data[0];
1937         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1938         $$.c = code_cutlast($$.c);
1939         $$.c = abc_deleteproperty2($$.c, name);
1940     } else {
1941         $$.c = abc_getlocal_0($$.c);
1942         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1943         $$.c = abc_deleteproperty2($$.c, &m);
1944     }
1945     $$.t = TYPE_BOOLEAN;
1946 }
1947
1948 RETURN: "return" %prec prec_none {
1949     $$ = abc_returnvoid(0);
1950 }
1951 RETURN: "return" EXPRESSION {
1952     $$ = $2.c;
1953     $$ = abc_returnvalue($$);
1954 }
1955
1956 // ----------------------- expression types -------------------------------------
1957
1958 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
1959 EXPRESSION : E                %prec below_minus {$$ = $1;}
1960 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1961     $$.c = $1.c;
1962     $$.c = cut_last_push($$.c);
1963     $$.c = code_append($$.c,$3.c);
1964     $$.t = $3.t;
1965 }
1966 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1967     $$=cut_last_push($1.c);
1968 }
1969
1970 // ----------------------- expression evaluation -------------------------------------
1971
1972 E : CONSTANT
1973 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1974 E : NEW                         {$$ = $1;}
1975 E : DELETE                      {$$ = $1;}
1976 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1977                                  $$.t = TYPE_ANY;
1978                                 }
1979
1980 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1981                    //MULTINAME(m, registry_getintclass());
1982                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1983                    $$.t = TYPE_INT;
1984                   }
1985 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1986                     $$.t = TYPE_INT;
1987                    }
1988 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1989                   $$.t = TYPE_INT;
1990                  }
1991 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1992                    $$.t = TYPE_UINT;
1993                   }
1994 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1995                     $$.t = TYPE_FLOAT;
1996                    }
1997 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1998                      $$.t = TYPE_STRING;
1999                     }
2000 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2001                     $$.t = TYPE_ANY;
2002                    }
2003 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2004                     $$.t = TYPE_BOOLEAN;
2005                    }
2006 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2007                      $$.t = TYPE_BOOLEAN;
2008                     }
2009 CONSTANT : "null" {$$.c = abc_pushnull(0);
2010                     $$.t = TYPE_NULL;
2011                    }
2012
2013 E : FUNCTIONCALL
2014 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2015              $$.t = TYPE_BOOLEAN;
2016             }
2017 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2018              $$.t = TYPE_BOOLEAN;
2019             }
2020 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2021               $$.t = TYPE_BOOLEAN;
2022              }
2023 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2024               $$.t = TYPE_BOOLEAN;
2025              }
2026 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2027               $$.t = TYPE_BOOLEAN;
2028              }
2029 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2030               $$.t = TYPE_BOOLEAN;
2031               }
2032 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2033               $$.t = TYPE_BOOLEAN;
2034              }
2035 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2036               $$.t = TYPE_BOOLEAN;
2037              }
2038
2039 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2040               $$.c = $1.c;
2041               $$.c = converttype($$.c, $1.t, $$.t);
2042               $$.c = abc_dup($$.c);
2043               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2044               $$.c = cut_last_push($$.c);
2045               $$.c = code_append($$.c,$3.c);
2046               $$.c = converttype($$.c, $3.t, $$.t);
2047               code_t*label = $$.c = abc_label($$.c);
2048               jmp->branch = label;
2049              }
2050 E : E "&&" E {
2051               $$.t = join_types($1.t, $3.t, 'A');
2052               /*printf("%08x:\n",$1.t);
2053               code_dump($1.c, 0, 0, "", stdout);
2054               printf("%08x:\n",$3.t);
2055               code_dump($3.c, 0, 0, "", stdout);
2056               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2057               $$.c = $1.c;
2058               $$.c = converttype($$.c, $1.t, $$.t);
2059               $$.c = abc_dup($$.c);
2060               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2061               $$.c = cut_last_push($$.c);
2062               $$.c = code_append($$.c,$3.c);
2063               $$.c = converttype($$.c, $3.t, $$.t);
2064               code_t*label = $$.c = abc_label($$.c);
2065               jmp->branch = label;              
2066              }
2067
2068 E : '!' E    {$$.c=$2.c;
2069               $$.c = abc_not($$.c);
2070               $$.t = TYPE_BOOLEAN;
2071              }
2072
2073 E : '~' E    {$$.c=$2.c;
2074               $$.c = abc_bitnot($$.c);
2075               $$.t = TYPE_INT;
2076              }
2077
2078 E : E '&' E {$$.c = code_append($1.c,$3.c);
2079              $$.c = abc_bitand($$.c);
2080              $$.t = TYPE_INT;
2081             }
2082
2083 E : E '^' E {$$.c = code_append($1.c,$3.c);
2084              $$.c = abc_bitxor($$.c);
2085              $$.t = TYPE_INT;
2086             }
2087
2088 E : E '|' E {$$.c = code_append($1.c,$3.c);
2089              $$.c = abc_bitor($$.c);
2090              $$.t = TYPE_INT;
2091             }
2092
2093 E : E '-' E {$$.c = code_append($1.c,$3.c);
2094              if(BOTH_INT($1,$3)) {
2095                 $$.c = abc_subtract_i($$.c);
2096                 $$.t = TYPE_INT;
2097              } else {
2098                 $$.c = abc_subtract($$.c);
2099                 $$.t = TYPE_NUMBER;
2100              }
2101             }
2102 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2103              $$.c = abc_rshift($$.c);
2104              $$.t = TYPE_INT;
2105             }
2106 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2107              $$.c = abc_urshift($$.c);
2108              $$.t = TYPE_INT;
2109             }
2110 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2111              $$.c = abc_lshift($$.c);
2112              $$.t = TYPE_INT;
2113             }
2114
2115 E : E '/' E {$$.c = code_append($1.c,$3.c);
2116              $$.c = abc_divide($$.c);
2117              $$.t = TYPE_NUMBER;
2118             }
2119 E : E '+' E {$$.c = code_append($1.c,$3.c);
2120              $$.c = abc_add($$.c);
2121              $$.t = TYPE_NUMBER;
2122             }
2123 E : E '%' E {$$.c = code_append($1.c,$3.c);
2124              $$.c = abc_modulo($$.c);
2125              $$.t = TYPE_NUMBER;
2126             }
2127 E : E '*' E {$$.c = code_append($1.c,$3.c);
2128              if(BOTH_INT($1,$3)) {
2129                 $$.c = abc_multiply_i($$.c);
2130                 $$.t = TYPE_INT;
2131              } else {
2132                 $$.c = abc_multiply($$.c);
2133                 $$.t = TYPE_NUMBER;
2134              }
2135             }
2136
2137 E : E "in" E {$$.c = code_append($1.c,$3.c);
2138               $$.c = abc_in($$.c);
2139               $$.t = TYPE_BOOLEAN;
2140              }
2141
2142 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2143               if(use_astype && TYPE_IS_CLASS($3.t)) {
2144                 MULTINAME(m,$3.t->cls);
2145                 $$.c = abc_astype2($1.c, &m);
2146                 $$.t = $3.t->cls;
2147               } else {
2148                 $$.c = code_append($1.c, $3.c);
2149                 $$.c = abc_astypelate($$.c);
2150                 $$.t = TYPE_ANY;
2151               }
2152              }
2153
2154 E : E "instanceof" E 
2155              {$$.c = code_append($1.c, $3.c);
2156               $$.c = abc_instanceof($$.c);
2157               $$.t = TYPE_BOOLEAN;
2158              }
2159
2160 E : E "is" E {$$.c = code_append($1.c, $3.c);
2161               $$.c = abc_istypelate($$.c);
2162               $$.t = TYPE_BOOLEAN;
2163              }
2164
2165 E : "typeof" '(' E ')' {
2166               $$.c = $3.c;
2167               $$.c = abc_typeof($$.c);
2168               $$.t = TYPE_STRING;
2169              }
2170
2171 E : "void" E {
2172               $$.c = cut_last_push($2.c);
2173               $$.c = abc_pushundefined($$.c);
2174               $$.t = TYPE_ANY;
2175              }
2176
2177 E : "void" { $$.c = abc_pushundefined(0);
2178              $$.t = TYPE_ANY;
2179            }
2180
2181 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2182
2183 E : '-' E {
2184   $$=$2;
2185   if(IS_INT($2)) {
2186    $$.c=abc_negate_i($$.c);
2187    $$.t = TYPE_INT;
2188   } else {
2189    $$.c=abc_negate($$.c);
2190    $$.t = TYPE_NUMBER;
2191   }
2192 }
2193
2194 E : E '[' E ']' {
2195   $$.c = $1.c;
2196   $$.c = code_append($$.c, $3.c);
2197  
2198   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2199   $$.c = abc_getproperty2($$.c, &m);
2200   $$.t = 0; // array elements have unknown type
2201 }
2202
2203 E : '[' MAYBE_EXPRESSION_LIST ']' {
2204     $$.c = code_new();
2205     $$.c = code_append($$.c, $2.cc);
2206     $$.c = abc_newarray($$.c, $2.len);
2207     $$.t = registry_getarrayclass();
2208 }
2209
2210 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2211 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2212
2213 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2214     $$.cc = 0;
2215     $$.cc = code_append($$.cc, $1.c);
2216     $$.cc = code_append($$.cc, $3.c);
2217     $$.len = 2;
2218 }
2219 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2220     $$.cc = $1.cc;
2221     $$.len = $1.len+2;
2222     $$.cc = code_append($$.cc, $3.c);
2223     $$.cc = code_append($$.cc, $5.c);
2224 }
2225 //MAYBECOMMA: ','
2226 //MAYBECOMMA:
2227
2228 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2229     $$.c = code_new();
2230     $$.c = code_append($$.c, $2.cc);
2231     $$.c = abc_newobject($$.c, $2.len/2);
2232     $$.t = registry_getobjectclass();
2233 }
2234
2235 E : E "*=" E { 
2236                code_t*c = $3.c;
2237                if(BOTH_INT($1,$3)) {
2238                 c=abc_multiply_i(c);
2239                } else {
2240                 c=abc_multiply(c);
2241                }
2242                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2243                $$.c = toreadwrite($1.c, c, 0, 0);
2244                $$.t = $1.t;
2245               }
2246
2247 E : E "%=" E { 
2248                code_t*c = abc_modulo($3.c);
2249                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2250                $$.c = toreadwrite($1.c, c, 0, 0);
2251                $$.t = $1.t;
2252               }
2253 E : E "<<=" E { 
2254                code_t*c = abc_lshift($3.c);
2255                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2256                $$.c = toreadwrite($1.c, c, 0, 0);
2257                $$.t = $1.t;
2258               }
2259 E : E ">>=" E { 
2260                code_t*c = abc_rshift($3.c);
2261                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2262                $$.c = toreadwrite($1.c, c, 0, 0);
2263                $$.t = $1.t;
2264               }
2265 E : E ">>>=" E { 
2266                code_t*c = abc_urshift($3.c);
2267                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2268                $$.c = toreadwrite($1.c, c, 0, 0);
2269                $$.t = $1.t;
2270               }
2271 E : E "/=" E { 
2272                code_t*c = abc_divide($3.c);
2273                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2274                $$.c = toreadwrite($1.c, c, 0, 0);
2275                $$.t = $1.t;
2276               }
2277 E : E "+=" E { 
2278                code_t*c = $3.c;
2279                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2280                 c=abc_add_i(c);
2281                } else {
2282                 c=abc_add(c);
2283                }
2284                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2285                
2286                $$.c = toreadwrite($1.c, c, 0, 0);
2287                $$.t = $1.t;
2288               }
2289 E : E "-=" E { code_t*c = $3.c; 
2290                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2291                 c=abc_subtract_i(c);
2292                } else {
2293                 c=abc_subtract(c);
2294                }
2295                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2296                
2297                $$.c = toreadwrite($1.c, c, 0, 0);
2298                $$.t = $1.t;
2299              }
2300 E : E '=' E { code_t*c = 0;
2301               c = code_append(c, $3.c);
2302               c = converttype(c, $3.t, $1.t);
2303               $$.c = toreadwrite($1.c, c, 1, 0);
2304               $$.t = $1.t;
2305             }
2306
2307 E : E '?' E ':' E %prec below_assignment { 
2308               $$.c = $1.c;
2309               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2310               $$.c = code_append($$.c, $3.c);
2311               code_t*j2 = $$.c = abc_jump($$.c, 0);
2312               $$.c = j1->branch = abc_label($$.c);
2313               $$.c = code_append($$.c, $5.c);
2314               $$.c = j2->branch = abc_label($$.c);
2315               $$.t = join_types($3.t,$5.t,'?');
2316             }
2317
2318 // TODO: use inclocal where appropriate
2319 E : E "++" { code_t*c = 0;
2320              classinfo_t*type = $1.t;
2321              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2322                  c=abc_increment_i(c);
2323                  type = TYPE_INT;
2324              } else {
2325                  c=abc_increment(c);
2326                  type = TYPE_NUMBER;
2327              }
2328              c=converttype(c, type, $1.t);
2329              $$.c = toreadwrite($1.c, c, 0, 1);
2330              $$.t = $1.t;
2331            }
2332 E : E "--" { code_t*c = 0;
2333              classinfo_t*type = $1.t;
2334              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2335                  c=abc_decrement_i(c);
2336                  type = TYPE_INT;
2337              } else {
2338                  c=abc_decrement(c);
2339                  type = TYPE_NUMBER;
2340              }
2341              c=converttype(c, type, $1.t);
2342              $$.c = toreadwrite($1.c, c, 0, 1);
2343              $$.t = $1.t;
2344             }
2345
2346 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2347              classinfo_t*type = $2.t;
2348              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2349                  c=abc_increment_i(c);
2350                  type = TYPE_INT;
2351              } else {
2352                  c=abc_increment(c);
2353                  type = TYPE_NUMBER;
2354              }
2355              c=converttype(c, type, $2.t);
2356              $$.c = toreadwrite($2.c, c, 0, 0);
2357              $$.t = $2.t;
2358            }
2359
2360 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2361              classinfo_t*type = $2.t;
2362              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2363                  c=abc_decrement_i(c);
2364                  type = TYPE_INT;
2365              } else {
2366                  c=abc_decrement(c);
2367                  type = TYPE_NUMBER;
2368              }
2369              c=converttype(c, type, $2.t);
2370              $$.c = toreadwrite($2.c, c, 0, 0);
2371              $$.t = $2.t;
2372            }
2373
2374 E : "super" '.' T_IDENTIFIER 
2375            { if(!state->cls->info)
2376                   syntaxerror("super keyword not allowed outside a class");
2377               classinfo_t*t = state->cls->info->superclass;
2378               if(!t) t = TYPE_OBJECT;
2379
2380               memberinfo_t*f = registry_findmember(t, $3, 1);
2381               namespace_t ns = {flags2access(f->flags), ""};
2382               MEMBER_MULTINAME(m, f, $3);
2383               $$.c = 0;
2384               $$.c = abc_getlocal_0($$.c);
2385               $$.c = abc_getsuper2($$.c, &m);
2386               $$.t = memberinfo_gettype(f);
2387            }
2388
2389 E : E '.' T_IDENTIFIER
2390             {$$.c = $1.c;
2391              classinfo_t*t = $1.t;
2392              char is_static = 0;
2393              if(TYPE_IS_CLASS(t) && t->cls) {
2394                  t = t->cls;
2395                  is_static = 1;
2396              }
2397              if(t) {
2398                  memberinfo_t*f = registry_findmember(t, $3, 1);
2399                  char noslot = 0;
2400                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2401                     noslot=1;
2402                  if(f && f->slot && !noslot) {
2403                      $$.c = abc_getslot($$.c, f->slot);
2404                  } else {
2405                      MEMBER_MULTINAME(m, f, $3);
2406                      $$.c = abc_getproperty2($$.c, &m);
2407                  }
2408                  /* determine type */
2409                  $$.t = memberinfo_gettype(f);
2410                  if(!$$.t)
2411                     $$.c = abc_coerce_a($$.c);
2412              } else {
2413                  /* when resolving a property on an unknown type, we do know the
2414                     name of the property (and don't seem to need the package), but
2415                     we need to make avm2 try out all access modes */
2416                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2417                  $$.c = abc_getproperty2($$.c, &m);
2418                  $$.c = abc_coerce_a($$.c);
2419                  $$.t = registry_getanytype();
2420              }
2421             }
2422
2423 VAR_READ : T_IDENTIFIER {
2424     $$.t = 0;
2425     $$.c = 0;
2426     classinfo_t*a = 0;
2427     memberinfo_t*f = 0;
2428
2429     variable_t*v;
2430     /* look at variables */
2431     if((v = find_variable($1))) {
2432         // $1 is a local variable
2433         $$.c = abc_getlocal($$.c, v->index);
2434         $$.t = v->type;
2435
2436     /* look at current class' members */
2437     } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2438         // $1 is a function in this class
2439         int var_is_static = (f->flags&FLAG_STATIC);
2440         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2441         if(var_is_static != i_am_static) {
2442             /* there doesn't seem to be any "static" way to access
2443                static properties of a class */
2444             state->method->late_binding = 1;
2445             $$.t = f->type;
2446             namespace_t ns = {flags2access(f->flags), ""};
2447             multiname_t m = {QNAME, &ns, 0, $1};
2448             $$.c = abc_findpropstrict2($$.c, &m);
2449             $$.c = abc_getproperty2($$.c, &m);
2450         } else {
2451             if(f->slot>0) {
2452                 $$.c = abc_getlocal_0($$.c);
2453                 $$.c = abc_getslot($$.c, f->slot);
2454             } else {
2455                 namespace_t ns = {flags2access(f->flags), ""};
2456                 multiname_t m = {QNAME, &ns, 0, $1};
2457                 $$.c = abc_getlocal_0($$.c);
2458                 $$.c = abc_getproperty2($$.c, &m);
2459             }
2460         }
2461         if(f->kind == MEMBER_METHOD) {
2462             $$.t = TYPE_FUNCTION(f);
2463         } else {
2464             $$.t = f->type;
2465         }
2466     
2467     /* look at actual classes, in the current package and imported */
2468     } else if((a = find_class($1))) {
2469         if(a->flags & FLAG_METHOD) {
2470             MULTINAME(m, a);
2471             $$.c = abc_findpropstrict2($$.c, &m);
2472             $$.c = abc_getproperty2($$.c, &m);
2473             $$.t = TYPE_FUNCTION(a->function);
2474         } else {
2475             if(a->slot) {
2476                 $$.c = abc_getglobalscope($$.c);
2477                 $$.c = abc_getslot($$.c, a->slot);
2478             } else {
2479                 MULTINAME(m, a);
2480                 $$.c = abc_getlex2($$.c, &m);
2481             }
2482             $$.t = TYPE_CLASS(a);
2483         }
2484
2485     /* unknown object, let the avm2 resolve it */
2486     } else {
2487         if(strcmp($1,"trace"))
2488             warning("Couldn't resolve '%s', doing late binding", $1);
2489         state->method->late_binding = 1;
2490                 
2491         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2492
2493         $$.t = 0;
2494         $$.c = abc_findpropstrict2($$.c, &m);
2495         $$.c = abc_getproperty2($$.c, &m);
2496     }
2497 }
2498
2499 //TODO: 
2500 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2501 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2502 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2503
2504 // ----------------- namespaces -------------------------------------------------
2505
2506 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2507 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2508 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2509
2510 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
2511