fixed bug in creation of dynamic classes
[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     param_t* param;
55     params_t params;
56     string_t str;
57     char*id;
58     constant_t*constant;
59 }
60
61
62 %token<id> T_IDENTIFIER
63 %token<str> T_STRING
64 %token<token> T_REGEXP
65 %token<token> T_EMPTY
66 %token<number_int> T_INT
67 %token<number_uint> T_UINT
68 %token<number_uint> T_BYTE
69 %token<number_uint> T_SHORT
70 %token<number_float> T_FLOAT
71
72 %token<token> KW_IMPLEMENTS
73 %token<token> KW_NAMESPACE "namespace"
74 %token<token> KW_PACKAGE "package"
75 %token<token> KW_PROTECTED
76 %token<token> KW_PUBLIC
77 %token<token> KW_PRIVATE
78 %token<token> KW_USE "use"
79 %token<token> KW_INTERNAL
80 %token<token> KW_NEW "new"
81 %token<token> KW_NATIVE
82 %token<token> KW_FUNCTION "function"
83 %token<token> KW_FOR "for"
84 %token<token> KW_CLASS "class"
85 %token<token> KW_CONST "const"
86 %token<token> KW_SET "set"
87 %token<token> KW_STATIC
88 %token<token> KW_IMPORT "import"
89 %token<token> KW_RETURN "return"
90 %token<token> KW_INTERFACE "interface"
91 %token<token> KW_NULL "null"
92 %token<token> KW_VAR "var"
93 %token<token> KW_DYNAMIC
94 %token<token> KW_OVERRIDE
95 %token<token> KW_FINAL
96 %token<token> KW_GET "get"
97 %token<token> KW_EXTENDS
98 %token<token> KW_FALSE "false"
99 %token<token> KW_TRUE "true"
100 %token<token> KW_BOOLEAN "Boolean"
101 %token<token> KW_UINT "uint"
102 %token<token> KW_INT "int"
103 %token<token> KW_WHILE "while"
104 %token<token> KW_NUMBER "Number"
105 %token<token> KW_STRING "String"
106 %token<token> KW_IF "if"
107 %token<token> KW_ELSE  "else"
108 %token<token> KW_BREAK   "break"
109 %token<token> KW_IS "is"
110 %token<token> KW_AS "as"
111
112 %token<token> T_EQEQ "=="
113 %token<token> T_EQEQEQ "==="
114 %token<token> T_NE "!="
115 %token<token> T_LE "<="
116 %token<token> T_GE ">="
117 %token<token> T_DIVBY "/=" 
118 %token<token> T_MODBY "%="
119 %token<token> T_MULBY "*="
120 %token<token> T_PLUSBY "+=" 
121 %token<token> T_MINUSBY "-="
122 %token<token> T_SHRBY ">>="
123 %token<token> T_SHLBY "<<="
124 %token<token> T_USHRBY ">>>="
125 %token<token> T_OROR "||"
126 %token<token> T_ANDAND "&&"
127 %token<token> T_COLONCOLON "::"
128 %token<token> T_MINUSMINUS "--"
129 %token<token> T_PLUSPLUS "++"
130 %token<token> T_DOTDOT ".."
131 %token<token> T_DOTDOTDOT "..."
132 %token<token> T_SHL "<<"
133 %token<token> T_USHR ">>>"
134 %token<token> T_SHR ">>"
135 %token<token> T_SEMICOLON ';'
136 %token<token> T_STAR '*'
137 %token<token> T_DOT '.'
138
139 %type <id> X_IDENTIFIER PACKAGE
140 %type <token> VARCONST
141 %type <code> CODE
142 %type <code> CODEPIECE
143 %type <code> CODEBLOCK MAYBECODE
144 %type <token> PACKAGE_DECLARATION
145 %type <token> FUNCTION_DECLARATION
146 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
147 %type <token> CLASS_DECLARATION
148 %type <token> NAMESPACE_DECLARATION
149 %type <token> INTERFACE_DECLARATION
150 %type <code> VOIDEXPRESSION
151 %type <value> EXPRESSION NONCOMMAEXPRESSION
152 %type <value> MAYBEEXPRESSION
153 %type <value> E
154 %type <value> CONSTANT
155 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
156 %type <token> USE_NAMESPACE
157 %type <code> FOR_INIT
158 %type <token> IMPORT
159 %type <classinfo> MAYBETYPE
160 %type <token> GETSET
161 %type <param> PARAM
162 %type <params> PARAM_LIST
163 %type <params> MAYBE_PARAM_LIST
164 %type <flags> MAYBE_MODIFIERS
165 %type <flags> MODIFIER_LIST
166 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
167 %type <classinfo_list> IMPLEMENTS_LIST
168 %type <classinfo> EXTENDS
169 %type <classinfo_list> EXTENDS_LIST
170 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
171 %type <classinfo_list> QNAME_LIST
172 %type <classinfo> TYPE
173 %type <token> VAR
174 //%type <token> VARIABLE
175 %type <value> VAR_READ
176 %type <value> NEW
177 //%type <token> T_IDENTIFIER
178 %type <token> MODIFIER
179 %type <value> FUNCTIONCALL
180 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
181
182 // precedence: from low to high
183 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
184
185 %left prec_none
186 %right '?' ':'
187 %right '=' "/=" "%=" "*=" "+=" "-=" ">>=" "<<=" ">>>="
188 %left "||"
189 %left "&&"
190 %nonassoc '|'
191 %nonassoc '^'
192 %nonassoc '&'
193 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
194 %nonassoc "is"
195 %left prec_belowminus
196 %left '-'
197 %left '+'
198 %left "<<"
199 %left ">>>"
200 %left ">>"
201 %left '%'
202 %left '/'
203 %left '*'
204 %left '!'
205 %left '~'
206 %left "--" "++"
207 %left '['
208 %nonassoc "as"
209 %left '.' ".." "::"
210 %nonassoc T_IDENTIFIER
211 %left below_semicolon
212 %left ';'
213 %nonassoc "else"
214 %left '('
215
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "new" "false" "true" "null"
220
221 %left prec_highest
222
223      
224 %{
225
226 static int yyerror(char*s)
227 {
228    syntaxerror("%s", s); 
229 }
230 static char* concat3str(const char* t1, const char* t2, const char* t3)
231 {
232     int l1 = strlen(t1);
233     int l2 = strlen(t2);
234     int l3 = strlen(t3);
235     char*text = malloc(l1+l2+l3+1);
236     memcpy(text   , t1, l1);
237     memcpy(text+l1, t2, l2);
238     memcpy(text+l1+l2, t3, l3);
239     text[l1+l2+l3] = 0;
240     return text;
241 }
242
243 typedef struct _import {
244     char*package;
245 } import_t;
246
247 DECLARE_LIST(import);
248
249 typedef struct _state {
250     abc_file_t*file;
251     abc_script_t*init;
252
253     int level;
254
255     char*package;     
256     char*function;
257     /* code that needs to be executed at the start of
258        a method (like initializing local registers) */
259     code_t*initcode;
260
261     import_list_t*wildcard_imports;
262     dict_t*imports;
263     char has_own_imports;
264    
265     /* class data */
266     classinfo_t*clsinfo;
267     abc_class_t*cls;
268     code_t*cls_init;
269     code_t*cls_static_init;
270     
271     /* method data */
272     memberinfo_t*minfo;
273     abc_method_t*m;
274
275     dict_t*vars;
276     char late_binding;
277 } state_t;
278
279 typedef struct _global {
280     int variable_count;
281 } global_t;
282
283 static global_t*global = 0;
284 static state_t* state = 0;
285
286 DECLARE_LIST(state);
287
288 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
289
290 /* warning: list length of namespace set is undefined */
291 #define MULTINAME_LATE(m, access, package) \
292     namespace_t m##_ns = {access, package}; \
293     namespace_set_t m##_nsset; \
294     namespace_list_t m##_l;m##_l.next = 0; \
295     m##_nsset.namespaces = &m##_l; \
296     m##_nsset = m##_nsset; \
297     m##_l.namespace = &m##_ns; \
298     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
299
300 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
301 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
302 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
303 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
304 static namespace_list_t nl4 = {&ns4,0};
305 static namespace_list_t nl3 = {&ns3,&nl4};
306 static namespace_list_t nl2 = {&ns2,&nl3};
307 static namespace_list_t nl1 = {&ns1,&nl2};
308 static namespace_set_t nopackage_namespace_set = {&nl1};
309
310 static state_list_t*state_stack=0;
311     
312 static void init_globals()
313 {
314     global = rfx_calloc(sizeof(global_t));
315 }
316
317 static void new_state()
318 {
319     NEW(state_t, s);
320     NEW(state_list_t, sl);
321
322     state_t*oldstate = state;
323     if(state)
324         memcpy(s, state, sizeof(state_t)); //shallow copy
325     sl->next = state_stack;
326     sl->state = s;
327     if(!s->imports) {
328         s->imports = dict_new();
329     }
330     state_stack = sl;
331     state = s;
332     state->level++;
333     state->vars = dict_new();
334     state->initcode = 0;
335     state->has_own_imports = 0;
336 }
337 static void state_has_imports()
338 {
339     state->wildcard_imports = list_clone(state->wildcard_imports);
340     state->imports = dict_clone(state->imports);
341     state->has_own_imports = 1;
342 }
343
344 static void old_state()
345 {
346     if(!state_stack || !state_stack->next)
347         syntaxerror("invalid nesting");
348     state_t*oldstate = state;
349     state_list_t*old = state_stack;
350     state_stack = state_stack->next;
351     free(old);
352     state = state_stack->state;
353     /*if(state->initcode) {
354         printf("residual initcode\n");
355         code_dump(state->initcode, 0, 0, "", stdout);
356     }*/
357     if(oldstate->has_own_imports) {
358         list_free(oldstate->wildcard_imports);
359         dict_destroy(oldstate->imports);oldstate->imports=0;
360     }
361     state->initcode = code_append(state->initcode, oldstate->initcode);
362 }
363 void initialize_state()
364 {
365     init_globals();
366     new_state();
367
368     state->file = abc_file_new();
369     state->file->flags &= ~ABCFILE_LAZY;
370     
371     state->init = abc_initscript(state->file, 0);
372     code_t*c = state->init->method->body->code;
373
374     c = abc_getlocal_0(c);
375     c = abc_pushscope(c);
376   
377     /* findpropstrict doesn't just return a scope object- it
378        also makes it "active" somehow. Push local_0 on the
379        scope stack and read it back with findpropstrict, it'll
380        contain properties like "trace". Trying to find the same
381        property on a "vanilla" local_0 yields only a "undefined" */
382     //c = abc_findpropstrict(c, "[package]::trace");
383     
384     /*c = abc_getlocal_0(c);
385     c = abc_findpropstrict(c, "[package]::trace");
386     c = abc_coerce_a(c);
387     c = abc_setlocal_1(c);
388
389     c = abc_pushbyte(c, 0);
390     c = abc_setlocal_2(c);
391    
392     code_t*xx = c = abc_label(c);
393     c = abc_findpropstrict(c, "[package]::trace");
394     c = abc_pushstring(c, "prop:");
395     c = abc_hasnext2(c, 1, 2);
396     c = abc_dup(c);
397     c = abc_setlocal_3(c);
398     c = abc_callpropvoid(c, "[package]::trace", 2);
399     c = abc_getlocal_3(c);
400     c = abc_kill(c, 3);
401     c = abc_iftrue(c,xx);*/
402
403     c = abc_findpropstrict(c, "[package]::trace");
404     c = abc_pushstring(c, "[entering global init function]");
405     c = abc_callpropvoid(c, "[package]::trace", 1);
406     
407     state->init->method->body->code = c;
408 }
409 void* finalize_state()
410 {
411     if(state->level!=1) {
412         syntaxerror("unexpected end of file");
413     }
414     abc_method_body_t*m = state->init->method->body;
415     //__ popscope(m);
416     
417     __ findpropstrict(m, "[package]::trace");
418     __ pushstring(m, "[leaving global init function]");
419     __ callpropvoid(m, "[package]::trace", 1);
420     __ returnvoid(m);
421     return state->file;
422 }
423
424
425 static void startpackage(char*name)
426 {
427     if(state->package) {
428         syntaxerror("Packages can not be nested."); 
429     } 
430     new_state();
431     /*printf("entering package \"%s\"\n", name);*/
432     state->package = name;
433 }
434 static void endpackage()
435 {
436     /*printf("leaving package \"%s\"\n", state->package);*/
437     old_state();
438 }
439
440 char*globalclass=0;
441 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
442 {
443     if(state->cls) {
444         syntaxerror("inner classes now allowed"); 
445     }
446     new_state();
447
448     token_list_t*t=0;
449     classinfo_list_t*mlist=0;
450     /*printf("entering class %s\n", name);
451     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token);printf("\n");
452     if(extends) 
453         printf("  extends: %s.%s\n", extends->package, extends->name);
454     printf("  implements (%d): ", list_length(implements));
455     for(mlist=implements;mlist;mlist=mlist->next)  {
456         printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
457     }
458     printf("\n");
459     */
460
461     if(flags&~(FLAG_INTERNAL|FLAG_PUBLIC|FLAG_FINAL))
462         syntaxerror("invalid modifier(s)");
463
464     if((flags&(FLAG_PUBLIC|FLAG_INTERNAL)) == (FLAG_PUBLIC|FLAG_INTERNAL))
465         syntaxerror("public and internal not supported at the same time.");
466
467     /* create the class name, together with the proper attributes */
468     int access=0;
469     char*package=0;
470
471     if(!(flags&FLAG_PUBLIC) && !state->package) {
472         access = ACCESS_PRIVATE; package = current_filename;
473     } else if(!(flags&FLAG_PUBLIC) && state->package) {
474         access = ACCESS_PACKAGEINTERNAL; package = state->package;
475     } else if(state->package) {
476         access = ACCESS_PACKAGE; package = state->package;
477     } else {
478         syntaxerror("public classes only allowed inside a package");
479     }
480
481     if(registry_findclass(package, classname)) {
482         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
483     }
484    
485     /* build info struct */
486     int num_interfaces = (list_length(implements));
487     state->clsinfo = classinfo_register(access, package, classname, num_interfaces);
488     state->clsinfo->superclass = extends;
489     int pos = 0;
490     classinfo_list_t*l = implements;
491     for(l=implements;l;l=l->next) {
492         state->clsinfo->interfaces[pos++] = l->classinfo;
493     }
494
495     MULTINAME(classname2,state->clsinfo);
496     
497     multiname_t*extends2 = sig2mname(extends);
498
499     /*if(extends) {
500         state->cls_init = abc_getlocal_0(state->cls_init);
501         state->cls_init = abc_constructsuper(state->cls_init, 0);
502     }*/
503
504     state->cls = abc_class_new(state->file, &classname2, extends2);
505     if(flags&FLAG_FINAL) abc_class_final(state->cls);
506     if(flags&FLAG_DYNAMIC) abc_class_sealed(state->cls);
507     if(interface) abc_class_interface(state->cls);
508
509     for(mlist=implements;mlist;mlist=mlist->next) {
510         MULTINAME(m, mlist->classinfo);
511         abc_class_add_interface(state->cls, &m);
512     }
513
514     /* now write the construction code for this class */
515     int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
516
517     abc_method_body_t*m = state->init->method->body;
518     __ getglobalscope(m);
519     classinfo_t*s = extends;
520
521     int count=0;
522     
523     while(s) {
524         //TODO: take a look at the current scope stack, maybe 
525         //      we can re-use something
526         s = s->superclass;
527         if(!s) 
528         break;
529        
530         multiname_t*s2 = sig2mname(s);
531         __ getlex2(m, s2);
532         multiname_destroy(s2);
533
534         __ pushscope(m); count++;
535         m->code = m->code->prev->prev; // invert
536     }
537     /* continue appending after last op end */
538     while(m->code && m->code->next) m->code = m->code->next; 
539
540     /* TODO: if this is one of *our* classes, we can also 
541              do a getglobalscope/getslot <nr> (which references
542              the init function's slots) */
543     if(extends2) {
544         __ getlex2(m, extends2);
545         __ dup(m);
546         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
547            stack is not the superclass */
548         __ pushscope(m);count++;
549     } else {
550         __ pushnull(m);
551         /* notice: we get a verify error #1107 if the top element on the scope 
552            stack is not the global object */
553         __ getlocal_0(m);
554         __ pushscope(m);count++;
555     }
556     __ newclass(m,state->cls);
557     while(count--) {
558         __ popscope(m);
559     }
560     __ setslot(m, slotindex);
561
562     /* flash.display.MovieClip handling */
563     if(!globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
564         if(state->package && state->package[0]) {
565             globalclass = concat3str(state->package, ".", classname);
566         } else {
567             globalclass = strdup(classname);
568         }
569     }
570     multiname_destroy(extends2);
571 }
572
573 static void endclass()
574 {
575     if(state->cls_init) {
576         if(!state->cls->constructor) {
577             abc_method_t*m = abc_class_constructor(state->cls, 0);
578             m->body->code = code_append(m->body->code, state->cls_init);
579             m->body->code = abc_returnvoid(m->body->code);
580         } else {
581             code_t*c = state->cls->constructor->body->code;
582             c = code_append(state->cls_init, c);
583             state->cls->constructor->body->code = c;
584
585         }
586     }
587     if(state->cls_static_init) {
588         if(!state->cls->static_constructor) {
589             abc_method_t*m = abc_class_staticconstructor(state->cls, 0);
590             m->body->code = code_append(m->body->code, state->cls_static_init);
591             m->body->code = abc_returnvoid(m->body->code);
592         } else {
593             state->cls->static_constructor->body->code = 
594                 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
595         }
596     }
597
598     old_state();
599 }
600
601 typedef struct _variable {
602     int index;
603     classinfo_t*type;
604 } variable_t;
605
606 static int find_variable(char*name, classinfo_t**m)
607 {
608     state_list_t* s = state_stack;
609     while(s) {
610         variable_t*v = dict_lookup(s->state->vars, name);
611         if(v) {
612             if(m) {
613                 *m = v->type;
614             }
615             return v->index;
616         }
617         s = s->next;
618     }
619     return -1;
620
621 static int find_variable_safe(char*name, classinfo_t**m)
622 {
623     int i = find_variable(name, m);
624     if(i<0)
625         syntaxerror("undefined variable: %s", name);
626     return i;
627 }
628 static char variable_exists(char*name) 
629 {
630     return dict_lookup(state->vars, name)!=0;
631 }
632 static int new_variable(char*name, classinfo_t*type)
633 {
634     NEW(variable_t, v);
635     v->index = global->variable_count;
636     v->type = type;
637     dict_put(state->vars, name, v);
638     return global->variable_count++;
639 }
640 #define TEMPVARNAME "__as3_temp__"
641 static int gettempvar()
642 {
643     int i = find_variable(TEMPVARNAME, 0);
644     if(i<0) {
645         return new_variable(TEMPVARNAME, 0);
646     } else {
647         return i;
648     }
649 }
650
651 code_t* killvars(code_t*c) 
652 {
653     int t;
654     for(t=0;t<state->vars->hashsize;t++) {
655         dictentry_t*e =state->vars->slots[t];
656         while(e) {
657             variable_t*v = (variable_t*)e->data;
658             //do this always, otherwise register types don't match
659             //in the verifier when doing nested loops
660             //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
661             c = abc_kill(c, v->index);
662             e = e->next;
663         }
664     }
665     return c;
666 }
667
668
669 static void check_constant_against_type(classinfo_t*t, constant_t*c)
670 {
671 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
672    if(TYPE_IS_NUMBER(t)) {
673         xassert(c->type == CONSTANT_FLOAT
674              || c->type == CONSTANT_INT
675              || c->type == CONSTANT_UINT);
676    } else if(TYPE_IS_UINT(t)) {
677         xassert(c->type == CONSTANT_UINT ||
678                (c->type == CONSTANT_INT && c->i>0));
679    } else if(TYPE_IS_INT(t)) {
680         xassert(c->type == CONSTANT_INT);
681    } else if(TYPE_IS_BOOLEAN(t)) {
682         xassert(c->type == CONSTANT_TRUE
683              || c->type == CONSTANT_FALSE);
684    }
685 }
686
687 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
688 {
689     memberinfo_t*minfo = 0;
690     if(getset != KW_GET && getset != KW_SET) {
691         if(registry_findmember(state->clsinfo, name)) {
692             syntaxerror("class already contains a member/method called '%s'", name);
693         }
694         minfo = memberinfo_register(state->clsinfo, name, MEMBER_METHOD);
695         minfo->return_type = return_type;
696         // getslot on a member slot only returns "undefined", so no need
697         // to actually store these
698         //state->minfo->slot = state->m->method->trait->slot_id;
699     } else {
700         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
701         classinfo_t*type=0;
702         if(getset == KW_GET)
703             type = return_type;
704         else if(params->list)
705             type = params->list->param->type;
706         if((minfo=registry_findmember(state->clsinfo, name))) {
707             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
708                 syntaxerror("class already contains a member or method called '%s'", name);
709             if(minfo->kind & gs)
710                 syntaxerror("getter/setter for '%s' already defined", name);
711             /* make a setter or getter into a getset */
712             minfo->kind |= gs;
713             if(!minfo->type) 
714                 minfo->type = type;
715             else
716                 if(type && minfo->type != type)
717                     syntaxerror("different type in getter and setter");
718         } else {
719             minfo = memberinfo_register(state->clsinfo, name, gs);
720             minfo->type = type;
721         }
722         /* can't assign a slot as getter and setter might have different slots */
723         //minfo->slot = slot;
724     }
725     if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
726     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
727     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
728     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
729     if(flags&FLAG_INTERNAL) minfo->flags |= FLAG_INTERNAL;
730     return minfo;
731 }
732
733 static int flags2access(int flags)
734 {
735     int access = 0;
736     if(flags&FLAG_PUBLIC)  {
737         if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
738         access = ACCESS_PACKAGE;
739     } else if(flags&FLAG_PRIVATE) {
740         if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
741         access = ACCESS_PRIVATE;
742     } else if(flags&FLAG_PROTECTED) {
743         if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_INTERNAL)) syntaxerror("invalid combination of access levels");
744         access = ACCESS_PROTECTED;
745     } else {
746         access = ACCESS_PACKAGEINTERNAL;
747     }
748     return access;
749 }
750
751 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
752                           params_t*params, classinfo_t*return_type)
753 {
754     token_list_t*t;
755     new_state();
756     global->variable_count = 0;
757     state->function = name;
758     
759     if(state->m) {
760         syntaxerror("not able to start another method scope");
761     }
762
763     namespace_t mname_ns = {flags2access(flags), ""};
764     multiname_t mname = {QNAME, &mname_ns, 0, name};
765
766     multiname_t*type2 = sig2mname(return_type);
767     int slot = 0;
768     if(!strcmp(state->clsinfo->name,name)) {
769         state->m = abc_class_constructor(state->cls, type2);
770         name = "__as3_constructor__";
771     } else {
772         if(flags&FLAG_STATIC)
773             state->m = abc_class_staticmethod(state->cls, type2, &mname);
774         else
775             state->m = abc_class_method(state->cls, type2, &mname);
776         slot = state->m->trait->slot_id;
777     }
778     state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
779
780     if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
781     if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
782     if(params->varargs) state->m->flags |= METHOD_NEED_REST;
783
784     char opt=0;
785     param_list_t*p=0;
786     for(p=params->list;p;p=p->next) {
787         if(params->varargs && !p->next) {
788             break; //varargs: omit last parameter in function signature
789         }
790         multiname_t*m = sig2mname(p->param->type);
791         list_append(state->m->parameters, m);
792         if(p->param->value) {
793             check_constant_against_type(p->param->type, p->param->value);
794             opt=1;list_append(state->m->optional_parameters, p->param->value);
795         } else if(opt) {
796             syntaxerror("non-optional parameter not allowed after optional parameters");
797         }
798     }
799
800     /* state->vars is initialized by state_new */
801     if(new_variable((flags&FLAG_STATIC)?"class":"this", state->clsinfo)!=0) syntaxerror("Internal error");
802
803     for(p=params->list;p;p=p->next) {
804         new_variable(p->param->name, p->param->type);
805     }
806 }
807 static void endfunction(code_t*body)
808 {
809         
810     if(!(state->cls->flags & CLASS_INTERFACE)) {
811         code_t*c = 0;
812         if(state->late_binding) {
813             c = abc_getlocal_0(c);
814             c = abc_pushscope(c);
815         }
816         c = code_append(c, state->initcode);
817         c = code_append(c, body);
818
819         /* append return if necessary */
820         if(!c || c->opcode != OPCODE_RETURNVOID && 
821                  c->opcode != OPCODE_RETURNVALUE) {
822             c = abc_returnvoid(c);
823         }
824         if(state->m->body->code) syntaxerror("internal error");
825         state->m->body->code = c;
826     }
827     old_state();
828 }
829
830
831
832 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
833 {
834     return 1; // FIXME
835 }
836
837 void breakjumpsto(code_t*c, code_t*jump) 
838 {
839     while(c->prev) 
840         c=c->prev;
841     while(c) {
842         if(c->opcode == OPCODE___BREAK__) {
843             c->opcode = OPCODE_JUMP;
844             c->branch = jump;
845         }
846         c = c->next;
847     }
848 }
849
850 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
851 {
852     if(!type1 || !type2) 
853         return registry_getanytype();
854     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
855         return registry_getanytype();
856     if(type1 == type2)
857         return type1;
858     return registry_getanytype();
859 }
860 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
861 {
862     if(from==to)
863         return c;
864     if(!to) {
865         return abc_coerce_a(c);
866     }
867     MULTINAME(m, to);
868     if(!from) {
869         // cast an "any" type to a specific type. subject to
870         // runtime exceptions
871         return abc_coerce2(c, &m);
872     }
873     
874     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
875         return abc_coerce2(c, &m);
876     }
877     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
878         return abc_coerce2(c, &m);
879     }
880     /* these are subject to overflow */
881     if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
882         return abc_coerce2(c, &m);
883     }
884     if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
885         return abc_coerce2(c, &m);
886     }
887
888     classinfo_t*supertype = from;
889     while(supertype) {
890         if(supertype == to) {
891              // target type is one of from's superclasses
892              return abc_coerce2(c, &m);
893         }
894         int t=0;
895         while(supertype->interfaces[t]) {
896             if(supertype->interfaces[t]==to) {
897                 // to type is one of from's interfaces
898                 return abc_coerce2(c, &m);
899             }
900             t++;
901         }
902         supertype = supertype->superclass;
903     }
904     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
905         return c;
906     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
907         return c;
908     syntaxerror("can't convert type %s to %s", from->name, to->name);
909 }
910
911 code_t*defaultvalue(code_t*c, classinfo_t*type)
912 {
913     if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
914        c = abc_pushbyte(c, 0);
915     } else if(TYPE_IS_BOOLEAN(type)) {
916        c = abc_pushfalse(c);
917     } else {
918        c = abc_pushnull(c);
919     }
920     return c;
921 }
922
923 char is_pushundefined(code_t*c)
924 {
925     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
926 }
927
928 void parserassert(int b)
929 {
930     if(!b) syntaxerror("internal error: assertion failed");
931 }
932
933 static classinfo_t* find_class(char*name)
934 {
935     classinfo_t*c=0;
936
937     c = registry_findclass(state->package, name);
938
939     /* try explicit imports */
940     dictentry_t* e = dict_get_slot(state->imports, name);
941     while(e) {
942         if(c)
943             break;
944         if(!strcmp(e->key, name)) {
945             c = (classinfo_t*)e->data;
946         }
947         e = e->next;
948     }
949
950     /* try package.* imports */
951     import_list_t*l = state->wildcard_imports;
952     while(l) {
953         if(c)
954             break;
955         //printf("does package %s contain a class %s?\n", l->import->package, name);
956         c = registry_findclass(l->import->package, name);
957         l = l->next;
958     }
959
960     /* try global package */
961     if(!c) {
962         c = registry_findclass("", name);
963     }
964     return c;
965 }
966
967 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
968 {
969     /* converts this:
970
971        [prefix code] [read instruction]
972
973        to this:
974
975        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
976     */
977     
978     if(in && in->opcode == OPCODE_COERCE_A) {
979         in = code_cutlast(in);
980     }
981     if(in->next)
982         syntaxerror("internal error");
983
984     /* chop off read instruction */
985     code_t*prefix = in;
986     code_t*r = in;
987     if(r->prev) {
988         prefix = r->prev;r->prev = 0;
989         prefix->next=0;
990     } else {
991         prefix = 0;
992     }
993
994     char use_temp_var = readbefore;
995
996     /* generate the write instruction, and maybe append a dup to the prefix code */
997     code_t* write = abc_nop(0);
998     if(r->opcode == OPCODE_GETPROPERTY) {
999         write->opcode = OPCODE_SETPROPERTY;
1000         multiname_t*m = (multiname_t*)r->data[0];
1001         write->data[0] = multiname_clone(m);
1002         if(m->type != QNAME && m->type != MULTINAME)
1003             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
1004         if(!justassign) {
1005             prefix = abc_dup(prefix); // we need the object, too
1006         }
1007         use_temp_var = 1;
1008     } else if(r->opcode == OPCODE_GETSLOT) {
1009         write->opcode = OPCODE_SETSLOT;
1010         write->data[0] = r->data[0];
1011         if(!justassign) {
1012             prefix = abc_dup(prefix); // we need the object, too
1013         }
1014         use_temp_var = 1;
1015     } else if(r->opcode == OPCODE_GETLOCAL) { 
1016         write->opcode = OPCODE_SETLOCAL;
1017         write->data[0] = r->data[0];
1018     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1019         write->opcode = OPCODE_SETLOCAL_0;
1020     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1021         write->opcode = OPCODE_SETLOCAL_1;
1022     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1023         write->opcode = OPCODE_SETLOCAL_2;
1024     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1025         write->opcode = OPCODE_SETLOCAL_3;
1026     } else {
1027         code_dump(r, 0, 0, "", stdout);
1028         syntaxerror("illegal lvalue: can't assign a value to this expression");
1029     }
1030     code_t* c = 0;
1031     
1032     int temp = -1;
1033     if(!justassign) {
1034         if(use_temp_var) {
1035             /* with getproperty/getslot, we have to be extra careful not
1036                to execute the read code twice, as it might have side-effects
1037                (e.g. if the property is in fact a setter/getter combination)
1038
1039                So read the value, modify it, and write it again,
1040                using prefix only once and making sure (by using a temporary
1041                register) that the return value is what we just wrote */
1042             temp = gettempvar();
1043             c = code_append(c, prefix);
1044             c = code_append(c, r);
1045             if(readbefore) {
1046                 c = abc_dup(c);
1047                 c = abc_setlocal(c, temp);
1048             }
1049             c = code_append(c, middlepart);
1050             if(!readbefore) {
1051                 c = abc_dup(c);
1052                 c = abc_setlocal(c, temp);
1053             }
1054             c = code_append(c, write);
1055             c = abc_getlocal(c, temp);
1056             c = abc_kill(c, temp);
1057         } else {
1058             /* if we're allowed to execute the read code twice *and*
1059                the middlepart doesn't modify the code, things are easier.
1060             */
1061             code_t* r2 = code_dup(r);
1062             //c = code_append(c, prefix);
1063             parserassert(!prefix);
1064             c = code_append(c, r);
1065             c = code_append(c, middlepart);
1066             c = code_append(c, write);
1067             c = code_append(c, r2);
1068         }
1069     } else {
1070         /* even smaller version: overwrite the value without reading
1071            it out first */
1072         if(!use_temp_var) {
1073             if(prefix) {
1074                 c = code_append(c, prefix);
1075                 c = abc_dup(c);
1076             }
1077             c = code_append(c, middlepart);
1078             c = code_append(c, write);
1079             c = code_append(c, r);
1080         } else {
1081             temp = gettempvar();
1082             if(prefix) {
1083                 c = code_append(c, prefix);
1084                 c = abc_dup(c);
1085             }
1086             c = code_append(c, middlepart);
1087             c = abc_dup(c);
1088             c = abc_setlocal(c, temp);
1089             c = code_append(c, write);
1090             c = abc_getlocal(c, temp);
1091         }
1092     }
1093
1094     return c;
1095 }
1096
1097
1098 %}
1099
1100
1101 %%
1102
1103 /* ------------ code blocks / statements ---------------- */
1104
1105 PROGRAM: MAYBECODE
1106
1107 MAYBECODE: CODE {$$=$1;}
1108 MAYBECODE:      {$$=code_new();}
1109
1110 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1111 CODE: CODEPIECE {$$=$1;}
1112
1113 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1114 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1115 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1116 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1117 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1118 CODEPIECE: ';'                   {$$=code_new();}
1119 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1120 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1121 CODEPIECE: FOR                   {$$=$1}
1122 CODEPIECE: WHILE                 {$$=$1}
1123 CODEPIECE: BREAK                 {$$=$1}
1124 CODEPIECE: RETURN                {$$=$1}
1125 CODEPIECE: IF                    {$$=$1}
1126 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1127 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1128
1129 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
1130 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1131 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1132
1133 /* ------------ variables --------------------------- */
1134
1135 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1136                 |                {$$.c=abc_pushundefined(0);
1137                                   $$.t=TYPE_ANY;
1138                                  }
1139
1140 VAR : "const" | "var"
1141 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1142
1143 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1144 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1145
1146 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1147 {
1148     if(variable_exists($2))
1149         syntaxerror("Variable %s already defined", $2);
1150    
1151     if(!is_subtype_of($4.t, $3)) {
1152         syntaxerror("Can't convert %s to %s", $4.t->name, 
1153                                               $3->name);
1154     }
1155
1156     int index = new_variable($2, $3);
1157     
1158     if($3) {
1159         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1160             $$ = $4.c;
1161             $$ = converttype($$, $4.t, $3);
1162             $$ = abc_setlocal($$, index);
1163         } else {
1164             $$ = defaultvalue(0, $3);
1165             $$ = abc_setlocal($$, index);
1166         }
1167
1168         /* if this is a typed variable:
1169            push default value for type on stack */
1170         if($3) {
1171             state->initcode = defaultvalue(state->initcode, $3);
1172             state->initcode = abc_setlocal(state->initcode, index);
1173         }
1174     } else {
1175         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1176             $$ = $4.c;
1177             $$ = abc_coerce_a($$);
1178             $$ = abc_setlocal($$, index);
1179         } else {
1180             $$ = code_new();
1181         }
1182     }
1183     
1184     /* that's the default for a local register, anyway
1185         else {
1186         state->initcode = abc_pushundefined(state->initcode);
1187         state->initcode = abc_setlocal(state->initcode, index);
1188     }*/
1189     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1190 }
1191
1192 /* ------------ control flow ------------------------- */
1193
1194 MAYBEELSE:  %prec prec_none {$$ = code_new();}
1195 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1196 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1197
1198 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1199     $$ = state->initcode;state->initcode=0;
1200
1201     $$ = code_append($$, $4.c);
1202     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1203    
1204     $$ = code_append($$, $6);
1205     if($7) {
1206         myjmp = $$ = abc_jump($$, 0);
1207     }
1208     myif->branch = $$ = abc_label($$);
1209     if($7) {
1210         $$ = code_append($$, $7);
1211         myjmp->branch = $$ = abc_label($$);
1212     }
1213     
1214     $$ = killvars($$);old_state();
1215 }
1216
1217 FOR_INIT : {$$=code_new();}
1218 FOR_INIT : VARIABLE_DECLARATION
1219 FOR_INIT : VOIDEXPRESSION
1220
1221 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1222     $$ = state->initcode;state->initcode=0;
1223
1224     $$ = code_append($$, $4);
1225     code_t*loopstart = $$ = abc_label($$);
1226     $$ = code_append($$, $6.c);
1227     code_t*myif = $$ = abc_iffalse($$, 0);
1228     $$ = code_append($$, $10);
1229     $$ = code_append($$, $8);
1230     $$ = abc_jump($$, loopstart);
1231     code_t*out = $$ = abc_label($$);
1232     breakjumpsto($$, out);
1233     myif->branch = out;
1234
1235     $$ = killvars($$);old_state();
1236 }
1237
1238 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1239     $$ = state->initcode;state->initcode=0;
1240
1241     code_t*myjmp = $$ = abc_jump($$, 0);
1242     code_t*loopstart = $$ = abc_label($$);
1243     $$ = code_append($$, $6);
1244     myjmp->branch = $$ = abc_label($$);
1245     $$ = code_append($$, $4.c);
1246     $$ = abc_iftrue($$, loopstart);
1247     code_t*out = $$ = abc_label($$);
1248     breakjumpsto($$, out);
1249
1250     $$ = killvars($$);old_state();
1251 }
1252
1253 BREAK : "break" {
1254     $$ = abc___break__(0);
1255 }
1256
1257 /* ------------ packages and imports ---------------- */
1258
1259 X_IDENTIFIER: T_IDENTIFIER
1260             | "package" {$$="package";}
1261
1262 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1263 PACKAGE: X_IDENTIFIER             {$$=$1;}
1264
1265 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1266 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1267
1268 IMPORT : "import" QNAME {
1269        classinfo_t*c = $2;
1270        if(!c) 
1271             syntaxerror("Couldn't import class\n");
1272        state_has_imports();
1273        dict_put(state->imports, c->name, c);
1274        $$=0;
1275 }
1276 IMPORT : "import" PACKAGE '.' '*' {
1277        NEW(import_t,i);
1278        i->package = $2;
1279        state_has_imports();
1280        list_append(state->wildcard_imports, i);
1281        $$=0;
1282 }
1283
1284 /* ------------ classes and interfaces (header) -------------- */
1285
1286 MAYBE_MODIFIERS : {$$=0;}
1287 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1288 MODIFIER_LIST : MODIFIER               {$$=$1;}
1289 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1290
1291 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1292          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1293          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1294          | KW_STATIC {$$=FLAG_STATIC;}
1295          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1296          | KW_FINAL {$$=FLAG_FINAL;}
1297          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1298          | KW_NATIVE {$$=FLAG_NATIVE;}
1299          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1300
1301 EXTENDS : {$$=registry_getobjectclass();}
1302 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1303
1304 EXTENDS_LIST : {$$=list_new();}
1305 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1306
1307 IMPLEMENTS_LIST : {$$=list_new();}
1308 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1309
1310 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1311                               EXTENDS IMPLEMENTS_LIST 
1312                               '{' {startclass($1,$3,$4,$5, 0);} 
1313                               MAYBE_DECLARATION_LIST 
1314                               '}' {endclass();}
1315
1316 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1317                               EXTENDS_LIST 
1318                               '{' {startclass($1,$3,0,$4,1);}
1319                               MAYBE_IDECLARATION_LIST 
1320                               '}' {endclass();}
1321
1322 /* ------------ classes and interfaces (body) -------------- */
1323
1324 MAYBE_DECLARATION_LIST : 
1325 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1326 DECLARATION_LIST : DECLARATION
1327 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1328 DECLARATION : ';'
1329 DECLARATION : SLOT_DECLARATION
1330 DECLARATION : FUNCTION_DECLARATION
1331
1332 MAYBE_IDECLARATION_LIST : 
1333 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1334 IDECLARATION_LIST : IDECLARATION
1335 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1336 IDECLARATION : ';'
1337 IDECLARATION : "var" T_IDENTIFIER {
1338     syntaxerror("variable declarations not allowed in interfaces");
1339 }
1340 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1341     $1 |= FLAG_PUBLIC;
1342     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1343         syntaxerror("invalid method modifiers: interface methods always need to be public");
1344     }
1345     startfunction(0,$1,$3,$4,&$6,$8);
1346     endfunction(0);
1347 }
1348
1349 /* ------------ classes and interfaces (body, slots ) ------- */
1350
1351 VARCONST: "var" | "const"
1352
1353 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1354     int flags = $1;
1355     memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1356     info->type = $4;
1357     info->flags = flags;
1358     trait_t*t=0;
1359
1360     namespace_t mname_ns = {flags2access(flags), ""};
1361     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1362
1363     if(!(flags&FLAG_STATIC)) {
1364         if($4) {
1365             MULTINAME(m, $4);
1366             t=abc_class_slot(state->cls, &mname, &m);
1367         } else {
1368             t=abc_class_slot(state->cls, &mname, 0);
1369         }
1370         info->slot = t->slot_id;
1371     } else {
1372         if($4) {
1373             MULTINAME(m, $4);
1374             t=abc_class_staticslot(state->cls, &mname, &m);
1375         } else {
1376             t=abc_class_staticslot(state->cls, &mname, 0);
1377         }
1378         info->slot = t->slot_id;
1379     }
1380     if($5.c && !is_pushundefined($5.c)) {
1381         code_t*c = 0;
1382         c = abc_getlocal_0(c);
1383         c = code_append(c, $5.c);
1384         c = converttype(c, $5.t, $4);
1385         c = abc_setslot(c, t->slot_id);
1386         if(!(flags&FLAG_STATIC))
1387             state->cls_init = code_append(state->cls_init, c);
1388         else
1389             state->cls_static_init = code_append(state->cls_static_init, c);
1390     }
1391     if($2==KW_CONST) {
1392         t->kind= TRAIT_CONST;
1393     }
1394 }
1395
1396 /* ------------ constants -------------------------------------- */
1397
1398 MAYBESTATICCONSTANT: {$$=0;}
1399 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1400
1401 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1402 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1403 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1404 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1405 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1406 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1407 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1408 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1409 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1410
1411 /* ------------ classes and interfaces (body, functions) ------- */
1412
1413 // non-vararg version
1414 MAYBE_PARAM_LIST: {
1415     memset(&$$,0,sizeof($$));
1416 }
1417 MAYBE_PARAM_LIST: PARAM_LIST {
1418     $$=$1;
1419 }
1420
1421 // vararg version
1422 MAYBE_PARAM_LIST: "..." PARAM {
1423     memset(&$$,0,sizeof($$));
1424     $$.varargs=1;
1425     list_append($$.list, $2);
1426 }
1427 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1428     $$ =$1;
1429     $$.varargs=1;
1430     list_append($$.list, $4);
1431 }
1432
1433 // non empty
1434 PARAM_LIST: PARAM_LIST ',' PARAM {
1435     $$ = $1;
1436     list_append($$.list, $3);
1437 }
1438 PARAM_LIST: PARAM {
1439     memset(&$$,0,sizeof($$));
1440     list_append($$.list, $1);
1441 }
1442
1443 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1444      $$ = malloc(sizeof(param_t));
1445      $$->name=$1;
1446      $$->type = $3;
1447      $$->value = $4;
1448 }
1449 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1450      $$ = malloc(sizeof(param_t));
1451      $$->name=$1;
1452      $$->type = TYPE_ANY;
1453      $$->value = $2;
1454 }
1455 GETSET : "get" {$$=$1;}
1456        | "set" {$$=$1;}
1457        |       {$$=0;}
1458
1459 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1460                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1461 {
1462     if(!state->m) syntaxerror("internal error: undefined function");
1463     endfunction($11);
1464 }
1465
1466 /* ------------- package + class ids --------------- */
1467
1468 CLASS: T_IDENTIFIER {
1469
1470     /* try current package */
1471     $$ = find_class($1);
1472     if(!$$) syntaxerror("Could not find class %s\n", $1);
1473 }
1474
1475 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1476     $$ = registry_findclass($1, $3);
1477     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1478 }
1479
1480 QNAME: PACKAGEANDCLASS
1481      | CLASS
1482
1483 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1484 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1485
1486 TYPE : QNAME      {$$=$1;}
1487      | '*'        {$$=registry_getanytype();}
1488      |  "String"  {$$=registry_getstringclass();}
1489      |  "int"     {$$=registry_getintclass();}
1490      |  "uint"    {$$=registry_getuintclass();}
1491      |  "Boolean" {$$=registry_getbooleanclass();}
1492      |  "Number"  {$$=registry_getnumberclass();}
1493
1494 MAYBETYPE: ':' TYPE {$$=$2;}
1495 MAYBETYPE:          {$$=0;}
1496
1497 /* ----------function calls, constructor calls ------ */
1498
1499 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1500 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1501
1502 MAYBE_EXPRESSION_LIST : {$$=0;}
1503 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1504 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1505                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1506                                                   *t = $1;
1507                                                   list_append($$, t);}
1508 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1509                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1510                                                   *t = $3;
1511                                                   list_append($$, t);}
1512
1513 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1514     MULTINAME(m, $2);
1515     $$.c = code_new();
1516
1517     if($2->slot) {
1518         $$.c = abc_getglobalscope($$.c);
1519         $$.c = abc_getslot($$.c, $2->slot);
1520     } else {
1521         $$.c = abc_findpropstrict2($$.c, &m);
1522     }
1523
1524     typedcode_list_t*l = $3;
1525     int len = 0;
1526     while(l) {
1527         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1528         l = l->next;
1529         len ++;
1530     }
1531     if($2->slot)
1532         $$.c = abc_construct($$.c, len);
1533     else
1534         $$.c = abc_constructprop2($$.c, &m, len);
1535     $$.t = $2;
1536 }
1537
1538 /* TODO: use abc_call (for calling local variables),
1539          abc_callstatic (for calling own methods) 
1540          call (for closures)
1541 */
1542 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1543     typedcode_list_t*l = $3;
1544     int len = 0;
1545     code_t*paramcode = 0;
1546     while(l) {
1547         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1548         l = l->next;
1549         len ++;
1550     }
1551        
1552     $$.c = $1.c;
1553     if($$.c->opcode == OPCODE_COERCE_A) {
1554         $$.c = code_cutlast($$.c);
1555     }
1556
1557     $$.t = TYPE_ANY;
1558     multiname_t*name = 0;
1559     if($$.c->opcode == OPCODE_GETPROPERTY) {
1560         name = multiname_clone($$.c->data[0]);
1561         $$.c = code_cutlast($$.c);
1562         $$.c = code_append($$.c, paramcode);
1563         $$.c = abc_callproperty2($$.c, name, len);
1564     } else if($$.c->opcode == OPCODE_GETSLOT) {
1565         int slot = (int)(ptroff_t)$$.c->data[0];
1566         trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1567         if(t->kind!=TRAIT_METHOD) {
1568             //flash allows to assign closures to members.
1569             //syntaxerror("not a function");
1570         }
1571         name = t->name;
1572         $$.c = code_cutlast($$.c);
1573         $$.c = code_append($$.c, paramcode);
1574         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1575         $$.c = abc_callproperty2($$.c, name, len);
1576     } else {
1577         $$.c = abc_getlocal_0($$.c);
1578         $$.c = code_append($$.c, paramcode);
1579         $$.c = abc_call($$.c, len);
1580     }
1581    
1582     memberinfo_t*f = 0;
1583    
1584     if(TYPE_IS_FUNCTION($1.t) &&
1585        (f = registry_findmember($1.t, "call"))) {
1586         $$.t = f->return_type;
1587     } else {
1588         $$.c = abc_coerce_a($$.c);
1589         $$.t = TYPE_ANY;
1590     }
1591 }
1592
1593 RETURN: "return" %prec prec_none {
1594     $$ = abc_returnvoid(0);
1595 }
1596 RETURN: "return" EXPRESSION {
1597     $$ = $2.c;
1598     $$ = abc_returnvalue($$);
1599 }
1600 // ----------------------- expression types -------------------------------------
1601
1602 NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
1603 EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
1604 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1605     $$.c = $1.c;
1606     $$.c = cut_last_push($$.c);
1607     $$.c = code_append($$.c,$3.c);
1608     $$.t = $3.t;
1609 }
1610 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1611
1612 // ----------------------- expression evaluation -------------------------------------
1613
1614 E : CONSTANT
1615 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1616 E : NEW                         {$$ = $1;}
1617 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1618                                  $$.t = TYPE_ANY;
1619                                 }
1620
1621 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1622                    //MULTINAME(m, registry_getintclass());
1623                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1624                    $$.t = TYPE_INT;
1625                   }
1626 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1627                     $$.t = TYPE_INT;
1628                    }
1629 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1630                   $$.t = TYPE_INT;
1631                  }
1632 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1633                    $$.t = TYPE_UINT;
1634                   }
1635 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1636                     $$.t = TYPE_FLOAT;
1637                    }
1638 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1639                      $$.t = TYPE_STRING;
1640                     }
1641 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1642                     $$.t = TYPE_BOOLEAN;
1643                    }
1644 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1645                      $$.t = TYPE_BOOLEAN;
1646                     }
1647 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1648                     $$.t = TYPE_NULL;
1649                    }
1650
1651 E : FUNCTIONCALL
1652 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1653              $$.t = TYPE_BOOLEAN;
1654             }
1655 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1656              $$.t = TYPE_BOOLEAN;
1657             }
1658 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1659               $$.t = TYPE_BOOLEAN;
1660              }
1661 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1662               $$.t = TYPE_BOOLEAN;
1663              }
1664 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1665               $$.t = TYPE_BOOLEAN;
1666              }
1667 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1668               $$.t = TYPE_BOOLEAN;
1669              }
1670 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1671               $$.t = TYPE_BOOLEAN;
1672              }
1673
1674 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1675               $$.c = $1.c;
1676               $$.c = converttype($$.c, $1.t, $$.t);
1677               $$.c = abc_dup($$.c);
1678               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1679               $$.c = cut_last_push($$.c);
1680               $$.c = code_append($$.c,$3.c);
1681               $$.c = converttype($$.c, $3.t, $$.t);
1682               code_t*label = $$.c = abc_label($$.c);
1683               jmp->branch = label;
1684              }
1685 E : E "&&" E {
1686               $$.t = join_types($1.t, $3.t, 'A');
1687               /*printf("%08x:\n",$1.t);
1688               code_dump($1.c, 0, 0, "", stdout);
1689               printf("%08x:\n",$3.t);
1690               code_dump($3.c, 0, 0, "", stdout);
1691               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1692               $$.c = $1.c;
1693               $$.c = converttype($$.c, $1.t, $$.t);
1694               $$.c = abc_dup($$.c);
1695               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1696               $$.c = cut_last_push($$.c);
1697               $$.c = code_append($$.c,$3.c);
1698               $$.c = converttype($$.c, $3.t, $$.t);
1699               code_t*label = $$.c = abc_label($$.c);
1700               jmp->branch = label;              
1701              }
1702
1703 E : '!' E    {$$.c=$2.c;
1704               $$.c = abc_not($$.c);
1705               $$.t = TYPE_BOOLEAN;
1706              }
1707
1708 E : E '-' E
1709 E : E '/' E
1710 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1711              $$.t = join_types($1.t, $3.t, '+');
1712             }
1713 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1714              $$.t = join_types($1.t, $3.t, '%');
1715             }
1716 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1717              $$.t = join_types($1.t, $3.t, '*');
1718             }
1719
1720 E : E "as" E
1721 E : E "is" E
1722 E : '(' E ')' {$$=$2;}
1723 E : '-' E {$$=$2;}
1724
1725 E : E '[' E ']' {
1726   $$.c = $1.c;
1727   $$.c = code_append($$.c, $3.c);
1728  
1729   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1730   $$.c = abc_getproperty2($$.c, &m);
1731 }
1732
1733 E : E "*=" E { 
1734                code_t*c = $3.c;
1735                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1736                 c=abc_multiply_i(c);
1737                } else {
1738                 c=abc_multiply(c);
1739                }
1740                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1741                $$.c = toreadwrite($1.c, c, 0, 0);
1742                $$.t = $1.t;
1743               }
1744 E : E "%=" E { 
1745                code_t*c = abc_modulo($3.c);
1746                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1747                $$.c = toreadwrite($1.c, c, 0, 0);
1748                $$.t = $1.t;
1749               }
1750 E : E "<<=" E { 
1751                code_t*c = abc_lshift($3.c);
1752                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1753                $$.c = toreadwrite($1.c, c, 0, 0);
1754                $$.t = $1.t;
1755               }
1756 E : E ">>=" E { 
1757                code_t*c = abc_rshift($3.c);
1758                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1759                $$.c = toreadwrite($1.c, c, 0, 0);
1760                $$.t = $1.t;
1761               }
1762 E : E ">>>=" E { 
1763                code_t*c = abc_urshift($3.c);
1764                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1765                $$.c = toreadwrite($1.c, c, 0, 0);
1766                $$.t = $1.t;
1767               }
1768 E : E "/=" E { 
1769                code_t*c = abc_divide($3.c);
1770                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1771                $$.c = toreadwrite($1.c, c, 0, 0);
1772                $$.t = $1.t;
1773               }
1774 E : E "+=" E { 
1775                code_t*c = $3.c;
1776                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1777                 c=abc_add_i(c);
1778                } else {
1779                 c=abc_add(c);
1780                }
1781                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1782                
1783                $$.c = toreadwrite($1.c, c, 0, 0);
1784                $$.t = $1.t;
1785               }
1786 E : E "-=" E { code_t*c = $3.c; 
1787                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1788                 c=abc_subtract_i(c);
1789                } else {
1790                 c=abc_subtract(c);
1791                }
1792                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1793                
1794                $$.c = toreadwrite($1.c, c, 0, 0);
1795                $$.t = $1.t;
1796              }
1797 E : E '=' E { code_t*c = 0;
1798               c = code_append(c, $3.c);
1799               c = converttype(c, $3.t, $1.t);
1800               $$.c = toreadwrite($1.c, c, 1, 0);
1801               $$.t = $1.t;
1802             }
1803
1804 // TODO: use inclocal where appropriate
1805 E : E "++" { code_t*c = 0;
1806              classinfo_t*type = $1.t;
1807              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1808                  c=abc_increment_i(c);
1809                  type = TYPE_INT;
1810              } else {
1811                  c=abc_increment(c);
1812                  type = TYPE_NUMBER;
1813              }
1814              c=converttype(c, type, $1.t);
1815              $$.c = toreadwrite($1.c, c, 0, 1);
1816              $$.t = $1.t;
1817            }
1818 E : E "--" { code_t*c = 0;
1819              classinfo_t*type = $1.t;
1820              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1821                  c=abc_decrement_i(c);
1822                  type = TYPE_INT;
1823              } else {
1824                  c=abc_decrement(c);
1825                  type = TYPE_NUMBER;
1826              }
1827              c=converttype(c, type, $1.t);
1828              $$.c = toreadwrite($1.c, c, 0, 1);
1829              $$.t = $1.t;
1830             }
1831
1832 E : "++" E { code_t*c = 0;
1833              classinfo_t*type = $2.t;
1834              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1835                  c=abc_increment_i(c);
1836                  type = TYPE_INT;
1837              } else {
1838                  c=abc_increment(c);
1839                  type = TYPE_NUMBER;
1840              }
1841              c=converttype(c, type, $2.t);
1842              $$.c = toreadwrite($2.c, c, 0, 0);
1843              $$.t = $2.t;
1844            }
1845
1846 E : "--" E { code_t*c = 0;
1847              classinfo_t*type = $2.t;
1848              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1849                  c=abc_decrement_i(c);
1850                  type = TYPE_INT;
1851              } else {
1852                  c=abc_decrement(c);
1853                  type = TYPE_NUMBER;
1854              }
1855              c=converttype(c, type, $2.t);
1856              $$.c = toreadwrite($2.c, c, 0, 0);
1857              $$.t = $2.t;
1858            }
1859
1860 E : E '.' T_IDENTIFIER
1861             {$$.c = $1.c;
1862              classinfo_t*t = $1.t;
1863              char is_static = 0;
1864              if(TYPE_IS_CLASS(t)) {
1865                  memberinfo_t*m = registry_findmember($1.t, "prototype");
1866                  if(!m) syntaxerror("identifier '%s' not found in anonymous class", $3);
1867                  t = m->type;
1868                  is_static = 1;
1869              }
1870              if(t) {
1871                  memberinfo_t*f = registry_findmember(t, $3);
1872                  char noslot = 0;
1873                  if(f && !is_static != !(f->flags&FLAG_STATIC))
1874                     noslot=1;
1875
1876                  if(f && f->slot && !noslot) {
1877                      $$.c = abc_getslot($$.c, f->slot);
1878                  } else {
1879                      if(f) {
1880                          namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1881                          multiname_t m = {QNAME, &ns, 0, $3};
1882                          $$.c = abc_getproperty2($$.c, &m);
1883                      } else {
1884                          multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1885                          $$.c = abc_getproperty2($$.c, &m);
1886                      }
1887                  }
1888                  /* determine type */
1889                  if(f) {
1890                     if(f->kind == MEMBER_METHOD) {
1891                         $$.t = TYPE_FUNCTION(f);
1892                     } else {
1893                         $$.t = f->type;
1894                     }
1895                  } else {
1896                     $$.c = abc_coerce_a($$.c);
1897                     $$.t = registry_getanytype();
1898                  }
1899              } else {
1900                  /* when resolving a property on an unknown type, we do know the
1901                     name of the property (and don't seem to need the package), but
1902                     we do need to make avm2 try out all access modes */
1903                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1904                  $$.c = abc_getproperty2($$.c, &m);
1905                  $$.c = abc_coerce_a($$.c);
1906                  $$.t = registry_getanytype();
1907              }
1908             }
1909
1910 VAR_READ : T_IDENTIFIER {
1911     $$.t = 0;
1912     $$.c = 0;
1913     int i;
1914     classinfo_t*a = 0;
1915     memberinfo_t*f = 0;
1916
1917     /* look at variables */
1918     if((i = find_variable($1, &$$.t)) >= 0) {
1919         // $1 is a local variable
1920         $$.c = abc_getlocal($$.c, i);
1921
1922     /* look at current class' members */
1923     } else if((f = registry_findmember(state->clsinfo, $1))) {
1924         // $1 is a function in this class
1925         int var_is_static = (f->flags&FLAG_STATIC);
1926         int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
1927         if(var_is_static != i_am_static) {
1928             /* there doesn't seem to be any "static" way to access
1929                static properties of a class */
1930             state->late_binding = 1;
1931             $$.t = f->type;
1932             namespace_t ns = {flags2access(f->flags), ""};
1933             multiname_t m = {QNAME, &ns, 0, $1};
1934             $$.c = abc_findpropstrict2($$.c, &m);
1935             $$.c = abc_getproperty2($$.c, &m);
1936         } else {
1937             if(f->slot>0) {
1938                 $$.c = abc_getlocal_0($$.c);
1939                 $$.c = abc_getslot($$.c, f->slot);
1940             } else {
1941                 namespace_t ns = {flags2access(f->flags), ""};
1942                 multiname_t m = {QNAME, &ns, 0, $1};
1943                 $$.c = abc_getlocal_0($$.c);
1944                 $$.c = abc_getproperty2($$.c, &m);
1945             }
1946         }
1947         if(f->kind == MEMBER_METHOD) {
1948             $$.t = TYPE_FUNCTION(f);
1949         } else {
1950             $$.t = f->type;
1951         }
1952     
1953     /* look at classes in the current package and imported classes */
1954     } else if((a = find_class($1))) {
1955         if(a->slot) {
1956             $$.c = abc_getglobalscope($$.c);
1957             $$.c = abc_getslot($$.c, a->slot);
1958         } else {
1959             MULTINAME(m, a);
1960             $$.c = abc_getlex2($$.c, &m);
1961         }
1962         $$.t = TYPE_CLASS(a);
1963
1964     /* unknown object, let the avm2 resolve it */
1965     } else {
1966         if(strcmp($1,"trace"))
1967             warning("Couldn't resolve %s, doing late binding", $1);
1968         state->late_binding = 1;
1969                 
1970         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
1971
1972         $$.t = 0;
1973         $$.c = abc_findpropstrict2($$.c, &m);
1974         $$.c = abc_getproperty2($$.c, &m);
1975     }
1976 }
1977
1978 //TODO: 
1979 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1980 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1981 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1982
1983 // ----------------- namespaces -------------------------------------------------
1984
1985 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
1986 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
1987 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
1988
1989 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1990