fixed reconcile bug in assignment
[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             c = abc_kill(c, temp);
1238         }
1239     }
1240
1241     return c;
1242 }
1243
1244 #define IS_INT(a) (TYPE_IS_INT((a).t) || TYPE_IS_UINT((a).t))
1245 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1246
1247 %}
1248
1249
1250 %%
1251
1252 /* ------------ code blocks / statements ---------------- */
1253
1254 PROGRAM: MAYBECODE {
1255     /* todo: do something with this code if we're outside a function */
1256     if($1)
1257         warning("ignored code");
1258 }
1259
1260 MAYBECODE: CODE {$$=$1;}
1261 MAYBECODE: {$$=code_new();}
1262
1263 CODE: CODE CODEPIECE {
1264     $$=code_append($1,$2);
1265 }
1266 CODE: CODEPIECE {
1267     $$=$1;
1268 }
1269
1270 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1271 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1272 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1273 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1274 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1275 CODEPIECE: ';'                   {$$=code_new();}
1276 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1277 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1278 CODEPIECE: FOR                   {$$=$1}
1279 CODEPIECE: FOR_IN                {$$=$1}
1280 CODEPIECE: WHILE                 {$$=$1}
1281 CODEPIECE: DO_WHILE              {$$=$1}
1282 CODEPIECE: SWITCH                {$$=$1}
1283 CODEPIECE: BREAK                 {$$=$1}
1284 CODEPIECE: CONTINUE              {$$=$1}
1285 CODEPIECE: RETURN                {$$=$1}
1286 CODEPIECE: IF                    {$$=$1}
1287 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1288 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1289
1290 CODEBLOCK :  '{' CODE '}' {$$=$2;}
1291 CODEBLOCK :  '{' '}'      {$$=0;}
1292 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1293 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1294
1295 /* ------------ variables --------------------------- */
1296
1297 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1298                 |                {$$.c=abc_pushundefined(0);
1299                                   $$.t=TYPE_ANY;
1300                                  }
1301
1302 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1303 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1304
1305 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1306 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1307
1308 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1309 {
1310     if(variable_exists($1))
1311         syntaxerror("Variable %s already defined", $1);
1312    
1313     if(!is_subtype_of($3.t, $2)) {
1314         syntaxerror("Can't convert %s to %s", $3.t->name, 
1315                                               $2->name);
1316     }
1317
1318     int index = new_variable($1, $2, 1);
1319     
1320     if($2) {
1321         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1322             $$ = $3.c;
1323             $$ = converttype($$, $3.t, $2);
1324             $$ = abc_setlocal($$, index);
1325         } else {
1326             $$ = defaultvalue(0, $2);
1327             $$ = abc_setlocal($$, index);
1328         }
1329     } else {
1330         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1331             $$ = $3.c;
1332             $$ = abc_coerce_a($$);
1333             $$ = abc_setlocal($$, index);
1334         } else {
1335             $$ = code_new();
1336         }
1337     }
1338     
1339     /* that's the default for a local register, anyway
1340         else {
1341         state->method->initcode = abc_pushundefined(state->method->initcode);
1342         state->method->initcode = abc_setlocal(state->method->initcode, index);
1343     }*/
1344     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1345 }
1346
1347 /* ------------ control flow ------------------------- */
1348
1349 MAYBEELSE:  %prec below_else {$$ = code_new();}
1350 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1351 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1352
1353 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1354     $$ = code_new();
1355     $$ = code_append($$, $4.c);
1356     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1357    
1358     $$ = code_append($$, $6);
1359     if($7) {
1360         myjmp = $$ = abc_jump($$, 0);
1361     }
1362     myif->branch = $$ = abc_nop($$);
1363     if($7) {
1364         $$ = code_append($$, $7);
1365         myjmp->branch = $$ = abc_nop($$);
1366     }
1367     
1368     $$ = killvars($$);old_state();
1369 }
1370
1371 FOR_INIT : {$$=code_new();}
1372 FOR_INIT : VARIABLE_DECLARATION
1373 FOR_INIT : VOIDEXPRESSION
1374 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1375     $$=$2;new_variable($2,$3,1);
1376 }
1377 FOR_IN_INIT : T_IDENTIFIER {
1378     $$=$1;
1379 }
1380
1381 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1382 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1383
1384 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1385     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1386     $$ = code_new();
1387     $$ = code_append($$, $2);
1388     code_t*loopstart = $$ = abc_label($$);
1389     $$ = code_append($$, $4.c);
1390     code_t*myif = $$ = abc_iffalse($$, 0);
1391     $$ = code_append($$, $8);
1392     code_t*cont = $$ = abc_nop($$);
1393     $$ = code_append($$, $6);
1394     $$ = abc_jump($$, loopstart);
1395     code_t*out = $$ = abc_nop($$);
1396     breakjumpsto($$, $1.name, out);
1397     continuejumpsto($$, $1.name, cont);
1398     myif->branch = out;
1399
1400     $$ = killvars($$);old_state();
1401 }
1402
1403 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1404     variable_t*var = find_variable($2);
1405     char*tmp1name = concat2($2, "__tmp1__");
1406     int it = new_variable(tmp1name, TYPE_INT, 0);
1407     char*tmp2name = concat2($2, "__array__");
1408     int array = new_variable(tmp1name, 0, 0);
1409
1410     $$ = code_new();
1411     $$ = code_append($$, $4.c);
1412     $$ = abc_coerce_a($$);
1413     $$ = abc_setlocal($$, array);
1414     $$ = abc_pushbyte($$, 0);
1415     $$ = abc_setlocal($$, it);
1416
1417     code_t*loopstart = $$ = abc_label($$);
1418     
1419     $$ = abc_hasnext2($$, array, it);
1420     code_t*myif = $$ = abc_iffalse($$, 0);
1421     $$ = abc_getlocal($$, array);
1422     $$ = abc_getlocal($$, it);
1423     if(!$1.each)
1424         $$ = abc_nextname($$);
1425     else
1426         $$ = abc_nextvalue($$);
1427     $$ = converttype($$, 0, var->type);
1428     $$ = abc_setlocal($$, var->index);
1429
1430     $$ = code_append($$, $6);
1431     $$ = abc_jump($$, loopstart);
1432     
1433     code_t*out = $$ = abc_nop($$);
1434     breakjumpsto($$, $1.name, out);
1435     continuejumpsto($$, $1.name, loopstart);
1436     
1437     $$ = killvars($$);
1438     
1439     myif->branch = out;
1440
1441     old_state();
1442     free(tmp1name);
1443     free(tmp2name);
1444 }
1445
1446 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1447     $$ = code_new();
1448
1449     code_t*myjmp = $$ = abc_jump($$, 0);
1450     code_t*loopstart = $$ = abc_label($$);
1451     $$ = code_append($$, $6);
1452     code_t*cont = $$ = abc_nop($$);
1453     myjmp->branch = cont;
1454     $$ = code_append($$, $4.c);
1455     $$ = abc_iftrue($$, loopstart);
1456     code_t*out = $$ = abc_nop($$);
1457     breakjumpsto($$, $1, out);
1458     continuejumpsto($$, $1, cont);
1459
1460     $$ = killvars($$);
1461     old_state();
1462 }
1463
1464 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1465     $$ = code_new();
1466     code_t*loopstart = $$ = abc_label($$);
1467     $$ = code_append($$, $3);
1468     code_t*cont = $$ = abc_nop($$);
1469     $$ = code_append($$, $6.c);
1470     $$ = abc_iftrue($$, loopstart);
1471     code_t*out = $$ = abc_nop($$);
1472     breakjumpsto($$, $1, out);
1473     continuejumpsto($$, $1, cont);
1474     $$ = killvars($$);
1475     old_state();
1476 }
1477
1478 BREAK : "break" %prec prec_none {
1479     $$ = abc___break__(0, "");
1480 }
1481 BREAK : "break" T_IDENTIFIER {
1482     $$ = abc___break__(0, $2);
1483 }
1484 CONTINUE : "continue" %prec prec_none {
1485     $$ = abc___continue__(0, "");
1486 }
1487 CONTINUE : "continue" T_IDENTIFIER {
1488     $$ = abc___continue__(0, $2);
1489 }
1490
1491 MAYBE_CASE_LIST :           {$$=0;}
1492 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1493 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
1494 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1495 CASE_LIST: CASE             {$$=$1}
1496 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
1497
1498 CASE: "case" E ':' MAYBECODE {
1499     $$ = abc_dup(0);
1500     $$ = code_append($$, $2.c);
1501     code_t*j = $$ = abc_ifne($$, 0);
1502     $$ = code_append($$, $4);
1503     if($$->opcode != OPCODE___BREAK__) {
1504         $$ = abc___fallthrough__($$, "");
1505     }
1506     code_t*e = $$ = abc_nop($$);
1507     j->branch = e;
1508 }
1509 DEFAULT: "default" ':' MAYBECODE {
1510     $$ = $3;
1511 }
1512 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1513     $$=$4.c;
1514     $$ = code_append($$, $7);
1515     code_t*out = $$ = abc_pop($$);
1516     breakjumpsto($$, $1, out);
1517     
1518     code_t*c = $$,*lastblock=0;
1519     while(c) {
1520         if(c->opcode == OPCODE_IFNE) {
1521             if(!c->next) syntaxerror("internal error in fallthrough handling");
1522             lastblock=c->next;
1523         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1524             if(lastblock) {
1525                 c->opcode = OPCODE_JUMP;
1526                 c->branch = lastblock;
1527             } else {
1528                 /* fall through end of switch */
1529                 c->opcode = OPCODE_NOP;
1530             }
1531         }
1532         c=c->prev;
1533     }
1534     old_state();
1535 }
1536
1537 /* ------------ packages and imports ---------------- */
1538
1539 X_IDENTIFIER: T_IDENTIFIER
1540             | "package" {$$="package";}
1541
1542 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,".",$3);free($1);$1=0;}
1543 PACKAGE: X_IDENTIFIER             {$$=strdup($1);}
1544
1545 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2);free($2);$2=0;} MAYBECODE '}' {endpackage()}
1546 PACKAGE_DECLARATION : "package" '{' {startpackage("")} MAYBECODE '}' {endpackage()}
1547
1548 IMPORT : "import" QNAME {
1549        classinfo_t*c = $2;
1550        if(!c) 
1551             syntaxerror("Couldn't import class\n");
1552        state_has_imports();
1553        dict_put(state->imports, c->name, c);
1554        $$=0;
1555 }
1556 IMPORT : "import" PACKAGE '.' '*' {
1557        NEW(import_t,i);
1558        i->package = $2;
1559        state_has_imports();
1560        list_append(state->wildcard_imports, i);
1561        $$=0;
1562 }
1563
1564 /* ------------ classes and interfaces (header) -------------- */
1565
1566 MAYBE_MODIFIERS : {$$=0;}
1567 MAYBE_MODIFIERS : MODIFIER_LIST {$$=$1}
1568 MODIFIER_LIST : MODIFIER               {$$=$1;}
1569 MODIFIER_LIST : MODIFIER_LIST MODIFIER {$$=$1|$2;}
1570
1571 MODIFIER : KW_PUBLIC {$$=FLAG_PUBLIC;}
1572          | KW_PRIVATE {$$=FLAG_PRIVATE;}
1573          | KW_PROTECTED {$$=FLAG_PROTECTED;}
1574          | KW_STATIC {$$=FLAG_STATIC;}
1575          | KW_DYNAMIC {$$=FLAG_DYNAMIC;}
1576          | KW_FINAL {$$=FLAG_FINAL;}
1577          | KW_OVERRIDE {$$=FLAG_OVERRIDE;}
1578          | KW_NATIVE {$$=FLAG_NATIVE;}
1579          | KW_INTERNAL {$$=FLAG_INTERNAL;}
1580
1581 EXTENDS : {$$=registry_getobjectclass();}
1582 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1583
1584 EXTENDS_LIST : {$$=list_new();}
1585 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1586
1587 IMPLEMENTS_LIST : {$$=list_new();}
1588 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1589
1590 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
1591                               EXTENDS IMPLEMENTS_LIST 
1592                               '{' {startclass($1,$3,$4,$5, 0);} 
1593                               MAYBE_DECLARATION_LIST 
1594                               '}' {endclass();}
1595
1596 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
1597                               EXTENDS_LIST 
1598                               '{' {startclass($1,$3,0,$4,1);}
1599                               MAYBE_IDECLARATION_LIST 
1600                               '}' {endclass();}
1601
1602 /* ------------ classes and interfaces (body) -------------- */
1603
1604 MAYBE_DECLARATION_LIST : 
1605 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1606 DECLARATION_LIST : DECLARATION
1607 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1608 DECLARATION : ';'
1609 DECLARATION : SLOT_DECLARATION
1610 DECLARATION : FUNCTION_DECLARATION
1611
1612 MAYBE_IDECLARATION_LIST : 
1613 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1614 IDECLARATION_LIST : IDECLARATION
1615 IDECLARATION_LIST : IDECLARATION_LIST IDECLARATION
1616 IDECLARATION : ';'
1617 IDECLARATION : "var" T_IDENTIFIER {
1618     syntaxerror("variable declarations not allowed in interfaces");
1619 }
1620 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
1621     $1 |= FLAG_PUBLIC;
1622     if($1&(FLAG_PRIVATE|FLAG_INTERNAL|FLAG_PROTECTED)) {
1623         syntaxerror("invalid method modifiers: interface methods always need to be public");
1624     }
1625     startfunction(0,$1,$3,$4,&$6,$8);
1626     endfunction(0,$1,$3,$4,&$6,$8, 0);
1627 }
1628
1629 /* ------------ classes and interfaces (body, slots ) ------- */
1630
1631 VARCONST: "var" | "const"
1632
1633 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1634     int flags = $1;
1635     memberinfo_t* info = memberinfo_register(state->cls->info, $3, MEMBER_SLOT);
1636     info->type = $4;
1637     info->flags = flags;
1638     trait_t*t=0;
1639
1640     namespace_t mname_ns = {flags2access(flags), ""};
1641     multiname_t mname = {QNAME, &mname_ns, 0, $3};
1642
1643     if(!(flags&FLAG_STATIC)) {
1644         if($4) {
1645             MULTINAME(m, $4);
1646             t=abc_class_slot(state->cls->abc, &mname, &m);
1647         } else {
1648             t=abc_class_slot(state->cls->abc, &mname, 0);
1649         }
1650         info->slot = t->slot_id;
1651     } else {
1652         if($4) {
1653             MULTINAME(m, $4);
1654             t=abc_class_staticslot(state->cls->abc, &mname, &m);
1655         } else {
1656             t=abc_class_staticslot(state->cls->abc, &mname, 0);
1657         }
1658         info->slot = t->slot_id;
1659     }
1660     if($5.c && !is_pushundefined($5.c)) {
1661         code_t*c = 0;
1662         c = abc_getlocal_0(c);
1663         c = code_append(c, $5.c);
1664         c = converttype(c, $5.t, $4);
1665         c = abc_setslot(c, t->slot_id);
1666         if(!(flags&FLAG_STATIC))
1667             state->cls->init = code_append(state->cls->init, c);
1668         else
1669             state->cls->static_init = code_append(state->cls->static_init, c);
1670     }
1671     if($2==KW_CONST) {
1672         t->kind= TRAIT_CONST;
1673     }
1674 }
1675
1676 /* ------------ constants -------------------------------------- */
1677
1678 MAYBESTATICCONSTANT: {$$=0;}
1679 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1680
1681 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1682 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1683 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1684 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1685 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
1686 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1687 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
1688 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
1689 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
1690
1691 /* ------------ classes and interfaces (body, functions) ------- */
1692
1693 // non-vararg version
1694 MAYBE_PARAM_LIST: {
1695     memset(&$$,0,sizeof($$));
1696 }
1697 MAYBE_PARAM_LIST: PARAM_LIST {
1698     $$=$1;
1699 }
1700
1701 // vararg version
1702 MAYBE_PARAM_LIST: "..." PARAM {
1703     memset(&$$,0,sizeof($$));
1704     $$.varargs=1;
1705     list_append($$.list, $2);
1706 }
1707 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1708     $$ =$1;
1709     $$.varargs=1;
1710     list_append($$.list, $4);
1711 }
1712
1713 // non empty
1714 PARAM_LIST: PARAM_LIST ',' PARAM {
1715     $$ = $1;
1716     list_append($$.list, $3);
1717 }
1718 PARAM_LIST: PARAM {
1719     memset(&$$,0,sizeof($$));
1720     list_append($$.list, $1);
1721 }
1722
1723 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1724      $$ = malloc(sizeof(param_t));
1725      $$->name=$1;
1726      $$->type = $3;
1727      $$->value = $4;
1728 }
1729 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1730      $$ = malloc(sizeof(param_t));
1731      $$->name=$1;
1732      $$->type = TYPE_ANY;
1733      $$->value = $2;
1734 }
1735 GETSET : "get" {$$=$1;}
1736        | "set" {$$=$1;}
1737        |       {$$=0;}
1738
1739 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1740                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1741 {
1742     code_t*c = 0;
1743     if(state->method->late_binding) {
1744         c = abc_getlocal_0(c);
1745         c = abc_pushscope(c);
1746     }
1747     if(state->method->is_constructor && !state->method->has_super) {
1748         // call default constructor
1749         c = abc_getlocal_0(c);
1750         c = abc_constructsuper(c, 0);
1751     }
1752     c = wrap_function(c, state->method->initcode, $11);
1753     endfunction(0,$1,$3,$4,&$6,$8,c);
1754 }
1755
1756 /* ------------- package + class ids --------------- */
1757
1758 CLASS: T_IDENTIFIER {
1759
1760     /* try current package */
1761     $$ = find_class($1);
1762     if(!$$) syntaxerror("Could not find class %s\n", $1);
1763 }
1764
1765 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1766     $$ = registry_findclass($1, $3);
1767     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
1768     free($1);$1=0;
1769 }
1770
1771 QNAME: PACKAGEANDCLASS
1772      | CLASS
1773
1774 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1775 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1776
1777 TYPE : QNAME      {$$=$1;}
1778      | '*'        {$$=registry_getanytype();}
1779      | "void"     {$$=registry_getanytype();}
1780     /*
1781      |  "String"  {$$=registry_getstringclass();}
1782      |  "int"     {$$=registry_getintclass();}
1783      |  "uint"    {$$=registry_getuintclass();}
1784      |  "Boolean" {$$=registry_getbooleanclass();}
1785      |  "Number"  {$$=registry_getnumberclass();}
1786     */
1787
1788 MAYBETYPE: ':' TYPE {$$=$2;}
1789 MAYBETYPE:          {$$=0;}
1790
1791 /* ----------function calls, delete, constructor calls ------ */
1792
1793 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
1794 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1795
1796 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
1797 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1798 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
1799                                                   $$.cc = $1.c;
1800                                                  }
1801 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
1802                                                   $$.len= $1.len+1;
1803                                                   $$.cc = code_append($1.cc, $3.c);
1804                                                   }
1805
1806 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1807     MULTINAME(m, $2);
1808     $$.c = code_new();
1809
1810     if($2->slot) {
1811         $$.c = abc_getglobalscope($$.c);
1812         $$.c = abc_getslot($$.c, $2->slot);
1813     } else {
1814         $$.c = abc_findpropstrict2($$.c, &m);
1815     }
1816
1817     $$.c = code_append($$.c, $3.cc);
1818
1819     if($2->slot)
1820         $$.c = abc_construct($$.c, $3.len);
1821     else
1822         $$.c = abc_constructprop2($$.c, &m, $3.len);
1823     $$.t = $2;
1824 }
1825
1826 /* TODO: use abc_call (for calling local variables),
1827          abc_callstatic (for calling own methods) 
1828          call (for closures)
1829 */
1830 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1831     
1832     $$.c = $1.c;
1833     if($$.c->opcode == OPCODE_COERCE_A) {
1834         $$.c = code_cutlast($$.c);
1835     }
1836     code_t*paramcode = $3.cc;
1837
1838     $$.t = TYPE_ANY;
1839     if($$.c->opcode == OPCODE_GETPROPERTY) {
1840         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1841         $$.c = code_cutlast($$.c);
1842         $$.c = code_append($$.c, paramcode);
1843         $$.c = abc_callproperty2($$.c, name, $3.len);
1844         multiname_destroy(name);
1845     } else if($$.c->opcode == OPCODE_GETSLOT) {
1846         int slot = (int)(ptroff_t)$$.c->data[0];
1847         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
1848         if(t->kind!=TRAIT_METHOD) {
1849             //ok: flash allows to assign closures to members.
1850         }
1851         multiname_t*name = t->name;
1852         $$.c = code_cutlast($$.c);
1853         $$.c = code_append($$.c, paramcode);
1854         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1855         $$.c = abc_callproperty2($$.c, name, $3.len);
1856     } else if($$.c->opcode == OPCODE_GETSUPER) {
1857         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
1858         $$.c = code_cutlast($$.c);
1859         $$.c = code_append($$.c, paramcode);
1860         $$.c = abc_callsuper2($$.c, name, $3.len);
1861         multiname_destroy(name);
1862     } else {
1863         $$.c = abc_getlocal_0($$.c);
1864         $$.c = code_append($$.c, paramcode);
1865         $$.c = abc_call($$.c, $3.len);
1866     }
1867    
1868     memberinfo_t*f = 0;
1869    
1870     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
1871         $$.t = $1.t->function->return_type;
1872     } else {
1873         $$.c = abc_coerce_a($$.c);
1874         $$.t = TYPE_ANY;
1875     }
1876
1877 }
1878 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
1879     if(!state->cls) syntaxerror("super() not allowed outside of a class");
1880     if(!state->method) syntaxerror("super() not allowed outside of a function");
1881     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
1882
1883     $$.c = code_new();
1884     $$.c = abc_getlocal_0($$.c);
1885
1886     $$.c = code_append($$.c, $3.cc);
1887     /*
1888     this is dependent on the control path, check this somewhere else
1889     if(state->method->has_super)
1890         syntaxerror("constructor may call super() only once");
1891     */
1892     state->method->has_super = 1;
1893     $$.c = abc_constructsuper($$.c, $3.len);
1894     $$.c = abc_pushundefined($$.c);
1895     $$.t = TYPE_ANY;
1896 }
1897
1898 DELETE: "delete" E {
1899     $$.c = $2.c;
1900     if($$.c->opcode == OPCODE_COERCE_A) {
1901         $$.c = code_cutlast($$.c);
1902     }
1903     multiname_t*name = 0;
1904     if($$.c->opcode == OPCODE_GETPROPERTY) {
1905         $$.c->opcode = OPCODE_DELETEPROPERTY;
1906     } else if($$.c->opcode == OPCODE_GETSLOT) {
1907         int slot = (int)(ptroff_t)$$.c->data[0];
1908         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
1909         $$.c = code_cutlast($$.c);
1910         $$.c = abc_deleteproperty2($$.c, name);
1911     } else {
1912         $$.c = abc_getlocal_0($$.c);
1913         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
1914         $$.c = abc_deleteproperty2($$.c, &m);
1915     }
1916     $$.t = TYPE_BOOLEAN;
1917 }
1918
1919 RETURN: "return" %prec prec_none {
1920     $$ = abc_returnvoid(0);
1921 }
1922 RETURN: "return" EXPRESSION {
1923     $$ = $2.c;
1924     $$ = abc_returnvalue($$);
1925 }
1926
1927 // ----------------------- expression types -------------------------------------
1928
1929 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
1930 EXPRESSION : E                %prec below_minus {$$ = $1;}
1931 EXPRESSION : EXPRESSION ',' E %prec below_minus {
1932     $$.c = $1.c;
1933     $$.c = cut_last_push($$.c);
1934     $$.c = code_append($$.c,$3.c);
1935     $$.t = $3.t;
1936 }
1937 VOIDEXPRESSION : EXPRESSION %prec below_minus {
1938     $$=cut_last_push($1.c);
1939 }
1940
1941 // ----------------------- expression evaluation -------------------------------------
1942
1943 E : CONSTANT
1944 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1945 E : NEW                         {$$ = $1;}
1946 E : DELETE                      {$$ = $1;}
1947 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1948                                  $$.t = TYPE_ANY;
1949                                 }
1950
1951 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1952                    //MULTINAME(m, registry_getintclass());
1953                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1954                    $$.t = TYPE_INT;
1955                   }
1956 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1957                     $$.t = TYPE_INT;
1958                    }
1959 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1960                   $$.t = TYPE_INT;
1961                  }
1962 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1963                    $$.t = TYPE_UINT;
1964                   }
1965 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1966                     $$.t = TYPE_FLOAT;
1967                    }
1968 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1969                      $$.t = TYPE_STRING;
1970                     }
1971 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
1972                     $$.t = TYPE_ANY;
1973                    }
1974 CONSTANT : "true" {$$.c = abc_pushtrue(0);
1975                     $$.t = TYPE_BOOLEAN;
1976                    }
1977 CONSTANT : "false" {$$.c = abc_pushfalse(0);
1978                      $$.t = TYPE_BOOLEAN;
1979                     }
1980 CONSTANT : "null" {$$.c = abc_pushnull(0);
1981                     $$.t = TYPE_NULL;
1982                    }
1983
1984 E : FUNCTIONCALL
1985 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1986              $$.t = TYPE_BOOLEAN;
1987             }
1988 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1989              $$.t = TYPE_BOOLEAN;
1990             }
1991 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1992               $$.t = TYPE_BOOLEAN;
1993              }
1994 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1995               $$.t = TYPE_BOOLEAN;
1996              }
1997 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1998               $$.t = TYPE_BOOLEAN;
1999              }
2000 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2001               $$.t = TYPE_BOOLEAN;
2002               }
2003 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2004               $$.t = TYPE_BOOLEAN;
2005              }
2006 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2007               $$.t = TYPE_BOOLEAN;
2008              }
2009
2010 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2011               $$.c = $1.c;
2012               $$.c = converttype($$.c, $1.t, $$.t);
2013               $$.c = abc_dup($$.c);
2014               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2015               $$.c = cut_last_push($$.c);
2016               $$.c = code_append($$.c,$3.c);
2017               $$.c = converttype($$.c, $3.t, $$.t);
2018               code_t*label = $$.c = abc_label($$.c);
2019               jmp->branch = label;
2020              }
2021 E : E "&&" E {
2022               $$.t = join_types($1.t, $3.t, 'A');
2023               /*printf("%08x:\n",$1.t);
2024               code_dump($1.c, 0, 0, "", stdout);
2025               printf("%08x:\n",$3.t);
2026               code_dump($3.c, 0, 0, "", stdout);
2027               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2028               $$.c = $1.c;
2029               $$.c = converttype($$.c, $1.t, $$.t);
2030               $$.c = abc_dup($$.c);
2031               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2032               $$.c = cut_last_push($$.c);
2033               $$.c = code_append($$.c,$3.c);
2034               $$.c = converttype($$.c, $3.t, $$.t);
2035               code_t*label = $$.c = abc_label($$.c);
2036               jmp->branch = label;              
2037              }
2038
2039 E : '!' E    {$$.c=$2.c;
2040               $$.c = abc_not($$.c);
2041               $$.t = TYPE_BOOLEAN;
2042              }
2043
2044 E : '~' E    {$$.c=$2.c;
2045               $$.c = abc_bitnot($$.c);
2046               $$.t = TYPE_INT;
2047              }
2048
2049 E : E '&' E {$$.c = code_append($1.c,$3.c);
2050              $$.c = abc_bitand($$.c);
2051              $$.t = TYPE_INT;
2052             }
2053
2054 E : E '^' E {$$.c = code_append($1.c,$3.c);
2055              $$.c = abc_bitxor($$.c);
2056              $$.t = TYPE_INT;
2057             }
2058
2059 E : E '|' E {$$.c = code_append($1.c,$3.c);
2060              $$.c = abc_bitor($$.c);
2061              $$.t = TYPE_INT;
2062             }
2063
2064 E : E '-' E {$$.c = code_append($1.c,$3.c);
2065              if(BOTH_INT($1,$3)) {
2066                 $$.c = abc_subtract_i($$.c);
2067                 $$.t = TYPE_INT;
2068              } else {
2069                 $$.c = abc_subtract($$.c);
2070                 $$.t = TYPE_NUMBER;
2071              }
2072             }
2073 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2074              $$.c = abc_rshift($$.c);
2075              $$.t = TYPE_INT;
2076             }
2077 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2078              $$.c = abc_urshift($$.c);
2079              $$.t = TYPE_INT;
2080             }
2081 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2082              $$.c = abc_lshift($$.c);
2083              $$.t = TYPE_INT;
2084             }
2085
2086 E : E '/' E {$$.c = code_append($1.c,$3.c);
2087              $$.c = abc_divide($$.c);
2088              $$.t = TYPE_NUMBER;
2089             }
2090 E : E '+' E {$$.c = code_append($1.c,$3.c);
2091              $$.c = abc_add($$.c);
2092              $$.t = TYPE_NUMBER;
2093             }
2094 E : E '%' E {$$.c = code_append($1.c,$3.c);
2095              $$.c = abc_modulo($$.c);
2096              $$.t = TYPE_NUMBER;
2097             }
2098 E : E '*' E {$$.c = code_append($1.c,$3.c);
2099              if(BOTH_INT($1,$3)) {
2100                 $$.c = abc_multiply_i($$.c);
2101                 $$.t = TYPE_INT;
2102              } else {
2103                 $$.c = abc_multiply($$.c);
2104                 $$.t = TYPE_NUMBER;
2105              }
2106             }
2107
2108 E : E "in" E {$$.c = code_append($1.c,$3.c);
2109               $$.c = abc_in($$.c);
2110               $$.t = TYPE_BOOLEAN;
2111              }
2112
2113 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2114               if(use_astype && TYPE_IS_CLASS($3.t)) {
2115                 MULTINAME(m,$3.t->cls);
2116                 $$.c = abc_astype2($1.c, &m);
2117                 $$.t = $3.t->cls;
2118               } else {
2119                 $$.c = code_append($1.c, $3.c);
2120                 $$.c = abc_astypelate($$.c);
2121                 $$.t = TYPE_ANY;
2122               }
2123              }
2124
2125 E : E "instanceof" E 
2126              {$$.c = code_append($1.c, $3.c);
2127               $$.c = abc_instanceof($$.c);
2128               $$.t = TYPE_BOOLEAN;
2129              }
2130
2131 E : E "is" E {$$.c = code_append($1.c, $3.c);
2132               $$.c = abc_istypelate($$.c);
2133               $$.t = TYPE_BOOLEAN;
2134              }
2135
2136 E : "typeof" '(' E ')' {
2137               $$.c = $3.c;
2138               $$.c = abc_typeof($$.c);
2139               $$.t = TYPE_STRING;
2140              }
2141
2142 E : "void" E {
2143               $$.c = cut_last_push($2.c);
2144               $$.c = abc_pushundefined($$.c);
2145               $$.t = TYPE_ANY;
2146              }
2147
2148 E : "void" { $$.c = abc_pushundefined(0);
2149              $$.t = TYPE_ANY;
2150            }
2151
2152 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2153
2154 E : '-' E {
2155   $$=$2;
2156   if(IS_INT($2)) {
2157    $$.c=abc_negate_i($$.c);
2158    $$.t = TYPE_INT;
2159   } else {
2160    $$.c=abc_negate($$.c);
2161    $$.t = TYPE_NUMBER;
2162   }
2163 }
2164
2165 E : E '[' E ']' {
2166   $$.c = $1.c;
2167   $$.c = code_append($$.c, $3.c);
2168  
2169   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2170   $$.c = abc_getproperty2($$.c, &m);
2171   $$.t = 0; // array elements have unknown type
2172 }
2173
2174 E : '[' MAYBE_EXPRESSION_LIST ']' {
2175     $$.c = code_new();
2176     $$.c = code_append($$.c, $2.cc);
2177     $$.c = abc_newarray($$.c, $2.len);
2178     $$.t = registry_getarrayclass();
2179 }
2180
2181 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2182 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1};
2183
2184 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2185     $$.cc = 0;
2186     $$.cc = code_append($$.cc, $1.c);
2187     $$.cc = code_append($$.cc, $3.c);
2188     $$.len = 2;
2189 }
2190 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2191     $$.cc = $1.cc;
2192     $$.len = $1.len+2;
2193     $$.cc = code_append($$.cc, $3.c);
2194     $$.cc = code_append($$.cc, $5.c);
2195 }
2196 //MAYBECOMMA: ','
2197 //MAYBECOMMA:
2198
2199 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2200     $$.c = code_new();
2201     $$.c = code_append($$.c, $2.cc);
2202     $$.c = abc_newobject($$.c, $2.len/2);
2203     $$.t = registry_getobjectclass();
2204 }
2205
2206 E : E "*=" E { 
2207                code_t*c = $3.c;
2208                if(BOTH_INT($1,$3)) {
2209                 c=abc_multiply_i(c);
2210                } else {
2211                 c=abc_multiply(c);
2212                }
2213                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2214                $$.c = toreadwrite($1.c, c, 0, 0);
2215                $$.t = $1.t;
2216               }
2217
2218 E : E "%=" E { 
2219                code_t*c = abc_modulo($3.c);
2220                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2221                $$.c = toreadwrite($1.c, c, 0, 0);
2222                $$.t = $1.t;
2223               }
2224 E : E "<<=" E { 
2225                code_t*c = abc_lshift($3.c);
2226                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2227                $$.c = toreadwrite($1.c, c, 0, 0);
2228                $$.t = $1.t;
2229               }
2230 E : E ">>=" E { 
2231                code_t*c = abc_rshift($3.c);
2232                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2233                $$.c = toreadwrite($1.c, c, 0, 0);
2234                $$.t = $1.t;
2235               }
2236 E : E ">>>=" E { 
2237                code_t*c = abc_urshift($3.c);
2238                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2239                $$.c = toreadwrite($1.c, c, 0, 0);
2240                $$.t = $1.t;
2241               }
2242 E : E "/=" E { 
2243                code_t*c = abc_divide($3.c);
2244                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2245                $$.c = toreadwrite($1.c, c, 0, 0);
2246                $$.t = $1.t;
2247               }
2248 E : E "+=" E { 
2249                code_t*c = $3.c;
2250                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2251                 c=abc_add_i(c);
2252                } else {
2253                 c=abc_add(c);
2254                }
2255                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2256                
2257                $$.c = toreadwrite($1.c, c, 0, 0);
2258                $$.t = $1.t;
2259               }
2260 E : E "-=" E { code_t*c = $3.c; 
2261                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
2262                 c=abc_subtract_i(c);
2263                } else {
2264                 c=abc_subtract(c);
2265                }
2266                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2267                
2268                $$.c = toreadwrite($1.c, c, 0, 0);
2269                $$.t = $1.t;
2270              }
2271 E : E '=' E { code_t*c = 0;
2272               c = code_append(c, $3.c);
2273               c = converttype(c, $3.t, $1.t);
2274               $$.c = toreadwrite($1.c, c, 1, 0);
2275               $$.t = $1.t;
2276             }
2277
2278 E : E '?' E ':' E %prec below_assignment { 
2279               $$.c = $1.c;
2280               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2281               $$.c = code_append($$.c, $3.c);
2282               code_t*j2 = $$.c = abc_jump($$.c, 0);
2283               $$.c = j1->branch = abc_label($$.c);
2284               $$.c = code_append($$.c, $5.c);
2285               $$.c = j2->branch = abc_label($$.c);
2286               $$.t = join_types($3.t,$5.t,'?');
2287             }
2288
2289 // TODO: use inclocal where appropriate
2290 E : E "++" { code_t*c = 0;
2291              classinfo_t*type = $1.t;
2292              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2293                  c=abc_increment_i(c);
2294                  type = TYPE_INT;
2295              } else {
2296                  c=abc_increment(c);
2297                  type = TYPE_NUMBER;
2298              }
2299              c=converttype(c, type, $1.t);
2300              $$.c = toreadwrite($1.c, c, 0, 1);
2301              $$.t = $1.t;
2302            }
2303 E : E "--" { code_t*c = 0;
2304              classinfo_t*type = $1.t;
2305              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2306                  c=abc_decrement_i(c);
2307                  type = TYPE_INT;
2308              } else {
2309                  c=abc_decrement(c);
2310                  type = TYPE_NUMBER;
2311              }
2312              c=converttype(c, type, $1.t);
2313              $$.c = toreadwrite($1.c, c, 0, 1);
2314              $$.t = $1.t;
2315             }
2316
2317 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2318              classinfo_t*type = $2.t;
2319              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2320                  c=abc_increment_i(c);
2321                  type = TYPE_INT;
2322              } else {
2323                  c=abc_increment(c);
2324                  type = TYPE_NUMBER;
2325              }
2326              c=converttype(c, type, $2.t);
2327              $$.c = toreadwrite($2.c, c, 0, 0);
2328              $$.t = $2.t;
2329            }
2330
2331 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2332              classinfo_t*type = $2.t;
2333              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2334                  c=abc_decrement_i(c);
2335                  type = TYPE_INT;
2336              } else {
2337                  c=abc_decrement(c);
2338                  type = TYPE_NUMBER;
2339              }
2340              c=converttype(c, type, $2.t);
2341              $$.c = toreadwrite($2.c, c, 0, 0);
2342              $$.t = $2.t;
2343            }
2344
2345 E : "super" '.' T_IDENTIFIER 
2346            { if(!state->cls->info)
2347                   syntaxerror("super keyword not allowed outside a class");
2348               classinfo_t*t = state->cls->info->superclass;
2349               if(!t) t = TYPE_OBJECT;
2350
2351               memberinfo_t*f = registry_findmember(t, $3, 1);
2352               namespace_t ns = {flags2access(f->flags), ""};
2353               MEMBER_MULTINAME(m, f, $3);
2354               $$.c = 0;
2355               $$.c = abc_getlocal_0($$.c);
2356               $$.c = abc_getsuper2($$.c, &m);
2357               $$.t = memberinfo_gettype(f);
2358            }
2359
2360 E : E '.' T_IDENTIFIER
2361             {$$.c = $1.c;
2362              classinfo_t*t = $1.t;
2363              char is_static = 0;
2364              if(TYPE_IS_CLASS(t) && t->cls) {
2365                  t = t->cls;
2366                  is_static = 1;
2367              }
2368              if(t) {
2369                  memberinfo_t*f = registry_findmember(t, $3, 1);
2370                  char noslot = 0;
2371                  if(f && !is_static != !(f->flags&FLAG_STATIC))
2372                     noslot=1;
2373                  if(f && f->slot && !noslot) {
2374                      $$.c = abc_getslot($$.c, f->slot);
2375                  } else {
2376                      MEMBER_MULTINAME(m, f, $3);
2377                      $$.c = abc_getproperty2($$.c, &m);
2378                  }
2379                  /* determine type */
2380                  $$.t = memberinfo_gettype(f);
2381                  if(!$$.t)
2382                     $$.c = abc_coerce_a($$.c);
2383              } else {
2384                  /* when resolving a property on an unknown type, we do know the
2385                     name of the property (and don't seem to need the package), but
2386                     we need to make avm2 try out all access modes */
2387                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
2388                  $$.c = abc_getproperty2($$.c, &m);
2389                  $$.c = abc_coerce_a($$.c);
2390                  $$.t = registry_getanytype();
2391              }
2392             }
2393
2394 VAR_READ : T_IDENTIFIER {
2395     $$.t = 0;
2396     $$.c = 0;
2397     classinfo_t*a = 0;
2398     memberinfo_t*f = 0;
2399
2400     variable_t*v;
2401     /* look at variables */
2402     if((v = find_variable($1))) {
2403         // $1 is a local variable
2404         $$.c = abc_getlocal($$.c, v->index);
2405         $$.t = v->type;
2406
2407     /* look at current class' members */
2408     } else if((f = registry_findmember(state->cls->info, $1, 1))) {
2409         // $1 is a function in this class
2410         int var_is_static = (f->flags&FLAG_STATIC);
2411         int i_am_static = ((state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC);
2412         if(var_is_static != i_am_static) {
2413             /* there doesn't seem to be any "static" way to access
2414                static properties of a class */
2415             state->method->late_binding = 1;
2416             $$.t = f->type;
2417             namespace_t ns = {flags2access(f->flags), ""};
2418             multiname_t m = {QNAME, &ns, 0, $1};
2419             $$.c = abc_findpropstrict2($$.c, &m);
2420             $$.c = abc_getproperty2($$.c, &m);
2421         } else {
2422             if(f->slot>0) {
2423                 $$.c = abc_getlocal_0($$.c);
2424                 $$.c = abc_getslot($$.c, f->slot);
2425             } else {
2426                 namespace_t ns = {flags2access(f->flags), ""};
2427                 multiname_t m = {QNAME, &ns, 0, $1};
2428                 $$.c = abc_getlocal_0($$.c);
2429                 $$.c = abc_getproperty2($$.c, &m);
2430             }
2431         }
2432         if(f->kind == MEMBER_METHOD) {
2433             $$.t = TYPE_FUNCTION(f);
2434         } else {
2435             $$.t = f->type;
2436         }
2437     
2438     /* look at actual classes, in the current package and imported */
2439     } else if((a = find_class($1))) {
2440         if(a->flags & FLAG_METHOD) {
2441             MULTINAME(m, a);
2442             $$.c = abc_findpropstrict2($$.c, &m);
2443             $$.c = abc_getproperty2($$.c, &m);
2444             $$.t = TYPE_FUNCTION(a->function);
2445         } else {
2446             if(a->slot) {
2447                 $$.c = abc_getglobalscope($$.c);
2448                 $$.c = abc_getslot($$.c, a->slot);
2449             } else {
2450                 MULTINAME(m, a);
2451                 $$.c = abc_getlex2($$.c, &m);
2452             }
2453             $$.t = TYPE_CLASS(a);
2454         }
2455
2456     /* unknown object, let the avm2 resolve it */
2457     } else {
2458         if(strcmp($1,"trace"))
2459             warning("Couldn't resolve '%s', doing late binding", $1);
2460         state->method->late_binding = 1;
2461                 
2462         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
2463
2464         $$.t = 0;
2465         $$.c = abc_findpropstrict2($$.c, &m);
2466         $$.c = abc_getproperty2($$.c, &m);
2467     }
2468 }
2469
2470 //TODO: 
2471 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
2472 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
2473 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
2474
2475 // ----------------- namespaces -------------------------------------------------
2476
2477 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=$2;}
2478 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=$2;}
2479 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=$2;}
2480
2481 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
2482