allow a static function to access static slots directly
[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     } else {
771         if(flags&FLAG_STATIC)
772             state->m = abc_class_staticmethod(state->cls, type2, &mname);
773         else
774             state->m = abc_class_method(state->cls, type2, &mname);
775         slot = state->m->trait->slot_id;
776     }
777     state->minfo = registerfunction(getset, flags, name, params, return_type, slot);
778
779     if(getset == KW_GET) state->m->trait->kind = TRAIT_GETTER;
780     if(getset == KW_SET) state->m->trait->kind = TRAIT_SETTER;
781     if(params->varargs) state->m->flags |= METHOD_NEED_REST;
782
783     char opt=0;
784     param_list_t*p=0;
785     for(p=params->list;p;p=p->next) {
786         if(params->varargs && !p->next) {
787             break; //varargs: omit last parameter in function signature
788         }
789         multiname_t*m = sig2mname(p->param->type);
790         list_append(state->m->parameters, m);
791         if(p->param->value) {
792             check_constant_against_type(p->param->type, p->param->value);
793             opt=1;list_append(state->m->optional_parameters, p->param->value);
794         } else if(opt) {
795             syntaxerror("non-optional parameter not allowed after optional parameters");
796         }
797     }
798
799     /* state->vars is initialized by state_new */
800     if(new_variable((flags&FLAG_STATIC)?"class":"this", state->clsinfo)!=0) syntaxerror("Internal error");
801
802     for(p=params->list;p;p=p->next) {
803         new_variable(p->param->name, p->param->type);
804     }
805 }
806 static void endfunction(code_t*body)
807 {
808         
809     if(!(state->cls->flags & CLASS_INTERFACE)) {
810         code_t*c = 0;
811         if(state->late_binding) {
812             c = abc_getlocal_0(c);
813             c = abc_pushscope(c);
814         }
815         c = code_append(c, state->initcode);
816         c = code_append(c, body);
817
818         /* append return if necessary */
819         if(!c || c->opcode != OPCODE_RETURNVOID && 
820                  c->opcode != OPCODE_RETURNVALUE) {
821             c = abc_returnvoid(c);
822         }
823         if(state->m->body->code) syntaxerror("internal error");
824         state->m->body->code = c;
825     }
826     old_state();
827 }
828
829
830
831 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
832 {
833     return 1; // FIXME
834 }
835
836 void breakjumpsto(code_t*c, code_t*jump) 
837 {
838     while(c->prev) 
839         c=c->prev;
840     while(c) {
841         if(c->opcode == OPCODE___BREAK__) {
842             c->opcode = OPCODE_JUMP;
843             c->branch = jump;
844         }
845         c = c->next;
846     }
847 }
848
849 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
850 {
851     if(!type1 || !type2) 
852         return registry_getanytype();
853     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
854         return registry_getanytype();
855     if(type1 == type2)
856         return type1;
857     return registry_getanytype();
858 }
859 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
860 {
861     if(from==to)
862         return c;
863     if(!to) {
864         return abc_coerce_a(c);
865     }
866     MULTINAME(m, to);
867     if(!from) {
868         // cast an "any" type to a specific type. subject to
869         // runtime exceptions
870         return abc_coerce2(c, &m);
871     }
872     
873     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
874         return abc_coerce2(c, &m);
875     }
876     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
877         return abc_coerce2(c, &m);
878     }
879     /* these are subject to overflow */
880     if(TYPE_IS_INT(from) && TYPE_IS_UINT(to)) {
881         return abc_coerce2(c, &m);
882     }
883     if(TYPE_IS_UINT(from) && TYPE_IS_INT(to)) {
884         return abc_coerce2(c, &m);
885     }
886
887     classinfo_t*supertype = from;
888     while(supertype) {
889         if(supertype == to) {
890              // target type is one of from's superclasses
891              return abc_coerce2(c, &m);
892         }
893         int t=0;
894         while(supertype->interfaces[t]) {
895             if(supertype->interfaces[t]==to) {
896                 // to type is one of from's interfaces
897                 return abc_coerce2(c, &m);
898             }
899             t++;
900         }
901         supertype = supertype->superclass;
902     }
903     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
904         return c;
905     syntaxerror("can't convert type %s to %s", from->name, to->name);
906 }
907
908 code_t*defaultvalue(code_t*c, classinfo_t*type)
909 {
910     if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
911        c = abc_pushbyte(c, 0);
912     } else if(TYPE_IS_BOOLEAN(type)) {
913        c = abc_pushfalse(c);
914     } else {
915        c = abc_pushnull(c);
916     }
917     return c;
918 }
919
920 char is_pushundefined(code_t*c)
921 {
922     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
923 }
924
925 void parserassert(int b)
926 {
927     if(!b) syntaxerror("internal error: assertion failed");
928 }
929
930 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
931 {
932     /* converts this:
933
934        [prefix code] [read instruction]
935
936        to this:
937
938        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
939     */
940     
941     if(in && in->opcode == OPCODE_COERCE_A) {
942         in = code_cutlast(in);
943     }
944     if(in->next)
945         syntaxerror("internal error");
946
947     /* chop off read instruction */
948     code_t*prefix = in;
949     code_t*r = in;
950     if(r->prev) {
951         prefix = r->prev;r->prev = 0;
952         prefix->next=0;
953     } else {
954         prefix = 0;
955     }
956
957     char use_temp_var = readbefore;
958
959     /* generate the write instruction, and maybe append a dup to the prefix code */
960     code_t* write = abc_nop(0);
961     if(r->opcode == OPCODE_GETPROPERTY) {
962         write->opcode = OPCODE_SETPROPERTY;
963         multiname_t*m = (multiname_t*)r->data[0];
964         write->data[0] = multiname_clone(m);
965         if(m->type != QNAME && m->type != MULTINAME)
966             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
967         if(!justassign) {
968             prefix = abc_dup(prefix); // we need the object, too
969         }
970         use_temp_var = 1;
971     } else if(r->opcode == OPCODE_GETSLOT) {
972         write->opcode = OPCODE_SETSLOT;
973         write->data[0] = r->data[0];
974         if(!justassign) {
975             prefix = abc_dup(prefix); // we need the object, too
976         }
977         use_temp_var = 1;
978     } else if(r->opcode == OPCODE_GETLOCAL) { 
979         write->opcode = OPCODE_SETLOCAL;
980         write->data[0] = r->data[0];
981     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
982         write->opcode = OPCODE_SETLOCAL_0;
983     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
984         write->opcode = OPCODE_SETLOCAL_1;
985     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
986         write->opcode = OPCODE_SETLOCAL_2;
987     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
988         write->opcode = OPCODE_SETLOCAL_3;
989     } else {
990         code_dump(r, 0, 0, "", stdout);
991         syntaxerror("illegal lvalue: can't assign a value to this expression");
992     }
993     code_t* c = 0;
994     
995     int temp = -1;
996     if(!justassign) {
997         if(use_temp_var) {
998             /* with getproperty/getslot, we have to be extra careful not
999                to execute the read code twice, as it might have side-effects
1000                (e.g. if the property is in fact a setter/getter combination)
1001
1002                So read the value, modify it, and write it again,
1003                using prefix only once and making sure (by using a temporary
1004                register) that the return value is what we just wrote */
1005             temp = gettempvar();
1006             c = code_append(c, prefix);
1007             c = code_append(c, r);
1008             if(readbefore) {
1009                 c = abc_dup(c);
1010                 c = abc_setlocal(c, temp);
1011             }
1012             c = code_append(c, middlepart);
1013             if(!readbefore) {
1014                 c = abc_dup(c);
1015                 c = abc_setlocal(c, temp);
1016             }
1017             c = code_append(c, write);
1018             c = abc_getlocal(c, temp);
1019             c = abc_kill(c, temp);
1020         } else {
1021             /* if we're allowed to execute the read code twice *and*
1022                the middlepart doesn't modify the code, things are easier.
1023             */
1024             code_t* r2 = code_dup(r);
1025             //c = code_append(c, prefix);
1026             parserassert(!prefix);
1027             c = code_append(c, r);
1028             c = code_append(c, middlepart);
1029             c = code_append(c, write);
1030             c = code_append(c, r2);
1031         }
1032     } else {
1033         /* even smaller version: overwrite the value without reading
1034            it out first */
1035         if(!use_temp_var) {
1036             if(prefix) {
1037                 c = code_append(c, prefix);
1038                 c = abc_dup(c);
1039             }
1040             c = code_append(c, middlepart);
1041             c = code_append(c, write);
1042             c = code_append(c, r);
1043         } else {
1044             temp = gettempvar();
1045             if(prefix) {
1046                 c = code_append(c, prefix);
1047                 c = abc_dup(c);
1048             }
1049             c = code_append(c, middlepart);
1050             c = abc_dup(c);
1051             c = abc_setlocal(c, temp);
1052             c = code_append(c, write);
1053             c = abc_getlocal(c, temp);
1054         }
1055     }
1056
1057     return c;
1058 }
1059
1060
1061 %}
1062
1063
1064 %%
1065
1066 /* ------------ code blocks / statements ---------------- */
1067
1068 PROGRAM: MAYBECODE
1069
1070 MAYBECODE: CODE {$$=$1;}
1071 MAYBECODE:      {$$=code_new();}
1072
1073 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1074 CODE: CODEPIECE {$$=$1;}
1075
1076 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1077 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1078 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1079 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1080 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1081 CODEPIECE: ';'                   {$$=code_new();}
1082 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1083 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1084 CODEPIECE: FOR                   {$$=$1}
1085 CODEPIECE: WHILE                 {$$=$1}
1086 CODEPIECE: BREAK                 {$$=$1}
1087 CODEPIECE: RETURN                {$$=$1}
1088 CODEPIECE: IF                    {$$=$1}
1089 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1090 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1091
1092 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
1093 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1094 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1095
1096 /* ------------ variables --------------------------- */
1097
1098 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1099                 |                {$$.c=abc_pushundefined(0);
1100                                   $$.t=TYPE_ANY;
1101                                  }
1102
1103 VAR : "const" | "var"
1104 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1105
1106 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1107 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1108
1109 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1110 {
1111     if(variable_exists($2))
1112         syntaxerror("Variable %s already defined", $2);
1113    
1114     if(!is_subtype_of($4.t, $3)) {
1115         syntaxerror("Can't convert %s to %s", $4.t->name, 
1116                                               $3->name);
1117     }
1118
1119     int index = new_variable($2, $3);
1120     
1121     if($3) {
1122         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1123             $$ = $4.c;
1124             $$ = converttype($$, $4.t, $3);
1125             $$ = abc_setlocal($$, index);
1126         } else {
1127             $$ = defaultvalue(0, $3);
1128             $$ = abc_setlocal($$, index);
1129         }
1130
1131         /* if this is a typed variable:
1132            push default value for type on stack */
1133         if($3) {
1134             state->initcode = defaultvalue(state->initcode, $3);
1135             state->initcode = abc_setlocal(state->initcode, index);
1136         }
1137     } else {
1138         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1139             $$ = $4.c;
1140             $$ = abc_coerce_a($$);
1141             $$ = abc_setlocal($$, index);
1142         } else {
1143             $$ = code_new();
1144         }
1145     }
1146     
1147     /* that's the default for a local register, anyway
1148         else {
1149         state->initcode = abc_pushundefined(state->initcode);
1150         state->initcode = abc_setlocal(state->initcode, index);
1151     }*/
1152     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1153 }
1154
1155 /* ------------ control flow ------------------------- */
1156
1157 MAYBEELSE:  %prec prec_none {$$ = code_new();}
1158 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1159 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1160
1161 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1162     $$ = state->initcode;state->initcode=0;
1163
1164     $$ = code_append($$, $4.c);
1165     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1166    
1167     $$ = code_append($$, $6);
1168     if($7) {
1169         myjmp = $$ = abc_jump($$, 0);
1170     }
1171     myif->branch = $$ = abc_label($$);
1172     if($7) {
1173         $$ = code_append($$, $7);
1174         myjmp->branch = $$ = abc_label($$);
1175     }
1176     
1177     $$ = killvars($$);old_state();
1178 }
1179
1180 FOR_INIT : {$$=code_new();}
1181 FOR_INIT : VARIABLE_DECLARATION
1182 FOR_INIT : VOIDEXPRESSION
1183
1184 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1185     $$ = state->initcode;state->initcode=0;
1186
1187     $$ = code_append($$, $4);
1188     code_t*loopstart = $$ = abc_label($$);
1189     $$ = code_append($$, $6.c);
1190     code_t*myif = $$ = abc_iffalse($$, 0);
1191     $$ = code_append($$, $10);
1192     $$ = code_append($$, $8);
1193     $$ = abc_jump($$, loopstart);
1194     code_t*out = $$ = abc_label($$);
1195     breakjumpsto($$, out);
1196     myif->branch = out;
1197
1198     $$ = killvars($$);old_state();
1199 }
1200
1201 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1202     $$ = state->initcode;state->initcode=0;
1203
1204     code_t*myjmp = $$ = abc_jump($$, 0);
1205     code_t*loopstart = $$ = abc_label($$);
1206     $$ = code_append($$, $6);
1207     myjmp->branch = $$ = abc_label($$);
1208     $$ = code_append($$, $4.c);
1209     $$ = abc_iftrue($$, loopstart);
1210     code_t*out = $$ = abc_label($$);
1211     breakjumpsto($$, out);
1212
1213     $$ = killvars($$);old_state();
1214 }
1215
1216 BREAK : "break" {
1217     $$ = abc___break__(0);
1218 }
1219
1220 /* ------------ packages and imports ---------------- */
1221
1222 X_IDENTIFIER: T_IDENTIFIER
1223             | "package" {$$="package";}
1224
1225 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3str($1,".",$3);}
1226 PACKAGE: X_IDENTIFIER             {$$=$1;}
1227
1228 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1229 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1230
1231 IMPORT : "import" QNAME {
1232        classinfo_t*c = $2;
1233        if(!c) 
1234             syntaxerror("Couldn't import class\n");
1235        state_has_imports();
1236        dict_put(state->imports, c->name, c);
1237        $$=0;
1238 }
1239 IMPORT : "import" PACKAGE '.' '*' {
1240        NEW(import_t,i);
1241        i->package = $2;
1242        state_has_imports();
1243        list_append(state->wildcard_imports, i);
1244        $$=0;
1245 }
1246
1247 /* ------------ classes and interfaces (header) -------------- */
1248
1249 MAYBE_MODIFIERS : {$$=0;}
1250 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1251 MODIFIER_LIST : MODIFIER               {$$=$1;}
1252 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1253
1254 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1255          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1256          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1257          | KW_STATIC {$$=FLAG_STATIC;}
1258          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1259          | KW_FINAL {$$=FLAG_FINAL;}
1260          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1261          | KW_NATIVE {$$=FLAG_NATIVE;}
1262          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1263
1264 EXTENDS : {$$=registry_getobjectclass();}
1265 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1266
1267 EXTENDS_LIST : {$$=list_new();}
1268 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1269
1270 IMPLEMENTS_LIST : {$$=list_new();}
1271 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1272
1273 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1274                               EXTENDS IMPLEMENTS_LIST 
1275                               '{' {startclass($1,$3,$4,$5, 0);} 
1276                               MAYBE_DECLARATION_LIST 
1277                               '}' {endclass();}
1278
1279 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1280                               EXTENDS_LIST 
1281                               '{' {startclass($1,$3,0,$4,1);}
1282                               MAYBE_IDECLARATION_LIST 
1283                               '}' {endclass();}
1284
1285 /* ------------ classes and interfaces (body) -------------- */
1286
1287 MAYBE_DECLARATION_LIST : 
1288 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1289 DECLARATION_LIST : DECLARATION
1290 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1291 DECLARATION : ';'
1292 DECLARATION : SLOT_DECLARATION
1293 DECLARATION : FUNCTION_DECLARATION
1294
1295 MAYBE_IDECLARATION_LIST : 
1296 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1297 IDECLARATION_LIST : IDECLARATION
1298 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1299 IDECLARATION : ';'
1300 IDECLARATION : "var" T_IDENTIFIER {
1301     syntaxerror("variable declarations not allowed in interfaces");
1302 }
1303 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1304     $1 |= FLAG_PUBLIC;
1305     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1306         syntaxerror("invalid method modifiers: interface methods always need to be public");
1307     }
1308     startfunction(0,$1,$3,$4,&$6,$8);
1309     endfunction(0);
1310 }
1311
1312 /* ------------ classes and interfaces (body, slots ) ------- */
1313
1314 VARCONST: "var" | "const"
1315
1316 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1317     int flags = $1;
1318     memberinfo_t* info = memberinfo_register(state->clsinfo, $3, MEMBER_SLOT);
1319     info->type = $4;
1320     info->flags = flags;
1321     trait_t*t=0;
1322
1323     namespace_t mname_ns = {flags2access(flags), ""};
1324     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1325
1326     if(!(flags&FLAG_STATIC)) {
1327         if($4) {
1328             MULTINAME(m, $4);
1329             t=abc_class_slot(state->cls, &mname, &m);
1330         } else {
1331             t=abc_class_slot(state->cls, &mname, 0);
1332         }
1333         info->slot = t->slot_id;
1334     } else {
1335         if($4) {
1336             MULTINAME(m, $4);
1337             t=abc_class_staticslot(state->cls, &mname, &m);
1338         } else {
1339             t=abc_class_staticslot(state->cls, &mname, 0);
1340         }
1341         info->slot = t->slot_id;
1342     }
1343     if($5.c && !is_pushundefined($5.c)) {
1344         code_t*c = 0;
1345         c = abc_getlocal_0(c);
1346         c = code_append(c, $5.c);
1347         c = converttype(c, $5.t, $4);
1348         c = abc_setslot(c, t->slot_id);
1349         if(!(flags&FLAG_STATIC))
1350             state->cls_init = code_append(state->cls_init, c);
1351         else
1352             state->cls_static_init = code_append(state->cls_static_init, c);
1353     }
1354     if($2==KW_CONST) {
1355         t->kind= TRAIT_CONST;
1356     }
1357 }
1358
1359 /* ------------ constants -------------------------------------- */
1360
1361 MAYBESTATICCONSTANT: {$$=0;}
1362 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1363
1364 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1365 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1366 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1367 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1368 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1369 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1370 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1371 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1372 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1373
1374 /* ------------ classes and interfaces (body, functions) ------- */
1375
1376 // non-vararg version
1377 MAYBE_PARAM_LIST: {
1378     memset(&$$,0,sizeof($$));
1379 }
1380 MAYBE_PARAM_LIST: PARAM_LIST {
1381     $$=$1;
1382 }
1383
1384 // vararg version
1385 MAYBE_PARAM_LIST: "..." PARAM {
1386     memset(&$$,0,sizeof($$));
1387     $$.varargs=1;
1388     list_append($$.list, $2);
1389 }
1390 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1391     $$ =$1;
1392     $$.varargs=1;
1393     list_append($$.list, $4);
1394 }
1395
1396 // non empty
1397 PARAM_LIST: PARAM_LIST ',' PARAM {
1398     $$ = $1;
1399     list_append($$.list, $3);
1400 }
1401 PARAM_LIST: PARAM {
1402     memset(&$$,0,sizeof($$));
1403     list_append($$.list, $1);
1404 }
1405
1406 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1407      $$ = malloc(sizeof(param_t));
1408      $$->name=$1;
1409      $$->type = $3;
1410      $$->value = $4;
1411 }
1412 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1413      $$ = malloc(sizeof(param_t));
1414      $$->name=$1;
1415      $$->type = TYPE_ANY;
1416      $$->value = $2;
1417 }
1418 GETSET : "get" {$$=$1;}
1419        | "set" {$$=$1;}
1420        |       {$$=0;}
1421
1422 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1423                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1424 {
1425     if(!state->m) syntaxerror("internal error: undefined function");
1426     endfunction($11);
1427 }
1428
1429 /* ------------- package + class ids --------------- */
1430
1431 CLASS: T_IDENTIFIER {
1432
1433     /* try current package */
1434     $$ = registry_findclass(state->package, $1);
1435
1436     /* try explicit imports */
1437     dictentry_t* e = dict_get_slot(state->imports, $1);
1438     while(e) {
1439         if($$)
1440             break;
1441         if(!strcmp(e->key, $1)) {
1442             $$ = (classinfo_t*)e->data;
1443         }
1444         e = e->next;
1445     }
1446
1447     /* try package.* imports */
1448     import_list_t*l = state->wildcard_imports;
1449     while(l) {
1450         if($$)
1451             break;
1452         //printf("does package %s contain a class %s?\n", l->import->package, $1);
1453         $$ = registry_findclass(l->import->package, $1);
1454         l = l->next;
1455     }
1456
1457     /* try global package */
1458     if(!$$) {
1459         $$ = registry_findclass("", $1);
1460     }
1461
1462     if(!$$) syntaxerror("Could not find class %s\n", $1);
1463 }
1464
1465 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1466     $$ = registry_findclass($1, $3);
1467     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1468 }
1469
1470 QNAME: PACKAGEANDCLASS
1471      | CLASS
1472
1473 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1474 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1475
1476 TYPE : QNAME      {$$=$1;}
1477      | '*'        {$$=registry_getanytype();}
1478      |  "String"  {$$=registry_getstringclass();}
1479      |  "int"     {$$=registry_getintclass();}
1480      |  "uint"    {$$=registry_getuintclass();}
1481      |  "Boolean" {$$=registry_getbooleanclass();}
1482      |  "Number"  {$$=registry_getnumberclass();}
1483
1484 MAYBETYPE: ':' TYPE {$$=$2;}
1485 MAYBETYPE:          {$$=0;}
1486
1487 /* ----------function calls, constructor calls ------ */
1488
1489 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1490 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1491
1492 MAYBE_EXPRESSION_LIST : {$$=0;}
1493 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1494 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1495                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1496                                                   *t = $1;
1497                                                   list_append($$, t);}
1498 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1499                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1500                                                   *t = $3;
1501                                                   list_append($$, t);}
1502
1503 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1504     MULTINAME(m, $2);
1505     $$.c = code_new();
1506
1507     /* TODO: why do we have to *find* our own classes? */
1508     $$.c = abc_findpropstrict2($$.c, &m);
1509
1510     typedcode_list_t*l = $3;
1511     int len = 0;
1512     while(l) {
1513         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1514         l = l->next;
1515         len ++;
1516     }
1517     $$.c = abc_constructprop2($$.c, &m, len);
1518     $$.t = $2;
1519 }
1520
1521 /* TODO: use abc_call (for calling local variables),
1522          abc_callstatic (for calling own methods) 
1523          call (for closures)
1524 */
1525 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1526     typedcode_list_t*l = $3;
1527     int len = 0;
1528     code_t*paramcode = 0;
1529     while(l) {
1530         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1531         l = l->next;
1532         len ++;
1533     }
1534        
1535     $$.c = $1.c;
1536     if($$.c->opcode == OPCODE_COERCE_A) {
1537         $$.c = code_cutlast($$.c);
1538     }
1539
1540     $$.t = TYPE_ANY;
1541     multiname_t*name = 0;
1542     if($$.c->opcode == OPCODE_GETPROPERTY) {
1543         name = multiname_clone($$.c->data[0]);
1544         $$.c = code_cutlast($$.c);
1545         $$.c = code_append($$.c, paramcode);
1546         $$.c = abc_callproperty2($$.c, name, len);
1547     } else if($$.c->opcode == OPCODE_GETSLOT) {
1548         int slot = (int)(ptroff_t)$$.c->data[0];
1549         trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1550         if(t->kind!=TRAIT_METHOD) {
1551             //flash allows to assign closures to members.
1552             //syntaxerror("not a function");
1553         }
1554         name = t->name;
1555         $$.c = code_cutlast($$.c);
1556         $$.c = code_append($$.c, paramcode);
1557         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1558         $$.c = abc_callproperty2($$.c, name, len);
1559     } else {
1560         $$.c = abc_getlocal_0($$.c);
1561         $$.c = code_append($$.c, paramcode);
1562         $$.c = abc_call($$.c, len);
1563     }
1564    
1565     memberinfo_t*f = 0;
1566    
1567     if(TYPE_IS_FUNCTION($1.t) &&
1568        (f = registry_findmember($1.t, "call"))) {
1569         $$.t = f->return_type;
1570     } else {
1571         $$.c = abc_coerce_a($$.c);
1572         $$.t = TYPE_ANY;
1573     }
1574 }
1575
1576 RETURN: "return" %prec prec_none {
1577     $$ = abc_returnvoid(0);
1578 }
1579 RETURN: "return" EXPRESSION {
1580     $$ = $2.c;
1581     $$ = abc_returnvalue($$);
1582 }
1583 // ----------------------- expression types -------------------------------------
1584
1585 NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
1586 EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
1587 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1588     $$.c = $1.c;
1589     $$.c = cut_last_push($$.c);
1590     $$.c = code_append($$.c,$3.c);
1591     $$.t = $3.t;
1592 }
1593 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1594
1595 // ----------------------- expression evaluation -------------------------------------
1596
1597 E : CONSTANT
1598 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1599 E : NEW                         {$$ = $1;}
1600 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1601                                  $$.t = TYPE_ANY;
1602                                 }
1603
1604 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1605                    //MULTINAME(m, registry_getintclass());
1606                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1607                    $$.t = TYPE_INT;
1608                   }
1609 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1610                     $$.t = TYPE_INT;
1611                    }
1612 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1613                   $$.t = TYPE_INT;
1614                  }
1615 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1616                    $$.t = TYPE_UINT;
1617                   }
1618 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1619                     $$.t = TYPE_FLOAT;
1620                    }
1621 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1622                      $$.t = TYPE_STRING;
1623                     }
1624 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1625                     $$.t = TYPE_BOOLEAN;
1626                    }
1627 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1628                      $$.t = TYPE_BOOLEAN;
1629                     }
1630 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1631                     $$.t = TYPE_NULL;
1632                    }
1633
1634 E : FUNCTIONCALL
1635 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1636              $$.t = TYPE_BOOLEAN;
1637             }
1638 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1639              $$.t = TYPE_BOOLEAN;
1640             }
1641 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1642               $$.t = TYPE_BOOLEAN;
1643              }
1644 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1645               $$.t = TYPE_BOOLEAN;
1646              }
1647 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1648               $$.t = TYPE_BOOLEAN;
1649              }
1650 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1651               $$.t = TYPE_BOOLEAN;
1652              }
1653 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1654               $$.t = TYPE_BOOLEAN;
1655              }
1656
1657 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1658               $$.c = $1.c;
1659               $$.c = converttype($$.c, $1.t, $$.t);
1660               $$.c = abc_dup($$.c);
1661               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1662               $$.c = cut_last_push($$.c);
1663               $$.c = code_append($$.c,$3.c);
1664               $$.c = converttype($$.c, $3.t, $$.t);
1665               code_t*label = $$.c = abc_label($$.c);
1666               jmp->branch = label;
1667              }
1668 E : E "&&" E {
1669               $$.t = join_types($1.t, $3.t, 'A');
1670               /*printf("%08x:\n",$1.t);
1671               code_dump($1.c, 0, 0, "", stdout);
1672               printf("%08x:\n",$3.t);
1673               code_dump($3.c, 0, 0, "", stdout);
1674               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1675               $$.c = $1.c;
1676               $$.c = converttype($$.c, $1.t, $$.t);
1677               $$.c = abc_dup($$.c);
1678               code_t*jmp = $$.c = abc_iffalse($$.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
1686 E : '!' E    {$$.c=$2.c;
1687               $$.c = abc_not($$.c);
1688               $$.t = TYPE_BOOLEAN;
1689              }
1690
1691 E : E '-' E
1692 E : E '/' E
1693 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1694              $$.t = join_types($1.t, $3.t, '+');
1695             }
1696 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1697              $$.t = join_types($1.t, $3.t, '%');
1698             }
1699 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1700              $$.t = join_types($1.t, $3.t, '*');
1701             }
1702
1703 E : E "as" E
1704 E : E "is" E
1705 E : '(' E ')' {$$=$2;}
1706 E : '-' E {$$=$2;}
1707
1708 E : E '[' E ']' {
1709   $$.c = $1.c;
1710   $$.c = code_append($$.c, $3.c);
1711  
1712   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1713   $$.c = abc_getproperty2($$.c, &m);
1714 }
1715
1716 E : E "*=" E { 
1717                code_t*c = $3.c;
1718                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1719                 c=abc_multiply_i(c);
1720                } else {
1721                 c=abc_multiply(c);
1722                }
1723                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1724                $$.c = toreadwrite($1.c, c, 0, 0);
1725                $$.t = $1.t;
1726               }
1727 E : E "%=" E { 
1728                code_t*c = abc_modulo($3.c);
1729                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1730                $$.c = toreadwrite($1.c, c, 0, 0);
1731                $$.t = $1.t;
1732               }
1733 E : E "<<=" E { 
1734                code_t*c = abc_lshift($3.c);
1735                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1736                $$.c = toreadwrite($1.c, c, 0, 0);
1737                $$.t = $1.t;
1738               }
1739 E : E ">>=" E { 
1740                code_t*c = abc_rshift($3.c);
1741                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1742                $$.c = toreadwrite($1.c, c, 0, 0);
1743                $$.t = $1.t;
1744               }
1745 E : E ">>>=" E { 
1746                code_t*c = abc_urshift($3.c);
1747                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1748                $$.c = toreadwrite($1.c, c, 0, 0);
1749                $$.t = $1.t;
1750               }
1751 E : E "/=" E { 
1752                code_t*c = abc_divide($3.c);
1753                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1754                $$.c = toreadwrite($1.c, c, 0, 0);
1755                $$.t = $1.t;
1756               }
1757 E : E "+=" E { 
1758                code_t*c = $3.c;
1759                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1760                 c=abc_add_i(c);
1761                } else {
1762                 c=abc_add(c);
1763                }
1764                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1765                
1766                $$.c = toreadwrite($1.c, c, 0, 0);
1767                $$.t = $1.t;
1768               }
1769 E : E "-=" E { code_t*c = $3.c; 
1770                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1771                 c=abc_subtract_i(c);
1772                } else {
1773                 c=abc_subtract(c);
1774                }
1775                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1776                
1777                $$.c = toreadwrite($1.c, c, 0, 0);
1778                $$.t = $1.t;
1779              }
1780 E : E '=' E { code_t*c = 0;
1781               c = code_append(c, $3.c);
1782               c = converttype(c, $3.t, $1.t);
1783               $$.c = toreadwrite($1.c, c, 1, 0);
1784               $$.t = $1.t;
1785             }
1786
1787 // TODO: use inclocal where appropriate
1788 E : E "++" { code_t*c = 0;
1789              classinfo_t*type = $1.t;
1790              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1791                  c=abc_increment_i(c);
1792                  type = TYPE_INT;
1793              } else {
1794                  c=abc_increment(c);
1795                  type = TYPE_NUMBER;
1796              }
1797              c=converttype(c, type, $1.t);
1798              $$.c = toreadwrite($1.c, c, 0, 1);
1799              $$.t = $1.t;
1800            }
1801 E : E "--" { code_t*c = 0;
1802              classinfo_t*type = $1.t;
1803              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1804                  c=abc_decrement_i(c);
1805                  type = TYPE_INT;
1806              } else {
1807                  c=abc_decrement(c);
1808                  type = TYPE_NUMBER;
1809              }
1810              c=converttype(c, type, $1.t);
1811              $$.c = toreadwrite($1.c, c, 0, 1);
1812              $$.t = $1.t;
1813             }
1814
1815 E : "++" E { code_t*c = 0;
1816              classinfo_t*type = $2.t;
1817              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1818                  c=abc_increment_i(c);
1819                  type = TYPE_INT;
1820              } else {
1821                  c=abc_increment(c);
1822                  type = TYPE_NUMBER;
1823              }
1824              c=converttype(c, type, $2.t);
1825              $$.c = toreadwrite($2.c, c, 0, 0);
1826              $$.t = $2.t;
1827            }
1828
1829 E : "--" E { code_t*c = 0;
1830              classinfo_t*type = $2.t;
1831              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1832                  c=abc_decrement_i(c);
1833                  type = TYPE_INT;
1834              } else {
1835                  c=abc_decrement(c);
1836                  type = TYPE_NUMBER;
1837              }
1838              c=converttype(c, type, $2.t);
1839              $$.c = toreadwrite($2.c, c, 0, 0);
1840              $$.t = $2.t;
1841            }
1842
1843 E : E '.' T_IDENTIFIER
1844             {$$.c = $1.c;
1845              if($$.t) {
1846                  memberinfo_t*f = registry_findmember($$.t, $3);
1847
1848                  if(f && f->slot) {
1849                      $$.c = abc_getslot($$.c, f->slot);
1850                  } else {
1851                      if(f) {
1852                          namespace_t ns = {flags2access(f->flags), ""}; // needs to be "", not $$.t->package (!)
1853                          multiname_t m = {QNAME, &ns, 0, $3};
1854                          $$.c = abc_getproperty2($$.c, &m);
1855                      } else {
1856                          multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1857                          $$.c = abc_getproperty2($$.c, &m);
1858                      }
1859                  }
1860                  /* determine type */
1861                  if(f) {
1862                     if(f->kind == MEMBER_METHOD) {
1863                         $$.t = TYPE_FUNCTION(f);
1864                     } else {
1865                         $$.t = f->type;
1866                     }
1867                  } else {
1868                     $$.c = abc_coerce_a($$.c);
1869                     $$.t = registry_getanytype();
1870                  }
1871              } else {
1872                  /* when resolving a property on an unknown type, we do know the
1873                     name of the property (and don't seem to need the package), but
1874                     we do need to make avm2 try out all access modes */
1875                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
1876                  $$.c = abc_getproperty2($$.c, &m);
1877                  $$.c = abc_coerce_a($$.c);
1878                  $$.t = registry_getanytype();
1879              }
1880             }
1881
1882 VAR_READ : T_IDENTIFIER {
1883     $$.t = 0;
1884     $$.c = 0;
1885     int i;
1886     memberinfo_t*f = 0;
1887     if((i = find_variable($1, &$$.t)) >= 0) {
1888         // $1 is a local variable
1889         $$.c = abc_getlocal($$.c, i);
1890     } else if(f = registry_findmember(state->clsinfo, $1)) {
1891         // $1 is a function in this class
1892         int var_is_static = (f->flags&FLAG_STATIC);
1893         int i_am_static = (state->minfo?(state->minfo->flags&FLAG_STATIC):FLAG_STATIC);
1894         if(var_is_static != i_am_static) {
1895             /* there doesn't seem to be any "static" way to access
1896                static properties of a class */
1897             state->late_binding = 1;
1898             $$.t = f->type;
1899             namespace_t ns = {flags2access(f->flags), ""};
1900             multiname_t m = {QNAME, &ns, 0, $1};
1901             $$.c = abc_findpropstrict2($$.c, &m);
1902             $$.c = abc_getproperty2($$.c, &m);
1903         } else {
1904             if(f->slot>0) {
1905                 $$.c = abc_getlocal_0($$.c);
1906                 $$.c = abc_getslot($$.c, f->slot);
1907             } else {
1908                 namespace_t ns = {flags2access(f->flags), ""};
1909                 multiname_t m = {QNAME, &ns, 0, $1};
1910                 $$.c = abc_getlocal_0($$.c);
1911                 $$.c = abc_getproperty2($$.c, &m);
1912             }
1913         }
1914         if(f->kind == MEMBER_METHOD) {
1915             $$.t = TYPE_FUNCTION(f);
1916         } else {
1917             $$.t = f->type;
1918         }
1919     } else {
1920         // let the avm2 resolve $1 
1921         if(strcmp($1,"trace"))
1922             warning("Couldn't resolve %s, doing late binding", $1);
1923         state->late_binding = 1;
1924                 
1925         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
1926
1927         $$.t = 0;
1928         $$.c = abc_findpropstrict2($$.c, &m);
1929         $$.c = abc_getproperty2($$.c, &m);
1930     }
1931 }
1932
1933 //TODO: 
1934 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1935 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1936 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1937
1938 // ----------------- namespaces -------------------------------------------------
1939
1940 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
1941 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
1942 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
1943
1944 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1945