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