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