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