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