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