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