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