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