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