bugfixes, closure support
[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     tokenptr_t token;
43
44     classinfo_t*classinfo;
45     classinfo_list_t*classinfo_list;
46
47     int number_int;
48     unsigned int number_uint;
49     double number_float;
50     code_t*code;
51     typedcode_t value;
52     typedcode_list_t*value_list;
53     param_t* param;
54     params_t params;
55     char*string;
56 }
57
58
59 %token<token> T_IDENTIFIER
60 %token<string> T_STRING
61 %token<token> T_REGEXP
62 %token<token> T_EMPTY
63 %token<number_int> T_INT
64 %token<number_uint> T_UINT
65 %token<number_uint> T_BYTE
66 %token<number_uint> T_SHORT
67 %token<number_float> T_FLOAT
68
69 %token<token> KW_IMPLEMENTS
70 %token<token> KW_NAMESPACE "namespace"
71 %token<token> KW_PACKAGE "package"
72 %token<token> KW_PROTECTED
73 %token<token> KW_PUBLIC
74 %token<token> KW_PRIVATE
75 %token<token> KW_USE "use"
76 %token<token> KW_INTERNAL
77 %token<token> KW_NEW "new"
78 %token<token> KW_NATIVE
79 %token<token> KW_FUNCTION "function"
80 %token<token> KW_FOR "for"
81 %token<token> KW_CLASS "class"
82 %token<token> KW_CONST "const"
83 %token<token> KW_SET "set"
84 %token<token> KW_STATIC
85 %token<token> KW_IMPORT "import"
86 %token<token> KW_RETURN "return"
87 %token<token> KW_INTERFACE "interface"
88 %token<token> KW_NULL "null"
89 %token<token> KW_VAR "var"
90 %token<token> KW_DYNAMIC
91 %token<token> KW_OVERRIDE
92 %token<token> KW_FINAL
93 %token<token> KW_GET "get"
94 %token<token> KW_EXTENDS
95 %token<token> KW_FALSE "false"
96 %token<token> KW_TRUE "true"
97 %token<token> KW_BOOLEAN "Boolean"
98 %token<token> KW_UINT "uint"
99 %token<token> KW_INT "int"
100 %token<token> KW_WHILE "while"
101 %token<token> KW_NUMBER "Number"
102 %token<token> KW_STRING "String"
103 %token<token> KW_IF "if"
104 %token<token> KW_ELSE  "else"
105 %token<token> KW_BREAK   "break"
106 %token<token> KW_IS "is"
107 %token<token> KW_AS "as"
108
109 %token<token> T_EQEQ "=="
110 %token<token> T_EQEQEQ "==="
111 %token<token> T_NE "!="
112 %token<token> T_LE "<="
113 %token<token> T_GE ">="
114 %token<token> T_DIVBY "/=" 
115 %token<token> T_MODBY "%="
116 %token<token> T_PLUSBY "+=" 
117 %token<token> T_MINUSBY "-="
118 %token<token> T_SHRBY ">>="
119 %token<token> T_SHLBY "<<="
120 %token<token> T_USHRBY ">>>="
121 %token<token> T_OROR "||"
122 %token<token> T_ANDAND "&&"
123 %token<token> T_COLONCOLON "::"
124 %token<token> T_MINUSMINUS "--"
125 %token<token> T_PLUSPLUS "++"
126 %token<token> T_DOTDOT ".."
127 %token<token> T_DOTDOTDOT "..."
128 %token<token> T_SHL "<<"
129 %token<token> T_USHR ">>>"
130 %token<token> T_SHR ">>"
131 %token<token> T_SEMICOLON ';'
132 %token<token> T_STAR '*'
133 %token<token> T_DOT '.'
134
135 %type <token> X_IDENTIFIER VARCONST
136 %type <code> CODE
137 %type <code> CODEPIECE
138 %type <code> CODEBLOCK MAYBECODE
139 %type <token> PACKAGE_DECLARATION
140 %type <token> FUNCTION_DECLARATION
141 %type <code> VARIABLE_DECLARATION ONE_VARIABLE VARIABLE_LIST
142 %type <token> CLASS_DECLARATION
143 %type <token> NAMESPACE_DECLARATION
144 %type <token> INTERFACE_DECLARATION
145 %type <code> VOIDEXPRESSION
146 %type <value> EXPRESSION NONCOMMAEXPRESSION
147 %type <value> MAYBEEXPRESSION
148 %type <value> E
149 %type <value> CONSTANT
150 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
151 %type <token> USE_NAMESPACE
152 %type <code> FOR_INIT
153 %type <token> IMPORT
154 %type <classinfo> MAYBETYPE
155 %type <token> GETSET
156 %type <param> PARAM
157 %type <params> PARAM_LIST
158 %type <params> MAYBE_PARAM_LIST
159 %type <token> MODIFIERS
160 %type <token> MODIFIER_LIST
161 %type <classinfo_list> IMPLEMENTS_LIST
162 %type <classinfo> EXTENDS
163 %type <classinfo_list> EXTENDS_LIST
164 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
165 %type <classinfo_list> QNAME_LIST
166 %type <classinfo> TYPE
167 %type <token> VAR
168 //%type <token> VARIABLE
169 %type <value> VAR_READ
170 %type <value> NEW
171 //%type <token> T_IDENTIFIER
172 %type <token> MODIFIER
173 %type <token> PACKAGE
174 %type <value> FUNCTIONCALL
175 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
176
177 // precedence: from low to high
178 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
179
180 %left prec_none
181 %right '?' ':'
182 %nonassoc '='
183 %nonassoc "/=" "%="
184 %nonassoc "+=" "-="
185 %nonassoc ">>="
186 %nonassoc "<<="
187 %nonassoc ">>>="
188 %left "||"
189 %left "&&"
190 %nonassoc '|'
191 %nonassoc '^'
192 %nonassoc '&'
193 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
194 %nonassoc "is"
195 %left prec_belowminus
196 %left '-'
197 %left '+'
198 %left "<<"
199 %left ">>>"
200 %left ">>"
201 %left '%'
202 %left '/'
203 %left '*'
204 %left '!'
205 %left '~'
206 %left "--" "++"
207 %left '['
208 %nonassoc "as"
209 %left '.' ".." "::"
210 %nonassoc T_IDENTIFIER
211 %left below_semicolon
212 %left ';'
213 %nonassoc "else"
214 %left '('
215
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "new" "false" "true" "null"
220
221 %left prec_highest
222
223      
224 %{
225
226 static int yyerror(char*s)
227 {
228    syntaxerror("%s", s); 
229 }
230 static token_t* concat2(token_t* t1, token_t* t2)
231 {
232     NEW(token_t,t);
233     int l1 = strlen(t1->text);
234     int l2 = strlen(t2->text);
235     t->text = malloc(l1+l2+1);
236     memcpy(t->text   , t1->text, l1);
237     memcpy(t->text+l1, t2->text, l2);
238     t->text[l1+l2] = 0;
239     return t;
240 }
241 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
242 {
243     NEW(token_t,t);
244     int l1 = strlen(t1->text);
245     int l2 = strlen(t2->text);
246     int l3 = strlen(t3->text);
247     t->text = malloc(l1+l2+l3+1);
248     memcpy(t->text   , t1->text, l1);
249     memcpy(t->text+l1, t2->text, l2);
250     memcpy(t->text+l1+l2, t3->text, l3);
251     t->text[l1+l2+l3] = 0;
252     return t;
253 }
254 static char* concat3str(const char* t1, const char* t2, const char* t3)
255 {
256     int l1 = strlen(t1);
257     int l2 = strlen(t2);
258     int l3 = strlen(t3);
259     char*text = malloc(l1+l2+l3+1);
260     memcpy(text   , t1, l1);
261     memcpy(text+l1, t2, l2);
262     memcpy(text+l1+l2, t3, l3);
263     text[l1+l2+l3] = 0;
264     return text;
265 }
266
267 typedef struct _import {
268     char*package;
269 } import_t;
270
271 DECLARE_LIST(import);
272
273 typedef struct _state {
274     abc_file_t*file;
275     abc_script_t*init;
276
277     int level;
278
279     char*package;     
280     char*function;
281     /* code that needs to be executed at the start of
282        a method (like initializing local registers) */
283     code_t*initcode;
284
285     import_list_t*wildcard_imports;
286     dict_t*imports;
287     char has_own_imports;
288    
289     /* class data */
290     classinfo_t*clsinfo;
291     abc_class_t*cls;
292     code_t*cls_init;
293     code_t*cls_static_init;
294     
295     /* method data */
296     memberinfo_t*minfo;
297     abc_method_body_t*m;
298
299     array_t*vars;
300     int local_var_base;
301     char late_binding;
302 } state_t;
303
304 static state_t* state = 0;
305
306 DECLARE_LIST(state);
307
308 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
309
310 /* warning: list length of namespace set is undefined */
311 #define MULTINAME_LATE(m, access, package) \
312     namespace_t m##_ns = {access, package}; \
313     namespace_set_t m##_nsset; \
314     namespace_list_t m##_l;m##_l.next = 0; \
315     m##_nsset.namespaces = &m##_l; \
316     m##_nsset = m##_nsset; \
317     m##_l.namespace = &m##_ns; \
318     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
319
320 static state_list_t*state_stack=0;
321
322 static void new_state()
323 {
324     NEW(state_t, s);
325     NEW(state_list_t, sl);
326
327     state_t*oldstate = state;
328     if(state)
329         memcpy(s, state, sizeof(state_t)); //shallow copy
330     sl->next = state_stack;
331     sl->state = s;
332     if(oldstate) {
333         s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
334     }
335     if(!s->imports) {
336         s->imports = dict_new();
337     }
338     state_stack = sl;
339     state = s;
340     state->level++;
341     state->vars = array_new();
342     state->initcode = 0;
343     state->has_own_imports = 0;
344 }
345 static void state_has_imports()
346 {
347     state->wildcard_imports = list_clone(state->wildcard_imports);
348     state->imports = dict_clone(state->imports);
349     state->has_own_imports = 1;
350 }
351
352 static void old_state()
353 {
354     if(!state_stack || !state_stack->next)
355         syntaxerror("invalid nesting");
356     state_t*oldstate = state;
357     state_list_t*old = state_stack;
358     state_stack = state_stack->next;
359     free(old);
360     state = state_stack->state;
361     /*if(state->initcode) {
362         printf("residual initcode\n");
363         code_dump(state->initcode, 0, 0, "", stdout);
364     }*/
365     if(oldstate->has_own_imports) {
366         list_free(oldstate->wildcard_imports);
367         dict_destroy(oldstate->imports);oldstate->imports=0;
368     }
369     state->initcode = code_append(state->initcode, oldstate->initcode);
370 }
371 void initialize_state()
372 {
373     new_state();
374
375     state->file = abc_file_new();
376     state->file->flags &= ~ABCFILE_LAZY;
377     
378     state->init = abc_initscript(state->file, 0, 0);
379     code_t*c = state->init->method->body->code;
380
381     c = abc_getlocal_0(c);
382     c = abc_pushscope(c);
383   
384     /* findpropstrict doesn't just return a scope object- it
385        also makes it "active" somehow. Push local_0 on the
386        scope stack and read it back with findpropstrict, it'll
387        contain properties like "trace". Trying to find the same
388        property on a "vanilla" local_0 yields only a "undefined" */
389     //c = abc_findpropstrict(c, "[package]::trace");
390     
391     /*c = abc_getlocal_0(c);
392     c = abc_findpropstrict(c, "[package]::trace");
393     c = abc_coerce_a(c);
394     c = abc_setlocal_1(c);
395
396     c = abc_pushbyte(c, 0);
397     c = abc_setlocal_2(c);
398    
399     code_t*xx = c = abc_label(c);
400     c = abc_findpropstrict(c, "[package]::trace");
401     c = abc_pushstring(c, "prop:");
402     c = abc_hasnext2(c, 1, 2);
403     c = abc_dup(c);
404     c = abc_setlocal_3(c);
405     c = abc_callpropvoid(c, "[package]::trace", 2);
406     c = abc_getlocal_3(c);
407     c = abc_kill(c, 3);
408     c = abc_iftrue(c,xx);*/
409
410     c = abc_findpropstrict(c, "[package]::trace");
411     c = abc_pushstring(c, "[entering global init function]");
412     c = abc_callpropvoid(c, "[package]::trace", 1);
413     
414     state->init->method->body->code = c;
415 }
416 void* finalize_state()
417 {
418     if(state->level!=1) {
419         syntaxerror("unexpected end of file");
420     }
421     abc_method_body_t*m = state->init->method->body;
422     //__ popscope(m);
423     
424     __ findpropstrict(m, "[package]::trace");
425     __ pushstring(m, "[leaving global init function]");
426     __ callpropvoid(m, "[package]::trace", 1);
427     __ returnvoid(m);
428     return state->file;
429 }
430
431
432 static void startpackage(token_t*t) 
433 {
434     if(state->package) {
435         syntaxerror("Packages can not be nested."); 
436     } 
437     new_state();
438     char*name = t?t->text:"";
439     /*printf("entering package \"%s\"\n", name);*/
440     state->package = name;
441 }
442 static void endpackage()
443 {
444     /*printf("leaving package \"%s\"\n", state->package);*/
445     old_state();
446 }
447
448 char*globalclass=0;
449 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
450 {
451     if(state->cls) {
452         syntaxerror("inner classes now allowed"); 
453     }
454     new_state();
455     char*classname = name->text;
456
457     token_list_t*t=0;
458     classinfo_list_t*mlist=0;
459     /*printf("entering class %s\n", name->text);
460     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
461     if(extends) 
462         printf("  extends: %s.%s\n", extends->package, extends->name);
463     printf("  implements (%d): ", list_length(implements));
464     for(mlist=implements;mlist;mlist=mlist->next)  {
465         printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
466     }
467     printf("\n");
468     */
469
470     char public=0,internal=0,final=0,sealed=1;
471     for(t=modifiers->tokens;t;t=t->next) {
472         if(t->token->type == KW_INTERNAL) {
473             /* the programmer is being explicit- 
474                being internal is the default anyway */
475             internal = 1;
476         } else if(t->token->type == KW_PUBLIC) {
477             public = 1;
478         } else if(t->token->type == KW_FINAL) {
479             final = 1;
480         } else {
481             syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
482         }
483     }
484     if(public&&internal)
485         syntaxerror("public and internal not supported at the same time.");
486
487     /* create the class name, together with the proper attributes */
488     int access=0;
489     char*package=0;
490
491     if(!public && !state->package) {
492         access = ACCESS_PRIVATE; package = current_filename;
493     } else if(!public && state->package) {
494         access = ACCESS_PACKAGEINTERNAL; package = state->package;
495     } else if(state->package) {
496         access = ACCESS_PACKAGE; package = state->package;
497     } else {
498         syntaxerror("public classes only allowed inside a package");
499     }
500
501     if(registry_findclass(package, classname)) {
502         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
503     }
504     
505     state->clsinfo = classinfo_register(access, package, classname);
506
507     MULTINAME(classname2,state->clsinfo);
508     
509     multiname_t*extends2 = sig2mname(extends);
510
511     /*if(extends) {
512         state->cls_init = abc_getlocal_0(state->cls_init);
513         state->cls_init = abc_constructsuper(state->cls_init, 0);
514     }*/
515
516     state->cls = abc_class_new(state->file, &classname2, extends2);
517     if(final) abc_class_final(state->cls);
518     if(sealed) abc_class_sealed(state->cls);
519     if(interface) abc_class_interface(state->cls);
520
521     for(mlist=implements;mlist;mlist=mlist->next) {
522         MULTINAME(m, mlist->classinfo);
523         abc_class_add_interface(state->cls, &m);
524     }
525
526     /* now write the construction code for this class */
527     int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
528
529     abc_method_body_t*m = state->init->method->body;
530     __ getglobalscope(m);
531     classinfo_t*s = extends;
532
533     int count=0;
534     
535     while(s) {
536         //TODO: take a look at the current scope stack, maybe 
537         //      we can re-use something
538         s = s->superclass;
539         if(!s) 
540         break;
541        
542         multiname_t*s2 = sig2mname(s);
543         __ getlex2(m, s2);
544         multiname_destroy(s2);
545
546         __ pushscope(m); count++;
547         m->code = m->code->prev->prev; // invert
548     }
549     /* continue appending after last op end */
550     while(m->code && m->code->next) m->code = m->code->next; 
551
552     /* TODO: if this is one of *our* classes, we can also 
553              do a getglobalscope/getslot <nr> (which references
554              the init function's slots) */
555     if(extends2) {
556         __ getlex2(m, extends2);
557         __ dup(m);
558         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
559            stack is not the superclass */
560         __ pushscope(m);count++;
561     } else {
562         __ pushnull(m);
563         /* notice: we get a verify error #1107 if the top element on the scope 
564            stack is not the global object */
565         __ getlocal_0(m);
566         __ pushscope(m);count++;
567     }
568     __ newclass(m,state->cls);
569     while(count--) {
570         __ popscope(m);
571     }
572     __ setslot(m, slotindex);
573
574     /* flash.display.MovieClip handling */
575     if(!globalclass && public && classinfo_equals(registry_getMovieClip(),extends)) {
576         if(state->package && state->package[0]) {
577             globalclass = concat3str(state->package, ".", classname);
578         } else {
579             globalclass = strdup(classname);
580         }
581     }
582     multiname_destroy(extends2);
583 }
584
585 static void endclass()
586 {
587     if(state->cls_init) {
588         if(!state->cls->constructor) {
589             abc_method_body_t*m = abc_class_constructor(state->cls, 0, 0);
590             m->code = code_append(m->code, state->cls_init);
591             m->code = abc_returnvoid(m->code);
592         } else {
593             code_t*c = state->cls->constructor->body->code;
594             c = code_append(state->cls_init, c);
595             state->cls->constructor->body->code = c;
596
597         }
598     }
599     if(state->cls_static_init) {
600         if(!state->cls->static_constructor) {
601             abc_method_body_t*m = abc_class_staticconstructor(state->cls, 0, 0);
602             m->code = state->cls_static_init;
603         } else {
604             state->cls->static_constructor->body->code = 
605                 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
606         }
607     }
608
609     old_state();
610 }
611 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
612                           params_t*params, classinfo_t*type)
613 {
614     token_list_t*t;
615     new_state();
616     state->function = name->text;
617     
618     if(state->m) {
619         syntaxerror("not able to start another method scope");
620     }
621
622     multiname_t*type2 = sig2mname(type);
623     if(!strcmp(state->clsinfo->name,name->text)) {
624         state->m = abc_class_constructor(state->cls, type2, 0);
625     } else {
626         state->minfo = memberinfo_register(state->clsinfo, name->text, MEMBER_METHOD);
627         state->m = abc_class_method(state->cls, type2, name->text, 0);
628         // getslot on a member slot only returns "undefined", so no need
629         // to actually store these
630         //state->minfo->slot = state->m->method->trait->slot_id;
631     }
632     if(getset->type == KW_GET) {
633         state->m->method->trait->kind = TRAIT_GETTER;
634     }
635     if(getset->type == KW_SET) {
636         state->m->method->trait->kind = TRAIT_SETTER;
637     }
638     if(params->varargs) {
639         state->m->method->flags |= METHOD_NEED_REST;
640     }
641
642     param_list_t*p;
643     for(p=params->list;p;p=p->next) {
644         if(params->varargs && !p->next) {
645             break; //varargs: omit last parameter in function signature
646         }
647         multiname_t*m = sig2mname(p->param->type);
648         list_append(state->m->method->parameters, m);
649     }
650
651     /* state->vars is initialized by state_new */
652     array_append(state->vars, "this", state->clsinfo);
653     for(p=params->list;p;p=p->next) {
654         array_append(state->vars, p->param->name, 0);
655     }
656 }
657 static void endfunction(code_t*body)
658 {
659     code_t*c = 0;
660     if(state->late_binding) {
661         c = abc_getlocal_0(c);
662         c = abc_pushscope(c);
663     }
664     c = code_append(c, state->initcode);
665     c = code_append(c, body);
666
667     /* append return if necessary */
668     if(!c || c->opcode != OPCODE_RETURNVOID && 
669              c->opcode != OPCODE_RETURNVALUE)
670         c = abc_returnvoid(c);
671     
672     if(state->m->code) syntaxerror("internal error");
673     state->m->code = c;
674     old_state();
675 }
676
677
678 static token_t* empty_token()
679 {
680     NEW(token_t,t);
681     t->type=T_EMPTY;
682     t->text=0;
683     return t;
684 }
685
686 void extend(token_t*list, token_t*add) {
687     list_append(list->tokens,add);
688     if(!list->text)
689         list->text = add->text;
690 }
691 void extend_s(token_t*list, char*seperator, token_t*add) {
692     list_append(list->tokens,add);
693     char*t1 = list->text;
694     char*t2 = seperator;
695     char*t3 = add->text;
696     int l1 = strlen(t1);
697     int l2 = strlen(t2);
698     int l3 = strlen(t3);
699     list->text = malloc(l1+l2+l3+1);
700     strcpy(list->text, t1);
701     strcpy(list->text+l1, t2);
702     strcpy(list->text+l1+l2, t3);
703     list->text[l1+l2+l3]=0;
704 }
705
706 static int find_variable(char*name, classinfo_t**m)
707 {
708     state_list_t* s = state_stack;
709     while(s) {
710         int i = array_find(s->state->vars, name);
711         if(i>=0) {
712             if(m) {
713                 *m = array_getvalue(s->state->vars, i);
714             }
715             return i + s->state->local_var_base;
716         }
717         s = s->next;
718     }
719     return -1;
720
721 static int find_variable_safe(char*name, classinfo_t**m)
722 {
723     int i = find_variable(name, m);
724     if(i<0)
725         syntaxerror("undefined variable: %s", name);
726     return i;
727 }
728 static char variable_exists(char*name) 
729 {
730     return array_contains(state->vars, name);
731 }
732 static int new_variable(char*name, classinfo_t*type)
733 {
734     return array_append(state->vars, name, type) + state->local_var_base;
735 }
736 #define TEMPVARNAME "__as3_temp__"
737 static int gettempvar()
738 {
739     int i = find_variable(TEMPVARNAME, 0);
740     if(i<0) {
741         return new_variable(TEMPVARNAME, 0);
742     } else {
743         return i;
744     }
745 }
746
747 code_t* killvars(code_t*c) 
748 {
749     int t;
750     for(t=0;t<state->vars->num;t++) {
751         classinfo_t*type = array_getvalue(state->vars, t);
752         //do this always, otherwise register types don't match
753         //in the verifier when doing nested loops
754         //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
755             c = abc_kill(c, t+state->local_var_base);
756         //}
757     }
758     return c;
759 }
760
761 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
762 {
763     return 1; // FIXME
764 }
765
766 void breakjumpsto(code_t*c, code_t*jump) 
767 {
768     while(c->prev) 
769         c=c->prev;
770     while(c) {
771         if(c->opcode == OPCODE___BREAK__) {
772             c->opcode = OPCODE_JUMP;
773             c->branch = jump;
774         }
775         c = c->next;
776     }
777 }
778
779 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
780 {
781     if(!type1 || !type2) 
782         return registry_getanytype();
783     if(TYPE_IS_ANY(type1) || TYPE_IS_ANY(type2))
784         return registry_getanytype();
785     if(type1 == type2)
786         return type1;
787     return registry_getanytype();
788 }
789 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
790 {
791     if(from==to)
792         return c;
793     if(!to) {
794         /*TODO: can omit this if from is zero? */
795         return abc_coerce_a(c);
796     }
797     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
798         MULTINAME(m, TYPE_UINT);
799         return abc_coerce2(c, &m);
800     }
801     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
802         MULTINAME(m, TYPE_INT);
803         return abc_coerce2(c, &m);
804     }
805     return c;
806 }
807
808 code_t*defaultvalue(code_t*c, classinfo_t*type)
809 {
810     if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
811        c = abc_pushbyte(c, 0);
812     } else if(TYPE_IS_BOOLEAN(type)) {
813        c = abc_pushfalse(c);
814     } else {
815        c = abc_pushnull(c);
816     }
817     return c;
818 }
819
820 char is_pushundefined(code_t*c)
821 {
822     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
823 }
824
825 static code_t* toreadwrite(code_t*in, code_t*middlepart, char justassign)
826 {
827     /* converts this:
828
829        [prefix code] [read instruction]
830
831        to this:
832
833        [prefix code] ([dup]) [read instruction] [middlepart] [setvar] [write instruction] [getvar]
834     */
835     
836     if(in && in->opcode == OPCODE_COERCE_A) {
837         in = code_cutlast(in);
838     }
839     if(in->next)
840         syntaxerror("internal error");
841
842     /* chop off read instruction */
843     code_t*prefix = in;
844     code_t*r = in;
845     if(r->prev) {
846         prefix = r->prev;r->prev = 0;
847         prefix->next=0;
848     } else {
849         prefix = 0;
850     }
851
852     /* generate the write instruction, and maybe append a dup to the prefix code */
853     code_t* write = abc_nop(0);
854     if(r->opcode == OPCODE_GETPROPERTY) {
855         write->opcode = OPCODE_SETPROPERTY;
856         multiname_t*m = (multiname_t*)r->data[0];
857         write->data[0] = multiname_clone(m);
858         if(m->type != QNAME)
859             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
860         if(!justassign)
861             prefix = abc_dup(prefix); // we need the object, too
862     } else if(r->opcode == OPCODE_GETSLOT) {
863         write->opcode = OPCODE_SETSLOT;
864         write->data[0] = r->data[0];
865         if(!justassign)
866             prefix = abc_dup(prefix); // we need the object, too
867     } else if(r->opcode == OPCODE_GETLOCAL) { 
868         write->opcode = OPCODE_SETLOCAL;
869         write->data[0] = r->data[0];
870     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
871         write->opcode = OPCODE_SETLOCAL_0;
872     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
873         write->opcode = OPCODE_SETLOCAL_1;
874     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
875         write->opcode = OPCODE_SETLOCAL_2;
876     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
877         write->opcode = OPCODE_SETLOCAL_3;
878     } else {
879         code_dump(r, 0, 0, "", stdout);
880         syntaxerror("illegal lvalue: can't assign a value to this expression");
881     }
882     code_t* c = 0;
883     
884     int temp = -1;
885     if(!justassign) {
886         /* read value, modify it with middle part, and write it again,
887            using prefix only once and making sure (by using a temporary
888            register) that the return value is what we just wrote */
889         temp = gettempvar();
890         c = code_append(c, prefix);
891         c = code_append(c, r);
892         c = code_append(c, middlepart);
893         c = abc_dup(c);
894         c = abc_setlocal(c, temp);
895         c = code_append(c, write);
896         c = abc_getlocal(c, temp);
897         c = abc_kill(c, temp);
898     } else {
899         /* simpler version: overwrite the value without reading
900            it out first */
901         if(prefix) {
902             c = code_append(c, prefix);
903             c = abc_dup(c);
904         }
905         c = code_append(c, middlepart);
906         c = code_append(c, write);
907         c = code_append(c, r);
908     }
909
910     return c;
911 }
912
913
914 %}
915
916
917 %%
918
919 /* ------------ code blocks / statements ---------------- */
920
921 PROGRAM: MAYBECODE
922
923 MAYBECODE: CODE {$$=$1;}
924 MAYBECODE:      {$$=code_new();}
925
926 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
927 CODE: CODEPIECE {$$=$1;}
928
929 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
930 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
931 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
932 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
933 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
934 CODEPIECE: ';'                   {$$=code_new();}
935 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
936 CODEPIECE: VOIDEXPRESSION        {$$=$1}
937 CODEPIECE: FOR                   {$$=$1}
938 CODEPIECE: WHILE                 {$$=$1}
939 CODEPIECE: BREAK                 {$$=$1}
940 CODEPIECE: RETURN                {$$=$1}
941 CODEPIECE: IF                    {$$=$1}
942 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
943 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
944
945 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
946 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
947 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
948
949 /* ------------ variables --------------------------- */
950
951 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
952                 |                {$$.c=abc_pushundefined(0);
953                                   $$.t=TYPE_ANY;
954                                  }
955
956 VAR : "const" | "var"
957 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
958
959 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
960 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
961
962 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
963 {
964     if(variable_exists($2->text))
965         syntaxerror("Variable %s already defined", $2->text);
966    
967     if(!is_subtype_of($4.t, $3)) {
968         syntaxerror("Can't convert %s to %s", $4.t->name, 
969                                               $3->name);
970     }
971
972     int index = new_variable($2->text, $3);
973     
974     if($3) {
975         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
976             $$ = $4.c;
977             $$ = converttype($$, $4.t, $3);
978             $$ = abc_setlocal($$, index);
979         } else {
980             $$ = defaultvalue(0, $3);
981             $$ = abc_setlocal($$, index);
982         }
983
984         /* push default value for type on stack */
985         state->initcode = defaultvalue(state->initcode, $3);
986         state->initcode = abc_setlocal(state->initcode, index);
987     } else {
988         /* only bother to actually set this variable if its syntax is either
989             var x:type;
990            or
991             var x=expr;
992         */
993         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
994             $$ = $4.c;
995             $$ = abc_coerce_a($$);
996             $$ = abc_setlocal($$, index);
997         } else {
998             $$ = code_new();
999         }
1000     }
1001     
1002     /* that's the default for a local register, anyway
1003         else {
1004         state->initcode = abc_pushundefined(state->initcode);
1005         state->initcode = abc_setlocal(state->initcode, index);
1006     }*/
1007     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1008 }
1009
1010 /* ------------ control flow ------------------------- */
1011
1012 MAYBEELSE:  %prec prec_none {$$ = code_new();}
1013 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1014 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1015
1016 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1017     $$ = state->initcode;state->initcode=0;
1018
1019     $$ = code_append($$, $4.c);
1020     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1021    
1022     $$ = code_append($$, $6);
1023     if($7) {
1024         myjmp = $$ = abc_jump($$, 0);
1025     }
1026     myif->branch = $$ = abc_label($$);
1027     if($7) {
1028         $$ = code_append($$, $7);
1029         myjmp->branch = $$ = abc_label($$);
1030     }
1031     
1032     $$ = killvars($$);old_state();
1033 }
1034
1035 FOR_INIT : {$$=code_new();}
1036 FOR_INIT : VARIABLE_DECLARATION
1037 FOR_INIT : VOIDEXPRESSION
1038
1039 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1040     $$ = state->initcode;state->initcode=0;
1041
1042     $$ = code_append($$, $4);
1043     code_t*loopstart = $$ = abc_label($$);
1044     $$ = code_append($$, $6.c);
1045     code_t*myif = $$ = abc_iffalse($$, 0);
1046     $$ = code_append($$, $10);
1047     $$ = code_append($$, $8);
1048     $$ = abc_jump($$, loopstart);
1049     code_t*out = $$ = abc_label($$);
1050     breakjumpsto($$, out);
1051     myif->branch = out;
1052
1053     $$ = killvars($$);old_state();
1054 }
1055
1056 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1057     $$ = state->initcode;state->initcode=0;
1058
1059     code_t*myjmp = $$ = abc_jump($$, 0);
1060     code_t*loopstart = $$ = abc_label($$);
1061     $$ = code_append($$, $6);
1062     myjmp->branch = $$ = abc_label($$);
1063     $$ = code_append($$, $4.c);
1064     $$ = abc_iftrue($$, loopstart);
1065     code_t*out = $$ = abc_label($$);
1066     breakjumpsto($$, out);
1067
1068     $$ = killvars($$);old_state();
1069 }
1070
1071 BREAK : "break" {
1072     $$ = abc___break__(0);
1073 }
1074
1075 /* ------------ packages and imports ---------------- */
1076
1077 X_IDENTIFIER: T_IDENTIFIER
1078             | "package"
1079
1080 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
1081 PACKAGE: X_IDENTIFIER             {$$=$1;}
1082
1083 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1084 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
1085
1086 IMPORT : "import" QNAME {
1087        classinfo_t*c = $2;
1088        if(!c) 
1089             syntaxerror("Couldn't import class\n");
1090        state_has_imports();
1091        dict_put(state->imports, c->name, c);
1092        $$=0;
1093 }
1094 IMPORT : "import" PACKAGE '.' '*' {
1095        NEW(import_t,i);
1096        i->package = $2->text;
1097        state_has_imports();
1098        list_append(state->wildcard_imports, i);
1099        $$=0;
1100 }
1101
1102 /* ------------ classes and interfaces (header) -------------- */
1103
1104 MODIFIERS : {$$=empty_token();}
1105 MODIFIERS : MODIFIER_LIST {$$=$1}
1106 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1107 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
1108 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1109
1110 EXTENDS : {$$=registry_getobjectclass();}
1111 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1112
1113 EXTENDS_LIST : {$$=list_new();}
1114 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1115
1116 IMPLEMENTS_LIST : {$$=list_new();}
1117 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1118
1119 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER 
1120                               EXTENDS IMPLEMENTS_LIST 
1121                               '{' {startclass($1,$3,$4,$5, 0);} 
1122                               MAYBE_DECLARATION_LIST 
1123                               '}' {endclass();}
1124
1125 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER 
1126                               EXTENDS_LIST 
1127                               '{' {startclass($1,$3,0,$4,1);}
1128                               MAYBE_IDECLARATION_LIST 
1129                               '}' {endclass();}
1130
1131 /* ------------ classes and interfaces (body) -------------- */
1132
1133 MAYBE_DECLARATION_LIST : 
1134 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1135 DECLARATION_LIST : DECLARATION
1136 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1137 DECLARATION : ';'
1138 DECLARATION : SLOT_DECLARATION
1139 DECLARATION : FUNCTION_DECLARATION
1140
1141 /* ------------ classes and interfaces (body, slots ) ------- */
1142
1143 VARCONST: "var" | "const"
1144 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1145
1146     memberinfo_t* info = memberinfo_register(state->clsinfo, $3->text, MEMBER_SLOT);
1147     info->type = $4;
1148
1149     trait_t*t=0;
1150     if($4) {
1151         MULTINAME(m, $4);
1152         t=abc_class_slot(state->cls, $3->text, &m);
1153     } else {
1154         t=abc_class_slot(state->cls, $3->text, 0);
1155     }
1156     if($2->type==KW_CONST) {
1157         t->kind= TRAIT_CONST;
1158     }
1159     info->slot = t->slot_id;
1160     if($5.c && !is_pushundefined($5.c)) {
1161         code_t*c = 0;
1162         c = abc_getlocal_0(c);
1163         c = code_append(c, $5.c);
1164         c = converttype(c, $5.t, $4);
1165         c = abc_setslot(c, t->slot_id);
1166         //c = abc_setproperty(c, $3->text); 
1167         state->cls_init = code_append(state->cls_init, c);
1168     }
1169 }
1170
1171 /* ------------ classes and interfaces (body, functions) ------- */
1172
1173 // non-vararg version
1174 MAYBE_PARAM_LIST: {
1175     memset(&$$,0,sizeof($$));
1176 }
1177 MAYBE_PARAM_LIST: PARAM_LIST {
1178     $$=$1;
1179 }
1180
1181 // vararg version
1182 MAYBE_PARAM_LIST: "..." PARAM {
1183     memset(&$$,0,sizeof($$));
1184     $$.varargs=1;
1185     list_append($$.list, $2);
1186 }
1187 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1188     $$ =$1;
1189     $$.varargs=1;
1190     list_append($$.list, $4);
1191 }
1192
1193 // non empty
1194 PARAM_LIST: PARAM_LIST ',' PARAM {
1195     $$ = $1;
1196     list_append($$.list, $3);
1197 }
1198 PARAM_LIST: PARAM {
1199     memset(&$$,0,sizeof($$));
1200     list_append($$.list, $1);
1201 }
1202 PARAM:  T_IDENTIFIER ':' TYPE {
1203      $$ = malloc(sizeof(param_t));
1204      $$->name=$1->text;$$->type = $3;
1205 }
1206 PARAM:  T_IDENTIFIER          {
1207      $$ = malloc(sizeof(param_t));
1208      $$->name=$1->text;$$->type = TYPE_ANY;
1209 }
1210
1211 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1212                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1213 {
1214     if(!state->m) syntaxerror("internal error: undefined function");
1215     endfunction($11);
1216 }
1217
1218 /* ------------- package + class ids --------------- */
1219
1220 CLASS: T_IDENTIFIER {
1221
1222     /* try current package */
1223     $$ = registry_findclass(state->package, $1->text);
1224
1225     /* try explicit imports */
1226     dictentry_t* e = dict_get_slot(state->imports, $1->text);
1227     while(e) {
1228         if($$)
1229             break;
1230         if(!strcmp(e->key, $1->text)) {
1231             $$ = (classinfo_t*)e->data;
1232         }
1233         e = e->next;
1234     }
1235
1236     /* try package.* imports */
1237     import_list_t*l = state->wildcard_imports;
1238     while(l) {
1239         if($$)
1240             break;
1241         //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1242         $$ = registry_findclass(l->import->package, $1->text);
1243         l = l->next;
1244     }
1245
1246     /* try global package */
1247     if(!$$) {
1248         $$ = registry_findclass("", $1->text);
1249     }
1250
1251     if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1252 }
1253
1254 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1255     $$ = registry_findclass($1->text, $3->text);
1256     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1257 }
1258
1259 QNAME: PACKAGEANDCLASS
1260      | CLASS
1261
1262
1263 /* ----------function calls, constructor calls ------ */
1264
1265 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1266 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1267
1268 MAYBE_EXPRESSION_LIST : {$$=0;}
1269 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1270 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1271                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1272                                                   *t = $1;
1273                                                   list_append($$, t);}
1274 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1275                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1276                                                   *t = $3;
1277                                                   list_append($$, t);}
1278
1279 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1280     MULTINAME(m, $2);
1281     $$.c = code_new();
1282
1283     /* TODO: why do we have to *find* our own classes? */
1284     $$.c = abc_findpropstrict2($$.c, &m);
1285
1286     typedcode_list_t*l = $3;
1287     int len = 0;
1288     while(l) {
1289         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1290         l = l->next;
1291         len ++;
1292     }
1293     $$.c = abc_constructprop2($$.c, &m, len);
1294     $$.t = $2;
1295 }
1296
1297 /* TODO: use abc_call (for calling local variables),
1298          abc_callstatic (for calling own methods) 
1299          call (for closures)
1300 */
1301 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1302     typedcode_list_t*l = $3;
1303     int len = 0;
1304     code_t*paramcode = 0;
1305     while(l) {
1306         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1307         l = l->next;
1308         len ++;
1309     }
1310        
1311     $$.c = $1.c;
1312     if($$.c->opcode == OPCODE_COERCE_A) {
1313         $$.c = code_cutlast($$.c);
1314     }
1315
1316     $$.t = TYPE_ANY;
1317     multiname_t*name = 0;
1318     if($$.c->opcode == OPCODE_GETPROPERTY) {
1319         name = multiname_clone($$.c->data[0]);
1320         $$.c = code_cutlast($$.c);
1321         $$.c = code_append($$.c, paramcode);
1322         $$.c = abc_callproperty2($$.c, name, len);
1323     } else if($$.c->opcode == OPCODE_GETSLOT) {
1324         int slot = (int)(ptroff_t)$$.c->data[0];
1325         trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1326         if(t->kind!=TRAIT_METHOD) {
1327             //flash allows to assign closures to members.
1328             //syntaxerror("not a function");
1329         }
1330         name = t->name;
1331         $$.c = code_cutlast($$.c);
1332         $$.c = code_append($$.c, paramcode);
1333         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1334         $$.c = abc_callproperty2($$.c, name, len);
1335     } else {
1336         $$.c = abc_getlocal_0($$.c);
1337         $$.c = code_append($$.c, paramcode);
1338         $$.c = abc_call($$.c, len);
1339     }
1340    
1341     memberinfo_t*f = 0;
1342     if(TYPE_IS_FUNCTION($1.t) &&
1343        (f = registry_findmember($1.t, "__funcptr__"))) {
1344         $$.t = f->return_type;
1345     } else {
1346         $$.c = abc_coerce_a($$.c);
1347         $$.t = TYPE_ANY;
1348     }
1349 }
1350
1351 RETURN: "return" %prec prec_none {
1352     $$ = abc_returnvoid(0);
1353 }
1354 RETURN: "return" EXPRESSION {
1355     $$ = $2.c;
1356     $$ = abc_returnvalue($$);
1357 }
1358 // ----------------------- expression types -------------------------------------
1359
1360 NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
1361 EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
1362 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1363     $$.c = $1.c;
1364     $$.c = cut_last_push($$.c);
1365     $$.c = code_append($$.c,$3.c);
1366     $$.t = $3.t;
1367 }
1368 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1369
1370 // ----------------------- expression evaluation -------------------------------------
1371
1372 E : CONSTANT
1373 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1374 E : NEW                         {$$ = $1;}
1375 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1376                                  $$.t = TYPE_ANY;
1377                                 }
1378 E : FUNCTIONCALL
1379 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1380              $$.t = TYPE_BOOLEAN;
1381             }
1382 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1383              $$.t = TYPE_BOOLEAN;
1384             }
1385 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1386               $$.t = TYPE_BOOLEAN;
1387              }
1388 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1389               $$.t = TYPE_BOOLEAN;
1390              }
1391 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1392               $$.t = TYPE_BOOLEAN;
1393              }
1394 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1395               $$.t = TYPE_BOOLEAN;
1396              }
1397 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1398               $$.t = TYPE_BOOLEAN;
1399              }
1400
1401 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1402               $$.c = $1.c;
1403               $$.c = converttype($$.c, $1.t, $$.t);
1404               $$.c = abc_dup($$.c);
1405               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1406               $$.c = cut_last_push($$.c);
1407               $$.c = code_append($$.c,$3.c);
1408               $$.c = converttype($$.c, $3.t, $$.t);
1409               code_t*label = $$.c = abc_label($$.c);
1410               jmp->branch = label;
1411              }
1412 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1413               $$.c = $1.c;
1414               $$.c = converttype($$.c, $1.t, $$.t);
1415               $$.c = abc_dup($$.c);
1416               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1417               $$.c = cut_last_push($$.c);
1418               $$.c = code_append($$.c,$3.c);
1419               $$.c = converttype($$.c, $3.t, $$.t);
1420               code_t*label = $$.c = abc_label($$.c);
1421               jmp->branch = label;              
1422              }
1423
1424 E : '!' E    {$$.c=$2.c;
1425               $$.c = abc_not($$.c);
1426               $$.t = TYPE_BOOLEAN;
1427              }
1428
1429 E : E '-' E
1430 E : E '/' E
1431 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1432              $$.t = join_types($1.t, $3.t, '+');
1433             }
1434 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1435              $$.t = join_types($1.t, $3.t, '%');
1436             }
1437 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1438              $$.t = join_types($1.t, $3.t, '*');
1439             }
1440
1441 E : E "as" E
1442 E : E "is" E
1443 E : '(' E ')' {$$=$2;}
1444 E : '-' E {$$=$2;}
1445
1446 E : E '[' E ']' {
1447   $$.c = $1.c;
1448   $$.c = code_append($$.c, $3.c);
1449  
1450   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1451   $$.c = abc_getproperty2($$.c, &m);
1452 }
1453
1454 E : E "+=" E { 
1455                code_t*c = $3.c;
1456                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1457                 c=abc_add_i(c);
1458                } else {
1459                 c=abc_add(c);
1460                }
1461                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1462                
1463                $$.c = toreadwrite($1.c, c, 0);
1464                $$.t = $1.t;
1465               }
1466 E : E "-=" E { code_t*c = $3.c; 
1467                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1468                 c=abc_subtract_i(c);
1469                } else {
1470                 c=abc_subtract(c);
1471                }
1472                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1473                
1474                $$.c = toreadwrite($1.c, c, 0);
1475                $$.t = $1.t;
1476              }
1477 E : E '=' E { code_t*c = 0;
1478               c = code_append(c, $3.c);
1479               c = converttype(c, $3.t, $1.t);
1480               $$.c = toreadwrite($1.c, c, 1);
1481               $$.t = $1.t;
1482             }
1483
1484 // TODO: use inclocal where appropriate
1485 E : E "++" { code_t*c = 0;
1486              classinfo_t*type = $1.t;
1487              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1488                  c=abc_increment_i(c);
1489              } else {
1490                  c=abc_increment(c);
1491                  type = TYPE_NUMBER;
1492              }
1493              c=converttype(c, type, $1.t);
1494              $$.c = toreadwrite($1.c, c, 0);
1495              $$.t = $1.t;
1496            }
1497 E : E "--" { code_t*c = 0;
1498              classinfo_t*type = $1.t;
1499              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1500                  c=abc_increment_i(c);
1501              } else {
1502                  c=abc_increment(c);
1503                  type = TYPE_NUMBER;
1504              }
1505              c=converttype(c, type, $1.t);
1506              $$.c = toreadwrite($1.c, c, 0);
1507              $$.t = $1.t;
1508             }
1509
1510 E : E '.' T_IDENTIFIER
1511             {$$.c = $1.c;
1512              if($$.t) {
1513                  memberinfo_t*f = registry_findmember($$.t, $3->text);
1514
1515                  if(f && f->slot) {
1516                      $$.c = abc_getslot($$.c, f->slot);
1517                  } else {
1518                      namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
1519                      multiname_t m = {QNAME, &ns, 0, $3->text};
1520                      $$.c = abc_getproperty2($$.c, &m);
1521                  }
1522                  /* determine type */
1523                  if(f) {
1524                     if(f->kind == MEMBER_METHOD) {
1525                         $$.t = TYPE_FUNCTION(f);
1526                     } else {
1527                         $$.t = f->type;
1528                     }
1529                  } else {
1530                     $$.c = abc_coerce_a($$.c);
1531                     $$.t = registry_getanytype();
1532                  }
1533              } else {
1534                  namespace_t ns = {ACCESS_PACKAGE, ""};
1535                  multiname_t m = {QNAME, &ns, 0, $3->text};
1536                  $$.c = abc_getproperty2($$.c, &m);
1537                  $$.c = abc_coerce_a($$.c);
1538                  $$.t = registry_getanytype();
1539              }
1540             }
1541
1542 VAR_READ : T_IDENTIFIER {
1543     $$.t = 0;
1544     $$.c = 0;
1545     int i;
1546     memberinfo_t*f = 0;
1547     if((i = find_variable($1->text, &$$.t)) >= 0) {
1548         // $1 is a local variable
1549         $$.c = abc_getlocal($$.c, i);
1550     } else if((f = registry_findmember(state->clsinfo, $1->text))) {
1551         // $1 is a function in this class
1552         if(f->kind == MEMBER_METHOD) {
1553             $$.t = TYPE_FUNCTION(f);
1554         } else {
1555             $$.t = f->type;
1556         }
1557         if(f->slot>0) {
1558             $$.c = abc_getlocal_0($$.c);
1559             $$.c = abc_getslot($$.c, f->slot);
1560         } else {
1561             namespace_t ns = {state->clsinfo->access, ""};
1562             multiname_t m = {QNAME, &ns, 0, $1->text};
1563             $$.c = abc_getlocal_0($$.c);
1564             $$.c = abc_getproperty2($$.c, &m);
1565         }
1566     } else {
1567         // let the avm2 resolve $1 
1568         if(strcmp($1->text,"trace"))
1569         warning("Couldn't resolve %s, doing late binding", $1->text);
1570         state->late_binding = 1;
1571
1572         $$.t = 0;
1573         $$.c = abc_findpropstrict($$.c, $1->text);
1574         $$.c = abc_getproperty($$.c, $1->text);
1575     }
1576 }
1577
1578
1579 // ------------------------------------------------------------------------------
1580
1581
1582 TYPE : QNAME {$$=$1;}
1583      | '*'        {$$=registry_getanytype();}
1584      |  "String"  {$$=registry_getstringclass();}
1585      |  "int"     {$$=registry_getintclass();}
1586      |  "uint"    {$$=registry_getuintclass();}
1587      |  "Boolean" {$$=registry_getbooleanclass();}
1588      |  "Number"  {$$=registry_getnumberclass();}
1589
1590 MAYBETYPE: ':' TYPE {$$=$2;}
1591 MAYBETYPE:          {$$=0;}
1592
1593 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
1594 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1595                       MAYBETYPE
1596
1597 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1598 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1599 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1600
1601 //NAMESPACE :              {$$=empty_token();}
1602 //NAMESPACE : T_IDENTIFIER {$$=$1};
1603
1604 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1605                    //MULTINAME(m, registry_getintclass());
1606                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1607                    $$.t = TYPE_INT;
1608                   }
1609 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1610                     $$.t = TYPE_INT;
1611                    }
1612 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1613                   $$.t = TYPE_INT;
1614                  }
1615 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1616                    $$.t = TYPE_UINT;
1617                   }
1618 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1619                     $$.t = TYPE_FLOAT;
1620                    }
1621 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1622                      $$.t = TYPE_STRING;
1623                     }
1624 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1625                     $$.t = TYPE_BOOLEAN;
1626                    }
1627 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1628                      $$.t = TYPE_BOOLEAN;
1629                     }
1630 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1631                     $$.t = TYPE_NULL;
1632                    }
1633
1634 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1635
1636
1637 //VARIABLE : T_IDENTIFIER
1638 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1639 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1640 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1641 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1642 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1643
1644 GETSET : "get" {$$=$1;}
1645        | "set" {$$=$1;}
1646        |       {$$=empty_token();}
1647
1648 IDECLARATION : VARIABLE_DECLARATION
1649 IDECLARATION : FUNCTION_DECLARATION
1650
1651 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1652 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1653
1654 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1655 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1656
1657
1658 MAYBE_IDECLARATION_LIST : 
1659 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1660 IDECLARATION_LIST : IDECLARATION
1661 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1662
1663 // chapter 14
1664 // keywords: as break case catch class const continue default delete do else extends false finally for function if implements import in instanceof interface internal is native new null package private protected public return super switch this throw to true try typeof use var void while with
1665 // syntactic keywords: each get set namespace include dynamic final native override static
1666