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