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