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