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