fixed a few mem leaks
[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 extern int a3_lex();
36
37 %}
38
39 //%glr-parser
40 //%expect-rr 1
41 %error-verbose
42
43 %union tokenunion {
44     enum yytokentype token;
45     int flags;
46
47     classinfo_t*classinfo;
48     classinfo_list_t*classinfo_list;
49
50     int number_int;
51     unsigned int number_uint;
52     double number_float;
53     code_t*code;
54     typedcode_t value;
55     //typedcode_list_t*value_list;
56     codeandnumber_t value_list;
57     param_t* param;
58     params_t params;
59     string_t str;
60     char*id;
61     constant_t*constant;
62     for_start_t for_start;
63     abc_exception_t *exception;
64     regexp_t regexp;
65     struct {
66         abc_exception_list_t *l;
67         code_t*finally;
68     } catch_list;
69 }
70
71
72 %token<id> T_IDENTIFIER
73 %token<str> T_STRING
74 %token<regexp> T_REGEXP
75 %token<token> T_EMPTY
76 %token<number_int> T_INT
77 %token<number_uint> T_UINT
78 %token<number_uint> T_BYTE
79 %token<number_uint> T_SHORT
80 %token<number_float> T_FLOAT
81
82 %token<id> T_FOR "for"
83 %token<id> T_WHILE "while"
84 %token<id> T_DO "do"
85 %token<id> T_SWITCH "switch"
86
87 %token<token> KW_IMPLEMENTS "implements"
88 %token<token> KW_NAMESPACE "namespace"
89 %token<token> KW_PACKAGE "package"
90 %token<token> KW_PROTECTED "protected"
91 %token<token> KW_PUBLIC "public"
92 %token<token> KW_PRIVATE "private"
93 %token<token> KW_USE "use"
94 %token<token> KW_INTERNAL "internal"
95 %token<token> KW_NEW "new"
96 %token<token> KW_NATIVE "native"
97 %token<token> KW_FUNCTION "function"
98 %token<token> KW_FINALLY "finally"
99 %token<token> KW_UNDEFINED "undefined"
100 %token<token> KW_CONTINUE "continue"
101 %token<token> KW_CLASS "class"
102 %token<token> KW_CONST "const"
103 %token<token> KW_CATCH "catch"
104 %token<token> KW_CASE "case"
105 %token<token> KW_SET "set"
106 %token<token> KW_VOID "void"
107 %token<token> KW_THROW "throw"
108 %token<token> KW_STATIC "static"
109 %token<token> KW_WITH "with"
110 %token<token> KW_INSTANCEOF "instanceof"
111 %token<token> KW_IMPORT "import"
112 %token<token> KW_RETURN "return"
113 %token<token> KW_TYPEOF "typeof"
114 %token<token> KW_INTERFACE "interface"
115 %token<token> KW_NULL "null"
116 %token<token> KW_VAR "var"
117 %token<token> KW_DYNAMIC "dynamic"
118 %token<token> KW_OVERRIDE "override"
119 %token<token> KW_FINAL "final"
120 %token<token> KW_EACH "each"
121 %token<token> KW_GET "get"
122 %token<token> KW_TRY "try"
123 %token<token> KW_SUPER "super"
124 %token<token> KW_EXTENDS "extends"
125 %token<token> KW_FALSE "false"
126 %token<token> KW_TRUE "true"
127 %token<token> KW_BOOLEAN "Boolean"
128 %token<token> KW_UINT "uint"
129 %token<token> KW_INT "int"
130 %token<token> KW_NUMBER "Number"
131 %token<token> KW_STRING "String"
132 %token<token> KW_DEFAULT "default"
133 %token<token> KW_DELETE "delete"
134 %token<token> KW_IF "if"
135 %token<token> KW_ELSE  "else"
136 %token<token> KW_BREAK   "break"
137 %token<token> KW_IS "is"
138 %token<token> KW_IN "in"
139 %token<token> KW_AS "as"
140
141 %token<token> T_EQEQ "=="
142 %token<token> T_EQEQEQ "==="
143 %token<token> T_NE "!="
144 %token<token> T_NEE "!=="
145 %token<token> T_LE "<="
146 %token<token> T_GE ">="
147 %token<token> T_ORBY "|=" 
148 %token<token> T_DIVBY "/=" 
149 %token<token> T_MODBY "%="
150 %token<token> T_MULBY "*="
151 %token<token> T_PLUSBY "+=" 
152 %token<token> T_MINUSBY "-="
153 %token<token> T_SHRBY ">>="
154 %token<token> T_SHLBY "<<="
155 %token<token> T_USHRBY ">>>="
156 %token<token> T_OROR "||"
157 %token<token> T_ANDAND "&&"
158 %token<token> T_COLONCOLON "::"
159 %token<token> T_MINUSMINUS "--"
160 %token<token> T_PLUSPLUS "++"
161 %token<token> T_DOTDOT ".."
162 %token<token> T_DOTDOTDOT "..."
163 %token<token> T_SHL "<<"
164 %token<token> T_USHR ">>>"
165 %token<token> T_SHR ">>"
166
167 %type <for_start> FOR_START
168 %type <id> X_IDENTIFIER PACKAGE FOR_IN_INIT MAYBE_IDENTIFIER
169 %type <token> VARCONST
170 %type <code> CODE
171 %type <code> CODEPIECE CODE_STATEMENT
172 %type <code> CODEBLOCK MAYBECODE MAYBE_CASE_LIST CASE_LIST DEFAULT CASE SWITCH WITH
173 %type <code> PACKAGE_DECLARATION SLOT_DECLARATION
174 %type <code> FUNCTION_DECLARATION PACKAGE_INITCODE
175 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST THROW 
176 %type <exception> CATCH FINALLY
177 %type <catch_list> CATCH_LIST CATCH_FINALLY_LIST
178 %type <code> CLASS_DECLARATION
179 %type <code> NAMESPACE_DECLARATION
180 %type <code> INTERFACE_DECLARATION
181 %type <code> VOIDEXPRESSION
182 %type <value> EXPRESSION NONCOMMAEXPRESSION
183 %type <value> MAYBEEXPRESSION
184 %type <value> E DELETE
185 %type <value> CONSTANT
186 %type <code> FOR FOR_IN IF WHILE DO_WHILE MAYBEELSE BREAK RETURN CONTINUE TRY 
187 %type <value> INNERFUNCTION
188 %type <token> USE_NAMESPACE
189 %type <code> FOR_INIT
190 %type <code> IMPORT
191 %type <classinfo> MAYBETYPE
192 %type <token> GETSET
193 %type <param> PARAM
194 %type <params> PARAM_LIST
195 %type <params> MAYBE_PARAM_LIST
196 %type <flags> MAYBE_MODIFIERS
197 %type <flags> MODIFIER_LIST
198 %type <constant> STATICCONSTANT MAYBESTATICCONSTANT
199 %type <classinfo_list> IMPLEMENTS_LIST
200 %type <classinfo> EXTENDS
201 %type <classinfo_list> EXTENDS_LIST
202 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
203 %type <classinfo_list> QNAME_LIST
204 %type <classinfo> TYPE
205 //%type <token> VARIABLE
206 %type <value> VAR_READ
207 %type <value> NEW
208 //%type <token> T_IDENTIFIER
209 %type <token> MODIFIER
210 %type <value> FUNCTIONCALL
211 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES MAYBE_EXPRPAIR_LIST EXPRPAIR_LIST
212
213 // precedence: from low to high
214
215 %left prec_none
216
217 %left below_semicolon
218 %left ';'
219 %left ','
220 %nonassoc below_assignment // for ?:, contrary to spec
221 %right '=' "*=" "/=" "%=" "+=" "-=" "<<=" ">>=" ">>>=" "&=" "^=" "|="
222 %right '?' ':'
223 %left "||"
224 %left "&&"
225 %left '|'
226 %left '^'
227 %nonassoc '&'
228 %nonassoc "==" "!=" "===" "!=="
229 %nonassoc "is" "as" "in"
230 %nonassoc "<=" '<' ">=" '>' "instanceof" // TODO: support "a < b < c" syntax?
231 %left "<<" ">>" ">>>" 
232 %left below_minus
233 %left '-' '+'
234 %left '/' '*' '%'
235 %left plusplus_prefix minusminus_prefix '~' '!' "void" "delete" "typeof" //FIXME: *unary* + - should be here, too
236 %left "--" "++" 
237 %nonassoc below_curly
238
239 %left '('
240 %left new2
241 %left '[' ']' "new" '{' '.' ".." "::"
242
243 %nonassoc T_IDENTIFIER
244 %left above_identifier
245 %left below_else
246 %nonassoc "else"
247
248 // needed for "return" precedence:
249 %nonassoc T_STRING T_REGEXP
250 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
251 %nonassoc "false" "true" "null" "undefined" "super" "function"
252 %left above_function
253
254
255      
256 %{
257
258 static int a3_error(char*s)
259 {
260    syntaxerror("%s", s); 
261    return 0; //make gcc happy
262 }
263
264
265 static char* concat2(const char* t1, const char* t2)
266 {
267     int l1 = strlen(t1);
268     int l2 = strlen(t2);
269     char*text = malloc(l1+l2+1);
270     memcpy(text   , t1, l1);
271     memcpy(text+l1, t2, l2);
272     text[l1+l2] = 0;
273     return text;
274 }
275 static char* concat3(const char* t1, const char* t2, const char* t3)
276 {
277     int l1 = strlen(t1);
278     int l2 = strlen(t2);
279     int l3 = strlen(t3);
280     char*text = malloc(l1+l2+l3+1);
281     memcpy(text   , t1, l1);
282     memcpy(text+l1, t2, l2);
283     memcpy(text+l1+l2, t3, l3);
284     text[l1+l2+l3] = 0;
285     return text;
286 }
287
288 typedef struct _import {
289     char*package;
290 } import_t;
291
292 DECLARE_LIST(import);
293
294 typedef struct _classstate {
295     /* class data */
296     classinfo_t*info;
297     abc_class_t*abc;
298     code_t*init;
299     code_t*static_init;
300     char has_constructor;
301 } classstate_t;
302
303 DECLARE_LIST(methodstate);
304
305 typedef struct _methodstate {
306     /* method data */
307     memberinfo_t*info;
308     char late_binding;
309     char is_constructor;
310     char has_super;
311     char is_global;
312     int variable_count;
313
314     char inner;
315     abc_method_t*abc;
316     int var_index; // for inner methods
317
318     abc_exception_list_t*exceptions;
319     
320     methodstate_list_t*innerfunctions;
321 } methodstate_t;
322
323 typedef struct _state {
324     struct _state*old;
325     int level;
326     
327     char*package;     
328     import_list_t*wildcard_imports;
329     dict_t*imports;
330     char has_own_imports;
331     char new_vars; // e.g. transition between two functions
332   
333     classstate_t*cls;   
334     methodstate_t*method;
335
336     char*exception_name;
337     
338     dict_t*vars;
339 } state_t;
340
341 typedef struct _global {
342     abc_file_t*file;
343     abc_script_t*init;
344     dict_t*token2info;
345 } global_t;
346
347 static global_t*global = 0;
348 static state_t* state = 0;
349
350 DECLARE_LIST(state);
351
352 #define MULTINAME(m,x) \
353     multiname_t m;\
354     namespace_t m##_ns;\
355     registry_fill_multiname(&m, &m##_ns, x);
356                     
357 #define MEMBER_MULTINAME(m,f,n) \
358     multiname_t m;\
359     namespace_t m##_ns;\
360     if(f) { \
361         m##_ns = flags2namespace(f->flags, ""); \
362         m.type = QNAME; \
363         m.ns = &m##_ns; \
364         m.namespace_set = 0; \
365         m.name = f->name; \
366     } else { \
367         m.type = MULTINAME; \
368         m.ns =0; \
369         m.namespace_set = &nopackage_namespace_set; \
370         m.name = n; \
371     }
372
373 /* warning: list length of namespace set is undefined */
374 #define MULTINAME_LATE(m, access, package) \
375     namespace_t m##_ns = {access, package}; \
376     namespace_set_t m##_nsset; \
377     namespace_list_t m##_l;m##_l.next = 0; \
378     m##_nsset.namespaces = &m##_l; \
379     m##_nsset = m##_nsset; \
380     m##_l.namespace = &m##_ns; \
381     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
382
383 static namespace_t ns1 = {ACCESS_PRIVATE, ""};
384 static namespace_t ns2 = {ACCESS_PROTECTED, ""};
385 static namespace_t ns3 = {ACCESS_PACKAGEINTERNAL, ""};
386 static namespace_t ns4 = {ACCESS_PACKAGE, ""};
387 static namespace_list_t nl4 = {&ns4,0};
388 static namespace_list_t nl3 = {&ns3,&nl4};
389 static namespace_list_t nl2 = {&ns2,&nl3};
390 static namespace_list_t nl1 = {&ns1,&nl2};
391 static namespace_set_t nopackage_namespace_set = {&nl1};
392
393 static void new_state()
394 {
395     NEW(state_t, s);
396     state_t*oldstate = state;
397     if(state)
398         memcpy(s, state, sizeof(state_t)); //shallow copy
399     if(!s->imports) {
400         s->imports = dict_new();
401     }
402     state = s;
403     state->level++;
404     state->has_own_imports = 0;    
405     state->vars = dict_new(); 
406     state->old = oldstate;
407 }
408 static void state_has_imports()
409 {
410     state->wildcard_imports = list_clone(state->wildcard_imports);
411     state->imports = dict_clone(state->imports);
412     state->has_own_imports = 1;
413 }
414
415 static void state_destroy(state_t*state)
416 {
417     if(state->has_own_imports) {
418         list_free(state->wildcard_imports);
419         dict_destroy(state->imports);state->imports=0;
420     }
421     if(state->imports && (!state->old || state->old->imports!=state->imports)) {
422         dict_destroy(state->imports);state->imports=0;
423     }
424     if(state->vars) {
425         int t;
426         for(t=0;t<state->vars->hashsize;t++) {
427             dictentry_t*e =state->vars->slots[t];
428             while(e) {
429                 free(e->data);e->data=0;
430                 e = e->next;
431             }
432         }
433         dict_destroy(state->vars);state->vars=0;
434     }
435     
436     free(state);
437 }
438
439 static void old_state()
440 {
441     if(!state || !state->old)
442         syntaxerror("invalid nesting");
443     state_t*leaving = state;
444     
445     state = state->old;
446     
447     if(as3_pass>1 && leaving->method && leaving->method != state->method && !leaving->method->inner) {
448         free(leaving->method);
449         leaving->method=0;
450     }
451     if(leaving->cls && leaving->cls != state->cls) {
452         free(leaving->cls);
453         leaving->cls=0;
454     }
455     
456     state_destroy(leaving);
457 }
458
459 void initialize_file(char*filename)
460 {
461     new_state();
462     state->package = strdup(filename);
463     
464     state->method = rfx_calloc(sizeof(methodstate_t));
465     state->method->variable_count = 1;
466 }
467
468 void finish_file()
469 {
470     if(!state || state->level!=1) {
471         syntaxerror("unexpected end of file in pass %d", as3_pass);
472     }
473     free(state->package);state->package=0;
474     state_destroy(state);state=0;
475 }
476
477 void initialize_parser()
478 {
479     global = rfx_calloc(sizeof(global_t));
480     global->file = abc_file_new();
481     global->file->flags &= ~ABCFILE_LAZY;
482     global->token2info = dict_new2(&ptr_type);
483     
484     global->init = abc_initscript(global->file);
485     code_t*c = global->init->method->body->code;
486     c = abc_getlocal_0(c);
487     c = abc_pushscope(c);
488     global->init->method->body->code = c;
489 }
490
491 void* finish_parser()
492 {
493     code_t*c = global->init->method->body->code;
494     /*c = abc_findpropstrict(c, "[package]::trace");
495       c = abc_pushstring(c, "[leaving global init function]");
496       c = abc_callpropvoid(c, "[package]::trace", 1);*/
497     c = abc_returnvoid(c);
498     global->init->method->body->code = c;
499     dict_destroy(global->token2info);global->token2info=0;
500     return global->file;
501 }
502
503
504 static void xx_scopetest() 
505 {
506     /* findpropstrict doesn't just return a scope object- it
507        also makes it "active" somehow. Push local_0 on the
508        scope stack and read it back with findpropstrict, it'll
509        contain properties like "trace". Trying to find the same
510        property on a "vanilla" local_0 yields only a "undefined" */
511     //c = abc_findpropstrict(c, "[package]::trace");
512     
513     /*c = abc_getlocal_0(c);
514     c = abc_findpropstrict(c, "[package]::trace");
515     c = abc_coerce_a(c);
516     c = abc_setlocal_1(c);
517
518     c = abc_pushbyte(c, 0);
519     c = abc_setlocal_2(c);
520    
521     code_t*xx = c = abc_label(c);
522     c = abc_findpropstrict(c, "[package]::trace");
523     c = abc_pushstring(c, "prop:");
524     c = abc_hasnext2(c, 1, 2);
525     c = abc_dup(c);
526     c = abc_setlocal_3(c);
527     c = abc_callpropvoid(c, "[package]::trace", 2);
528     c = abc_getlocal_3(c);
529     c = abc_kill(c, 3);
530     c = abc_iftrue(c,xx);*/
531 }
532
533
534 typedef struct _variable {
535     int index;
536     classinfo_t*type;
537     char init;
538 } variable_t;
539
540 static variable_t* find_variable(char*name)
541 {
542     state_t* s = state;
543     while(s) {
544         variable_t*v = 0;
545         if(s->method)
546             v = dict_lookup(s->vars, name);
547         if(v) {
548             return v;
549         }
550         if(s->new_vars)
551             break;
552         s = s->old;
553     }
554     return 0;
555
556 static variable_t* find_variable_safe(char*name)
557 {
558     variable_t* v = find_variable(name);
559     if(!v)
560         syntaxerror("undefined variable: %s", name);
561     return v;
562 }
563 static char variable_exists(char*name) 
564 {
565     return dict_lookup(state->vars, name)!=0;
566 }
567 code_t*defaultvalue(code_t*c, classinfo_t*type);
568 static int new_variable(const char*name, classinfo_t*type, char init)
569 {
570     NEW(variable_t, v);
571     v->index = state->method->variable_count;
572     v->type = type;
573     v->init = init;
574     
575     dict_put(state->vars, name, v);
576
577     return state->method->variable_count++;
578 }
579 #define TEMPVARNAME "__as3_temp__"
580 static int gettempvar()
581 {
582     variable_t*v = find_variable(TEMPVARNAME);
583     if(v) 
584         return v->index;
585     return new_variable(TEMPVARNAME, 0, 0);
586 }
587
588 code_t* var_block(code_t*body) 
589 {
590     code_t*c = 0;
591     code_t*k = 0;
592     int t;
593     int num=0;
594     for(t=0;t<state->vars->hashsize;t++) {
595         dictentry_t*e = state->vars->slots[t];
596         while(e) {
597             variable_t*v = (variable_t*)e->data;
598             if(v->type && v->init) {
599                 c = defaultvalue(c, v->type);
600                 c = abc_setlocal(c, v->index);
601                 k = abc_kill(k, v->index); 
602                 num++;
603             }
604             e = e->next;
605         }
606     }
607
608     if(k) {
609         code_t*x = body;
610         while(x) {
611             if(x->opcode== OPCODE___BREAK__ ||
612                x->opcode== OPCODE___CONTINUE__) {
613                /* link kill code before break/continue */
614                 code_t*e = code_dup(k);
615                 code_t*s = code_start(e);
616                 s->prev = x->prev;
617                 if(x->prev) {
618                     x->prev->next = s;
619                 }
620                 e->next = x;
621                 x->prev = e;
622             }
623             x = x->prev;
624         }
625     }
626     
627     c = code_append(c, body);
628     c = code_append(c, k);
629     return c;
630 }
631
632 #define parserassert(b) {if(!(b)) parsererror(__FILE__, __LINE__,__func__);}
633
634 static void parsererror(const char*file, int line, const char*f)
635 {
636     syntaxerror("internal error in %s, %s:%d", f, file, line);
637 }
638
639    
640 code_t* method_header()
641 {
642     code_t*c = 0;
643     if(state->method->late_binding && !state->method->inner) {
644         c = abc_getlocal_0(c);
645         c = abc_pushscope(c);
646     }
647     /*if(state->method->innerfunctions) {
648         c = abc_newactivation(c);
649         c = abc_pushscope(c);
650     }*/
651     if(state->method->is_constructor && !state->method->has_super) {
652         // call default constructor
653         c = abc_getlocal_0(c);
654         c = abc_constructsuper(c, 0);
655     }
656     methodstate_list_t*l = state->method->innerfunctions;
657     while(l) {
658         parserassert(l->methodstate->abc);
659         c = abc_newfunction(c, l->methodstate->abc);
660         c = abc_setlocal(c, l->methodstate->var_index);
661         free(l->methodstate);l->methodstate=0;
662         l = l->next;
663     }
664     list_free(state->method->innerfunctions);
665     state->method->innerfunctions = 0;
666     return c;
667 }
668     
669
670 static code_t* wrap_function(code_t*c,code_t*header, code_t*body)
671 {
672     c = code_append(c, header);
673     c = code_append(c, var_block(body));
674     /* append return if necessary */
675     if(!c || (c->opcode != OPCODE_RETURNVOID && 
676               c->opcode != OPCODE_RETURNVALUE)) {
677         c = abc_returnvoid(c);
678     }
679     return c;
680 }
681
682
683 static void startpackage(char*name)
684 {
685     new_state();
686     /*printf("entering package \"%s\"\n", name);*/
687     state->package = strdup(name);
688 }
689 static void endpackage()
690 {
691     /*printf("leaving package \"%s\"\n", state->package);*/
692
693     //used e.g. in classinfo_register:
694     //free(state->package);state->package=0;
695
696     old_state();
697 }
698
699
700 char*as3_globalclass=0;
701 static void startclass(int flags, char*classname, classinfo_t*extends, classinfo_list_t*implements, char interface)
702 {
703     if(state->cls) {
704         syntaxerror("inner classes now allowed"); 
705     }
706     new_state();
707     state->cls = rfx_calloc(sizeof(classstate_t));
708     state->method = rfx_calloc(sizeof(methodstate_t)); // method state, for static constructor
709     state->method->variable_count = 1;
710
711     token_list_t*t=0;
712     classinfo_list_t*mlist=0;
713
714     if(flags&~(FLAG_PACKAGEINTERNAL|FLAG_PUBLIC|FLAG_FINAL|FLAG_DYNAMIC))
715         syntaxerror("invalid modifier(s)");
716
717     if((flags&(FLAG_PUBLIC|FLAG_PACKAGEINTERNAL)) == (FLAG_PUBLIC|FLAG_PACKAGEINTERNAL))
718         syntaxerror("public and internal not supported at the same time.");
719
720     /* create the class name, together with the proper attributes */
721     int access=0;
722     char*package=0;
723
724     if(!(flags&FLAG_PUBLIC) && !state->package) {
725         access = ACCESS_PRIVATE; package = current_filename;
726     } else if(!(flags&FLAG_PUBLIC) && state->package) {
727         access = ACCESS_PACKAGEINTERNAL; package = state->package;
728     } else if(state->package) {
729         access = ACCESS_PACKAGE; package = state->package;
730     } else {
731         syntaxerror("public classes only allowed inside a package");
732     }
733
734     if(as3_pass==1) {
735         if(registry_findclass(package, classname)) {
736             syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
737         }
738         /* build info struct */
739         int num_interfaces = (list_length(implements));
740         state->cls->info = classinfo_register(access, package, classname, num_interfaces);
741     }
742     
743     if(as3_pass == 2) {
744         state->cls->info = registry_findclass(package, classname);
745         parserassert((int)state->cls->info);
746
747         /* fill out interfaces and extends (we couldn't resolve those during the first pass) */
748         state->cls->info->superclass = extends?extends:TYPE_OBJECT;
749         int pos = 0;
750         classinfo_list_t*l = implements;
751         for(l=implements;l;l=l->next) {
752             state->cls->info->interfaces[pos++] = l->classinfo;
753         }
754
755         /* generate the abc code for this class */
756         MULTINAME(classname2,state->cls->info);
757         multiname_t*extends2 = sig2mname(extends);
758
759         state->cls->abc = abc_class_new(global->file, &classname2, extends2);
760         if(flags&FLAG_FINAL) abc_class_final(state->cls->abc);
761         if(!(flags&FLAG_DYNAMIC)) abc_class_sealed(state->cls->abc);
762         if(interface) {
763             state->cls->info->flags |= CLASS_INTERFACE;
764             abc_class_interface(state->cls->abc);
765         }
766
767         abc_class_protectedNS(state->cls->abc, classname);
768
769         for(mlist=implements;mlist;mlist=mlist->next) {
770             MULTINAME(m, mlist->classinfo);
771             abc_class_add_interface(state->cls->abc, &m);
772         }
773
774         /* write the construction code for this class to the global init
775            function */
776         int slotindex = abc_initscript_addClassTrait(global->init, &classname2, state->cls->abc);
777
778         abc_method_body_t*m = global->init->method->body;
779         __ getglobalscope(m);
780         classinfo_t*s = extends;
781
782         int count=0;
783         
784         while(s) {
785             //TODO: take a look at the current scope stack, maybe 
786             //      we can re-use something
787             s = s->superclass;
788             if(!s) 
789             break;
790            
791             multiname_t*s2 = sig2mname(s);
792             __ getlex2(m, s2);
793             multiname_destroy(s2);
794
795             __ pushscope(m); count++;
796             m->code = m->code->prev->prev; // invert
797         }
798         /* continue appending after last op end */
799         while(m->code && m->code->next) m->code = m->code->next; 
800
801         /* TODO: if this is one of *our* classes, we can also 
802                  do a getglobalscope/getslot <nr> (which references
803                  the init function's slots) */
804         if(extends2) {
805             __ getlex2(m, extends2);
806             __ dup(m);
807             /* notice: we get a Verify Error #1107 if the top elemnt on the scope
808                stack is not the superclass */
809             __ pushscope(m);count++;
810         } else {
811             __ pushnull(m);
812             /* notice: we get a verify error #1107 if the top element on the scope 
813                stack is not the global object */
814             __ getlocal_0(m);
815             __ pushscope(m);count++;
816         }
817         __ newclass(m,state->cls->abc);
818         while(count--) {
819             __ popscope(m);
820         }
821         __ setslot(m, slotindex);
822         multiname_destroy(extends2);
823
824         /* flash.display.MovieClip handling */
825
826         if(!as3_globalclass && (flags&FLAG_PUBLIC) && classinfo_equals(registry_getMovieClip(),extends)) {
827             if(state->package && state->package[0]) {
828                 as3_globalclass = concat3(state->package, ".", classname);
829             } else {
830                 as3_globalclass = strdup(classname);
831             }
832         }
833     }
834 }
835
836 static void endclass()
837 {
838     if(as3_pass == 2) {
839         if(!state->cls->has_constructor && !(state->cls->info->flags&CLASS_INTERFACE)) {
840             code_t*c = 0;
841             c = abc_getlocal_0(c);
842             c = abc_constructsuper(c, 0);
843             state->cls->init = code_append(state->cls->init, c);
844         }
845         if(!state->method->late_binding) {
846             // class initialization code uses late binding
847             code_t*c = 0;
848             c = abc_getlocal_0(c);
849             c = abc_pushscope(c);
850             state->cls->static_init = code_append(c, state->cls->static_init);
851         }
852
853         if(state->cls->init) {
854             abc_method_t*m = abc_class_getconstructor(state->cls->abc, 0);
855             m->body->code = wrap_function(0, state->cls->init, m->body->code);
856         }
857         if(state->cls->static_init) {
858             abc_method_t*m = abc_class_getstaticconstructor(state->cls->abc, 0);
859             m->body->code = wrap_function(0, state->cls->static_init, m->body->code);
860         }
861     }
862
863     old_state();
864 }
865
866 void check_code_for_break(code_t*c)
867 {
868     while(c) {
869         if(c->opcode == OPCODE___BREAK__) {
870             char*name = string_cstr(c->data[0]);
871             syntaxerror("Unresolved \"break %s\"", name);
872         }
873         if(c->opcode == OPCODE___CONTINUE__) {
874             char*name = string_cstr(c->data[0]);
875             syntaxerror("Unresolved \"continue %s\"", name);
876         }
877         c=c->prev;
878     }
879 }
880
881
882 static void check_constant_against_type(classinfo_t*t, constant_t*c)
883 {
884 #define xassert(b) if(!(b)) syntaxerror("Invalid default value %s for type '%s'", constant_tostring(c), t->name)
885    if(TYPE_IS_NUMBER(t)) {
886         xassert(c->type == CONSTANT_FLOAT
887              || c->type == CONSTANT_INT
888              || c->type == CONSTANT_UINT);
889    } else if(TYPE_IS_UINT(t)) {
890         xassert(c->type == CONSTANT_UINT ||
891                (c->type == CONSTANT_INT && c->i>0));
892    } else if(TYPE_IS_INT(t)) {
893         xassert(c->type == CONSTANT_INT);
894    } else if(TYPE_IS_BOOLEAN(t)) {
895         xassert(c->type == CONSTANT_TRUE
896              || c->type == CONSTANT_FALSE);
897    }
898 }
899
900
901 static int flags2access(int flags)
902 {
903     int access = 0;
904     if(flags&FLAG_PUBLIC)  {
905         if(access&(FLAG_PRIVATE|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
906             syntaxerror("invalid combination of access levels");
907         access = ACCESS_PACKAGE;
908     } else if(flags&FLAG_PRIVATE) {
909         if(access&(FLAG_PUBLIC|FLAG_PROTECTED|FLAG_PACKAGEINTERNAL)) 
910             syntaxerror("invalid combination of access levels");
911         access = ACCESS_PRIVATE;
912     } else if(flags&FLAG_PROTECTED) {
913         if(access&(FLAG_PUBLIC|FLAG_PRIVATE|FLAG_PACKAGEINTERNAL)) 
914             syntaxerror("invalid combination of access levels");
915         access = ACCESS_PROTECTED;
916     } else {
917         access = ACCESS_PACKAGEINTERNAL;
918     }
919     return access;
920 }
921
922
923 static memberinfo_t*registerfunction(enum yytokentype getset, int flags, char*name, params_t*params, classinfo_t*return_type, int slot)
924 {
925     memberinfo_t*minfo = 0;
926     if(!state->cls) {
927         //package method
928         minfo = memberinfo_register_global(flags2access(flags), state->package, name, MEMBER_METHOD);
929         minfo->return_type = return_type;
930     } else if(getset != KW_GET && getset != KW_SET) {
931         //class method
932         if((minfo = registry_findmember(state->cls->info, name, 0))) {
933             if(minfo->parent == state->cls->info) {
934                 syntaxerror("class already contains a member/method called '%s'", name);
935             } else if(!minfo->parent) {
936                 syntaxerror("internal error: overriding method %s, which doesn't have parent", name);
937             } else {
938                 if(!(minfo->flags&(FLAG_STATIC|FLAG_PRIVATE)))
939                     syntaxerror("function %s already exists in superclass. Did you forget the 'override' keyword?");
940             }
941         }
942         minfo = memberinfo_register(state->cls->info, name, MEMBER_METHOD);
943         minfo->return_type = return_type;
944         // getslot on a member slot only returns "undefined", so no need
945         // to actually store these
946         //state->minfo->slot = state->method->abc->method->trait->slot_id;
947     } else {
948         //class getter/setter
949         int gs = getset==KW_GET?MEMBER_GET:MEMBER_SET;
950         classinfo_t*type=0;
951         if(getset == KW_GET)
952             type = return_type;
953         else if(params->list && params->list->param)
954             type = params->list->param->type;
955         // not sure wether to look into superclasses here, too
956         if((minfo=registry_findmember(state->cls->info, name, 0))) {
957             if(minfo->kind & ~(MEMBER_GET|MEMBER_SET))
958                 syntaxerror("class already contains a member or method called '%s'", name);
959             if(minfo->kind & gs)
960                 syntaxerror("getter/setter for '%s' already defined", name);
961             /* make a setter or getter into a getset */
962             minfo->kind |= gs;
963             if(!minfo->type) 
964                 minfo->type = type;
965             else
966                 if(type && minfo->type != type)
967                     syntaxerror("different type in getter and setter");
968         } else {
969             minfo = memberinfo_register(state->cls->info, name, gs);
970             minfo->type = type;
971         }
972         /* can't assign a slot as getter and setter might have different slots */
973         //minfo->slot = slot;
974     }
975     if(flags&FLAG_STATIC) minfo->flags |= FLAG_STATIC;
976     if(flags&FLAG_PUBLIC) minfo->flags |= FLAG_PUBLIC;
977     if(flags&FLAG_PRIVATE) minfo->flags |= FLAG_PRIVATE;
978     if(flags&FLAG_PROTECTED) minfo->flags |= FLAG_PROTECTED;
979     if(flags&FLAG_PACKAGEINTERNAL) minfo->flags |= FLAG_PACKAGEINTERNAL;
980     if(flags&FLAG_OVERRIDE) minfo->flags |= FLAG_OVERRIDE;
981     return minfo;
982 }
983
984 static void function_initvars(params_t*params, int flags)
985 {
986     if(state->method->inner)
987         new_variable("this", 0, 0);
988     else if(!state->method->is_global)
989         new_variable((flags&FLAG_STATIC)?"class":"this", state->cls->info, 0);
990     else
991         new_variable("globalscope", 0, 0);
992
993     param_list_t*p=0;
994     for(p=params->list;p;p=p->next) {
995         new_variable(p->param->name, p->param->type, 0);
996     }
997     
998     methodstate_list_t*l = state->method->innerfunctions;
999     while(l) {
1000         methodstate_t*m = l->methodstate;
1001         m->var_index = new_variable(m->info->name, TYPE_FUNCTION(m->info), 0);
1002         l = l->next;
1003     }
1004 }
1005
1006 static void innerfunction(char*name, params_t*params, classinfo_t*return_type)
1007 {
1008     parserassert(state->method && state->method->info);
1009
1010     methodstate_t*parent_method = state->method;
1011
1012     if(as3_pass==1) {
1013         // not valid yet
1014         params = 0;
1015         return_type = 0;
1016     }
1017
1018     new_state();
1019     state->new_vars = 1;
1020    
1021     if(as3_pass == 1) {
1022         state->method = rfx_calloc(sizeof(methodstate_t));
1023         state->method->inner = 1;
1024         state->method->variable_count = 0;
1025         state->method->abc = rfx_calloc(sizeof(abc_method_t));
1026
1027         NEW(memberinfo_t,minfo);
1028         minfo->name = name;
1029         state->method->info = minfo;
1030
1031         list_append(parent_method->innerfunctions, state->method);
1032
1033         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1034     }
1035
1036     if(as3_pass == 2) {
1037         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1038         parserassert(state->method);
1039
1040         state->method->info->return_type = return_type;
1041         function_initvars(params, 0);
1042     }
1043 }
1044
1045 static void startfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1046                           params_t*params, classinfo_t*return_type)
1047 {
1048     if(state->method && state->method->info) {
1049         syntaxerror("not able to start another method scope");
1050     }
1051     new_state();
1052     
1053     if(as3_pass == 1) {
1054         state->method = rfx_calloc(sizeof(methodstate_t));
1055         state->method->has_super = 0;
1056         state->method->variable_count = 0;
1057
1058         if(state->cls) {
1059             state->method->is_constructor = !strcmp(state->cls->info->name,name);
1060         } else {
1061             state->method->is_global = 1;
1062             state->method->late_binding = 1; // for global methods, always push local_0 on the scope stack
1063         }
1064         if(state->method->is_constructor)
1065             name = "__as3_constructor__";
1066
1067         return_type = 0;
1068         state->method->info = registerfunction(getset, flags, name, params, return_type, 0);
1069         
1070         dict_put(global->token2info, (void*)(ptroff_t)as3_tokencount, state->method);
1071     }
1072
1073     if(as3_pass == 2) {
1074         state->method = dict_lookup(global->token2info, (void*)(ptroff_t)as3_tokencount);
1075         parserassert(state->method);
1076             
1077         if(state->cls) { 
1078             state->cls->has_constructor |= state->method->is_constructor;
1079         }
1080         
1081         state->method->info->return_type = return_type;
1082         function_initvars(params, flags);
1083     } 
1084 }
1085
1086 static abc_method_t* endfunction(token_t*ns, int flags, enum yytokentype getset, char*name,
1087                           params_t*params, classinfo_t*return_type, code_t*body)
1088 {
1089     if(as3_pass==1) {
1090         old_state();
1091         return 0;
1092     }
1093
1094     abc_method_t*f = 0;
1095
1096     multiname_t*type2 = sig2mname(return_type);
1097     int slot = 0;
1098     if(state->method->inner) {
1099         f = state->method->abc;
1100         abc_method_init(f, global->file, type2, 1);
1101     } else if(state->method->is_constructor) {
1102         f = abc_class_getconstructor(state->cls->abc, type2);
1103     } else if(!state->method->is_global) {
1104         namespace_t mname_ns = flags2namespace(flags, "");
1105         multiname_t mname = {QNAME, &mname_ns, 0, name};
1106
1107         if(flags&FLAG_STATIC)
1108             f = abc_class_staticmethod(state->cls->abc, type2, &mname);
1109         else
1110             f = abc_class_method(state->cls->abc, type2, &mname);
1111         slot = f->trait->slot_id;
1112     } else {
1113         namespace_t mname_ns = flags2namespace(flags, state->package);
1114         multiname_t mname = {QNAME, &mname_ns, 0, name};
1115
1116         f = abc_method_new(global->file, type2, 1);
1117         trait_t*t = trait_new_method(&global->init->traits, multiname_clone(&mname), f);
1118         //abc_code_t*c = global->init->method->body->code;
1119     }
1120     //flash doesn't seem to allow us to access function slots
1121     //state->method->info->slot = slot;
1122
1123     if(flags&FLAG_OVERRIDE) f->trait->attributes |= TRAIT_ATTR_OVERRIDE;
1124     if(getset == KW_GET) f->trait->kind = TRAIT_GETTER;
1125     if(getset == KW_SET) f->trait->kind = TRAIT_SETTER;
1126     if(params->varargs) f->flags |= METHOD_NEED_REST;
1127
1128     char opt=0;
1129     param_list_t*p=0;
1130     for(p=params->list;p;p=p->next) {
1131         if(params->varargs && !p->next) {
1132             break; //varargs: omit last parameter in function signature
1133         }
1134         multiname_t*m = sig2mname(p->param->type);
1135         list_append(f->parameters, m);
1136         if(p->param->value) {
1137             check_constant_against_type(p->param->type, p->param->value);
1138             opt=1;list_append(f->optional_parameters, p->param->value);
1139         } else if(opt) {
1140             syntaxerror("non-optional parameter not allowed after optional parameters");
1141         }
1142     }
1143     check_code_for_break(body);
1144
1145     if(f->body) {
1146         f->body->code = body;
1147         f->body->exceptions = state->method->exceptions;
1148     } else { //interface
1149         if(body)
1150             syntaxerror("interface methods can't have a method body");
1151     }
1152        
1153     old_state();
1154     return f;
1155 }
1156
1157 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
1158 {
1159     return 1; // FIXME
1160 }
1161
1162 void breakjumpsto(code_t*c, char*name, code_t*jump) 
1163 {
1164     while(c) {
1165         if(c->opcode == OPCODE___BREAK__) {
1166             string_t*name2 = c->data[0];
1167             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1168                 c->opcode = OPCODE_JUMP;
1169                 c->branch = jump;
1170             }
1171         }
1172         c=c->prev;
1173     }
1174 }
1175 void continuejumpsto(code_t*c, char*name, code_t*jump) 
1176 {
1177     while(c) {
1178         if(c->opcode == OPCODE___CONTINUE__) {
1179             string_t*name2 = c->data[0];
1180             if(!name2->len || !strncmp(name2->str, name, name2->len)) {
1181                 c->opcode = OPCODE_JUMP;
1182                 c->branch = jump;
1183             }
1184         }
1185         c = c->prev;
1186     }
1187 }
1188
1189 #define IS_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)))
1190 #define IS_NUMBER_OR_INT(a) (TYPE_IS_INT((a)) || TYPE_IS_UINT((a)) || TYPE_IS_NUMBER((a)))
1191 #define BOTH_INT(a,b) (IS_INT(a) && IS_INT(b))
1192
1193 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
1194 {
1195     if(!type1 || !type2) 
1196         return registry_getanytype();
1197     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
1198         return registry_getanytype();
1199
1200     if(op=='+') {
1201         if(IS_NUMBER_OR_INT(type1) && IS_NUMBER_OR_INT(type2)) {
1202             return TYPE_NUMBER;
1203         } else {
1204             return TYPE_ANY;
1205         }
1206     }
1207
1208     if(type1 == type2)
1209         return type1;
1210     return registry_getanytype();
1211 }
1212 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
1213 {
1214     if(from==to)
1215         return c;
1216     if(!to) {
1217         return abc_coerce_a(c);
1218     }
1219     MULTINAME(m, to);
1220     if(!from) {
1221         // cast an "any" type to a specific type. subject to
1222         // runtime exceptions
1223         return abc_coerce2(c, &m);
1224     }
1225     
1226     if((TYPE_IS_NUMBER(from) || TYPE_IS_UINT(from) || TYPE_IS_INT(from)) &&
1227        (TYPE_IS_NUMBER(to) || TYPE_IS_UINT(to) || TYPE_IS_INT(to))) {
1228         // allow conversion between number types
1229         return abc_coerce2(c, &m);
1230     }
1231     //printf("%s.%s\n", from.package, from.name);
1232     //printf("%s.%s\n", to.package, to.name);
1233
1234     classinfo_t*supertype = from;
1235     while(supertype) {
1236         if(supertype == to) {
1237              // target type is one of from's superclasses
1238              return abc_coerce2(c, &m);
1239         }
1240         int t=0;
1241         while(supertype->interfaces[t]) {
1242             if(supertype->interfaces[t]==to) {
1243                 // target type is one of from's interfaces
1244                 return abc_coerce2(c, &m);
1245             }
1246             t++;
1247         }
1248         supertype = supertype->superclass;
1249     }
1250     if(TYPE_IS_FUNCTION(from) && TYPE_IS_FUNCTION(to))
1251         return c;
1252     if(TYPE_IS_CLASS(from) && TYPE_IS_CLASS(to))
1253         return c;
1254     syntaxerror("can't convert type %s to %s", from->name, to->name);
1255     return 0; // make gcc happy
1256 }
1257
1258 code_t*defaultvalue(code_t*c, classinfo_t*type)
1259 {
1260     if(TYPE_IS_INT(type)) {
1261        c = abc_pushbyte(c, 0);
1262     } else if(TYPE_IS_UINT(type)) {
1263        c = abc_pushuint(c, 0);
1264     } else if(TYPE_IS_FLOAT(type)) {
1265        c = abc_pushnan(c);
1266     } else if(TYPE_IS_BOOLEAN(type)) {
1267        c = abc_pushfalse(c);
1268     } else if(!type) {
1269        //c = abc_pushundefined(c);
1270     } else {
1271        c = abc_pushnull(c);
1272        MULTINAME(m, type);
1273        c = abc_coerce2(c, &m);
1274     }
1275     return c;
1276 }
1277
1278 char is_pushundefined(code_t*c)
1279 {
1280     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
1281 }
1282
1283 static classinfo_t* find_class(char*name)
1284 {
1285     classinfo_t*c=0;
1286
1287     c = registry_findclass(state->package, name);
1288     if(c) return c;
1289
1290     /* try explicit imports */
1291     dictentry_t* e = dict_get_slot(state->imports, name);
1292     if(c) return c;
1293     while(e) {
1294         if(!strcmp(e->key, name)) {
1295             c = (classinfo_t*)e->data;
1296             if(c) return c;
1297         }
1298         e = e->next;
1299     }
1300
1301     /* try package.* imports */
1302     import_list_t*l = state->wildcard_imports;
1303     while(l) {
1304         //printf("does package %s contain a class %s?\n", l->import->package, name);
1305         c = registry_findclass(l->import->package, name);
1306         if(c) return c;
1307         l = l->next;
1308     }
1309
1310     /* try global package */
1311     c = registry_findclass("", name);
1312     if(c) return c;
1313    
1314     /* try local "filename" package */
1315     c = registry_findclass(current_filename_short, name);
1316     if(c) return c;
1317
1318     return 0;
1319 }
1320
1321 static char is_getlocal(code_t*c)
1322 {
1323     if(!c || c->prev || c->next)
1324         return 0;
1325     return(c->opcode == OPCODE_GETLOCAL
1326         || c->opcode == OPCODE_GETLOCAL_0
1327         || c->opcode == OPCODE_GETLOCAL_1
1328         || c->opcode == OPCODE_GETLOCAL_2
1329         || c->opcode == OPCODE_GETLOCAL_3);
1330 }
1331 static int getlocalnr(code_t*c)
1332 {
1333     if(c->opcode == OPCODE_GETLOCAL) {return (ptroff_t)c->data[0];}
1334     else if(c->opcode == OPCODE_GETLOCAL_0) {return 0;}
1335     else if(c->opcode == OPCODE_GETLOCAL_1) {return 1;}
1336     else if(c->opcode == OPCODE_GETLOCAL_2) {return 2;}
1337     else if(c->opcode == OPCODE_GETLOCAL_3) {return 3;}
1338     else syntaxerror("Internal error: opcode %02x is not a getlocal call", c->opcode);
1339     return 0;
1340 }
1341
1342 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign, char readbefore)
1343 {
1344     /* converts this:
1345
1346        [prefix code] [read instruction]
1347
1348        to this:
1349
1350        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
1351     */
1352     
1353     if(in && in->opcode == OPCODE_COERCE_A) {
1354         in = code_cutlast(in);
1355     }
1356     if(in->next)
1357         syntaxerror("internal error");
1358
1359     /* chop off read instruction */
1360     code_t*prefix = in;
1361     code_t*r = in;
1362     if(r->prev) {
1363         prefix = r->prev;r->prev = 0;
1364         prefix->next=0;
1365     } else {
1366         prefix = 0;
1367     }
1368
1369     char use_temp_var = readbefore;
1370
1371     /* generate the write instruction, and maybe append a dup to the prefix code */
1372     code_t* write = abc_nop(0);
1373     if(r->opcode == OPCODE_GETPROPERTY) {
1374         write->opcode = OPCODE_SETPROPERTY;
1375         multiname_t*m = (multiname_t*)r->data[0];
1376         write->data[0] = multiname_clone(m);
1377         if(m->type == QNAME || m->type == MULTINAME) {
1378             if(!justassign) {
1379                 prefix = abc_dup(prefix); // we need the object, too
1380             }
1381             use_temp_var = 1;
1382         } else if(m->type == MULTINAMEL) {
1383             if(!justassign) {
1384                 /* dupping two values on the stack requires 5 operations and one register- 
1385                    couldn't adobe just have given us a dup2? */
1386                 int temp = gettempvar();
1387                 prefix = abc_setlocal(prefix, temp);
1388                 prefix = abc_dup(prefix);
1389                 prefix = abc_getlocal(prefix, temp);
1390                 prefix = abc_swap(prefix);
1391                 prefix = abc_getlocal(prefix, temp);
1392                 if(!use_temp_var);
1393                     prefix = abc_kill(prefix, temp);
1394             }
1395             use_temp_var = 1;
1396         } else {
1397             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname/multiname)");
1398         }
1399     } else if(r->opcode == OPCODE_GETSLOT) {
1400         write->opcode = OPCODE_SETSLOT;
1401         write->data[0] = r->data[0];
1402         if(!justassign) {
1403             prefix = abc_dup(prefix); // we need the object, too
1404         }
1405         use_temp_var = 1;
1406     } else if(r->opcode == OPCODE_GETLOCAL) { 
1407         write->opcode = OPCODE_SETLOCAL;
1408         write->data[0] = r->data[0];
1409     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
1410         write->opcode = OPCODE_SETLOCAL_0;
1411     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
1412         write->opcode = OPCODE_SETLOCAL_1;
1413     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
1414         write->opcode = OPCODE_SETLOCAL_2;
1415     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
1416         write->opcode = OPCODE_SETLOCAL_3;
1417     } else {
1418         code_dump(r);
1419         syntaxerror("illegal lvalue: can't assign a value to this expression");
1420     }
1421     code_t* c = 0;
1422     
1423     int temp = -1;
1424     if(!justassign) {
1425         if(use_temp_var) {
1426             /* with getproperty/getslot, we have to be extra careful not
1427                to execute the read code twice, as it might have side-effects
1428                (e.g. if the property is in fact a setter/getter combination)
1429
1430                So read the value, modify it, and write it again,
1431                using prefix only once and making sure (by using a temporary
1432                register) that the return value is what we just wrote */
1433             temp = gettempvar();
1434             c = code_append(c, prefix);
1435             c = code_append(c, r);
1436             if(readbefore) {
1437                 c = abc_dup(c);
1438                 c = abc_setlocal(c, temp);
1439             }
1440             c = code_append(c, middlepart);
1441             if(!readbefore) {
1442                 c = abc_dup(c);
1443                 c = abc_setlocal(c, temp);
1444             }
1445             c = code_append(c, write);
1446             c = abc_getlocal(c, temp);
1447             c = abc_kill(c, temp);
1448         } else {
1449             /* if we're allowed to execute the read code twice *and*
1450                the middlepart doesn't modify the code, things are easier.
1451             */
1452             code_t* r2 = code_dup(r);
1453             //c = code_append(c, prefix);
1454             parserassert(!prefix);
1455             c = code_append(c, r);
1456             c = code_append(c, middlepart);
1457             c = code_append(c, write);
1458             c = code_append(c, r2);
1459         }
1460     } else {
1461         /* even smaller version: overwrite the value without reading
1462            it out first */
1463         if(!use_temp_var) {
1464             if(prefix) {
1465                 c = code_append(c, prefix);
1466                 c = abc_dup(c);
1467             }
1468             c = code_append(c, middlepart);
1469             c = code_append(c, write);
1470             c = code_append(c, r);
1471         } else {
1472             temp = gettempvar();
1473             if(prefix) {
1474                 c = code_append(c, prefix);
1475             }
1476             c = code_append(c, middlepart);
1477             c = abc_dup(c);
1478             c = abc_setlocal(c, temp);
1479             c = code_append(c, write);
1480             c = abc_getlocal(c, temp);
1481             c = abc_kill(c, temp);
1482         }
1483     }
1484     return c;
1485 }
1486
1487 char is_break_or_jump(code_t*c)
1488 {
1489     if(!c)
1490         return 0;
1491     if(c->opcode == OPCODE_JUMP ||
1492        c->opcode == OPCODE___BREAK__ ||
1493        c->opcode == OPCODE___CONTINUE__ ||
1494        c->opcode == OPCODE_THROW ||
1495        c->opcode == OPCODE_RETURNVOID ||
1496        c->opcode == OPCODE_RETURNVALUE) {
1497        return 1;
1498     }
1499     return 0;
1500 }
1501
1502
1503 #define IS_FINALLY_TARGET(op) \
1504         ((op) == OPCODE___CONTINUE__ || \
1505          (op) == OPCODE___BREAK__ || \
1506          (op) == OPCODE_RETURNVOID || \
1507          (op) == OPCODE_RETURNVALUE || \
1508          (op) == OPCODE___RETHROW__)
1509
1510 static code_t* insert_finally_lookup(code_t*c, code_t*finally, int tempvar)
1511 {
1512 #define NEED_EXTRA_STACK_ARG
1513     code_t*finally_label = abc_nop(0);
1514     NEW(lookupswitch_t, l);
1515     //_lookupswitch
1516
1517     code_t*i = c;
1518     int count=0;
1519     while(i) {
1520         code_t*prev = i->prev;
1521         if(IS_FINALLY_TARGET(i->opcode)) {
1522            code_t*p = prev;
1523            char needvalue=0;
1524            if(i->opcode == OPCODE___RETHROW__ ||
1525               i->opcode == OPCODE_RETURNVALUE) {
1526                if(i->opcode == OPCODE___RETHROW__)
1527                  i->opcode = OPCODE_THROW;
1528                needvalue=1;
1529                p = abc_coerce_a(p);
1530                p = abc_setlocal(p, tempvar);
1531            }
1532            p = abc_pushbyte(p, count++);
1533            p = abc_jump(p, finally_label);
1534            code_t*target = p = abc_label(p);
1535 #ifdef NEED_EXTRA_STACK_ARG
1536            p = abc_pop(p);
1537 #endif
1538            if(needvalue) {
1539                p = abc_getlocal(p, tempvar);
1540            }
1541
1542            p->next = i;i->prev = p;
1543            list_append(l->targets, target);
1544         }
1545         i = prev;
1546     }
1547
1548     code_t*j,*f;
1549     c = abc_pushbyte(c, -1);
1550     c = code_append(c, finally_label);
1551     c = code_append(c, finally);
1552
1553 #ifdef NEED_EXTRA_STACK_ARG
1554     c = abc_dup(c);
1555 #endif
1556     c = abc_lookupswitch(c, l);
1557     c = l->def = abc_label(c);
1558 #ifdef NEED_EXTRA_STACK_ARG
1559     c = abc_pop(c);
1560 #endif
1561
1562     return c;
1563 }
1564
1565 static code_t* insert_finally_simple(code_t*c, code_t*finally, int tempvar)
1566 {
1567     code_t*i = c;
1568     while(i) {
1569         code_t*prev = i->prev;
1570         if(IS_FINALLY_TARGET(i->opcode)) {
1571            if(i->opcode == OPCODE___RETHROW__)
1572                 i->opcode = OPCODE_THROW;
1573            code_t*end = code_dup(finally);
1574            code_t*start = code_start(end);
1575            if(prev) prev->next = start;
1576            start->prev = prev;
1577            i->prev = end;
1578            end->next = i;
1579         }
1580         i = prev;
1581     }
1582     return code_append(c, finally);
1583 }
1584
1585 code_t* insert_finally(code_t*c, code_t*finally, int tempvar)
1586 {
1587     if(!finally)
1588         return c;
1589     code_t*i = c;
1590     char cantdup=0;
1591     int num_insertion_points=0;
1592     while(i) {
1593         if(IS_FINALLY_TARGET(i->opcode))
1594             num_insertion_points++;
1595         i = i->prev;
1596     }
1597     i = finally;
1598     int code_size=0;
1599     while(i) {
1600         code_size++;
1601         if(i->branch || i->opcode == OPCODE_LOOKUPSWITCH) {
1602             cantdup=1;
1603         }
1604         i = i->prev;
1605     }
1606     int simple_version_cost = (1+num_insertion_points)*code_size;
1607     int lookup_version_cost = 4*num_insertion_points + 5;
1608
1609     if(cantdup || simple_version_cost > lookup_version_cost) {
1610         printf("lookup %d > *%d*\n", simple_version_cost, lookup_version_cost);
1611         return insert_finally_lookup(c, finally, tempvar);
1612     } else {
1613         printf("simple *%d* < %d\n", simple_version_cost, lookup_version_cost);
1614         return insert_finally_simple(c, finally, tempvar);
1615     }
1616 }
1617
1618 #define PASS1 }} if(as3_pass == 1) {{
1619 #define PASS1END }} if(as3_pass == 2) {{
1620 #define PASS2 }} if(as3_pass == 2) {{
1621 #define PASS12 }} {{
1622 #define PASS12END }} if(as3_pass == 2) {{
1623
1624 %}
1625
1626 %%
1627
1628 /* ------------ code blocks / statements ---------------- */
1629
1630 PROGRAM: MAYBE_PROGRAM_CODE_LIST
1631
1632 MAYBE_PROGRAM_CODE_LIST: | PROGRAM_CODE_LIST 
1633 PROGRAM_CODE_LIST: PROGRAM_CODE 
1634                  | PROGRAM_CODE_LIST PROGRAM_CODE
1635
1636 PROGRAM_CODE: PACKAGE_DECLARATION 
1637             | INTERFACE_DECLARATION 
1638             | CLASS_DECLARATION
1639             | FUNCTION_DECLARATION
1640             | SLOT_DECLARATION
1641             | PACKAGE_INITCODE
1642             | ';'
1643
1644 MAYBE_INPACKAGE_CODE_LIST: | INPACKAGE_CODE_LIST
1645 INPACKAGE_CODE_LIST: INPACKAGE_CODE 
1646                    | INPACKAGE_CODE_LIST INPACKAGE_CODE
1647
1648 INPACKAGE_CODE: INTERFACE_DECLARATION 
1649               | CLASS_DECLARATION
1650               | FUNCTION_DECLARATION
1651               | SLOT_DECLARATION
1652               | PACKAGE_INITCODE
1653               | ';'
1654
1655 MAYBECODE: CODE {$$=$1;}
1656 MAYBECODE: {$$=code_new();}
1657
1658 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1659 CODE: CODEPIECE {$$=$1;}
1660
1661 // code which also may appear outside a method
1662 CODE_STATEMENT: IMPORT 
1663 CODE_STATEMENT: FOR 
1664 CODE_STATEMENT: FOR_IN 
1665 CODE_STATEMENT: WHILE 
1666 CODE_STATEMENT: DO_WHILE 
1667 CODE_STATEMENT: SWITCH 
1668 CODE_STATEMENT: IF
1669 CODE_STATEMENT: WITH
1670 CODE_STATEMENT: TRY
1671 CODE_STATEMENT: VOIDEXPRESSION 
1672
1673 // code which may appear anywhere
1674 CODEPIECE: ';' {$$=0;}
1675 CODEPIECE: CODE_STATEMENT
1676 CODEPIECE: VARIABLE_DECLARATION
1677 CODEPIECE: BREAK
1678 CODEPIECE: CONTINUE
1679 CODEPIECE: RETURN
1680 CODEPIECE: THROW
1681
1682 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=0;}
1683 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=0;}
1684
1685 CODEBLOCK :  '{' CODE '}' {$$=$2;}
1686 CODEBLOCK :  '{' '}'      {$$=0;}
1687 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1688 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1689
1690 /* ------------ package init code ------------------- */
1691
1692 PACKAGE_INITCODE: CODE_STATEMENT {
1693     code_t**cc = &global->init->method->body->code;
1694     *cc = code_append(*cc, $1);
1695 }
1696
1697 /* ------------ variables --------------------------- */
1698
1699 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1700                 |                {$$.c=abc_pushundefined(0);
1701                                   $$.t=TYPE_ANY;
1702                                  }
1703
1704 VARIABLE_DECLARATION : "var" VARIABLE_LIST {$$=$2;}
1705 VARIABLE_DECLARATION : "const" VARIABLE_LIST {$$=$2;}
1706
1707 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1708 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1709
1710 ONE_VARIABLE: T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1711 {
1712     if(variable_exists($1))
1713         syntaxerror("Variable %s already defined", $1);
1714    
1715     if(!is_subtype_of($3.t, $2)) {
1716         syntaxerror("Can't convert %s to %s", $3.t->name, 
1717                                               $2->name);
1718     }
1719
1720     int index = new_variable($1, $2, 1);
1721     
1722     if($2) {
1723         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1724             $$ = $3.c;
1725             $$ = converttype($$, $3.t, $2);
1726             $$ = abc_setlocal($$, index);
1727         } else {
1728             $$ = defaultvalue(0, $2);
1729             $$ = abc_setlocal($$, index);
1730         }
1731     } else {
1732         if($3.c->prev || $3.c->opcode != OPCODE_PUSHUNDEFINED) {
1733             $$ = $3.c;
1734             $$ = abc_coerce_a($$);
1735             $$ = abc_setlocal($$, index);
1736         } else {
1737             $$ = code_new();
1738         }
1739     }
1740     
1741     /* that's the default for a local register, anyway
1742         else {
1743         state->method->initcode = abc_pushundefined(state->method->initcode);
1744         state->method->initcode = abc_setlocal(state->method->initcode, index);
1745     }*/
1746     //printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1747 }
1748
1749 /* ------------ control flow ------------------------- */
1750
1751 MAYBEELSE:  %prec below_else {$$ = code_new();}
1752 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1753 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1754
1755 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1756      
1757     $$ = code_new();
1758     $$ = code_append($$, $4.c);
1759     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1760    
1761     $$ = code_append($$, $6);
1762     if($7) {
1763         myjmp = $$ = abc_jump($$, 0);
1764     }
1765     myif->branch = $$ = abc_nop($$);
1766     if($7) {
1767         $$ = code_append($$, $7);
1768         myjmp->branch = $$ = abc_nop($$);
1769     }
1770     $$ = var_block($$);
1771     old_state();
1772 }
1773
1774 FOR_INIT : {$$=code_new();}
1775 FOR_INIT : VARIABLE_DECLARATION
1776 FOR_INIT : VOIDEXPRESSION
1777
1778 // TODO: why doesn't an %prec above_identifier resolve the r-r conflict here?
1779 FOR_IN_INIT : "var" T_IDENTIFIER MAYBETYPE {
1780     $$=$2;new_variable($2,$3,1);
1781 }
1782 FOR_IN_INIT : T_IDENTIFIER {
1783     $$=$1;
1784 }
1785
1786 FOR_START : T_FOR '(' {new_state();$$.name=$1;$$.each=0;}
1787 FOR_START : T_FOR "each" '(' {new_state();$$.name=$1;$$.each=1;}
1788
1789 FOR : FOR_START FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1790     if($1.each) syntaxerror("invalid syntax: ; not allowed in for each statement");
1791     $$ = code_new();
1792     $$ = code_append($$, $2);
1793     code_t*loopstart = $$ = abc_label($$);
1794     $$ = code_append($$, $4.c);
1795     code_t*myif = $$ = abc_iffalse($$, 0);
1796     $$ = code_append($$, $8);
1797     code_t*cont = $$ = abc_nop($$);
1798     $$ = code_append($$, $6);
1799     $$ = abc_jump($$, loopstart);
1800     code_t*out = $$ = abc_nop($$);
1801     breakjumpsto($$, $1.name, out);
1802     continuejumpsto($$, $1.name, cont);
1803     myif->branch = out;
1804
1805     $$ = var_block($$);
1806     old_state();
1807 }
1808
1809 FOR_IN : FOR_START FOR_IN_INIT "in" EXPRESSION ')' CODEBLOCK {
1810     variable_t*var = find_variable($2);
1811     char*tmp1name = concat2($2, "__tmp1__");
1812     int it = new_variable(tmp1name, TYPE_INT, 0);
1813     char*tmp2name = concat2($2, "__array__");
1814     int array = new_variable(tmp1name, 0, 0);
1815
1816     $$ = code_new();
1817     $$ = code_append($$, $4.c);
1818     $$ = abc_coerce_a($$);
1819     $$ = abc_setlocal($$, array);
1820     $$ = abc_pushbyte($$, 0);
1821     $$ = abc_setlocal($$, it);
1822
1823     code_t*loopstart = $$ = abc_label($$);
1824     
1825     $$ = abc_hasnext2($$, array, it);
1826     code_t*myif = $$ = abc_iffalse($$, 0);
1827     $$ = abc_getlocal($$, array);
1828     $$ = abc_getlocal($$, it);
1829     if(!$1.each)
1830         $$ = abc_nextname($$);
1831     else
1832         $$ = abc_nextvalue($$);
1833     $$ = converttype($$, 0, var->type);
1834     $$ = abc_setlocal($$, var->index);
1835
1836     $$ = code_append($$, $6);
1837     $$ = abc_jump($$, loopstart);
1838     
1839     code_t*out = $$ = abc_nop($$);
1840     breakjumpsto($$, $1.name, out);
1841     continuejumpsto($$, $1.name, loopstart);
1842     
1843     myif->branch = out;
1844
1845     $$ = var_block($$);
1846     old_state();
1847
1848     free(tmp1name);
1849     free(tmp2name);
1850 }
1851
1852 WHILE : T_WHILE '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1853
1854     $$ = code_new();
1855
1856     code_t*myjmp = $$ = abc_jump($$, 0);
1857     code_t*loopstart = $$ = abc_label($$);
1858     $$ = code_append($$, $6);
1859     code_t*cont = $$ = abc_nop($$);
1860     myjmp->branch = cont;
1861     $$ = code_append($$, $4.c);
1862     $$ = abc_iftrue($$, loopstart);
1863     code_t*out = $$ = abc_nop($$);
1864     breakjumpsto($$, $1, out);
1865     continuejumpsto($$, $1, cont);
1866
1867     $$ = var_block($$);
1868     old_state();
1869 }
1870
1871 DO_WHILE : T_DO {new_state();} CODEBLOCK "while" '(' EXPRESSION ')' {
1872     $$ = code_new();
1873     code_t*loopstart = $$ = abc_label($$);
1874     $$ = code_append($$, $3);
1875     code_t*cont = $$ = abc_nop($$);
1876     $$ = code_append($$, $6.c);
1877     $$ = abc_iftrue($$, loopstart);
1878     code_t*out = $$ = abc_nop($$);
1879     breakjumpsto($$, $1, out);
1880     continuejumpsto($$, $1, cont);
1881     
1882     $$ = var_block($$);
1883     old_state();
1884 }
1885
1886 BREAK : "break" %prec prec_none {
1887     $$ = abc___break__(0, "");
1888 }
1889 BREAK : "break" T_IDENTIFIER {
1890     $$ = abc___break__(0, $2);
1891 }
1892 CONTINUE : "continue" %prec prec_none {
1893     $$ = abc___continue__(0, "");
1894 }
1895 CONTINUE : "continue" T_IDENTIFIER {
1896     $$ = abc___continue__(0, $2);
1897 }
1898
1899 MAYBE_CASE_LIST :           {$$=0;}
1900 MAYBE_CASE_LIST : CASE_LIST {$$=$1;}
1901 MAYBE_CASE_LIST : DEFAULT   {$$=$1;}
1902 MAYBE_CASE_LIST : CASE_LIST DEFAULT {$$=code_append($1,$2);}
1903 CASE_LIST: CASE             {$$=$1;}
1904 CASE_LIST: CASE_LIST CASE   {$$=code_append($$,$2);}
1905
1906 CASE: "case" E ':' MAYBECODE {
1907     $$ = abc_dup(0);
1908     $$ = code_append($$, $2.c);
1909     code_t*j = $$ = abc_ifne($$, 0);
1910     $$ = code_append($$, $4);
1911     if($$->opcode != OPCODE___BREAK__) {
1912         $$ = abc___fallthrough__($$, "");
1913     }
1914     code_t*e = $$ = abc_nop($$);
1915     j->branch = e;
1916 }
1917 DEFAULT: "default" ':' MAYBECODE {
1918     $$ = $3;
1919 }
1920 SWITCH : T_SWITCH '(' {new_state();} E ')' '{' MAYBE_CASE_LIST '}' {
1921     $$=$4.c;
1922     $$ = code_append($$, $7);
1923     code_t*out = $$ = abc_pop($$);
1924     breakjumpsto($$, $1, out);
1925     
1926     code_t*c = $$,*lastblock=0;
1927     while(c) {
1928         if(c->opcode == OPCODE_IFNE) {
1929             if(!c->next) syntaxerror("internal error in fallthrough handling");
1930             lastblock=c->next;
1931         } else if(c->opcode == OPCODE___FALLTHROUGH__) {
1932             if(lastblock) {
1933                 c->opcode = OPCODE_JUMP;
1934                 c->branch = lastblock;
1935             } else {
1936                 /* fall through end of switch */
1937                 c->opcode = OPCODE_NOP;
1938             }
1939         }
1940         c=c->prev;
1941     }
1942    
1943     $$ = var_block($$);
1944     old_state();
1945 }
1946
1947 /* ------------ try / catch /finally ---------------- */
1948
1949 CATCH: "catch" '(' T_IDENTIFIER MAYBETYPE ')' {new_state();state->exception_name=$3;new_variable($3, $4, 0);} 
1950         '{' MAYBECODE '}' {
1951     namespace_t name_ns = {ACCESS_PACKAGE, ""};
1952     multiname_t name = {QNAME, &name_ns, 0, $3};
1953     
1954     NEW(abc_exception_t, e)
1955     e->exc_type = sig2mname($4);
1956     e->var_name = multiname_clone(&name);
1957     $$ = e;
1958
1959     code_t*c = 0;
1960     int i = find_variable_safe($3)->index;
1961     e->target = c = abc_nop(0);
1962     c = abc_setlocal(c, i);
1963     c = code_append(c, $8);
1964     c = abc_kill(c, i);
1965
1966     c = var_block(c);
1967     old_state();
1968 }
1969 FINALLY: "finally" '{' {new_state();state->exception_name=0;} MAYBECODE '}' {
1970     $4 = var_block($4);
1971     if(!$4) {
1972         $$=0;
1973         old_state();
1974     } else {
1975         NEW(abc_exception_t, e)
1976         e->exc_type = 0; //all exceptions
1977         e->var_name = 0; //no name
1978         e->target = 0;
1979         e->to = abc_nop(0);
1980         e->to = code_append(e->to, $4);
1981         old_state();
1982         $$ = e;
1983     }
1984 }
1985
1986 CATCH_LIST: CATCH {$$.l=list_new();$$.finally=0;list_append($$.l,$1);}
1987 CATCH_LIST: CATCH_LIST CATCH {$$=$1;list_append($$.l,$2);}
1988 CATCH_FINALLY_LIST: CATCH_LIST {$$=$1;}
1989 CATCH_FINALLY_LIST: CATCH_LIST FINALLY {
1990     $$ = $1;
1991     $$.finally = 0;
1992     if($2) {
1993         list_append($$.l,$2);
1994         $$.finally = $2->to;$2->to=0;
1995     }
1996 }
1997 CATCH_FINALLY_LIST: FINALLY {
1998     $$.l=list_new();
1999     $$.finally = 0;
2000     if($1) {
2001         list_append($$.l,$1);
2002         $$.finally = $1->to;$1->to=0;
2003     }
2004 }
2005
2006 TRY : "try" '{' {new_state();} MAYBECODE '}' CATCH_FINALLY_LIST {
2007     code_t*out = abc_nop(0);
2008
2009     code_t*start = abc_nop(0);
2010     $$ = code_append(start, $4);
2011     if(!is_break_or_jump($4)) {
2012         $$ = abc_jump($$, out);
2013     }
2014     code_t*end = $$ = abc_nop($$);
2015   
2016     int tmp;
2017     if($6.finally)
2018         tmp = new_variable("__finally__", 0, 0);
2019     
2020     abc_exception_list_t*l = $6.l;
2021     int count=0;
2022     while(l) {
2023         abc_exception_t*e = l->abc_exception;
2024         if(e->var_name) {
2025             $$ = code_append($$, e->target);
2026             $$ = abc_jump($$, out);
2027         } else {
2028             parserassert((ptroff_t)$6.finally);
2029             // finally block
2030             e->target = $$ = abc_nop($$);
2031             $$ = abc___rethrow__($$);
2032         }
2033         
2034         e->from = start;
2035         e->to = end;
2036
2037         l = l->next;
2038     }
2039     $$ = code_append($$, out);
2040
2041     $$ = insert_finally($$, $6.finally, tmp);
2042         
2043     list_concat(state->method->exceptions, $6.l);
2044    
2045     $$ = var_block($$);
2046     old_state();
2047 }
2048
2049 /* ------------ throw ------------------------------- */
2050
2051 THROW : "throw" EXPRESSION {
2052     $$=$2.c;
2053     $$=abc_throw($$);
2054 }
2055 THROW : "throw" %prec prec_none {
2056     if(!state->exception_name)
2057         syntaxerror("re-throw only possible within a catch block");
2058     variable_t*v = find_variable(state->exception_name);
2059     $$=code_new();
2060     $$=abc_getlocal($$, v->index);
2061     $$=abc_throw($$);
2062 }
2063
2064 /* ------------ with -------------------------------- */
2065
2066 WITH : "with" '(' EXPRESSION ')' CODEBLOCK {
2067      $$ = $3.c;
2068      $$ = abc_pushscope($$);
2069      $$ = code_append($$, $5);
2070      $$ = abc_popscope($$);
2071 }
2072
2073 /* ------------ packages and imports ---------------- */
2074
2075 X_IDENTIFIER: T_IDENTIFIER
2076             | "package" {PASS12 $$="package";}
2077
2078 PACKAGE: PACKAGE '.' X_IDENTIFIER {PASS12 $$ = concat3($1,".",$3);free($1);$1=0;}
2079 PACKAGE: X_IDENTIFIER             {PASS12 $$=strdup($1);}
2080
2081 PACKAGE_DECLARATION : "package" PACKAGE '{' {PASS12 startpackage($2);free($2);$2=0;}
2082                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2083 PACKAGE_DECLARATION : "package" '{' {PASS12 startpackage("");} 
2084                                 MAYBE_INPACKAGE_CODE_LIST '}' {PASS12 endpackage();$$=0;}
2085
2086 IMPORT : "import" QNAME {
2087        classinfo_t*c = $2;
2088        if(!c) 
2089             syntaxerror("Couldn't import class\n");
2090        state_has_imports();
2091        dict_put(state->imports, c->name, c);
2092        $$=0;
2093 }
2094 IMPORT : "import" PACKAGE '.' '*' {
2095        NEW(import_t,i);
2096        i->package = $2;
2097        state_has_imports();
2098        list_append(state->wildcard_imports, i);
2099        $$=0;
2100 }
2101
2102 /* ------------ classes and interfaces (header) -------------- */
2103
2104 MAYBE_MODIFIERS : %prec above_function {PASS12 $$=0;}
2105 MAYBE_MODIFIERS : MODIFIER_LIST        {PASS12 $$=$1;}
2106 MODIFIER_LIST : MODIFIER               {PASS12 $$=$1;}
2107 MODIFIER_LIST : MODIFIER_LIST MODIFIER {PASS12 $$=$1|$2;}
2108
2109 MODIFIER : KW_PUBLIC {PASS12 $$=FLAG_PUBLIC;}
2110          | KW_PRIVATE {PASS12 $$=FLAG_PRIVATE;}
2111          | KW_PROTECTED {PASS12 $$=FLAG_PROTECTED;}
2112          | KW_STATIC {PASS12 $$=FLAG_STATIC;}
2113          | KW_DYNAMIC {PASS12 $$=FLAG_DYNAMIC;}
2114          | KW_FINAL {PASS12 $$=FLAG_FINAL;}
2115          | KW_OVERRIDE {PASS12 $$=FLAG_OVERRIDE;}
2116          | KW_NATIVE {PASS12 $$=FLAG_NATIVE;}
2117          | KW_INTERNAL {PASS12 $$=FLAG_PACKAGEINTERNAL;}
2118
2119 EXTENDS : {$$=registry_getobjectclass();}
2120 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
2121
2122 EXTENDS_LIST : {PASS12 $$=list_new();}
2123 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {PASS12 $$=$2;}
2124
2125 IMPLEMENTS_LIST : {PASS12 $$=list_new();}
2126 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {PASS12 $$=$2;}
2127
2128 CLASS_DECLARATION : MAYBE_MODIFIERS "class" T_IDENTIFIER 
2129                               EXTENDS IMPLEMENTS_LIST 
2130                               '{' {PASS12 startclass($1,$3,$4,$5, 0);} 
2131                               MAYBE_CLASS_BODY 
2132                               '}' {PASS12 endclass();$$=0;}
2133
2134 INTERFACE_DECLARATION : MAYBE_MODIFIERS "interface" T_IDENTIFIER 
2135                               EXTENDS_LIST 
2136                               '{' {PASS12 startclass($1,$3,0,$4,1);}
2137                               MAYBE_INTERFACE_BODY 
2138                               '}' {PASS12 endclass();$$=0;}
2139
2140 /* ------------ classes and interfaces (body) -------------- */
2141
2142 MAYBE_CLASS_BODY : 
2143 MAYBE_CLASS_BODY : CLASS_BODY
2144 CLASS_BODY : CLASS_BODY_ITEM
2145 CLASS_BODY : CLASS_BODY CLASS_BODY_ITEM
2146 CLASS_BODY_ITEM : ';'
2147 CLASS_BODY_ITEM : SLOT_DECLARATION
2148 CLASS_BODY_ITEM : FUNCTION_DECLARATION
2149
2150 CLASS_BODY_ITEM : CODE_STATEMENT {
2151     code_t*c = state->cls->static_init;
2152     c = code_append(c, $1);  
2153     state->cls->static_init = c;
2154 }
2155
2156 MAYBE_INTERFACE_BODY : 
2157 MAYBE_INTERFACE_BODY : INTERFACE_BODY
2158 INTERFACE_BODY : IDECLARATION
2159 INTERFACE_BODY : INTERFACE_BODY IDECLARATION
2160 IDECLARATION : ';'
2161 IDECLARATION : "var" T_IDENTIFIER {
2162     syntaxerror("variable declarations not allowed in interfaces");
2163 }
2164 IDECLARATION : MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE {
2165     PASS12
2166     $1 |= FLAG_PUBLIC;
2167     if($1&(FLAG_PRIVATE|FLAG_PACKAGEINTERNAL|FLAG_PROTECTED)) {
2168         syntaxerror("invalid method modifiers: interface methods always need to be public");
2169     }
2170     startfunction(0,$1,$3,$4,&$6,$8);
2171     endfunction(0,$1,$3,$4,&$6,$8, 0);
2172     list_deep_free($6.list);
2173 }
2174
2175 /* ------------ classes and interfaces (body, slots ) ------- */
2176
2177 VARCONST: "var" | "const"
2178
2179 SLOT_DECLARATION: MAYBE_MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
2180     int flags = $1;
2181     memberinfo_t* info = state->cls?
2182             memberinfo_register(state->cls->info, $3, MEMBER_SLOT):
2183             memberinfo_register_global(flags2access($1), state->package, $3, MEMBER_SLOT);
2184
2185     info->type = $4;
2186     info->flags = flags;
2187
2188     /* slot name */
2189     namespace_t mname_ns = {flags2access(flags), ""};
2190     multiname_t mname = {QNAME, &mname_ns, 0, $3};
2191   
2192     trait_list_t**traits;
2193     code_t**code;
2194     if(!state->cls) {
2195         // global variable
2196         mname_ns.name = state->package;
2197         traits = &global->init->traits;
2198         code = &global->init->method->body->code;
2199     } else if(flags&FLAG_STATIC) {
2200         // static variable
2201         traits = &state->cls->abc->static_traits;
2202         code = &state->cls->static_init;
2203     } else {
2204         // instance variable
2205         traits = &state->cls->abc->traits;
2206         code = &state->cls->init;
2207     }
2208     
2209     trait_t*t=0;
2210     if($4) {
2211         MULTINAME(m, $4);
2212         t = trait_new_member(traits, multiname_clone(&m), multiname_clone(&mname), 0);
2213     } else {
2214         t = trait_new_member(traits, 0, multiname_clone(&mname), 0);
2215     }
2216     info->slot = t->slot_id;
2217     
2218     /* initalization code (if needed) */
2219     code_t*c = 0;
2220     if($5.c && !is_pushundefined($5.c)) {
2221         c = abc_getlocal_0(c);
2222         c = code_append(c, $5.c);
2223         c = converttype(c, $5.t, $4);
2224         c = abc_setslot(c, t->slot_id);
2225     }
2226
2227     *code = code_append(*code, c);
2228
2229     if($2==KW_CONST) {
2230         t->kind= TRAIT_CONST;
2231     }
2232
2233     $$=0;
2234 }
2235
2236 /* ------------ constants -------------------------------------- */
2237
2238 MAYBESTATICCONSTANT: {$$=0;}
2239 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
2240
2241 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
2242 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
2243 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
2244 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
2245 STATICCONSTANT : T_STRING {$$ = constant_new_string2($1.str,$1.len);}
2246 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
2247 STATICCONSTANT : "true" {$$ = constant_new_true($1);}
2248 STATICCONSTANT : "false" {$$ = constant_new_false($1);}
2249 STATICCONSTANT : "null" {$$ = constant_new_null($1);}
2250
2251 /* ------------ classes and interfaces (body, functions) ------- */
2252
2253 // non-vararg version
2254 MAYBE_PARAM_LIST: {
2255     PASS12
2256     memset(&$$,0,sizeof($$));
2257 }
2258 MAYBE_PARAM_LIST: PARAM_LIST {
2259     PASS12
2260     $$=$1;
2261 }
2262
2263 // vararg version
2264 MAYBE_PARAM_LIST: "..." PARAM {
2265     PASS12
2266     memset(&$$,0,sizeof($$));
2267     $$.varargs=1;
2268     list_append($$.list, $2);
2269 }
2270 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
2271     PASS12
2272     $$ =$1;
2273     $$.varargs=1;
2274     list_append($$.list, $4);
2275 }
2276
2277 // non empty
2278 PARAM_LIST: PARAM_LIST ',' PARAM {
2279     PASS12
2280     $$ = $1;
2281     list_append($$.list, $3);
2282 }
2283 PARAM_LIST: PARAM {
2284     PASS12
2285     memset(&$$,0,sizeof($$));
2286     list_append($$.list, $1);
2287 }
2288
2289 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
2290      PASS1 $$=0;
2291      PASS2
2292      $$ = malloc(sizeof(param_t));
2293      $$->name=$1;
2294      $$->type = $3;
2295      $$->value = $4;
2296 }
2297 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
2298      PASS1 $$=0;
2299      PASS2
2300      $$ = malloc(sizeof(param_t));
2301      $$->name=$1;
2302      $$->type = TYPE_ANY;
2303      $$->value = $2;
2304 }
2305 GETSET : "get" {$$=$1;}
2306        | "set" {$$=$1;}
2307        |       {$$=0;}
2308
2309 FUNCTION_DECLARATION: MAYBE_MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
2310                       MAYBETYPE '{' {PASS12 startfunction(0,$1,$3,$4,&$6,$8);} MAYBECODE '}' 
2311 {
2312     PASS1 old_state();list_deep_free($6.list);
2313     PASS2
2314     if(!state->method->info) syntaxerror("internal error");
2315     
2316     code_t*c = method_header();
2317     c = wrap_function(c, 0, $11);
2318
2319     endfunction(0,$1,$3,$4,&$6,$8,c);
2320     list_deep_free($6.list);
2321     $$=0;
2322 }
2323
2324 MAYBE_IDENTIFIER: T_IDENTIFIER
2325 MAYBE_IDENTIFIER: {PASS12 $$=0;}
2326 INNERFUNCTION: "function" MAYBE_IDENTIFIER '(' MAYBE_PARAM_LIST ')' MAYBETYPE 
2327                '{' {PASS12 innerfunction($2,&$4,$6);} MAYBECODE '}'
2328 {
2329     PASS1 old_state();list_deep_free($4.list);
2330     PASS2
2331     memberinfo_t*f = state->method->info;
2332     if(!f) syntaxerror("internal error");
2333     
2334     code_t*c = method_header();
2335     c = wrap_function(c, 0, $9);
2336
2337     int index = state->method->var_index;
2338     endfunction(0,0,0,$2,&$4,$6,c);
2339     list_deep_free($4.list);
2340     
2341     $$.c = abc_getlocal(0, index);
2342     $$.t = TYPE_FUNCTION(f);
2343 }
2344
2345
2346 /* ------------- package + class ids --------------- */
2347
2348 CLASS: T_IDENTIFIER {
2349     PASS1 $$=0;
2350     PASS2
2351     /* try current package */
2352     $$ = find_class($1);
2353     if(!$$) syntaxerror("Could not find class %s\n", $1);
2354 }
2355
2356 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
2357     PASS1 $$=0;
2358     PASS2
2359     $$ = registry_findclass($1, $3);
2360     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1, $3);
2361     free($1);$1=0;
2362 }
2363
2364 QNAME: PACKAGEANDCLASS
2365      | CLASS
2366
2367 QNAME_LIST : QNAME {PASS12 $$=list_new();list_append($$, $1);}
2368 QNAME_LIST : QNAME_LIST ',' QNAME {PASS12 $$=$1;list_append($$,$3);}
2369
2370 TYPE : QNAME      {$$=$1;}
2371      | '*'        {$$=registry_getanytype();}
2372      | "void"     {$$=registry_getanytype();}
2373     /*
2374      |  "String"  {$$=registry_getstringclass();}
2375      |  "int"     {$$=registry_getintclass();}
2376      |  "uint"    {$$=registry_getuintclass();}
2377      |  "Boolean" {$$=registry_getbooleanclass();}
2378      |  "Number"  {$$=registry_getnumberclass();}
2379     */
2380
2381 MAYBETYPE: ':' TYPE {$$=$2;}
2382 MAYBETYPE:          {$$=0;}
2383
2384 /* ----------function calls, delete, constructor calls ------ */
2385
2386 MAYBE_PARAM_VALUES :  %prec prec_none {$$.cc=0;$$.len=0;}
2387 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2;}
2388
2389 MAYBE_EXPRESSION_LIST : {$$.cc=0;$$.len=0;}
2390 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
2391 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$.len=1;
2392                                                   $$.cc = $1.c;
2393                                                  }
2394 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {
2395                                                   $$.len= $1.len+1;
2396                                                   $$.cc = code_append($1.cc, $3.c);
2397                                                   }
2398                
2399 XX : %prec new2
2400 NEW : "new" E XX MAYBE_PARAM_VALUES {
2401     $$.c = $2.c;
2402     if($$.c->opcode == OPCODE_COERCE_A) $$.c = code_cutlast($$.c);
2403     
2404     code_t*paramcode = $4.cc;
2405     if($$.c->opcode == OPCODE_GETPROPERTY) {
2406         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2407         $$.c = code_cutlast($$.c);
2408         $$.c = code_append($$.c, paramcode);
2409         $$.c = abc_constructprop2($$.c, name, $4.len);
2410         multiname_destroy(name);
2411     } else if($$.c->opcode == OPCODE_GETSLOT) {
2412         int slot = (int)(ptroff_t)$$.c->data[0];
2413         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2414         multiname_t*name = t->name;
2415         $$.c = code_cutlast($$.c);
2416         $$.c = code_append($$.c, paramcode);
2417         $$.c = abc_constructprop2($$.c, name, $4.len);
2418     } else {
2419         $$.c = code_append($$.c, paramcode);
2420         $$.c = abc_construct($$.c, $4.len);
2421     }
2422    
2423     $$.t = TYPE_ANY;
2424     if(TYPE_IS_CLASS($2.t) && $2.t->cls) {
2425         $$.t = $2.t->cls;
2426     } else {
2427         $$.c = abc_coerce_a($$.c);
2428         $$.t = TYPE_ANY;
2429     }
2430 }
2431
2432 /* TODO: use abc_call (for calling local variables),
2433          abc_callstatic (for calling own methods) 
2434          call (for closures)
2435 */
2436 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
2437     
2438     $$.c = $1.c;
2439     if($$.c->opcode == OPCODE_COERCE_A) {
2440         $$.c = code_cutlast($$.c);
2441     }
2442     code_t*paramcode = $3.cc;
2443
2444     $$.t = TYPE_ANY;
2445     if($$.c->opcode == OPCODE_GETPROPERTY) {
2446         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2447         $$.c = code_cutlast($$.c);
2448         $$.c = code_append($$.c, paramcode);
2449         $$.c = abc_callproperty2($$.c, name, $3.len);
2450         multiname_destroy(name);
2451     } else if($$.c->opcode == OPCODE_GETSLOT) {
2452         int slot = (int)(ptroff_t)$$.c->data[0];
2453         trait_t*t = abc_class_find_slotid(state->cls->abc,slot);//FIXME
2454         if(t->kind!=TRAIT_METHOD) {
2455             //ok: flash allows to assign closures to members.
2456         }
2457         multiname_t*name = t->name;
2458         $$.c = code_cutlast($$.c);
2459         $$.c = code_append($$.c, paramcode);
2460         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
2461         $$.c = abc_callproperty2($$.c, name, $3.len);
2462     } else if($$.c->opcode == OPCODE_GETSUPER) {
2463         multiname_t*name = $$.c->data[0];$$.c->data[0]=0;
2464         $$.c = code_cutlast($$.c);
2465         $$.c = code_append($$.c, paramcode);
2466         $$.c = abc_callsuper2($$.c, name, $3.len);
2467         multiname_destroy(name);
2468     } else {
2469         $$.c = abc_getglobalscope($$.c);
2470         $$.c = code_append($$.c, paramcode);
2471         $$.c = abc_call($$.c, $3.len);
2472     }
2473    
2474     if(TYPE_IS_FUNCTION($1.t) && $1.t->function) {
2475         $$.t = $1.t->function->return_type;
2476     } else {
2477         $$.c = abc_coerce_a($$.c);
2478         $$.t = TYPE_ANY;
2479     }
2480 }
2481
2482 FUNCTIONCALL : "super" '(' MAYBE_EXPRESSION_LIST ')' {
2483     if(!state->cls) syntaxerror("super() not allowed outside of a class");
2484     if(!state->method) syntaxerror("super() not allowed outside of a function");
2485     if(!state->method->is_constructor) syntaxerror("super() not allowed outside of a constructor");
2486
2487     $$.c = code_new();
2488     $$.c = abc_getlocal_0($$.c);
2489
2490     $$.c = code_append($$.c, $3.cc);
2491     /*
2492     this is dependent on the control path, check this somewhere else
2493     if(state->method->has_super)
2494         syntaxerror("constructor may call super() only once");
2495     */
2496     state->method->has_super = 1;
2497
2498     $$.c = abc_constructsuper($$.c, $3.len);
2499     $$.c = abc_pushundefined($$.c);
2500     $$.t = TYPE_ANY;
2501 }
2502
2503 DELETE: "delete" E {
2504     $$.c = $2.c;
2505     if($$.c->opcode == OPCODE_COERCE_A) {
2506         $$.c = code_cutlast($$.c);
2507     }
2508     multiname_t*name = 0;
2509     if($$.c->opcode == OPCODE_GETPROPERTY) {
2510         $$.c->opcode = OPCODE_DELETEPROPERTY;
2511     } else if($$.c->opcode == OPCODE_GETSLOT) {
2512         int slot = (int)(ptroff_t)$$.c->data[0];
2513         multiname_t*name = abc_class_find_slotid(state->cls->abc,slot)->name;
2514         $$.c = code_cutlast($$.c);
2515         $$.c = abc_deleteproperty2($$.c, name);
2516     } else {
2517         $$.c = abc_getlocal_0($$.c);
2518         MULTINAME_LATE(m, $2.t?$2.t->access:ACCESS_PACKAGE, "");
2519         $$.c = abc_deleteproperty2($$.c, &m);
2520     }
2521     $$.t = TYPE_BOOLEAN;
2522 }
2523
2524 RETURN: "return" %prec prec_none {
2525     $$ = abc_returnvoid(0);
2526 }
2527 RETURN: "return" EXPRESSION {
2528     $$ = $2.c;
2529     $$ = abc_returnvalue($$);
2530 }
2531
2532 // ----------------------- expression types -------------------------------------
2533
2534 NONCOMMAEXPRESSION : E        %prec below_minus {$$=$1;}
2535 EXPRESSION : E                %prec below_minus {$$ = $1;}
2536 EXPRESSION : EXPRESSION ',' E %prec below_minus {
2537     $$.c = $1.c;
2538     $$.c = cut_last_push($$.c);
2539     $$.c = code_append($$.c,$3.c);
2540     $$.t = $3.t;
2541 }
2542 VOIDEXPRESSION : EXPRESSION %prec below_minus {
2543     $$=cut_last_push($1.c);
2544 }
2545
2546 // ----------------------- expression evaluation -------------------------------------
2547
2548 E : INNERFUNCTION %prec prec_none {$$ = $1;}
2549 //V : CONSTANT                    {$$ = 0;}
2550 E : CONSTANT
2551 //V : VAR_READ %prec T_IDENTIFIER {$$ = 0;}
2552 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
2553 //V : NEW                         {$$ = $1.c;}
2554 E : NEW                         {$$ = $1;}
2555 //V : DELETE                      {$$ = $1.c;}
2556 E : DELETE                      {$$ = $1;}
2557
2558 E : FUNCTIONCALL
2559
2560 E : T_REGEXP {
2561     $$.c = 0;
2562     namespace_t ns = {ACCESS_PACKAGE, ""};
2563     multiname_t m = {QNAME, &ns, 0, "RegExp"};
2564     if(!$1.options) {
2565         $$.c = abc_getlex2($$.c, &m);
2566         $$.c = abc_pushstring($$.c, $1.pattern);
2567         $$.c = abc_construct($$.c, 1);
2568     } else {
2569         $$.c = abc_getlex2($$.c, &m);
2570         $$.c = abc_pushstring($$.c, $1.pattern);
2571         $$.c = abc_pushstring($$.c, $1.options);
2572         $$.c = abc_construct($$.c, 2);
2573     }
2574     $$.t = TYPE_REGEXP;
2575 }
2576
2577 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
2578                    //MULTINAME(m, registry_getintclass());
2579                    //$$.c = abc_coerce2($$.c, &m); // FIXME
2580                    $$.t = TYPE_INT;
2581                   }
2582 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
2583                     $$.t = TYPE_INT;
2584                    }
2585 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
2586                   $$.t = TYPE_INT;
2587                  }
2588 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
2589                    $$.t = TYPE_UINT;
2590                   }
2591 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
2592                     $$.t = TYPE_FLOAT;
2593                    }
2594 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
2595                      $$.t = TYPE_STRING;
2596                     }
2597 CONSTANT : "undefined" {$$.c = abc_pushundefined(0);
2598                     $$.t = TYPE_ANY;
2599                    }
2600 CONSTANT : "true" {$$.c = abc_pushtrue(0);
2601                     $$.t = TYPE_BOOLEAN;
2602                    }
2603 CONSTANT : "false" {$$.c = abc_pushfalse(0);
2604                      $$.t = TYPE_BOOLEAN;
2605                     }
2606 CONSTANT : "null" {$$.c = abc_pushnull(0);
2607                     $$.t = TYPE_NULL;
2608                    }
2609
2610 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
2611              $$.t = TYPE_BOOLEAN;
2612             }
2613 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
2614              $$.t = TYPE_BOOLEAN;
2615             }
2616 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
2617               $$.t = TYPE_BOOLEAN;
2618              }
2619 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
2620               $$.t = TYPE_BOOLEAN;
2621              }
2622 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
2623               $$.t = TYPE_BOOLEAN;
2624              }
2625 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
2626               $$.t = TYPE_BOOLEAN;
2627               }
2628 E : E "!==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);$$.c = abc_not($$.c);
2629               $$.t = TYPE_BOOLEAN;
2630              }
2631 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
2632               $$.t = TYPE_BOOLEAN;
2633              }
2634
2635 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
2636               $$.c = $1.c;
2637               $$.c = converttype($$.c, $1.t, $$.t);
2638               $$.c = abc_dup($$.c);
2639               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
2640               $$.c = cut_last_push($$.c);
2641               $$.c = code_append($$.c,$3.c);
2642               $$.c = converttype($$.c, $3.t, $$.t);
2643               code_t*label = $$.c = abc_label($$.c);
2644               jmp->branch = label;
2645              }
2646 E : E "&&" E {
2647               $$.t = join_types($1.t, $3.t, 'A');
2648               /*printf("%08x:\n",$1.t);
2649               code_dump($1.c, 0, 0, "", stdout);
2650               printf("%08x:\n",$3.t);
2651               code_dump($3.c, 0, 0, "", stdout);
2652               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
2653               $$.c = $1.c;
2654               $$.c = converttype($$.c, $1.t, $$.t);
2655               $$.c = abc_dup($$.c);
2656               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
2657               $$.c = cut_last_push($$.c);
2658               $$.c = code_append($$.c,$3.c);
2659               $$.c = converttype($$.c, $3.t, $$.t);
2660               code_t*label = $$.c = abc_label($$.c);
2661               jmp->branch = label;              
2662              }
2663
2664 E : '!' E    {$$.c=$2.c;
2665               $$.c = abc_not($$.c);
2666               $$.t = TYPE_BOOLEAN;
2667              }
2668
2669 E : '~' E    {$$.c=$2.c;
2670               $$.c = abc_bitnot($$.c);
2671               $$.t = TYPE_INT;
2672              }
2673
2674 E : E '&' E {$$.c = code_append($1.c,$3.c);
2675              $$.c = abc_bitand($$.c);
2676              $$.t = TYPE_INT;
2677             }
2678
2679 E : E '^' E {$$.c = code_append($1.c,$3.c);
2680              $$.c = abc_bitxor($$.c);
2681              $$.t = TYPE_INT;
2682             }
2683
2684 E : E '|' E {$$.c = code_append($1.c,$3.c);
2685              $$.c = abc_bitor($$.c);
2686              $$.t = TYPE_INT;
2687             }
2688
2689 E : E ">>" E {$$.c = code_append($1.c,$3.c);
2690              $$.c = abc_rshift($$.c);
2691              $$.t = TYPE_INT;
2692             }
2693 E : E ">>>" E {$$.c = code_append($1.c,$3.c);
2694              $$.c = abc_urshift($$.c);
2695              $$.t = TYPE_INT;
2696             }
2697 E : E "<<" E {$$.c = code_append($1.c,$3.c);
2698              $$.c = abc_lshift($$.c);
2699              $$.t = TYPE_INT;
2700             }
2701
2702 E : E '/' E {$$.c = code_append($1.c,$3.c);
2703              $$.c = abc_divide($$.c);
2704              $$.t = TYPE_NUMBER;
2705             }
2706 E : E '%' E {$$.c = code_append($1.c,$3.c);
2707              $$.c = abc_modulo($$.c);
2708              $$.t = TYPE_NUMBER;
2709             }
2710 E : E '+' E {$$.c = code_append($1.c,$3.c);
2711              if(BOTH_INT($1.t, $3.t)) {
2712                 $$.c = abc_add_i($$.c);
2713                 $$.t = TYPE_INT;
2714              } else {
2715                 $$.c = abc_add($$.c);
2716                 $$.t = join_types($1.t,$3.t,'+');
2717              }
2718             }
2719 E : E '-' E {$$.c = code_append($1.c,$3.c);
2720              if(BOTH_INT($1.t,$3.t)) {
2721                 $$.c = abc_subtract_i($$.c);
2722                 $$.t = TYPE_INT;
2723              } else {
2724                 $$.c = abc_subtract($$.c);
2725                 $$.t = TYPE_NUMBER;
2726              }
2727             }
2728 E : E '*' E {$$.c = code_append($1.c,$3.c);
2729              if(BOTH_INT($1.t,$3.t)) {
2730                 $$.c = abc_multiply_i($$.c);
2731                 $$.t = TYPE_INT;
2732              } else {
2733                 $$.c = abc_multiply($$.c);
2734                 $$.t = TYPE_NUMBER;
2735              }
2736             }
2737
2738 E : E "in" E {$$.c = code_append($1.c,$3.c);
2739               $$.c = abc_in($$.c);
2740               $$.t = TYPE_BOOLEAN;
2741              }
2742
2743 E : E "as" E {char use_astype=0; // flash player's astype works differently than astypelate
2744               if(use_astype && TYPE_IS_CLASS($3.t)) {
2745                 MULTINAME(m,$3.t->cls);
2746                 $$.c = abc_astype2($1.c, &m);
2747                 $$.t = $3.t->cls;
2748               } else {
2749                 $$.c = code_append($1.c, $3.c);
2750                 $$.c = abc_astypelate($$.c);
2751                 $$.t = TYPE_ANY;
2752               }
2753              }
2754
2755 E : E "instanceof" E 
2756              {$$.c = code_append($1.c, $3.c);
2757               $$.c = abc_instanceof($$.c);
2758               $$.t = TYPE_BOOLEAN;
2759              }
2760
2761 E : E "is" E {$$.c = code_append($1.c, $3.c);
2762               $$.c = abc_istypelate($$.c);
2763               $$.t = TYPE_BOOLEAN;
2764              }
2765
2766 E : "typeof" '(' E ')' {
2767               $$.c = $3.c;
2768               $$.c = abc_typeof($$.c);
2769               $$.t = TYPE_STRING;
2770              }
2771
2772 E : "void" E {
2773               $$.c = cut_last_push($2.c);
2774               $$.c = abc_pushundefined($$.c);
2775               $$.t = TYPE_ANY;
2776              }
2777
2778 E : "void" { $$.c = abc_pushundefined(0);
2779              $$.t = TYPE_ANY;
2780            }
2781
2782 E : '(' EXPRESSION ')' {$$=$2;} //allow commas in here, too
2783
2784 E : '-' E {
2785   $$=$2;
2786   if(IS_INT($2.t)) {
2787    $$.c=abc_negate_i($$.c);
2788    $$.t = TYPE_INT;
2789   } else {
2790    $$.c=abc_negate($$.c);
2791    $$.t = TYPE_NUMBER;
2792   }
2793 }
2794
2795 E : E '[' E ']' {
2796   $$.c = $1.c;
2797   $$.c = code_append($$.c, $3.c);
2798
2799   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
2800   $$.c = abc_getproperty2($$.c, &m);
2801   $$.t = 0; // array elements have unknown type
2802 }
2803
2804 E : '[' MAYBE_EXPRESSION_LIST ']' {
2805     $$.c = code_new();
2806     $$.c = code_append($$.c, $2.cc);
2807     $$.c = abc_newarray($$.c, $2.len);
2808     $$.t = registry_getarrayclass();
2809 }
2810
2811 MAYBE_EXPRPAIR_LIST : {$$.cc=0;$$.len=0;}
2812 MAYBE_EXPRPAIR_LIST : EXPRPAIR_LIST {$$=$1;}
2813
2814 EXPRPAIR_LIST : NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2815     $$.cc = 0;
2816     $$.cc = code_append($$.cc, $1.c);
2817     $$.cc = code_append($$.cc, $3.c);
2818     $$.len = 2;
2819 }
2820 EXPRPAIR_LIST : EXPRPAIR_LIST ',' NONCOMMAEXPRESSION ':' NONCOMMAEXPRESSION {
2821     $$.cc = $1.cc;
2822     $$.len = $1.len+2;
2823     $$.cc = code_append($$.cc, $3.c);
2824     $$.cc = code_append($$.cc, $5.c);
2825 }
2826 //MAYBECOMMA: ','
2827 //MAYBECOMMA:
2828
2829 E : '{' MAYBE_EXPRPAIR_LIST '}' {
2830     $$.c = code_new();
2831     $$.c = code_append($$.c, $2.cc);
2832     $$.c = abc_newobject($$.c, $2.len/2);
2833     $$.t = registry_getobjectclass();
2834 }
2835
2836 E : E "*=" E { 
2837                code_t*c = $3.c;
2838                if(BOTH_INT($1.t,$3.t)) {
2839                 c=abc_multiply_i(c);
2840                } else {
2841                 c=abc_multiply(c);
2842                }
2843                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
2844                $$.c = toreadwrite($1.c, c, 0, 0);
2845                $$.t = $1.t;
2846               }
2847
2848 E : E "%=" E { 
2849                code_t*c = abc_modulo($3.c);
2850                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
2851                $$.c = toreadwrite($1.c, c, 0, 0);
2852                $$.t = $1.t;
2853               }
2854 E : E "<<=" E { 
2855                code_t*c = abc_lshift($3.c);
2856                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
2857                $$.c = toreadwrite($1.c, c, 0, 0);
2858                $$.t = $1.t;
2859               }
2860 E : E ">>=" E { 
2861                code_t*c = abc_rshift($3.c);
2862                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
2863                $$.c = toreadwrite($1.c, c, 0, 0);
2864                $$.t = $1.t;
2865               }
2866 E : E ">>>=" E { 
2867                code_t*c = abc_urshift($3.c);
2868                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
2869                $$.c = toreadwrite($1.c, c, 0, 0);
2870                $$.t = $1.t;
2871               }
2872 E : E "/=" E { 
2873                code_t*c = abc_divide($3.c);
2874                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
2875                $$.c = toreadwrite($1.c, c, 0, 0);
2876                $$.t = $1.t;
2877               }
2878 E : E "|=" E { 
2879                code_t*c = abc_bitor($3.c);
2880                c=converttype(c, TYPE_INT, $1.t);
2881                $$.c = toreadwrite($1.c, c, 0, 0);
2882                $$.t = $1.t;
2883               }
2884 E : E "+=" E { 
2885                code_t*c = $3.c;
2886
2887                if(TYPE_IS_INT($1.t)) {
2888                 c=abc_add_i(c);
2889                } else {
2890                 c=abc_add(c);
2891                 c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
2892                }
2893                
2894                $$.c = toreadwrite($1.c, c, 0, 0);
2895                $$.t = $1.t;
2896               }
2897 E : E "-=" E { code_t*c = $3.c; 
2898                if(TYPE_IS_INT($1.t)) {
2899                 c=abc_subtract_i(c);
2900                } else {
2901                 c=abc_subtract(c);
2902                 c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
2903                }
2904                
2905                $$.c = toreadwrite($1.c, c, 0, 0);
2906                $$.t = $1.t;
2907              }
2908 E : E '=' E { code_t*c = 0;
2909               c = code_append(c, $3.c);
2910               c = converttype(c, $3.t, $1.t);
2911               $$.c = toreadwrite($1.c, c, 1, 0);
2912               $$.t = $1.t;
2913             }
2914
2915 E : E '?' E ':' E %prec below_assignment { 
2916               $$.t = join_types($3.t,$5.t,'?');
2917               $$.c = $1.c;
2918               code_t*j1 = $$.c = abc_iffalse($$.c, 0);
2919               $$.c = code_append($$.c, $3.c);
2920               $$.c = converttype($$.c, $3.t, $$.t);
2921               code_t*j2 = $$.c = abc_jump($$.c, 0);
2922               $$.c = j1->branch = abc_label($$.c);
2923               $$.c = code_append($$.c, $5.c);
2924               $$.c = converttype($$.c, $3.t, $$.t);
2925               $$.c = j2->branch = abc_label($$.c);
2926             }
2927
2928 E : E "++" { code_t*c = 0;
2929              classinfo_t*type = $1.t;
2930              if((is_getlocal($1.c) && TYPE_IS_INT($1.t)) || TYPE_IS_NUMBER($1.t)) {
2931                  int nr = getlocalnr($1.c);
2932                  code_free($1.c);$1.c=0;
2933                  if(TYPE_IS_INT($1.t)) {
2934                     $$.c = abc_getlocal(0, nr);
2935                     $$.c = abc_inclocal_i($$.c, nr);
2936                  } else if(TYPE_IS_NUMBER($1.t)) {
2937                     $$.c = abc_getlocal(0, nr);
2938                     $$.c = abc_inclocal($$.c, nr);
2939                  } else syntaxerror("internal error");
2940              } else {
2941                  if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2942                      c=abc_increment_i(c);
2943                      type = TYPE_INT;
2944                  } else {
2945                      c=abc_increment(c);
2946                      type = TYPE_NUMBER;
2947                  }
2948                  c=converttype(c, type, $1.t);
2949                  $$.c = toreadwrite($1.c, c, 0, 1);
2950                  $$.t = $1.t;
2951              }
2952            }
2953
2954 // TODO: use inclocal, like with ++
2955 E : E "--" { code_t*c = 0;
2956              classinfo_t*type = $1.t;
2957              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2958                  c=abc_decrement_i(c);
2959                  type = TYPE_INT;
2960              } else {
2961                  c=abc_decrement(c);
2962                  type = TYPE_NUMBER;
2963              }
2964              c=converttype(c, type, $1.t);
2965              $$.c = toreadwrite($1.c, c, 0, 1);
2966              $$.t = $1.t;
2967             }
2968
2969 E : "++" %prec plusplus_prefix E { code_t*c = 0;
2970              classinfo_t*type = $2.t;
2971              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2972                  c=abc_increment_i(c);
2973                  type = TYPE_INT;
2974              } else {
2975                  c=abc_increment(c);
2976                  type = TYPE_NUMBER;
2977              }
2978              c=converttype(c, type, $2.t);
2979              $$.c = toreadwrite($2.c, c, 0, 0);
2980              $$.t = $2.t;
2981            }
2982
2983 E : "--" %prec minusminus_prefix E { code_t*c = 0;
2984              classinfo_t*type = $2.t;
2985              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
2986                  c=abc_decrement_i(c);
2987                  type = TYPE_INT;
2988              } else {
2989                  c=abc_decrement(c);
2990                  type = TYPE_NUMBER;
2991              }
2992              c=converttype(c, type, $2.t);
2993              $$.c = toreadwrite($2.c, c, 0, 0);
2994              $$.t = $2.t;
2995            }
2996
2997 E : "super" '.' T_IDENTIFIER 
2998            { if(!state->cls->info)
2999                   syntaxerror("super keyword not allowed outside a class");
3000               classinfo_t*t = state->cls->info->superclass;
3001               if(!t) t = TYPE_OBJECT;
3002
3003               memberinfo_t*f = registry_findmember(t, $3, 1);
3004               namespace_t ns = flags2namespace(f->flags, "");
3005               MEMBER_MULTINAME(m, f, $3);
3006               $$.c = 0;
3007               $$.c = abc_getlocal_0($$.c);
3008               $$.c = abc_getsuper2($$.c, &m);
3009               $$.t = memberinfo_gettype(f);
3010            }
3011
3012 E : E '.' T_IDENTIFIER
3013             {$$.c = $1.c;
3014              classinfo_t*t = $1.t;
3015              char is_static = 0;
3016              if(TYPE_IS_CLASS(t) && t->cls) {
3017                  t = t->cls;
3018                  is_static = 1;
3019              }
3020              if(t) {
3021                  memberinfo_t*f = registry_findmember(t, $3, 1);
3022                  char noslot = 0;
3023                  if(f && !is_static != !(f->flags&FLAG_STATIC))
3024                     noslot=1;
3025                  if(f && f->slot && !noslot) {
3026                      $$.c = abc_getslot($$.c, f->slot);
3027                  } else {
3028                      MEMBER_MULTINAME(m, f, $3);
3029                      $$.c = abc_getproperty2($$.c, &m);
3030                  }
3031                  /* determine type */
3032                  $$.t = memberinfo_gettype(f);
3033                  if(!$$.t)
3034                     $$.c = abc_coerce_a($$.c);
3035              } else {
3036                  /* when resolving a property on an unknown type, we do know the
3037                     name of the property (and don't seem to need the package), but
3038                     we need to make avm2 try out all access modes */
3039                  multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $3};
3040                  $$.c = abc_getproperty2($$.c, &m);
3041                  $$.c = abc_coerce_a($$.c);
3042                  $$.t = registry_getanytype();
3043              }
3044             }
3045
3046 VAR_READ : T_IDENTIFIER {
3047     $$.t = 0;
3048     $$.c = 0;
3049     classinfo_t*a = 0;
3050     memberinfo_t*f = 0;
3051
3052     variable_t*v;
3053     /* look at variables */
3054     if((v = find_variable($1))) {
3055         // $1 is a local variable
3056         $$.c = abc_getlocal($$.c, v->index);
3057         $$.t = v->type;
3058         break;
3059     }
3060
3061     int i_am_static = (state->method && state->method->info)?(state->method->info->flags&FLAG_STATIC):FLAG_STATIC;
3062
3063     /* look at current class' members */
3064     if(state->cls && (f = registry_findmember(state->cls->info, $1, 1)) &&
3065         (f->flags&FLAG_STATIC) >= i_am_static) {
3066         // $1 is a function in this class
3067         int var_is_static = (f->flags&FLAG_STATIC);
3068
3069         if(f->kind == MEMBER_METHOD) {
3070             $$.t = TYPE_FUNCTION(f);
3071         } else {
3072             $$.t = f->type;
3073         }
3074         if(var_is_static && !i_am_static) {
3075         /* access to a static member from a non-static location.
3076            do this via findpropstrict:
3077            there doesn't seem to be any non-lookup way to access
3078            static properties of a class */
3079             state->method->late_binding = 1;
3080             $$.t = f->type;
3081             namespace_t ns = {flags2access(f->flags), ""};
3082             multiname_t m = {QNAME, &ns, 0, $1};
3083             $$.c = abc_findpropstrict2($$.c, &m);
3084             $$.c = abc_getproperty2($$.c, &m);
3085             break;
3086         } else if(f->slot>0) {
3087             $$.c = abc_getlocal_0($$.c);
3088             $$.c = abc_getslot($$.c, f->slot);
3089             break;
3090         } else {
3091             namespace_t ns = {flags2access(f->flags), ""};
3092             multiname_t m = {QNAME, &ns, 0, $1};
3093             $$.c = abc_getlocal_0($$.c);
3094             $$.c = abc_getproperty2($$.c, &m);
3095             break;
3096         }
3097     } 
3098     
3099     /* look at actual classes, in the current package and imported */
3100     if((a = find_class($1))) {
3101         if(a->flags & FLAG_METHOD) {
3102             MULTINAME(m, a);
3103             $$.c = abc_findpropstrict2($$.c, &m);
3104             $$.c = abc_getproperty2($$.c, &m);
3105             if(a->function->kind == MEMBER_METHOD) {
3106                 $$.t = TYPE_FUNCTION(a->function);
3107             } else {
3108                 $$.t = a->function->type;
3109             }
3110         } else {
3111             if(a->slot) {
3112                 $$.c = abc_getglobalscope($$.c);
3113                 $$.c = abc_getslot($$.c, a->slot);
3114             } else {
3115                 MULTINAME(m, a);
3116                 $$.c = abc_getlex2($$.c, &m);
3117             }
3118             $$.t = TYPE_CLASS(a);
3119         }
3120         break;
3121     }
3122
3123     /* unknown object, let the avm2 resolve it */
3124     if(1) {
3125         as3_softwarning("Couldn't resolve '%s', doing late binding", $1);
3126         state->method->late_binding = 1;
3127                 
3128         multiname_t m = {MULTINAME, 0, &nopackage_namespace_set, $1};
3129
3130         $$.t = 0;
3131         $$.c = abc_findpropstrict2($$.c, &m);
3132         $$.c = abc_getproperty2($$.c, &m);
3133     }
3134 }
3135
3136 //TODO: 
3137 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
3138 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
3139 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
3140
3141 // ----------------- namespaces -------------------------------------------------
3142
3143 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER {$$=0;}
3144 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_IDENTIFIER {$$=0;}
3145 NAMESPACE_DECLARATION : MAYBE_MODIFIERS "namespace" T_IDENTIFIER '=' T_STRING {$$=0;}
3146
3147 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER {$$=0;}
3148