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