implemented global methods
[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     state->method = rfx_calloc(sizeof(methodstate_t));
891     state->method->initcode = 0;
892     state->method->has_super = 0;
893     if(state->cls) {
894         state->method->is_constructor = !strcmp(state->cls->info->name,name);
895         state->cls->has_constructor |= state->method->is_constructor;
896         
897         new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
898     } else {
899         state->method->is_global = 1;
900         new_variable("globalscope", 0, 0);
901        
902         /* for global methods, always push local_0 on the scope stack: */
903         state->method->late_binding = 1;
904     }
905
906     global->variable_count = 0;
907
908     /* state->vars is initialized by state_new */
909
910     param_list_t*p=0;
911     for(p=params->list;p;p=p->next) {
912         new_variable(p->param->name, p->param->type, 0);
913     }
914     if(state->method->is_constructor)
915         name = "__as3_constructor__";
916     state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
917 }
918
919 static void endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
920                           params_t*params, classinfo_t*return_type, code_t*body)
921 {
922     abc_method_t*f = 0;
923
924     multiname_t*type2 = sig2mname(return_type);
925     int slot = 0;
926     if(state->method->is_constructor) {
927         f = abc_class_getconstructor(state->cls->abc, type2);
928     } else if(!state->method->is_global) {
929         namespace_t mname_ns = {flags2access(flags), ""};
930         multiname_t mname = {QNAME, &mname_ns, 0, name};
931
932         if(flags&FLAG_STATIC)
933             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
934         else
935             f = abc_class_method(state->cls->abc, type2, &mname);
936         slot = f->trait->slot_id;
937     } else {
938         namespace_t mname_ns = {flags2access(flags), state->package};
939         multiname_t mname = {QNAME, &mname_ns, 0, name};
940
941         f = abc_method_new(global->file, type2, 1);
942         trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
943         //abc_code_t*c = global->init->method->body->code;
944     }
945     //flash doesn't seem to allow us to access function slots
946     //state->method->info->slot = slot;
947
948     if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
949     if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
950     if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
951     if(params->varargs) f->flags |= METHOD_NEED_REST;
952
953     char opt=0;
954     param_list_t*p=0;
955     for(p=params->list;p;p=p->next) {
956         if(params->varargs && !p->next) {
957             break; //varargs: omit last parameter in function signature
958         }
959         multiname_t*m = sig2mname(p->param->type);
960         list_append(f->parameters, m);
961         if(p->param->value) {
962             check_constant_against_type(p->param->type, p->param->value);
963             opt=1;list_append(f->optional_parameters, p->param->value);
964         } else if(opt) {
965             syntaxerror("non-optional parameter not allowed after optional parameters");
966         }
967     }
968     check_code_for_break(body);
969
970     if(f->body)
971         f->body->code = body;
972     else //interface
973         if(body)
974             syntaxerror("interface methods can't have a method body");
975        
976     free(state->method);state->method=0;
977     old_state();
978 }
979
980
981
982 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
983 {
984     return 1; // FIXME
985 }
986
987 void breakjumpsto(code_t*c, char*name, code_t*jump) 
988 {
989     while(c) {
990         if(c->opcode == OPCODE___BREAK__) {
991             string_t*name2 = c->data[0];
992             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
993                 c->opcode = OPCODE_JUMP;
994                 c->branch = jump;
995             }
996         }
997         c=c->prev;
998     }
999 }
1000 void continuejumpsto(code_t*c, char*name, code_t*jump) 
1001 {
1002     while(c) {
1003         if(c->opcode == OPCODE___CONTINUE__) {
1004             string_t*name2 = c->data[0];
1005             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1006                 c->opcode = OPCODE_JUMP;
1007                 c->branch = jump;
1008             }
1009         }
1010         c = c->prev;
1011     }
1012 }
1013
1014 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1015 {
1016     if(!type1 || !type2) 
1017         return registry_getanytype();
1018     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1019         return registry_getanytype();
1020     if(type1 == type2)
1021         return type1;
1022     return registry_getanytype();
1023 }
1024 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1025 {
1026     if(from==to)
1027         return c;
1028     if(!to) {
1029         return abc_coerce_a(c);
1030     }
1031     MULTINAME(m, to);
1032     if(!from) {
1033         // cast an "any" type to a specific type. subject to
1034         // runtime exceptions
1035         return abc_coerce2(c, &m);
1036     }
1037     
1038     if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1039        (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1040         // allow conversion between number types
1041         return abc_coerce2(c, &m);
1042     }
1043     //printf("%s.%s\n", from.package, from.name);
1044     //printf("%s.%s\n", to.package, to.name);
1045
1046     classinfo_t*supertype = from;
1047     while(supertype) {
1048         if(supertype == to) {
1049              // target type is one of from's superclasses
1050              return abc_coerce2(c, &m);
1051         }
1052         int t=0;
1053         while(supertype->interfaces[t]) {
1054             if(supertype->interfaces[t]==to) {
1055                 // target type is one of from's interfaces
1056                 return abc_coerce2(c, &m);
1057             }
1058             t++;
1059         }
1060         supertype = supertype->superclass;
1061     }
1062     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1063         return c;
1064     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1065         return c;
1066     syntaxerror("can't convert type %s to %s", from->name, to->name);
1067 }
1068
1069 code_t*defaultvalue(code_t*c, classinfo_t*type)
1070 {
1071     if(TYPE_IS_INT(type)) {
1072        c = abc_pushbyte(c, 0);
1073     } else if(TYPE_IS_UINT(type)) {
1074        c = abc_pushuint(c, 0);
1075     } else if(TYPE_IS_FLOAT(type)) {
1076        c = abc_pushnan(c);
1077     } else if(TYPE_IS_BOOLEAN(type)) {
1078        c = abc_pushfalse(c);
1079     } else {
1080        c = abc_pushnull(c);
1081     }
1082     return c;
1083 }
1084
1085 char is_pushundefined(code_t*c)
1086 {
1087     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1088 }
1089
1090 void parserassert(int b)
1091 {
1092     if(!b) syntaxerror("internal error: assertion failed");
1093 }
1094
1095 static classinfo_t* find_class(char*name)
1096 {
1097     classinfo_t*c=0;
1098
1099     c = registry_findclass(state->package, name);
1100
1101     /* try explicit imports */
1102     dictentry_t* e = dict_get_slot(state->imports, name);
1103     while(e) {
1104         if(c)
1105             break;
1106         if(!strcmp(e->key, name)) {
1107             c = (classinfo_t*)e->data;
1108         }
1109         e = e->next;
1110     }
1111
1112     /* try package.* imports */
1113     import_list_t*l = state->wildcard_imports;
1114     while(l) {
1115         if(c)
1116             break;
1117         //printf("does package %s contain a class %s?\n", l->import->package, name);
1118         c = registry_findclass(l->import->package, name);
1119         l = l->next;
1120     }
1121
1122     /* try global package */
1123     if(!c) {
1124         c = registry_findclass("", name);
1125     }
1126     return c;
1127 }
1128
1129 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1130 {
1131     /* converts this:
1132
1133        [prefix code] [read instruction]
1134
1135        to this:
1136
1137        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1138     */
1139     
1140     if(in && in->opcode == OPCODE_COERCE_A) {
1141         in = code_cutlast(in);
1142     }
1143     if(in->next)
1144         syntaxerror("internal error");
1145
1146     /* chop off read instruction */
1147     code_t*prefix = in;
1148     code_t*r = in;
1149     if(r->prev) {
1150         prefix = r->prev;r->prev = 0;
1151         prefix->next=0;
1152     } else {
1153         prefix = 0;
1154     }
1155
1156     char use_temp_var = readbefore;
1157
1158     /* generate the write instruction, and maybe append a dup to the prefix code */
1159     code_t* write = abc_nop(0);
1160     if(r->opcode == OPCODE_GETPROPERTY) {
1161         write->opcode = OPCODE_SETPROPERTY;
1162         multiname_t*m = (multiname_t*)r->data[0];
1163         write->data[0] = multiname_clone(m);
1164         if(m->type == QNAME || m->type == MULTINAME) {
1165             if(!justassign) {
1166                 prefix = abc_dup(prefix); // we need the object, too
1167             }
1168             use_temp_var = 1;
1169         } else if(m->type == MULTINAMEL) {
1170             if(!justassign) {
1171                 /* dupping two values on the stack requires 5 operations and one register- 
1172                    couldn't adobe just have given us a dup2? */
1173                 int temp = gettempvar();
1174                 prefix = abc_setlocal(prefix, temp);
1175                 prefix = abc_dup(prefix);
1176                 prefix = abc_getlocal(prefix, temp);
1177                 prefix = abc_swap(prefix);
1178                 prefix = abc_getlocal(prefix, temp);
1179                 if(!use_temp_var);
1180                     prefix = abc_kill(prefix, temp);
1181             }
1182             use_temp_var = 1;
1183         } else {
1184             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1185         }
1186     } else if(r->opcode == OPCODE_GETSLOT) {
1187         write->opcode = OPCODE_SETSLOT;
1188         write->data[0] = r->data[0];
1189         if(!justassign) {
1190             prefix = abc_dup(prefix); // we need the object, too
1191         }
1192         use_temp_var = 1;
1193     } else if(r->opcode == OPCODE_GETLOCAL) { 
1194         write->opcode = OPCODE_SETLOCAL;
1195         write->data[0] = r->data[0];
1196     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1197         write->opcode = OPCODE_SETLOCAL_0;
1198     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1199         write->opcode = OPCODE_SETLOCAL_1;
1200     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1201         write->opcode = OPCODE_SETLOCAL_2;
1202     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1203         write->opcode = OPCODE_SETLOCAL_3;
1204     } else {
1205         code_dump(r, 0, 0, "", stdout);
1206         syntaxerror("illegal lvalue: can't assign a value to this expression");
1207     }
1208     code_t* c = 0;
1209     
1210     int temp = -1;
1211     if(!justassign) {
1212         if(use_temp_var) {
1213             /* with getproperty/getslot, we have to be extra careful not
1214                to execute the read code twice, as it might have side-effects
1215                (e.g. if the property is in fact a setter/getter combination)
1216
1217                So read the value, modify it, and write it again,
1218                using prefix only once and making sure (by using a temporary
1219                register) that the return value is what we just wrote */
1220             temp = gettempvar();
1221             c = code_append(c, prefix);
1222             c = code_append(c, r);
1223             if(readbefore) {
1224                 c = abc_dup(c);
1225                 c = abc_setlocal(c, temp);
1226             }
1227             c = code_append(c, middlepart);
1228             if(!readbefore) {
1229                 c = abc_dup(c);
1230                 c = abc_setlocal(c, temp);
1231             }
1232             c = code_append(c, write);
1233             c = abc_getlocal(c, temp);
1234             c = abc_kill(c, temp);
1235         } else {
1236             /* if we're allowed to execute the read code twice *and*
1237                the middlepart doesn't modify the code, things are easier.
1238             */
1239             code_t* r2 = code_dup(r);
1240             //c = code_append(c, prefix);
1241             parserassert(!prefix);
1242             c = code_append(c, r);
1243             c = code_append(c, middlepart);
1244             c = code_append(c, write);
1245             c = code_append(c, r2);
1246         }
1247     } else {
1248         /* even smaller version: overwrite the value without reading
1249            it out first */
1250         if(!use_temp_var) {
1251             if(prefix) {
1252                 c = code_append(c, prefix);
1253                 c = abc_dup(c);
1254             }
1255             c = code_append(c, middlepart);
1256             c = code_append(c, write);
1257             c = code_append(c, r);
1258         } else {
1259             temp = gettempvar();
1260             if(prefix) {
1261                 c = code_append(c, prefix);
1262             }
1263             c = code_append(c, middlepart);
1264             c = abc_dup(c);
1265             c = abc_setlocal(c, temp);
1266             c = code_append(c, write);
1267             c = abc_getlocal(c, temp);
1268             c = abc_kill(c, temp);
1269         }
1270     }
1271
1272     return c;
1273 }
1274
1275 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1276 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1277
1278 %}
1279
1280
1281 %%
1282
1283 /* ------------ code blocks / statements ---------------- */
1284
1285 PROGRAM: MAYBECODE {
1286     /* todo: do something with this code if we're outside a function */
1287     if($1)
1288         warning("ignored code");
1289 }
1290
1291 MAYBECODE: CODE {$$=$1;}
1292 MAYBECODE: {$$=code_new();}
1293
1294 CODE: CODE CODEPIECE {
1295     $$=code_append($1,$2);
1296 }
1297 CODE: CODEPIECE {
1298     $$=$1;
1299 }
1300
1301 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1302 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1303 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1304 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1305 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1306 CODEPIECE: ';'                   {$$=code_new();}
1307 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1308 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1309 CODEPIECE: FOR                   {$$=$1}
1310 CODEPIECE: FOR_IN                {$$=$1}
1311 CODEPIECE: WHILE                 {$$=$1}
1312 CODEPIECE: DO_WHILE              {$$=$1}
1313 CODEPIECE: SWITCH                {$$=$1}
1314 CODEPIECE: BREAK                 {$$=$1}
1315 CODEPIECE: CONTINUE              {$$=$1}
1316 CODEPIECE: RETURN                {$$=$1}
1317 CODEPIECE: IF                    {$$=$1}
1318 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1319 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1320
1321 CODEBLOCK :  '{' CODE '}' {$$=$2;}
1322 CODEBLOCK :  '{' '}'      {$$=0;}
1323 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1324 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1325
1326 /* ------------ variables --------------------------- */
1327
1328 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1329                 |                {$$.c=abc_pushundefined(0);
1330                                   $$.t=TYPE_ANY;
1331                                  }
1332
1333 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1334 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1335
1336 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1337 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1338
1339 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1340 {
1341     if(variable_exists($1))
1342         syntaxerror("Variable %s already defined", $1);
1343    
1344     if(!is_subtype_of($3.t, $2)) {
1345         syntaxerror("Can't convert %s to %s", $3.t->name, 
1346                                               $2->name);
1347     }
1348
1349     int index = new_variable($1, $2, 1);
1350     
1351     if($2) {
1352         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1353             $$ = $3.c;
1354             $$ = converttype($$, $3.t, $2);
1355             $$ = abc_setlocal($$, index);
1356         } else {
1357             $$ = defaultvalue(0, $2);
1358             $$ = abc_setlocal($$, index);
1359         }
1360     } else {
1361         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1362             $$ = $3.c;
1363             $$ = abc_coerce_a($$);
1364             $$ = abc_setlocal($$, index);
1365         } else {
1366             $$ = code_new();
1367         }
1368     }
1369     
1370     /* that's the default for a local register, anyway
1371         else {
1372         state->method->initcode = abc_pushundefined(state->method->initcode);
1373         state->method->initcode = abc_setlocal(state->method->initcode, index);
1374     }*/
1375     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1376 }
1377
1378 /* ------------ control flow ------------------------- */
1379
1380 MAYBEELSE:  %prec below_else {$$ = code_new();}
1381 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1382 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1383
1384 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1385     $$ = code_new();
1386     $$ = code_append($$, $4.c);
1387     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1388    
1389     $$ = code_append($$, $6);
1390     if($7) {
1391         myjmp = $$ = abc_jump($$, 0);
1392     }
1393     myif->branch = $$ = abc_nop($$);
1394     if($7) {
1395         $$ = code_append($$, $7);
1396         myjmp->branch = $$ = abc_nop($$);
1397     }
1398     
1399     $$ = killvars($$);old_state();
1400 }
1401
1402 FOR_INIT : {$$=code_new();}
1403 FOR_INIT : VARIABLE_DECLARATION
1404 FOR_INIT : VOIDEXPRESSION
1405 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1406     $$=$2;new_variable($2,$3,1);
1407 }
1408 FOR_IN_INIT : T_IDENTIFIER {
1409     $$=$1;
1410 }
1411
1412 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1413 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1414
1415 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1416     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1417     $$ = code_new();
1418     $$ = code_append($$, $2);
1419     code_t*loopstart = $$ = abc_label($$);
1420     $$ = code_append($$, $4.c);
1421     code_t*myif = $$ = abc_iffalse($$, 0);
1422     $$ = code_append($$, $8);
1423     code_t*cont = $$ = abc_nop($$);
1424     $$ = code_append($$, $6);
1425     $$ = abc_jump($$, loopstart);
1426     code_t*out = $$ = abc_nop($$);
1427     breakjumpsto($$, $1.name, out);
1428     continuejumpsto($$, $1.name, cont);
1429     myif->branch = out;
1430
1431     $$ = killvars($$);old_state();
1432 }
1433
1434 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1435     variable_t*var = find_variable($2);
1436     char*tmp1name = concat2($2, "__tmp1__");
1437     int it = new_variable(tmp1name, TYPE_INT, 0);
1438     char*tmp2name = concat2($2, "__array__");
1439     int array = new_variable(tmp1name, 0, 0);
1440
1441     $$ = code_new();
1442     $$ = code_append($$, $4.c);
1443     $$ = abc_coerce_a($$);
1444     $$ = abc_setlocal($$, array);
1445     $$ = abc_pushbyte($$, 0);
1446     $$ = abc_setlocal($$, it);
1447
1448     code_t*loopstart = $$ = abc_label($$);
1449     
1450     $$ = abc_hasnext2($$, array, it);
1451     code_t*myif = $$ = abc_iffalse($$, 0);
1452     $$ = abc_getlocal($$, array);
1453     $$ = abc_getlocal($$, it);
1454     if(!$1.each)
1455         $$ = abc_nextname($$);
1456     else
1457         $$ = abc_nextvalue($$);
1458     $$ = converttype($$, 0, var->type);
1459     $$ = abc_setlocal($$, var->index);
1460
1461     $$ = code_append($$, $6);
1462     $$ = abc_jump($$, loopstart);
1463     
1464     code_t*out = $$ = abc_nop($$);
1465     breakjumpsto($$, $1.name, out);
1466     continuejumpsto($$, $1.name, loopstart);
1467     
1468     $$ = killvars($$);
1469     
1470     myif->branch = out;
1471
1472     old_state();
1473     free(tmp1name);
1474     free(tmp2name);
1475 }
1476
1477 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1478     $$ = code_new();
1479
1480     code_t*myjmp = $$ = abc_jump($$, 0);
1481     code_t*loopstart = $$ = abc_label($$);
1482     $$ = code_append($$, $6);
1483     code_t*cont = $$ = abc_nop($$);
1484     myjmp->branch = cont;
1485     $$ = code_append($$, $4.c);
1486     $$ = abc_iftrue($$, loopstart);
1487     code_t*out = $$ = abc_nop($$);
1488     breakjumpsto($$, $1, out);
1489     continuejumpsto($$, $1, cont);
1490
1491     $$ = killvars($$);
1492     old_state();
1493 }
1494
1495 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1496     $$ = code_new();
1497     code_t*loopstart = $$ = abc_label($$);
1498     $$ = code_append($$, $3);
1499     code_t*cont = $$ = abc_nop($$);
1500     $$ = code_append($$, $6.c);
1501     $$ = abc_iftrue($$, loopstart);
1502     code_t*out = $$ = abc_nop($$);
1503     breakjumpsto($$, $1, out);
1504     continuejumpsto($$, $1, cont);
1505     $$ = killvars($$);
1506     old_state();
1507 }
1508
1509 BREAK : "break" %prec prec_none {
1510     $$ = abc___break__(0, "");
1511 }
1512 BREAK : "break" T_IDENTIFIER {
1513     $$ = abc___break__(0, $2);
1514 }
1515 CONTINUE : "continue" %prec prec_none {
1516     $$ = abc___continue__(0, "");
1517 }
1518 CONTINUE : "continue" T_IDENTIFIER {
1519     $$ = abc___continue__(0, $2);
1520 }
1521
1522 MAYBE_CASE_LIST :           {$$=0;}
1523 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1524 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
1525 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1526 CASE_LIST: CASE             {$$=$1}
1527 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
1528
1529 CASE: "case" E ':' MAYBECODE {
1530     $$ = abc_dup(0);
1531     $$ = code_append($$, $2.c);
1532     code_t*j = $$ = abc_ifne($$, 0);
1533     $$ = code_append($$, $4);
1534     if($$->opcode != OPCODE___BREAK__) {
1535         $$ = abc___fallthrough__($$, "");
1536     }
1537     code_t*e = $$ = abc_nop($$);
1538     j->branch = e;
1539 }
1540 DEFAULT: "default" ':' MAYBECODE {
1541     $$ = $3;
1542 }
1543 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1544     $$=$4.c;
1545     $$ = code_append($$, $7);
1546     code_t*out = $$ = abc_pop($$);
1547     breakjumpsto($$, $1, out);
1548     
1549     code_t*c = $$,*lastblock=0;
1550     while(c) {
1551         if(c->opcode == OPCODE_IFNE) {
1552             if(!c->next) syntaxerror("internal error in fallthrough handling");
1553             lastblock=c->next;
1554         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1555             if(lastblock) {
1556                 c->opcode = OPCODE_JUMP;
1557                 c->branch = lastblock;
1558             } else {
1559                 /* fall through end of switch */
1560                 c->opcode = OPCODE_NOP;
1561             }
1562         }
1563         c=c->prev;
1564     }
1565     old_state();
1566 }
1567
1568 /* ------------ packages and imports ---------------- */
1569
1570 X_IDENTIFIER: T_IDENTIFIER
1571             | "package" {$$="package";}
1572
1573 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1574 PACKAGE: X_IDENTIFIER             {$$=strdup($1);}
1575
1576 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
1577 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1578
1579 IMPORT : "import" QNAME {
1580        classinfo_t*c = $2;
1581        if(!c) 
1582             syntaxerror("Couldn't import class\n");
1583        state_has_imports();
1584        dict_put(state->imports, c->name, c);
1585        $$=0;
1586 }
1587 IMPORT : "import" PACKAGE '.' '*' {
1588        NEW(import_t,i);
1589        i->package = $2;
1590        state_has_imports();
1591        list_append(state->wildcard_imports, i);
1592        $$=0;
1593 }
1594
1595 /* ------------ classes and interfaces (header) -------------- */
1596
1597 MAYBE_MODIFIERS : {$$=0;}
1598 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1599 MODIFIER_LIST : MODIFIER               {$$=$1;}
1600 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1601
1602 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1603          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1604          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1605          | KW_STATIC {$$=FLAG_STATIC;}
1606          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1607          | KW_FINAL {$$=FLAG_FINAL;}
1608          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1609          | KW_NATIVE {$$=FLAG_NATIVE;}
1610          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1611
1612 EXTENDS : {$$=registry_getobjectclass();}
1613 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1614
1615 EXTENDS_LIST : {$$=list_new();}
1616 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1617
1618 IMPLEMENTS_LIST : {$$=list_new();}
1619 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1620
1621 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1622                               EXTENDS IMPLEMENTS_LIST 
1623                               '{' {startclass($1,$3,$4,$5, 0);} 
1624                               MAYBE_DECLARATION_LIST 
1625                               '}' {endclass();}
1626
1627 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1628                               EXTENDS_LIST 
1629                               '{' {startclass($1,$3,0,$4,1);}
1630                               MAYBE_IDECLARATION_LIST 
1631                               '}' {endclass();}
1632
1633 /* ------------ classes and interfaces (body) -------------- */
1634
1635 MAYBE_DECLARATION_LIST : 
1636 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1637 DECLARATION_LIST : DECLARATION
1638 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1639 DECLARATION : ';'
1640 DECLARATION : SLOT_DECLARATION
1641 DECLARATION : FUNCTION_DECLARATION
1642
1643 MAYBE_IDECLARATION_LIST : 
1644 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1645 IDECLARATION_LIST : IDECLARATION
1646 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1647 IDECLARATION : ';'
1648 IDECLARATION : "var" T_IDENTIFIER {
1649     syntaxerror("variable declarations not allowed in interfaces");
1650 }
1651 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1652     $1 |= FLAG_PUBLIC;
1653     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1654         syntaxerror("invalid method modifiers: interface methods always need to be public");
1655     }
1656     startfunction(0,$1,$3,$4,&$6,$8);
1657     endfunction(0,$1,$3,$4,&$6,$8, 0);
1658 }
1659
1660 /* ------------ classes and interfaces (body, slots ) ------- */
1661
1662 VARCONST: "var" | "const"
1663
1664 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1665     int flags = $1;
1666     memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1667     info->type = $4;
1668     info->flags = flags;
1669     trait_t*t=0;
1670
1671     namespace_t mname_ns = {flags2access(flags), ""};
1672     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1673
1674     if(!(flags&FLAG_STATIC)) {
1675         if($4) {
1676             MULTINAME(m, $4);
1677             t=abc_class_slot(state->cls->abc, &mname, &m);
1678         } else {
1679             t=abc_class_slot(state->cls->abc, &mname, 0);
1680         }
1681         info->slot = t->slot_id;
1682     } else {
1683         if($4) {
1684             MULTINAME(m, $4);
1685             t=abc_class_staticslot(state->cls->abc, &mname, &m);
1686         } else {
1687             t=abc_class_staticslot(state->cls->abc, &mname, 0);
1688         }
1689         info->slot = t->slot_id;
1690     }
1691     if($5.c && !is_pushundefined($5.c)) {
1692         code_t*c = 0;
1693         c = abc_getlocal_0(c);
1694         c = code_append(c, $5.c);
1695         c = converttype(c, $5.t, $4);
1696         c = abc_setslot(c, t->slot_id);
1697         if(!(flags&FLAG_STATIC))
1698             state->cls->init = code_append(state->cls->init, c);
1699         else
1700             state->cls->static_init = code_append(state->cls->static_init, c);
1701     }
1702     if($2==KW_CONST) {
1703         t->kind= TRAIT_CONST;
1704     }
1705 }
1706
1707 /* ------------ constants -------------------------------------- */
1708
1709 MAYBESTATICCONSTANT: {$$=0;}
1710 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1711
1712 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1713 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1714 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1715 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1716 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1717 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1718 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1719 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1720 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1721
1722 /* ------------ classes and interfaces (body, functions) ------- */
1723
1724 // non-vararg version
1725 MAYBE_PARAM_LIST: {
1726     memset(&$$,0,sizeof($$));
1727 }
1728 MAYBE_PARAM_LIST: PARAM_LIST {
1729     $$=$1;
1730 }
1731
1732 // vararg version
1733 MAYBE_PARAM_LIST: "..." PARAM {
1734     memset(&$$,0,sizeof($$));
1735     $$.varargs=1;
1736     list_append($$.list, $2);
1737 }
1738 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1739     $$ =$1;
1740     $$.varargs=1;
1741     list_append($$.list, $4);
1742 }
1743
1744 // non empty
1745 PARAM_LIST: PARAM_LIST ',' PARAM {
1746     $$ = $1;
1747     list_append($$.list, $3);
1748 }
1749 PARAM_LIST: PARAM {
1750     memset(&$$,0,sizeof($$));
1751     list_append($$.list, $1);
1752 }
1753
1754 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1755      $$ = malloc(sizeof(param_t));
1756      $$->name=$1;
1757      $$->type = $3;
1758      $$->value = $4;
1759 }
1760 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1761      $$ = malloc(sizeof(param_t));
1762      $$->name=$1;
1763      $$->type = TYPE_ANY;
1764      $$->value = $2;
1765 }
1766 GETSET : "get" {$$=$1;}
1767        | "set" {$$=$1;}
1768        |       {$$=0;}
1769
1770 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1771                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1772 {
1773     code_t*c = 0;
1774     if(state->method->late_binding) {
1775         c = abc_getlocal_0(c);
1776         c = abc_pushscope(c);
1777     }
1778     if(state->method->is_constructor && !state->method->has_super) {
1779         // call default constructor
1780         c = abc_getlocal_0(c);
1781         c = abc_constructsuper(c, 0);
1782     }
1783     c = wrap_function(c, state->method->initcode, $11);
1784     endfunction(0,$1,$3,$4,&$6,$8,c);
1785 }
1786
1787 /* ------------- package + class ids --------------- */
1788
1789 CLASS: T_IDENTIFIER {
1790
1791     /* try current package */
1792     $$ = find_class($1);
1793     if(!$$) syntaxerror("Could not find class %s\n", $1);
1794 }
1795
1796 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1797     $$ = registry_findclass($1, $3);
1798     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1799     free($1);$1=0;
1800 }
1801
1802 QNAME: PACKAGEANDCLASS
1803      | CLASS
1804
1805 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1806 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1807
1808 TYPE : QNAME      {$$=$1;}
1809      | '*'        {$$=registry_getanytype();}
1810      | "void"     {$$=registry_getanytype();}
1811     /*
1812      |  "String"  {$$=registry_getstringclass();}
1813      |  "int"     {$$=registry_getintclass();}
1814      |  "uint"    {$$=registry_getuintclass();}
1815      |  "Boolean" {$$=registry_getbooleanclass();}
1816      |  "Number"  {$$=registry_getnumberclass();}
1817     */
1818
1819 MAYBETYPE: ':' TYPE {$$=$2;}
1820 MAYBETYPE:          {$$=0;}
1821
1822 /* ----------function calls, delete, constructor calls ------ */
1823
1824 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
1825 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1826
1827 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1828 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1829 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
1830                                                   $$.cc = $1.c;
1831                                                  }
1832 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1833                                                   $$.len= $1.len+1;
1834                                                   $$.cc = code_append($1.cc, $3.c);
1835                                                   }
1836
1837 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1838     MULTINAME(m, $2);
1839     $$.c = code_new();
1840
1841     if($2->slot) {
1842         $$.c = abc_getglobalscope($$.c);
1843         $$.c = abc_getslot($$.c, $2->slot);
1844     } else {
1845         $$.c = abc_findpropstrict2($$.c, &m);
1846     }
1847
1848     $$.c = code_append($$.c, $3.cc);
1849
1850     if($2->slot)
1851         $$.c = abc_construct($$.c, $3.len);
1852     else
1853         $$.c = abc_constructprop2($$.c, &m, $3.len);
1854     $$.t = $2;
1855 }
1856
1857 /* TODO: use abc_call (for calling local variables),
1858          abc_callstatic (for calling own methods) 
1859          call (for closures)
1860 */
1861 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1862     
1863     $$.c = $1.c;
1864     if($$.c->opcode == OPCODE_COERCE_A) {
1865         $$.c = code_cutlast($$.c);
1866     }
1867     code_t*paramcode = $3.cc;
1868
1869     $$.t = TYPE_ANY;
1870     if($$.c->opcode == OPCODE_GETPROPERTY) {
1871         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1872         $$.c = code_cutlast($$.c);
1873         $$.c = code_append($$.c, paramcode);
1874         $$.c = abc_callproperty2($$.c, name, $3.len);
1875         multiname_destroy(name);
1876     } else if($$.c->opcode == OPCODE_GETSLOT) {
1877         int slot = (int)(ptroff_t)$$.c->data[0];
1878         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1879         if(t->kind!=TRAIT_METHOD) {
1880             //ok: flash allows to assign closures to members.
1881         }
1882         multiname_t*name = t->name;
1883         $$.c = code_cutlast($$.c);
1884         $$.c = code_append($$.c, paramcode);
1885         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1886         $$.c = abc_callproperty2($$.c, name, $3.len);
1887     } else if($$.c->opcode == OPCODE_GETSUPER) {
1888         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1889         $$.c = code_cutlast($$.c);
1890         $$.c = code_append($$.c, paramcode);
1891         $$.c = abc_callsuper2($$.c, name, $3.len);
1892         multiname_destroy(name);
1893     } else {
1894         $$.c = abc_getlocal_0($$.c);
1895         $$.c = code_append($$.c, paramcode);
1896         $$.c = abc_call($$.c, $3.len);
1897     }
1898    
1899     memberinfo_t*f = 0;
1900    
1901     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1902         $$.t = $1.t->function->return_type;
1903     } else {
1904         $$.c = abc_coerce_a($$.c);
1905         $$.t = TYPE_ANY;
1906     }
1907
1908 }
1909 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1910     if(!state->cls) syntaxerror("super() not allowed outside of a class");
1911     if(!state->method) syntaxerror("super() not allowed outside of a function");
1912     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1913
1914     $$.c = code_new();
1915     $$.c = abc_getlocal_0($$.c);
1916
1917     $$.c = code_append($$.c, $3.cc);
1918     /*
1919     this is dependent on the control path, check this somewhere else
1920     if(state->method->has_super)
1921         syntaxerror("constructor may call super() only once");
1922     */
1923     state->method->has_super = 1;
1924     $$.c = abc_constructsuper($$.c, $3.len);
1925     $$.c = abc_pushundefined($$.c);
1926     $$.t = TYPE_ANY;
1927 }
1928
1929 DELETE: "delete" E {
1930     $$.c = $2.c;
1931     if($$.c->opcode == OPCODE_COERCE_A) {
1932         $$.c = code_cutlast($$.c);
1933     }
1934     multiname_t*name = 0;
1935     if($$.c->opcode == OPCODE_GETPROPERTY) {
1936         $$.c->opcode = OPCODE_DELETEPROPERTY;
1937     } else if($$.c->opcode == OPCODE_GETSLOT) {
1938         int slot = (int)(ptroff_t)$$.c->data[0];
1939         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1940         $$.c = code_cutlast($$.c);
1941         $$.c = abc_deleteproperty2($$.c, name);
1942     } else {
1943         $$.c = abc_getlocal_0($$.c);
1944         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1945         $$.c = abc_deleteproperty2($$.c, &m);
1946     }
1947     $$.t = TYPE_BOOLEAN;
1948 }
1949
1950 RETURN: "return" %prec prec_none {
1951     $$ = abc_returnvoid(0);
1952 }
1953 RETURN: "return" EXPRESSION {
1954     $$ = $2.c;
1955     $$ = abc_returnvalue($$);
1956 }
1957
1958 // ----------------------- expression types -------------------------------------
1959
1960 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
1961 EXPRESSION : E                %prec below_minus {$$ = $1;}
1962 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1963     $$.c = $1.c;
1964     $$.c = cut_last_push($$.c);
1965     $$.c = code_append($$.c,$3.c);
1966     $$.t = $3.t;
1967 }
1968 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1969     $$=cut_last_push($1.c);
1970 }
1971
1972 // ----------------------- expression evaluation -------------------------------------
1973
1974 E : CONSTANT
1975 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1976 E : NEW                         {$$ = $1;}
1977 E : DELETE                      {$$ = $1;}
1978 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1979                                  $$.t = TYPE_ANY;
1980                                 }
1981
1982 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1983                    //MULTINAME(m, registry_getintclass());
1984                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1985                    $$.t = TYPE_INT;
1986                   }
1987 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1988                     $$.t = TYPE_INT;
1989                    }
1990 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1991                   $$.t = TYPE_INT;
1992                  }
1993 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1994                    $$.t = TYPE_UINT;
1995                   }
1996 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1997                     $$.t = TYPE_FLOAT;
1998                    }
1999 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2000                      $$.t = TYPE_STRING;
2001                     }
2002 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2003                     $$.t = TYPE_ANY;
2004                    }
2005 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2006                     $$.t = TYPE_BOOLEAN;
2007                    }
2008 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2009                      $$.t = TYPE_BOOLEAN;
2010                     }
2011 CONSTANT : "null" {$$.c = abc_pushnull(0);
2012                     $$.t = TYPE_NULL;
2013                    }
2014
2015 E : FUNCTIONCALL
2016 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2017              $$.t = TYPE_BOOLEAN;
2018             }
2019 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2020              $$.t = TYPE_BOOLEAN;
2021             }
2022 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2023               $$.t = TYPE_BOOLEAN;
2024              }
2025 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2026               $$.t = TYPE_BOOLEAN;
2027              }
2028 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2029               $$.t = TYPE_BOOLEAN;
2030              }
2031 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2032               $$.t = TYPE_BOOLEAN;
2033               }
2034 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2035               $$.t = TYPE_BOOLEAN;
2036              }
2037 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2038               $$.t = TYPE_BOOLEAN;
2039              }
2040
2041 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2042               $$.c = $1.c;
2043               $$.c = converttype($$.c, $1.t, $$.t);
2044               $$.c = abc_dup($$.c);
2045               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2046               $$.c = cut_last_push($$.c);
2047               $$.c = code_append($$.c,$3.c);
2048               $$.c = converttype($$.c, $3.t, $$.t);
2049               code_t*label = $$.c = abc_label($$.c);
2050               jmp->branch = label;
2051              }
2052 E : E "&&" E {
2053               $$.t = join_types($1.t, $3.t, 'A');
2054               /*printf("%08x:\n",$1.t);
2055               code_dump($1.c, 0, 0, "", stdout);
2056               printf("%08x:\n",$3.t);
2057               code_dump($3.c, 0, 0, "", stdout);
2058               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2059               $$.c = $1.c;
2060               $$.c = converttype($$.c, $1.t, $$.t);
2061               $$.c = abc_dup($$.c);
2062               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2063               $$.c = cut_last_push($$.c);
2064               $$.c = code_append($$.c,$3.c);
2065               $$.c = converttype($$.c, $3.t, $$.t);
2066               code_t*label = $$.c = abc_label($$.c);
2067               jmp->branch = label;              
2068              }
2069
2070 E : '!' E    {$$.c=$2.c;
2071               $$.c = abc_not($$.c);
2072               $$.t = TYPE_BOOLEAN;
2073              }
2074
2075 E : '~' E    {$$.c=$2.c;
2076               $$.c = abc_bitnot($$.c);
2077               $$.t = TYPE_INT;
2078              }
2079
2080 E : E '&' E {$$.c = code_append($1.c,$3.c);
2081              $$.c = abc_bitand($$.c);
2082              $$.t = TYPE_INT;
2083             }
2084
2085 E : E '^' E {$$.c = code_append($1.c,$3.c);
2086              $$.c = abc_bitxor($$.c);
2087              $$.t = TYPE_INT;
2088             }
2089
2090 E : E '|' E {$$.c = code_append($1.c,$3.c);
2091              $$.c = abc_bitor($$.c);
2092              $$.t = TYPE_INT;
2093             }
2094
2095 E : E '-' E {$$.c = code_append($1.c,$3.c);
2096              if(BOTH_INT($1,$3)) {
2097                 $$.c = abc_subtract_i($$.c);
2098                 $$.t = TYPE_INT;
2099              } else {
2100                 $$.c = abc_subtract($$.c);
2101                 $$.t = TYPE_NUMBER;
2102              }
2103             }
2104 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2105              $$.c = abc_rshift($$.c);
2106              $$.t = TYPE_INT;
2107             }
2108 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2109              $$.c = abc_urshift($$.c);
2110              $$.t = TYPE_INT;
2111             }
2112 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2113              $$.c = abc_lshift($$.c);
2114              $$.t = TYPE_INT;
2115             }
2116
2117 E : E '/' E {$$.c = code_append($1.c,$3.c);
2118              $$.c = abc_divide($$.c);
2119              $$.t = TYPE_NUMBER;
2120             }
2121 E : E '+' E {$$.c = code_append($1.c,$3.c);
2122              $$.c = abc_add($$.c);
2123              $$.t = TYPE_NUMBER;
2124             }
2125 E : E '%' E {$$.c = code_append($1.c,$3.c);
2126              $$.c = abc_modulo($$.c);
2127              $$.t = TYPE_NUMBER;
2128             }
2129 E : E '*' E {$$.c = code_append($1.c,$3.c);
2130              if(BOTH_INT($1,$3)) {
2131                 $$.c = abc_multiply_i($$.c);
2132                 $$.t = TYPE_INT;
2133              } else {
2134                 $$.c = abc_multiply($$.c);
2135                 $$.t = TYPE_NUMBER;
2136              }
2137             }
2138
2139 E : E "in" E {$$.c = code_append($1.c,$3.c);
2140               $$.c = abc_in($$.c);
2141               $$.t = TYPE_BOOLEAN;
2142              }
2143
2144 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2145               if(use_astype && TYPE_IS_CLASS($3.t)) {
2146                 MULTINAME(m,$3.t->cls);
2147                 $$.c = abc_astype2($1.c, &m);
2148                 $$.t = $3.t->cls;
2149               } else {
2150                 $$.c = code_append($1.c, $3.c);
2151                 $$.c = abc_astypelate($$.c);
2152                 $$.t = TYPE_ANY;
2153               }
2154              }
2155
2156 E : E "instanceof" E 
2157              {$$.c = code_append($1.c, $3.c);
2158               $$.c = abc_instanceof($$.c);
2159               $$.t = TYPE_BOOLEAN;
2160              }
2161
2162 E : E "is" E {$$.c = code_append($1.c, $3.c);
2163               $$.c = abc_istypelate($$.c);
2164               $$.t = TYPE_BOOLEAN;
2165              }
2166
2167 E : "typeof" '(' E ')' {
2168               $$.c = $3.c;
2169               $$.c = abc_typeof($$.c);
2170               $$.t = TYPE_STRING;
2171              }
2172
2173 E : "void" E {
2174               $$.c = cut_last_push($2.c);
2175               $$.c = abc_pushundefined($$.c);
2176               $$.t = TYPE_ANY;
2177              }
2178
2179 E : "void" { $$.c = abc_pushundefined(0);
2180              $$.t = TYPE_ANY;
2181            }
2182
2183 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2184
2185 E : '-' E {
2186   $$=$2;
2187   if(IS_INT($2)) {
2188    $$.c=abc_negate_i($$.c);
2189    $$.t = TYPE_INT;
2190   } else {
2191    $$.c=abc_negate($$.c);
2192    $$.t = TYPE_NUMBER;
2193   }
2194 }
2195
2196 E : E '[' E ']' {
2197   $$.c = $1.c;
2198   $$.c = code_append($$.c, $3.c);
2199  
2200   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2201   $$.c = abc_getproperty2($$.c, &m);
2202   $$.t = 0; // array elements have unknown type
2203 }
2204
2205 E : '[' MAYBE_EXPRESSION_LIST ']' {
2206     $$.c = code_new();
2207     $$.c = code_append($$.c, $2.cc);
2208     $$.c = abc_newarray($$.c, $2.len);
2209     $$.t = registry_getarrayclass();
2210 }
2211
2212 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2213 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2214
2215 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2216     $$.cc = 0;
2217     $$.cc = code_append($$.cc, $1.c);
2218     $$.cc = code_append($$.cc, $3.c);
2219     $$.len = 2;
2220 }
2221 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2222     $$.cc = $1.cc;
2223     $$.len = $1.len+2;
2224     $$.cc = code_append($$.cc, $3.c);
2225     $$.cc = code_append($$.cc, $5.c);
2226 }
2227 //MAYBECOMMA: ','
2228 //MAYBECOMMA:
2229
2230 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2231     $$.c = code_new();
2232     $$.c = code_append($$.c, $2.cc);
2233     $$.c = abc_newobject($$.c, $2.len/2);
2234     $$.t = registry_getobjectclass();
2235 }
2236
2237 E : E "*=" E { 
2238                code_t*c = $3.c;
2239                if(BOTH_INT($1,$3)) {
2240                 c=abc_multiply_i(c);
2241                } else {
2242                 c=abc_multiply(c);
2243                }
2244                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2245                $$.c = toreadwrite($1.c, c, 0, 0);
2246                $$.t = $1.t;
2247               }
2248
2249 E : E "%=" E { 
2250                code_t*c = abc_modulo($3.c);
2251                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2252                $$.c = toreadwrite($1.c, c, 0, 0);
2253                $$.t = $1.t;
2254               }
2255 E : E "<<=" E { 
2256                code_t*c = abc_lshift($3.c);
2257                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2258                $$.c = toreadwrite($1.c, c, 0, 0);
2259                $$.t = $1.t;
2260               }
2261 E : E ">>=" E { 
2262                code_t*c = abc_rshift($3.c);
2263                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2264                $$.c = toreadwrite($1.c, c, 0, 0);
2265                $$.t = $1.t;
2266               }
2267 E : E ">>>=" E { 
2268                code_t*c = abc_urshift($3.c);
2269                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2270                $$.c = toreadwrite($1.c, c, 0, 0);
2271                $$.t = $1.t;
2272               }
2273 E : E "/=" E { 
2274                code_t*c = abc_divide($3.c);
2275                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2276                $$.c = toreadwrite($1.c, c, 0, 0);
2277                $$.t = $1.t;
2278               }
2279 E : E "+=" E { 
2280                code_t*c = $3.c;
2281                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2282                 c=abc_add_i(c);
2283                } else {
2284                 c=abc_add(c);
2285                }
2286                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2287                
2288                $$.c = toreadwrite($1.c, c, 0, 0);
2289                $$.t = $1.t;
2290               }
2291 E : E "-=" E { code_t*c = $3.c; 
2292                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2293                 c=abc_subtract_i(c);
2294                } else {
2295                 c=abc_subtract(c);
2296                }
2297                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2298                
2299                $$.c = toreadwrite($1.c, c, 0, 0);
2300                $$.t = $1.t;
2301              }
2302 E : E '=' E { code_t*c = 0;
2303               c = code_append(c, $3.c);
2304               c = converttype(c, $3.t, $1.t);
2305               $$.c = toreadwrite($1.c, c, 1, 0);
2306               $$.t = $1.t;
2307             }
2308
2309 E : E '?' E ':' E %prec below_assignment { 
2310               $$.c = $1.c;
2311               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2312               $$.c = code_append($$.c, $3.c);
2313               code_t*j2 = $$.c = abc_jump($$.c, 0);
2314               $$.c = j1->branch = abc_label($$.c);
2315               $$.c = code_append($$.c, $5.c);
2316               $$.c = j2->branch = abc_label($$.c);
2317               $$.t = join_types($3.t,$5.t,'?');
2318             }
2319
2320 // TODO: use inclocal where appropriate
2321 E : E "++" { code_t*c = 0;
2322              classinfo_t*type = $1.t;
2323              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2324                  c=abc_increment_i(c);
2325                  type = TYPE_INT;
2326              } else {
2327                  c=abc_increment(c);
2328                  type = TYPE_NUMBER;
2329              }
2330              c=converttype(c, type, $1.t);
2331              $$.c = toreadwrite($1.c, c, 0, 1);
2332              $$.t = $1.t;
2333            }
2334 E : E "--" { code_t*c = 0;
2335              classinfo_t*type = $1.t;
2336              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2337                  c=abc_decrement_i(c);
2338                  type = TYPE_INT;
2339              } else {
2340                  c=abc_decrement(c);
2341                  type = TYPE_NUMBER;
2342              }
2343              c=converttype(c, type, $1.t);
2344              $$.c = toreadwrite($1.c, c, 0, 1);
2345              $$.t = $1.t;
2346             }
2347
2348 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2349              classinfo_t*type = $2.t;
2350              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2351                  c=abc_increment_i(c);
2352                  type = TYPE_INT;
2353              } else {
2354                  c=abc_increment(c);
2355                  type = TYPE_NUMBER;
2356              }
2357              c=converttype(c, type, $2.t);
2358              $$.c = toreadwrite($2.c, c, 0, 0);
2359              $$.t = $2.t;
2360            }
2361
2362 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2363              classinfo_t*type = $2.t;
2364              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2365                  c=abc_decrement_i(c);
2366                  type = TYPE_INT;
2367              } else {
2368                  c=abc_decrement(c);
2369                  type = TYPE_NUMBER;
2370              }
2371              c=converttype(c, type, $2.t);
2372              $$.c = toreadwrite($2.c, c, 0, 0);
2373              $$.t = $2.t;
2374            }
2375
2376 E : "super" '.' T_IDENTIFIER 
2377            { if(!state->cls->info)
2378                   syntaxerror("super keyword not allowed outside a class");
2379               classinfo_t*t = state->cls->info->superclass;
2380               if(!t) t = TYPE_OBJECT;
2381
2382               memberinfo_t*f = registry_findmember(t, $3, 1);
2383               namespace_t ns = {flags2access(f->flags), ""};
2384               MEMBER_MULTINAME(m, f, $3);
2385               $$.c = 0;
2386               $$.c = abc_getlocal_0($$.c);
2387               $$.c = abc_getsuper2($$.c, &m);
2388               $$.t = memberinfo_gettype(f);
2389            }
2390
2391 E : E '.' T_IDENTIFIER
2392             {$$.c = $1.c;
2393              classinfo_t*t = $1.t;
2394              char is_static = 0;
2395              if(TYPE_IS_CLASS(t) && t->cls) {
2396                  t = t->cls;
2397                  is_static = 1;
2398              }
2399              if(t) {
2400                  memberinfo_t*f = registry_findmember(t, $3, 1);
2401                  char noslot = 0;
2402                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2403                     noslot=1;
2404                  if(f && f->slot && !noslot) {
2405                      $$.c = abc_getslot($$.c, f->slot);
2406                  } else {
2407                      MEMBER_MULTINAME(m, f, $3);
2408                      $$.c = abc_getproperty2($$.c, &m);
2409                  }
2410                  /* determine type */
2411                  $$.t = memberinfo_gettype(f);
2412                  if(!$$.t)
2413                     $$.c = abc_coerce_a($$.c);
2414              } else {
2415                  /* when resolving a property on an unknown type, we do know the
2416                     name of the property (and don't seem to need the package), but
2417                     we need to make avm2 try out all access modes */
2418                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2419                  $$.c = abc_getproperty2($$.c, &m);
2420                  $$.c = abc_coerce_a($$.c);
2421                  $$.t = registry_getanytype();
2422              }
2423             }
2424
2425 VAR_READ : T_IDENTIFIER {
2426     $$.t = 0;
2427     $$.c = 0;
2428     classinfo_t*a = 0;
2429     memberinfo_t*f = 0;
2430
2431     variable_t*v;
2432     /* look at variables */
2433     if((v = find_variable($1))) {
2434         // $1 is a local variable
2435         $$.c = abc_getlocal($$.c, v->index);
2436         $$.t = v->type;
2437
2438     /* look at current class' members */
2439     } else if(state->cls && (f = registry_findmember(state->cls->info, $1, 1))) {
2440         // $1 is a function in this class
2441         int var_is_static = (f->flags&FLAG_STATIC);
2442         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2443         if(var_is_static != i_am_static) {
2444             /* there doesn't seem to be any "static" way to access
2445                static properties of a class */
2446             state->method->late_binding = 1;
2447             $$.t = f->type;
2448             namespace_t ns = {flags2access(f->flags), ""};
2449             multiname_t m = {QNAME, &ns, 0, $1};
2450             $$.c = abc_findpropstrict2($$.c, &m);
2451             $$.c = abc_getproperty2($$.c, &m);
2452         } else {
2453             if(f->slot>0) {
2454                 $$.c = abc_getlocal_0($$.c);
2455                 $$.c = abc_getslot($$.c, f->slot);
2456             } else {
2457                 namespace_t ns = {flags2access(f->flags), ""};
2458                 multiname_t m = {QNAME, &ns, 0, $1};
2459                 $$.c = abc_getlocal_0($$.c);
2460                 $$.c = abc_getproperty2($$.c, &m);
2461             }
2462         }
2463         if(f->kind == MEMBER_METHOD) {
2464             $$.t = TYPE_FUNCTION(f);
2465         } else {
2466             $$.t = f->type;
2467         }
2468     
2469     /* look at actual classes, in the current package and imported */
2470     } else if((a = find_class($1))) {
2471         if(a->flags & FLAG_METHOD) {
2472             MULTINAME(m, a);
2473             $$.c = abc_findpropstrict2($$.c, &m);
2474             $$.c = abc_getproperty2($$.c, &m);
2475             $$.t = TYPE_FUNCTION(a->function);
2476         } else {
2477             if(a->slot) {
2478                 $$.c = abc_getglobalscope($$.c);
2479                 $$.c = abc_getslot($$.c, a->slot);
2480             } else {
2481                 MULTINAME(m, a);
2482                 $$.c = abc_getlex2($$.c, &m);
2483             }
2484             $$.t = TYPE_CLASS(a);
2485         }
2486
2487     /* unknown object, let the avm2 resolve it */
2488     } else {
2489         if(strcmp($1,"trace"))
2490             warning("Couldn't resolve '%s', doing late binding", $1);
2491         state->method->late_binding = 1;
2492                 
2493         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2494
2495         $$.t = 0;
2496         $$.c = abc_findpropstrict2($$.c, &m);
2497         $$.c = abc_getproperty2($$.c, &m);
2498     }
2499 }
2500
2501 //TODO: 
2502 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2503 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2504 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2505
2506 // ----------------- namespaces -------------------------------------------------
2507
2508 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2509 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2510 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2511
2512 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
2513