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