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