optimized assignment code, added varargs
[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         c = code_append(c, prefix);
902         c = abc_dup(c);
903         c = code_append(c, middlepart);
904         c = code_append(c, write);
905         c = code_append(c, r);
906     }
907
908     return c;
909 }
910
911
912 %}
913
914
915 %%
916
917 /* ------------ code blocks / statements ---------------- */
918
919 PROGRAM: MAYBECODE
920
921 MAYBECODE: CODE {$$=$1;}
922 MAYBECODE:      {$$=code_new();}
923
924 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
925 CODE: CODEPIECE {$$=$1;}
926
927 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
928 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
929 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
930 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
931 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
932 CODEPIECE: ';'                   {$$=code_new();}
933 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
934 CODEPIECE: VOIDEXPRESSION        {$$=$1}
935 CODEPIECE: FOR                   {$$=$1}
936 CODEPIECE: WHILE                 {$$=$1}
937 CODEPIECE: BREAK                 {$$=$1}
938 CODEPIECE: RETURN                {$$=$1}
939 CODEPIECE: IF                    {$$=$1}
940 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
941 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
942
943 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
944 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
945 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
946
947 /* ------------ variables --------------------------- */
948
949 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
950                 |                {$$.c=abc_pushundefined(0);
951                                   $$.t=TYPE_ANY;
952                                  }
953
954 VAR : "const" | "var"
955 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
956
957 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
958 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
959
960 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
961 {
962     if(variable_exists($2->text))
963         syntaxerror("Variable %s already defined", $2->text);
964    
965     if(!is_subtype_of($4.t, $3)) {
966         syntaxerror("Can't convert %s to %s", $4.t->name, 
967                                               $3->name);
968     }
969
970     int index = new_variable($2->text, $3);
971     
972     if($3) {
973         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
974             $$ = $4.c;
975             $$ = converttype($$, $4.t, $3);
976             $$ = abc_setlocal($$, index);
977         } else {
978             $$ = defaultvalue(0, $3);
979             $$ = abc_setlocal($$, index);
980         }
981
982         /* push default value for type on stack */
983         state->initcode = defaultvalue(state->initcode, $3);
984         state->initcode = abc_setlocal(state->initcode, index);
985     } else {
986         /* only bother to actually set this variable if its syntax is either
987             var x:type;
988            or
989             var x=expr;
990         */
991         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
992             $$ = $4.c;
993             $$ = abc_coerce_a($$);
994             $$ = abc_setlocal($$, index);
995         } else {
996             $$ = code_new();
997         }
998     }
999     
1000     /* that's the default for a local register, anyway
1001         else {
1002         state->initcode = abc_pushundefined(state->initcode);
1003         state->initcode = abc_setlocal(state->initcode, index);
1004     }*/
1005     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1006 }
1007
1008 /* ------------ control flow ------------------------- */
1009
1010 MAYBEELSE:  %prec prec_none {$$ = code_new();}
1011 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1012 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1013
1014 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1015     $$ = state->initcode;state->initcode=0;
1016
1017     $$ = code_append($$, $4.c);
1018     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1019    
1020     $$ = code_append($$, $6);
1021     if($7) {
1022         myjmp = $$ = abc_jump($$, 0);
1023     }
1024     myif->branch = $$ = abc_label($$);
1025     if($7) {
1026         $$ = code_append($$, $7);
1027         myjmp->branch = $$ = abc_label($$);
1028     }
1029     
1030     $$ = killvars($$);old_state();
1031 }
1032
1033 FOR_INIT : {$$=code_new();}
1034 FOR_INIT : VARIABLE_DECLARATION
1035 FOR_INIT : VOIDEXPRESSION
1036
1037 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1038     $$ = state->initcode;state->initcode=0;
1039
1040     $$ = code_append($$, $4);
1041     code_t*loopstart = $$ = abc_label($$);
1042     $$ = code_append($$, $6.c);
1043     code_t*myif = $$ = abc_iffalse($$, 0);
1044     $$ = code_append($$, $10);
1045     $$ = code_append($$, $8);
1046     $$ = abc_jump($$, loopstart);
1047     code_t*out = $$ = abc_label($$);
1048     breakjumpsto($$, out);
1049     myif->branch = out;
1050
1051     $$ = killvars($$);old_state();
1052 }
1053
1054 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1055     $$ = state->initcode;state->initcode=0;
1056
1057     code_t*myjmp = $$ = abc_jump($$, 0);
1058     code_t*loopstart = $$ = abc_label($$);
1059     $$ = code_append($$, $6);
1060     myjmp->branch = $$ = abc_label($$);
1061     $$ = code_append($$, $4.c);
1062     $$ = abc_iftrue($$, loopstart);
1063     code_t*out = $$ = abc_label($$);
1064     breakjumpsto($$, out);
1065
1066     $$ = killvars($$);old_state();
1067 }
1068
1069 BREAK : "break" {
1070     $$ = abc___break__(0);
1071 }
1072
1073 /* ------------ packages and imports ---------------- */
1074
1075 X_IDENTIFIER: T_IDENTIFIER
1076             | "package"
1077
1078 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
1079 PACKAGE: X_IDENTIFIER             {$$=$1;}
1080
1081 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1082 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
1083
1084 IMPORT : "import" QNAME {
1085        classinfo_t*c = $2;
1086        if(!c) 
1087             syntaxerror("Couldn't import class\n");
1088        state_has_imports();
1089        dict_put(state->imports, c->name, c);
1090        $$=0;
1091 }
1092 IMPORT : "import" PACKAGE '.' '*' {
1093        NEW(import_t,i);
1094        i->package = $2->text;
1095        state_has_imports();
1096        list_append(state->wildcard_imports, i);
1097        $$=0;
1098 }
1099
1100 /* ------------ classes and interfaces (header) -------------- */
1101
1102 MODIFIERS : {$$=empty_token();}
1103 MODIFIERS : MODIFIER_LIST {$$=$1}
1104 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1105 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
1106 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1107
1108 EXTENDS : {$$=registry_getobjectclass();}
1109 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1110
1111 EXTENDS_LIST : {$$=list_new();}
1112 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1113
1114 IMPLEMENTS_LIST : {$$=list_new();}
1115 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1116
1117 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER 
1118                               EXTENDS IMPLEMENTS_LIST 
1119                               '{' {startclass($1,$3,$4,$5, 0);} 
1120                               MAYBE_DECLARATION_LIST 
1121                               '}' {endclass();}
1122
1123 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER 
1124                               EXTENDS_LIST 
1125                               '{' {startclass($1,$3,0,$4,1);}
1126                               MAYBE_IDECLARATION_LIST 
1127                               '}' {endclass();}
1128
1129 /* ------------ classes and interfaces (body) -------------- */
1130
1131 MAYBE_DECLARATION_LIST : 
1132 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1133 DECLARATION_LIST : DECLARATION
1134 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1135 DECLARATION : ';'
1136 DECLARATION : SLOT_DECLARATION
1137 DECLARATION : FUNCTION_DECLARATION
1138
1139 /* ------------ classes and interfaces (body, slots ) ------- */
1140
1141 VARCONST: "var" | "const"
1142 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1143
1144     memberinfo_t* info = memberinfo_register(state->clsinfo, $3->text, MEMBER_SLOT);
1145     info->type = $4;
1146
1147     trait_t*t=0;
1148     if($4) {
1149         MULTINAME(m, $4);
1150         t=abc_class_slot(state->cls, $3->text, &m);
1151     } else {
1152         t=abc_class_slot(state->cls, $3->text, 0);
1153     }
1154     if($2->type==KW_CONST) {
1155         t->kind= TRAIT_CONST;
1156     }
1157     info->slot = t->slot_id;
1158     if($5.c && !is_pushundefined($5.c)) {
1159         code_t*c = 0;
1160         c = abc_getlocal_0(c);
1161         c = code_append(c, $5.c);
1162         c = converttype(c, $5.t, $4);
1163         c = abc_setslot(c, t->slot_id);
1164         //c = abc_setproperty(c, $3->text); 
1165         state->cls_init = code_append(state->cls_init, c);
1166     }
1167 }
1168
1169 /* ------------ classes and interfaces (body, functions) ------- */
1170
1171 // non-vararg version
1172 MAYBE_PARAM_LIST: {
1173     memset(&$$,0,sizeof($$));
1174 }
1175 MAYBE_PARAM_LIST: PARAM_LIST {
1176     $$=$1;
1177 }
1178
1179 // vararg version
1180 MAYBE_PARAM_LIST: "..." PARAM {
1181     memset(&$$,0,sizeof($$));
1182     $$.varargs=1;
1183     list_append($$.list, $2);
1184 }
1185 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1186     $$ =$1;
1187     $$.varargs=1;
1188     list_append($$.list, $4);
1189 }
1190
1191 // non empty
1192 PARAM_LIST: PARAM_LIST ',' PARAM {
1193     $$ = $1;
1194     list_append($$.list, $3);
1195 }
1196 PARAM_LIST: PARAM {
1197     memset(&$$,0,sizeof($$));
1198     list_append($$.list, $1);
1199 }
1200 PARAM:  T_IDENTIFIER ':' TYPE {
1201      $$ = malloc(sizeof(param_t));
1202      $$->name=$1->text;$$->type = $3;
1203 }
1204 PARAM:  T_IDENTIFIER          {
1205      $$ = malloc(sizeof(param_t));
1206      $$->name=$1->text;$$->type = TYPE_ANY;
1207 }
1208
1209 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1210                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1211 {
1212     if(!state->m) syntaxerror("internal error: undefined function");
1213     endfunction($11);
1214 }
1215
1216 /* ------------- package + class ids --------------- */
1217
1218 CLASS: T_IDENTIFIER {
1219
1220     /* try current package */
1221     $$ = registry_findclass(state->package, $1->text);
1222
1223     /* try explicit imports */
1224     dictentry_t* e = dict_get_slot(state->imports, $1->text);
1225     while(e) {
1226         if($$)
1227             break;
1228         if(!strcmp(e->key, $1->text)) {
1229             $$ = (classinfo_t*)e->data;
1230         }
1231         e = e->next;
1232     }
1233
1234     /* try package.* imports */
1235     import_list_t*l = state->wildcard_imports;
1236     while(l) {
1237         if($$)
1238             break;
1239         //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1240         $$ = registry_findclass(l->import->package, $1->text);
1241         l = l->next;
1242     }
1243
1244     /* try global package */
1245     if(!$$) {
1246         $$ = registry_findclass("", $1->text);
1247     }
1248
1249     if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1250 }
1251
1252 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1253     $$ = registry_findclass($1->text, $3->text);
1254     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1255 }
1256
1257 QNAME: PACKAGEANDCLASS
1258      | CLASS
1259
1260
1261 /* ----------function calls, constructor calls ------ */
1262
1263 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1264 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1265
1266 MAYBE_EXPRESSION_LIST : {$$=0;}
1267 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1268 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1269                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1270                                                   *t = $1;
1271                                                   list_append($$, t);}
1272 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1273                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1274                                                   *t = $3;
1275                                                   list_append($$, t);}
1276
1277 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1278     MULTINAME(m, $2);
1279     $$.c = code_new();
1280
1281     /* TODO: why do we have to *find* our own classes? */
1282     $$.c = abc_findpropstrict2($$.c, &m);
1283
1284     typedcode_list_t*l = $3;
1285     int len = 0;
1286     while(l) {
1287         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1288         l = l->next;
1289         len ++;
1290     }
1291     $$.c = abc_constructprop2($$.c, &m, len);
1292     $$.t = $2;
1293 }
1294
1295 /* TODO: use abc_call (for calling local variables),
1296          abc_callstatic (for calling own methods) 
1297          call (for closures)
1298 */
1299 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1300     typedcode_list_t*l = $3;
1301     int len = 0;
1302     code_t*paramcode = 0;
1303     while(l) {
1304         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1305         l = l->next;
1306         len ++;
1307     }
1308        
1309     $$.c = $1.c;
1310     if($$.c->opcode == OPCODE_COERCE_A) {
1311         $$.c = code_cutlast($$.c);
1312     }
1313
1314     $$.t = TYPE_ANY;
1315     multiname_t*name = 0;
1316     if($$.c->opcode == OPCODE_GETPROPERTY) {
1317         name = multiname_clone($$.c->data[0]);
1318     } else if($$.c->opcode == OPCODE_GETSLOT) {
1319         int slot = (int)(ptroff_t)$$.c->data[0];
1320         trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1321         if(t->kind!=TRAIT_METHOD) {
1322             //flash allows to assign closures to members.
1323             //syntaxerror("not a function");
1324         }
1325         name = t->name;
1326     } else {
1327         code_dump($$.c, 0, 0, "", stdout);
1328         syntaxerror("Object is not callable");
1329     }
1330         
1331     $$.c = code_cutlast($$.c);
1332     $$.c = code_append($$.c, paramcode);
1333     //$$.c = abc_callmethod($$.c, m, len); //#1051 illegal early access binding
1334     $$.c = abc_callproperty2($$.c, name, len);
1335    
1336     memberinfo_t*f = 0;
1337     if(TYPE_IS_FUNCTION($1.t) &&
1338        (f = registry_findmember($1.t, "__funcptr__"))) {
1339         $$.t = f->return_type;
1340     } else {
1341         $$.c = abc_coerce_a($$.c);
1342         $$.t = TYPE_ANY;
1343     }
1344 }
1345
1346 RETURN: "return" %prec prec_none {
1347     $$ = abc_returnvoid(0);
1348 }
1349 RETURN: "return" EXPRESSION {
1350     $$ = $2.c;
1351     $$ = abc_returnvalue($$);
1352 }
1353 // ----------------------- expression types -------------------------------------
1354
1355 NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
1356 EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
1357 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1358     $$.c = $1.c;
1359     $$.c = cut_last_push($$.c);
1360     $$.c = code_append($$.c,$3.c);
1361     $$.t = $3.t;
1362 }
1363 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1364
1365 // ----------------------- expression evaluation -------------------------------------
1366
1367 E : CONSTANT
1368 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1369 E : NEW                         {$$ = $1;}
1370 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1371                                  $$.t = TYPE_ANY;
1372                                 }
1373 E : FUNCTIONCALL
1374 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1375              $$.t = TYPE_BOOLEAN;
1376             }
1377 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1378              $$.t = TYPE_BOOLEAN;
1379             }
1380 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1381               $$.t = TYPE_BOOLEAN;
1382              }
1383 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1384               $$.t = TYPE_BOOLEAN;
1385              }
1386 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1387               $$.t = TYPE_BOOLEAN;
1388              }
1389 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1390               $$.t = TYPE_BOOLEAN;
1391              }
1392 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1393               $$.t = TYPE_BOOLEAN;
1394              }
1395
1396 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1397               $$.c = $1.c;
1398               $$.c = converttype($$.c, $1.t, $$.t);
1399               $$.c = abc_dup($$.c);
1400               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1401               $$.c = cut_last_push($$.c);
1402               $$.c = code_append($$.c,$3.c);
1403               $$.c = converttype($$.c, $3.t, $$.t);
1404               code_t*label = $$.c = abc_label($$.c);
1405               jmp->branch = label;
1406              }
1407 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1408               $$.c = $1.c;
1409               $$.c = converttype($$.c, $1.t, $$.t);
1410               $$.c = abc_dup($$.c);
1411               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1412               $$.c = cut_last_push($$.c);
1413               $$.c = code_append($$.c,$3.c);
1414               $$.c = converttype($$.c, $3.t, $$.t);
1415               code_t*label = $$.c = abc_label($$.c);
1416               jmp->branch = label;              
1417              }
1418
1419 E : '!' E    {$$.c=$2.c;
1420               $$.c = abc_not($$.c);
1421               $$.t = TYPE_BOOLEAN;
1422              }
1423
1424 E : E '-' E
1425 E : E '/' E
1426 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1427              $$.t = join_types($1.t, $3.t, '+');
1428             }
1429 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1430              $$.t = join_types($1.t, $3.t, '%');
1431             }
1432 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1433              $$.t = join_types($1.t, $3.t, '*');
1434             }
1435
1436 E : E "as" E
1437 E : E "is" E
1438 E : '(' E ')' {$$=$2;}
1439 E : '-' E {$$=$2;}
1440
1441 E : E '[' E ']' {
1442   $$.c = $1.c;
1443   $$.c = code_append($$.c, $3.c);
1444  
1445   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1446   $$.c = abc_getproperty2($$.c, &m);
1447 }
1448
1449 E : E "+=" E { 
1450                code_t*c = $3.c;
1451                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1452                 c=abc_add_i(c);
1453                } else {
1454                 c=abc_add(c);
1455                }
1456                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1457                
1458                $$.c = toreadwrite($1.c, c, 0);
1459                $$.t = $1.t;
1460               }
1461 E : E "-=" E { code_t*c = $3.c; 
1462                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1463                 c=abc_subtract_i(c);
1464                } else {
1465                 c=abc_subtract(c);
1466                }
1467                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1468                
1469                $$.c = toreadwrite($1.c, c, 0);
1470                $$.t = $1.t;
1471              }
1472 E : E '=' E { code_t*c = 0;
1473               c = code_append(c, $3.c);
1474               c = converttype(c, $3.t, $1.t);
1475               $$.c = toreadwrite($1.c, c, 1);
1476               $$.t = $1.t;
1477             }
1478
1479 // TODO: use inclocal where appropriate
1480 E : E "++" { code_t*c = 0;
1481              classinfo_t*type = $1.t;
1482              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1483                  c=abc_increment_i(c);
1484              } else {
1485                  c=abc_increment(c);
1486                  type = TYPE_NUMBER;
1487              }
1488              c=converttype(c, type, $1.t);
1489              $$.c = toreadwrite($1.c, c, 0);
1490              $$.t = $1.t;
1491            }
1492 E : E "--" { code_t*c = 0;
1493              classinfo_t*type = $1.t;
1494              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1495                  c=abc_increment_i(c);
1496              } else {
1497                  c=abc_increment(c);
1498                  type = TYPE_NUMBER;
1499              }
1500              c=converttype(c, type, $1.t);
1501              $$.c = toreadwrite($1.c, c, 0);
1502              $$.t = $1.t;
1503             }
1504
1505 E : E '.' T_IDENTIFIER
1506             {$$.c = $1.c;
1507              if($$.t) {
1508                  memberinfo_t*f = registry_findmember($$.t, $3->text);
1509
1510                  if(f && f->slot) {
1511                      $$.c = abc_getslot($$.c, f->slot);
1512                  } else {
1513                      namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
1514                      multiname_t m = {QNAME, &ns, 0, $3->text};
1515                      $$.c = abc_getproperty2($$.c, &m);
1516                  }
1517                  /* determine type */
1518                  if(f) {
1519                     if(f->kind == MEMBER_METHOD) {
1520                         $$.t = TYPE_FUNCTION(f);
1521                     } else {
1522                         $$.t = f->type;
1523                     }
1524                  } else {
1525                     $$.c = abc_coerce_a($$.c);
1526                     $$.t = registry_getanytype();
1527                  }
1528              } else {
1529                  namespace_t ns = {ACCESS_PACKAGE, ""};
1530                  multiname_t m = {QNAME, &ns, 0, $3->text};
1531                  $$.c = abc_getproperty2($$.c, &m);
1532                  $$.c = abc_coerce_a($$.c);
1533                  $$.t = registry_getanytype();
1534              }
1535             }
1536
1537 VAR_READ : T_IDENTIFIER {
1538     $$.t = 0;
1539     $$.c = 0;
1540     int i;
1541     memberinfo_t*f = 0;
1542     if((i = find_variable($1->text, &$$.t)) >= 0) {
1543         // $1 is a local variable
1544         $$.c = abc_getlocal($$.c, i);
1545     } else if((f = registry_findmember(state->clsinfo, $1->text))) {
1546         // $1 is a function in this class
1547         if(f->kind == MEMBER_METHOD) {
1548             $$.t = TYPE_FUNCTION(f);
1549         } else {
1550             $$.t = f->type;
1551         }
1552         if(f->slot>0) {
1553             $$.c = abc_getlocal_0($$.c);
1554             $$.c = abc_getslot($$.c, f->slot);
1555         } else {
1556             namespace_t ns = {state->clsinfo->access, ""};
1557             multiname_t m = {QNAME, &ns, 0, $1->text};
1558             $$.c = abc_getlocal_0($$.c);
1559             $$.c = abc_getproperty2($$.c, &m);
1560         }
1561     } else {
1562         // let the avm2 resolve $1 
1563         if(strcmp($1->text,"trace"))
1564         warning("Couldn't resolve %s, doing late binding", $1->text);
1565         state->late_binding = 1;
1566
1567         $$.t = 0;
1568         $$.c = abc_findpropstrict($$.c, $1->text);
1569         $$.c = abc_getproperty($$.c, $1->text);
1570     }
1571 }
1572
1573
1574 // ------------------------------------------------------------------------------
1575
1576
1577 TYPE : QNAME {$$=$1;}
1578      | '*'        {$$=registry_getanytype();}
1579      |  "String"  {$$=registry_getstringclass();}
1580      |  "int"     {$$=registry_getintclass();}
1581      |  "uint"    {$$=registry_getuintclass();}
1582      |  "Boolean" {$$=registry_getbooleanclass();}
1583      |  "Number"  {$$=registry_getnumberclass();}
1584
1585 MAYBETYPE: ':' TYPE {$$=$2;}
1586 MAYBETYPE:          {$$=0;}
1587
1588 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
1589 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1590                       MAYBETYPE
1591
1592 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1593 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1594 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1595
1596 //NAMESPACE :              {$$=empty_token();}
1597 //NAMESPACE : T_IDENTIFIER {$$=$1};
1598
1599 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1600                    //MULTINAME(m, registry_getintclass());
1601                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1602                    $$.t = TYPE_INT;
1603                   }
1604 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1605                     $$.t = TYPE_INT;
1606                    }
1607 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1608                   $$.t = TYPE_INT;
1609                  }
1610 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1611                    $$.t = TYPE_UINT;
1612                   }
1613 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1614                     $$.t = TYPE_FLOAT;
1615                    }
1616 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1617                      $$.t = TYPE_STRING;
1618                     }
1619 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1620                     $$.t = TYPE_BOOLEAN;
1621                    }
1622 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1623                      $$.t = TYPE_BOOLEAN;
1624                     }
1625 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1626                     $$.t = TYPE_NULL;
1627                    }
1628
1629 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1630
1631
1632 //VARIABLE : T_IDENTIFIER
1633 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1634 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1635 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1636 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1637 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1638
1639 GETSET : "get" {$$=$1;}
1640        | "set" {$$=$1;}
1641        |       {$$=empty_token();}
1642
1643 IDECLARATION : VARIABLE_DECLARATION
1644 IDECLARATION : FUNCTION_DECLARATION
1645
1646 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1647 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1648
1649 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1650 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1651
1652
1653 MAYBE_IDECLARATION_LIST : 
1654 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1655 IDECLARATION_LIST : IDECLARATION
1656 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1657
1658 // chapter 14
1659 // 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
1660 // syntactic keywords: each get set namespace include dynamic final native override static
1661