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