fixed variable killing on scope end
[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     char late_binding;
303 } state_t;
304
305 typedef struct _global {
306     int variable_count;
307 } global_t;
308
309 static global_t*global = 0;
310 static state_t* state = 0;
311
312 DECLARE_LIST(state);
313
314 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
315
316 /* warning: list length of namespace set is undefined */
317 #define MULTINAME_LATE(m, access, package) \
318     namespace_t m##_ns = {access, package}; \
319     namespace_set_t m##_nsset; \
320     namespace_list_t m##_l;m##_l.next = 0; \
321     m##_nsset.namespaces = &m##_l; \
322     m##_nsset = m##_nsset; \
323     m##_l.namespace = &m##_ns; \
324     multiname_t m = {MULTINAMEL, 0, &m##_nsset, 0};
325
326 static state_list_t*state_stack=0;
327     
328 static void init_globals()
329 {
330     global = rfx_calloc(sizeof(global_t));
331 }
332
333 static void new_state()
334 {
335     NEW(state_t, s);
336     NEW(state_list_t, sl);
337
338     state_t*oldstate = state;
339     if(state)
340         memcpy(s, state, sizeof(state_t)); //shallow copy
341     sl->next = state_stack;
342     sl->state = s;
343     if(!s->imports) {
344         s->imports = dict_new();
345     }
346     state_stack = sl;
347     state = s;
348     state->level++;
349     state->vars = dict_new();
350     state->initcode = 0;
351     state->has_own_imports = 0;
352 }
353 static void state_has_imports()
354 {
355     state->wildcard_imports = list_clone(state->wildcard_imports);
356     state->imports = dict_clone(state->imports);
357     state->has_own_imports = 1;
358 }
359
360 static void old_state()
361 {
362     if(!state_stack || !state_stack->next)
363         syntaxerror("invalid nesting");
364     state_t*oldstate = state;
365     state_list_t*old = state_stack;
366     state_stack = state_stack->next;
367     free(old);
368     state = state_stack->state;
369     /*if(state->initcode) {
370         printf("residual initcode\n");
371         code_dump(state->initcode, 0, 0, "", stdout);
372     }*/
373     if(oldstate->has_own_imports) {
374         list_free(oldstate->wildcard_imports);
375         dict_destroy(oldstate->imports);oldstate->imports=0;
376     }
377     state->initcode = code_append(state->initcode, oldstate->initcode);
378 }
379 void initialize_state()
380 {
381     init_globals();
382     new_state();
383
384     state->file = abc_file_new();
385     state->file->flags &= ~ABCFILE_LAZY;
386     
387     state->init = abc_initscript(state->file, 0, 0);
388     code_t*c = state->init->method->body->code;
389
390     c = abc_getlocal_0(c);
391     c = abc_pushscope(c);
392   
393     /* findpropstrict doesn't just return a scope object- it
394        also makes it "active" somehow. Push local_0 on the
395        scope stack and read it back with findpropstrict, it'll
396        contain properties like "trace". Trying to find the same
397        property on a "vanilla" local_0 yields only a "undefined" */
398     //c = abc_findpropstrict(c, "[package]::trace");
399     
400     /*c = abc_getlocal_0(c);
401     c = abc_findpropstrict(c, "[package]::trace");
402     c = abc_coerce_a(c);
403     c = abc_setlocal_1(c);
404
405     c = abc_pushbyte(c, 0);
406     c = abc_setlocal_2(c);
407    
408     code_t*xx = c = abc_label(c);
409     c = abc_findpropstrict(c, "[package]::trace");
410     c = abc_pushstring(c, "prop:");
411     c = abc_hasnext2(c, 1, 2);
412     c = abc_dup(c);
413     c = abc_setlocal_3(c);
414     c = abc_callpropvoid(c, "[package]::trace", 2);
415     c = abc_getlocal_3(c);
416     c = abc_kill(c, 3);
417     c = abc_iftrue(c,xx);*/
418
419     c = abc_findpropstrict(c, "[package]::trace");
420     c = abc_pushstring(c, "[entering global init function]");
421     c = abc_callpropvoid(c, "[package]::trace", 1);
422     
423     state->init->method->body->code = c;
424 }
425 void* finalize_state()
426 {
427     if(state->level!=1) {
428         syntaxerror("unexpected end of file");
429     }
430     abc_method_body_t*m = state->init->method->body;
431     //__ popscope(m);
432     
433     __ findpropstrict(m, "[package]::trace");
434     __ pushstring(m, "[leaving global init function]");
435     __ callpropvoid(m, "[package]::trace", 1);
436     __ returnvoid(m);
437     return state->file;
438 }
439
440
441 static void startpackage(token_t*t) 
442 {
443     if(state->package) {
444         syntaxerror("Packages can not be nested."); 
445     } 
446     new_state();
447     char*name = t?t->text:"";
448     /*printf("entering package \"%s\"\n", name);*/
449     state->package = name;
450 }
451 static void endpackage()
452 {
453     /*printf("leaving package \"%s\"\n", state->package);*/
454     old_state();
455 }
456
457 char*globalclass=0;
458 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
459 {
460     if(state->cls) {
461         syntaxerror("inner classes now allowed"); 
462     }
463     new_state();
464     char*classname = name->text;
465
466     token_list_t*t=0;
467     classinfo_list_t*mlist=0;
468     /*printf("entering class %s\n", name->text);
469     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
470     if(extends) 
471         printf("  extends: %s.%s\n", extends->package, extends->name);
472     printf("  implements (%d): ", list_length(implements));
473     for(mlist=implements;mlist;mlist=mlist->next)  {
474         printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
475     }
476     printf("\n");
477     */
478
479     char public=0,internal=0,final=0,sealed=1;
480     for(t=modifiers->tokens;t;t=t->next) {
481         if(t->token->type == KW_INTERNAL) {
482             /* the programmer is being explicit- 
483                being internal is the default anyway */
484             internal = 1;
485         } else if(t->token->type == KW_PUBLIC) {
486             public = 1;
487         } else if(t->token->type == KW_FINAL) {
488             final = 1;
489         } else {
490             syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
491         }
492     }
493     if(public&&internal)
494         syntaxerror("public and internal not supported at the same time.");
495
496     /* create the class name, together with the proper attributes */
497     int access=0;
498     char*package=0;
499
500     if(!public && !state->package) {
501         access = ACCESS_PRIVATE; package = current_filename;
502     } else if(!public && state->package) {
503         access = ACCESS_PACKAGEINTERNAL; package = state->package;
504     } else if(state->package) {
505         access = ACCESS_PACKAGE; package = state->package;
506     } else {
507         syntaxerror("public classes only allowed inside a package");
508     }
509
510     if(registry_findclass(package, classname)) {
511         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
512     }
513     
514     state->clsinfo = classinfo_register(access, package, classname);
515
516     MULTINAME(classname2,state->clsinfo);
517     
518     multiname_t*extends2 = sig2mname(extends);
519
520     /*if(extends) {
521         state->cls_init = abc_getlocal_0(state->cls_init);
522         state->cls_init = abc_constructsuper(state->cls_init, 0);
523     }*/
524
525     state->cls = abc_class_new(state->file, &classname2, extends2);
526     if(final) abc_class_final(state->cls);
527     if(sealed) abc_class_sealed(state->cls);
528     if(interface) abc_class_interface(state->cls);
529
530     for(mlist=implements;mlist;mlist=mlist->next) {
531         MULTINAME(m, mlist->classinfo);
532         abc_class_add_interface(state->cls, &m);
533     }
534
535     /* now write the construction code for this class */
536     int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
537
538     abc_method_body_t*m = state->init->method->body;
539     __ getglobalscope(m);
540     classinfo_t*s = extends;
541
542     int count=0;
543     
544     while(s) {
545         //TODO: take a look at the current scope stack, maybe 
546         //      we can re-use something
547         s = s->superclass;
548         if(!s) 
549         break;
550        
551         multiname_t*s2 = sig2mname(s);
552         __ getlex2(m, s2);
553         multiname_destroy(s2);
554
555         __ pushscope(m); count++;
556         m->code = m->code->prev->prev; // invert
557     }
558     /* continue appending after last op end */
559     while(m->code && m->code->next) m->code = m->code->next; 
560
561     /* TODO: if this is one of *our* classes, we can also 
562              do a getglobalscope/getslot <nr> (which references
563              the init function's slots) */
564     if(extends2) {
565         __ getlex2(m, extends2);
566         __ dup(m);
567         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
568            stack is not the superclass */
569         __ pushscope(m);count++;
570     } else {
571         __ pushnull(m);
572         /* notice: we get a verify error #1107 if the top element on the scope 
573            stack is not the global object */
574         __ getlocal_0(m);
575         __ pushscope(m);count++;
576     }
577     __ newclass(m,state->cls);
578     while(count--) {
579         __ popscope(m);
580     }
581     __ setslot(m, slotindex);
582
583     /* flash.display.MovieClip handling */
584     if(!globalclass && public && classinfo_equals(registry_getMovieClip(),extends)) {
585         if(state->package && state->package[0]) {
586             globalclass = concat3str(state->package, ".", classname);
587         } else {
588             globalclass = strdup(classname);
589         }
590     }
591     multiname_destroy(extends2);
592 }
593
594 static void endclass()
595 {
596     if(state->cls_init) {
597         if(!state->cls->constructor) {
598             abc_method_body_t*m = abc_class_constructor(state->cls, 0, 0);
599             m->code = code_append(m->code, state->cls_init);
600             m->code = abc_returnvoid(m->code);
601         } else {
602             code_t*c = state->cls->constructor->body->code;
603             c = code_append(state->cls_init, c);
604             state->cls->constructor->body->code = c;
605
606         }
607     }
608     if(state->cls_static_init) {
609         if(!state->cls->static_constructor) {
610             abc_method_body_t*m = abc_class_staticconstructor(state->cls, 0, 0);
611             m->code = state->cls_static_init;
612         } else {
613             state->cls->static_constructor->body->code = 
614                 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
615         }
616     }
617
618     old_state();
619 }
620
621 static token_t* empty_token()
622 {
623     NEW(token_t,t);
624     t->type=T_EMPTY;
625     t->text=0;
626     return t;
627 }
628
629 void extend(token_t*list, token_t*add) {
630     list_append(list->tokens,add);
631     if(!list->text)
632         list->text = add->text;
633 }
634 void extend_s(token_t*list, char*seperator, token_t*add) {
635     list_append(list->tokens,add);
636     char*t1 = list->text;
637     char*t2 = seperator;
638     char*t3 = add->text;
639     int l1 = strlen(t1);
640     int l2 = strlen(t2);
641     int l3 = strlen(t3);
642     list->text = malloc(l1+l2+l3+1);
643     strcpy(list->text, t1);
644     strcpy(list->text+l1, t2);
645     strcpy(list->text+l1+l2, t3);
646     list->text[l1+l2+l3]=0;
647 }
648
649 typedef struct _variable {
650     int index;
651     classinfo_t*type;
652 } variable_t;
653
654 static int find_variable(char*name, classinfo_t**m)
655 {
656     state_list_t* s = state_stack;
657     while(s) {
658         variable_t*v = dict_lookup(s->state->vars, name);
659         if(v) {
660             if(m) {
661                 *m = v->type;
662             }
663             return v->index;
664         }
665         s = s->next;
666     }
667     return -1;
668
669 static int find_variable_safe(char*name, classinfo_t**m)
670 {
671     int i = find_variable(name, m);
672     if(i<0)
673         syntaxerror("undefined variable: %s", name);
674     return i;
675 }
676 static char variable_exists(char*name) 
677 {
678     return dict_lookup(state->vars, name)!=0;
679 }
680 static int new_variable(char*name, classinfo_t*type)
681 {
682     NEW(variable_t, v);
683     v->index = global->variable_count;
684     v->type = type;
685     dict_put(state->vars, name, v);
686     return global->variable_count++;
687 }
688 #define TEMPVARNAME "__as3_temp__"
689 static int gettempvar()
690 {
691     int i = find_variable(TEMPVARNAME, 0);
692     if(i<0) {
693         return new_variable(TEMPVARNAME, 0);
694     } else {
695         return i;
696     }
697 }
698
699 code_t* killvars(code_t*c) 
700 {
701     int t;
702     for(t=0;t<state->vars->hashsize;t++) {
703         dictentry_t*e =state->vars->slots[t];
704         while(e) {
705             variable_t*v = (variable_t*)e->data;
706             //do this always, otherwise register types don't match
707             //in the verifier when doing nested loops
708             //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
709             c = abc_kill(c, v->index);
710             e = e->next;
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     /* generate the write instruction, and maybe append a dup to the prefix code */
910     code_t* write = abc_nop(0);
911     if(r->opcode == OPCODE_GETPROPERTY) {
912         write->opcode = OPCODE_SETPROPERTY;
913         multiname_t*m = (multiname_t*)r->data[0];
914         write->data[0] = multiname_clone(m);
915         if(m->type != QNAME)
916             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
917         if(!justassign) {
918             prefix = abc_dup(prefix); // we need the object, too
919         }
920     } else if(r->opcode == OPCODE_GETSLOT) {
921         write->opcode = OPCODE_SETSLOT;
922         write->data[0] = r->data[0];
923         if(!justassign) {
924             prefix = abc_dup(prefix); // we need the object, too
925         }
926     } else if(r->opcode == OPCODE_GETLOCAL) { 
927         write->opcode = OPCODE_SETLOCAL;
928         write->data[0] = r->data[0];
929     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
930         write->opcode = OPCODE_SETLOCAL_0;
931     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
932         write->opcode = OPCODE_SETLOCAL_1;
933     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
934         write->opcode = OPCODE_SETLOCAL_2;
935     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
936         write->opcode = OPCODE_SETLOCAL_3;
937     } else {
938         code_dump(r, 0, 0, "", stdout);
939         syntaxerror("illegal lvalue: can't assign a value to this expression");
940     }
941     code_t* c = 0;
942     
943     int temp = -1;
944     if(!justassign) {
945 #if 1
946             /* with getproperty/getslot, we have to be extra careful not
947                to execute the read code twice, as it might have side-effects
948                (e.g. if the property is in fact a setter/getter combination)
949
950                So read the value, modify it, and write it again,
951                using prefix only once and making sure (by using a temporary
952                register) that the return value is what we just wrote */
953             temp = gettempvar();
954             c = code_append(c, prefix);
955             c = code_append(c, r);
956             c = code_append(c, middlepart);
957             c = abc_dup(c);
958             c = abc_setlocal(c, temp);
959             c = code_append(c, write);
960             c = abc_getlocal(c, temp);
961             c = abc_kill(c, temp);
962 #else
963             /* if we're allowed to execute the read code twice *and*
964                the middlepart doesn't modify the code, things are easier.
965             */
966             code_t* r2 = code_dup(r);
967             //c = code_append(c, prefix);
968             parserassert(!prefix);
969             c = code_append(c, r);
970             c = code_append(c, middlepart);
971             c = code_append(c, write);
972             c = code_append(c, r2);
973 #endif
974     } else {
975         /* even smaller version: overwrite the value without reading
976            it out first */
977         if(prefix) {
978             c = code_append(c, prefix);
979             c = abc_dup(c);
980         }
981         c = code_append(c, middlepart);
982         c = code_append(c, write);
983         c = code_append(c, r);
984     }
985
986     return c;
987 }
988
989
990 %}
991
992
993 %%
994
995 /* ------------ code blocks / statements ---------------- */
996
997 PROGRAM: MAYBECODE
998
999 MAYBECODE: CODE {$$=$1;}
1000 MAYBECODE:      {$$=code_new();}
1001
1002 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
1003 CODE: CODEPIECE {$$=$1;}
1004
1005 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
1006 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
1007 CODEPIECE: FUNCTION_DECLARATION  {$$=code_new();/*enters a scope*/}
1008 CODEPIECE: INTERFACE_DECLARATION {$$=code_new();}
1009 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
1010 CODEPIECE: ';'                   {$$=code_new();}
1011 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
1012 CODEPIECE: VOIDEXPRESSION        {$$=$1}
1013 CODEPIECE: FOR                   {$$=$1}
1014 CODEPIECE: WHILE                 {$$=$1}
1015 CODEPIECE: BREAK                 {$$=$1}
1016 CODEPIECE: RETURN                {$$=$1}
1017 CODEPIECE: IF                    {$$=$1}
1018 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
1019 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
1020
1021 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
1022 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
1023 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
1024
1025 /* ------------ variables --------------------------- */
1026
1027 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
1028                 |                {$$.c=abc_pushundefined(0);
1029                                   $$.t=TYPE_ANY;
1030                                  }
1031
1032 VAR : "const" | "var"
1033 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
1034
1035 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
1036 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
1037
1038 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
1039 {
1040     if(variable_exists($2->text))
1041         syntaxerror("Variable %s already defined", $2->text);
1042    
1043     if(!is_subtype_of($4.t, $3)) {
1044         syntaxerror("Can't convert %s to %s", $4.t->name, 
1045                                               $3->name);
1046     }
1047
1048     int index = new_variable($2->text, $3);
1049     
1050     if($3) {
1051         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1052             $$ = $4.c;
1053             $$ = converttype($$, $4.t, $3);
1054             $$ = abc_setlocal($$, index);
1055         } else {
1056             $$ = defaultvalue(0, $3);
1057             $$ = abc_setlocal($$, index);
1058         }
1059
1060         /* if this is a typed variable:
1061            push default value for type on stack */
1062         if($3) {
1063             state->initcode = defaultvalue(state->initcode, $3);
1064             state->initcode = abc_setlocal(state->initcode, index);
1065         }
1066     } else {
1067         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
1068             $$ = $4.c;
1069             $$ = abc_coerce_a($$);
1070             $$ = abc_setlocal($$, index);
1071         } else {
1072             $$ = code_new();
1073         }
1074     }
1075     
1076     /* that's the default for a local register, anyway
1077         else {
1078         state->initcode = abc_pushundefined(state->initcode);
1079         state->initcode = abc_setlocal(state->initcode, index);
1080     }*/
1081     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
1082 }
1083
1084 /* ------------ control flow ------------------------- */
1085
1086 MAYBEELSE:  %prec prec_none {$$ = code_new();}
1087 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
1088 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
1089
1090 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
1091     $$ = state->initcode;state->initcode=0;
1092
1093     $$ = code_append($$, $4.c);
1094     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
1095    
1096     $$ = code_append($$, $6);
1097     if($7) {
1098         myjmp = $$ = abc_jump($$, 0);
1099     }
1100     myif->branch = $$ = abc_label($$);
1101     if($7) {
1102         $$ = code_append($$, $7);
1103         myjmp->branch = $$ = abc_label($$);
1104     }
1105     
1106     $$ = killvars($$);old_state();
1107 }
1108
1109 FOR_INIT : {$$=code_new();}
1110 FOR_INIT : VARIABLE_DECLARATION
1111 FOR_INIT : VOIDEXPRESSION
1112
1113 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
1114     $$ = state->initcode;state->initcode=0;
1115
1116     $$ = code_append($$, $4);
1117     code_t*loopstart = $$ = abc_label($$);
1118     $$ = code_append($$, $6.c);
1119     code_t*myif = $$ = abc_iffalse($$, 0);
1120     $$ = code_append($$, $10);
1121     $$ = code_append($$, $8);
1122     $$ = abc_jump($$, loopstart);
1123     code_t*out = $$ = abc_label($$);
1124     breakjumpsto($$, out);
1125     myif->branch = out;
1126
1127     $$ = killvars($$);old_state();
1128 }
1129
1130 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
1131     $$ = state->initcode;state->initcode=0;
1132
1133     code_t*myjmp = $$ = abc_jump($$, 0);
1134     code_t*loopstart = $$ = abc_label($$);
1135     $$ = code_append($$, $6);
1136     myjmp->branch = $$ = abc_label($$);
1137     $$ = code_append($$, $4.c);
1138     $$ = abc_iftrue($$, loopstart);
1139     code_t*out = $$ = abc_label($$);
1140     breakjumpsto($$, out);
1141
1142     $$ = killvars($$);old_state();
1143 }
1144
1145 BREAK : "break" {
1146     $$ = abc___break__(0);
1147 }
1148
1149 /* ------------ packages and imports ---------------- */
1150
1151 X_IDENTIFIER: T_IDENTIFIER
1152             | "package"
1153
1154 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
1155 PACKAGE: X_IDENTIFIER             {$$=$1;}
1156
1157 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1158 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
1159
1160 IMPORT : "import" QNAME {
1161        classinfo_t*c = $2;
1162        if(!c) 
1163             syntaxerror("Couldn't import class\n");
1164        state_has_imports();
1165        dict_put(state->imports, c->name, c);
1166        $$=0;
1167 }
1168 IMPORT : "import" PACKAGE '.' '*' {
1169        NEW(import_t,i);
1170        i->package = $2->text;
1171        state_has_imports();
1172        list_append(state->wildcard_imports, i);
1173        $$=0;
1174 }
1175
1176 /* ------------ classes and interfaces (header) -------------- */
1177
1178 MODIFIERS : {$$=empty_token();}
1179 MODIFIERS : MODIFIER_LIST {$$=$1}
1180 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1181 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
1182 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1183
1184 EXTENDS : {$$=registry_getobjectclass();}
1185 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1186
1187 EXTENDS_LIST : {$$=list_new();}
1188 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1189
1190 IMPLEMENTS_LIST : {$$=list_new();}
1191 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1192
1193 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER 
1194                               EXTENDS IMPLEMENTS_LIST 
1195                               '{' {startclass($1,$3,$4,$5, 0);} 
1196                               MAYBE_DECLARATION_LIST 
1197                               '}' {endclass();}
1198
1199 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER 
1200                               EXTENDS_LIST 
1201                               '{' {startclass($1,$3,0,$4,1);}
1202                               MAYBE_IDECLARATION_LIST 
1203                               '}' {endclass();}
1204
1205 /* ------------ classes and interfaces (body) -------------- */
1206
1207 MAYBE_DECLARATION_LIST : 
1208 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1209 DECLARATION_LIST : DECLARATION
1210 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1211 DECLARATION : ';'
1212 DECLARATION : SLOT_DECLARATION
1213 DECLARATION : FUNCTION_DECLARATION
1214
1215 /* ------------ classes and interfaces (body, slots ) ------- */
1216
1217 VARCONST: "var" | "const"
1218 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1219
1220     memberinfo_t* info = memberinfo_register(state->clsinfo, $3->text, MEMBER_SLOT);
1221     info->type = $4;
1222
1223     trait_t*t=0;
1224     if($4) {
1225         MULTINAME(m, $4);
1226         t=abc_class_slot(state->cls, $3->text, &m);
1227     } else {
1228         t=abc_class_slot(state->cls, $3->text, 0);
1229     }
1230     if($2->type==KW_CONST) {
1231         t->kind= TRAIT_CONST;
1232     }
1233     info->slot = t->slot_id;
1234     if($5.c && !is_pushundefined($5.c)) {
1235         code_t*c = 0;
1236         c = abc_getlocal_0(c);
1237         c = code_append(c, $5.c);
1238         c = converttype(c, $5.t, $4);
1239         c = abc_setslot(c, t->slot_id);
1240         //c = abc_setproperty(c, $3->text); 
1241         state->cls_init = code_append(state->cls_init, c);
1242     }
1243 }
1244
1245 /* ------------ constants -------------------------------------- */
1246
1247 MAYBESTATICCONSTANT: {$$=0;}
1248 MAYBESTATICCONSTANT: '=' STATICCONSTANT {$$=$2;}
1249
1250 STATICCONSTANT : T_BYTE {$$ = constant_new_int($1);}
1251 STATICCONSTANT : T_INT {$$ = constant_new_int($1);}
1252 STATICCONSTANT : T_UINT {$$ = constant_new_uint($1);}
1253 STATICCONSTANT : T_FLOAT {$$ = constant_new_float($1);}
1254 STATICCONSTANT : T_STRING {$$ = constant_new_string($1);}
1255 //STATICCONSTANT : T_NAMESPACE {$$ = constant_new_namespace($1);}
1256 STATICCONSTANT : KW_TRUE {$$ = constant_new_true($1);}
1257 STATICCONSTANT : KW_FALSE {$$ = constant_new_false($1);}
1258 STATICCONSTANT : KW_NULL {$$ = constant_new_null($1);}
1259
1260 /* ------------ classes and interfaces (body, functions) ------- */
1261
1262 // non-vararg version
1263 MAYBE_PARAM_LIST: {
1264     memset(&$$,0,sizeof($$));
1265 }
1266 MAYBE_PARAM_LIST: PARAM_LIST {
1267     $$=$1;
1268 }
1269
1270 // vararg version
1271 MAYBE_PARAM_LIST: "..." PARAM {
1272     memset(&$$,0,sizeof($$));
1273     $$.varargs=1;
1274     list_append($$.list, $2);
1275 }
1276 MAYBE_PARAM_LIST: PARAM_LIST ',' "..." PARAM {
1277     $$ =$1;
1278     $$.varargs=1;
1279     list_append($$.list, $4);
1280 }
1281
1282 // non empty
1283 PARAM_LIST: PARAM_LIST ',' PARAM {
1284     $$ = $1;
1285     list_append($$.list, $3);
1286 }
1287 PARAM_LIST: PARAM {
1288     memset(&$$,0,sizeof($$));
1289     list_append($$.list, $1);
1290 }
1291 PARAM:  T_IDENTIFIER ':' TYPE MAYBESTATICCONSTANT {
1292      $$ = malloc(sizeof(param_t));
1293      $$->name=$1->text;
1294      $$->type = $3;
1295      $$->value = $4;
1296 }
1297 PARAM:  T_IDENTIFIER MAYBESTATICCONSTANT {
1298      $$ = malloc(sizeof(param_t));
1299      $$->name=$1->text;$$->type = TYPE_ANY;
1300 }
1301
1302 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1303                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1304 {
1305     if(!state->m) syntaxerror("internal error: undefined function");
1306     endfunction($11);
1307 }
1308
1309 /* ------------- package + class ids --------------- */
1310
1311 CLASS: T_IDENTIFIER {
1312
1313     /* try current package */
1314     $$ = registry_findclass(state->package, $1->text);
1315
1316     /* try explicit imports */
1317     dictentry_t* e = dict_get_slot(state->imports, $1->text);
1318     while(e) {
1319         if($$)
1320             break;
1321         if(!strcmp(e->key, $1->text)) {
1322             $$ = (classinfo_t*)e->data;
1323         }
1324         e = e->next;
1325     }
1326
1327     /* try package.* imports */
1328     import_list_t*l = state->wildcard_imports;
1329     while(l) {
1330         if($$)
1331             break;
1332         //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1333         $$ = registry_findclass(l->import->package, $1->text);
1334         l = l->next;
1335     }
1336
1337     /* try global package */
1338     if(!$$) {
1339         $$ = registry_findclass("", $1->text);
1340     }
1341
1342     if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1343 }
1344
1345 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1346     $$ = registry_findclass($1->text, $3->text);
1347     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1348 }
1349
1350 QNAME: PACKAGEANDCLASS
1351      | CLASS
1352
1353
1354 /* ----------function calls, constructor calls ------ */
1355
1356 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1357 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1358
1359 MAYBE_EXPRESSION_LIST : {$$=0;}
1360 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1361 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1362                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1363                                                   *t = $1;
1364                                                   list_append($$, t);}
1365 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1366                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1367                                                   *t = $3;
1368                                                   list_append($$, t);}
1369
1370 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1371     MULTINAME(m, $2);
1372     $$.c = code_new();
1373
1374     /* TODO: why do we have to *find* our own classes? */
1375     $$.c = abc_findpropstrict2($$.c, &m);
1376
1377     typedcode_list_t*l = $3;
1378     int len = 0;
1379     while(l) {
1380         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1381         l = l->next;
1382         len ++;
1383     }
1384     $$.c = abc_constructprop2($$.c, &m, len);
1385     $$.t = $2;
1386 }
1387
1388 /* TODO: use abc_call (for calling local variables),
1389          abc_callstatic (for calling own methods) 
1390          call (for closures)
1391 */
1392 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1393     typedcode_list_t*l = $3;
1394     int len = 0;
1395     code_t*paramcode = 0;
1396     while(l) {
1397         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1398         l = l->next;
1399         len ++;
1400     }
1401        
1402     $$.c = $1.c;
1403     if($$.c->opcode == OPCODE_COERCE_A) {
1404         $$.c = code_cutlast($$.c);
1405     }
1406
1407     $$.t = TYPE_ANY;
1408     multiname_t*name = 0;
1409     if($$.c->opcode == OPCODE_GETPROPERTY) {
1410         name = multiname_clone($$.c->data[0]);
1411         $$.c = code_cutlast($$.c);
1412         $$.c = code_append($$.c, paramcode);
1413         $$.c = abc_callproperty2($$.c, name, len);
1414     } else if($$.c->opcode == OPCODE_GETSLOT) {
1415         int slot = (int)(ptroff_t)$$.c->data[0];
1416         trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1417         if(t->kind!=TRAIT_METHOD) {
1418             //flash allows to assign closures to members.
1419             //syntaxerror("not a function");
1420         }
1421         name = t->name;
1422         $$.c = code_cutlast($$.c);
1423         $$.c = code_append($$.c, paramcode);
1424         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1425         $$.c = abc_callproperty2($$.c, name, len);
1426     } else {
1427         $$.c = abc_getlocal_0($$.c);
1428         $$.c = code_append($$.c, paramcode);
1429         $$.c = abc_call($$.c, len);
1430     }
1431    
1432     memberinfo_t*f = 0;
1433    
1434     if(TYPE_IS_FUNCTION($1.t) &&
1435        (f = registry_findmember($1.t, "call"))) {
1436         $$.t = f->return_type;
1437     } else {
1438         $$.c = abc_coerce_a($$.c);
1439         $$.t = TYPE_ANY;
1440     }
1441 }
1442
1443 RETURN: "return" %prec prec_none {
1444     $$ = abc_returnvoid(0);
1445 }
1446 RETURN: "return" EXPRESSION {
1447     $$ = $2.c;
1448     $$ = abc_returnvalue($$);
1449 }
1450 // ----------------------- expression types -------------------------------------
1451
1452 NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
1453 EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
1454 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1455     $$.c = $1.c;
1456     $$.c = cut_last_push($$.c);
1457     $$.c = code_append($$.c,$3.c);
1458     $$.t = $3.t;
1459 }
1460 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1461
1462 // ----------------------- expression evaluation -------------------------------------
1463
1464 E : CONSTANT
1465 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1466 E : NEW                         {$$ = $1;}
1467 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1468                                  $$.t = TYPE_ANY;
1469                                 }
1470 E : FUNCTIONCALL
1471 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1472              $$.t = TYPE_BOOLEAN;
1473             }
1474 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1475              $$.t = TYPE_BOOLEAN;
1476             }
1477 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1478               $$.t = TYPE_BOOLEAN;
1479              }
1480 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1481               $$.t = TYPE_BOOLEAN;
1482              }
1483 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1484               $$.t = TYPE_BOOLEAN;
1485              }
1486 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1487               $$.t = TYPE_BOOLEAN;
1488              }
1489 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1490               $$.t = TYPE_BOOLEAN;
1491              }
1492
1493 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1494               $$.c = $1.c;
1495               $$.c = converttype($$.c, $1.t, $$.t);
1496               $$.c = abc_dup($$.c);
1497               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1498               $$.c = cut_last_push($$.c);
1499               $$.c = code_append($$.c,$3.c);
1500               $$.c = converttype($$.c, $3.t, $$.t);
1501               code_t*label = $$.c = abc_label($$.c);
1502               jmp->branch = label;
1503              }
1504 E : E "&&" E {
1505               $$.t = join_types($1.t, $3.t, 'A');
1506               /*printf("%08x:\n",$1.t);
1507               code_dump($1.c, 0, 0, "", stdout);
1508               printf("%08x:\n",$3.t);
1509               code_dump($3.c, 0, 0, "", stdout);
1510               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1511               $$.c = $1.c;
1512               $$.c = converttype($$.c, $1.t, $$.t);
1513               $$.c = abc_dup($$.c);
1514               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1515               $$.c = cut_last_push($$.c);
1516               $$.c = code_append($$.c,$3.c);
1517               $$.c = converttype($$.c, $3.t, $$.t);
1518               code_t*label = $$.c = abc_label($$.c);
1519               jmp->branch = label;              
1520              }
1521
1522 E : '!' E    {$$.c=$2.c;
1523               $$.c = abc_not($$.c);
1524               $$.t = TYPE_BOOLEAN;
1525              }
1526
1527 E : E '-' E
1528 E : E '/' E
1529 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1530              $$.t = join_types($1.t, $3.t, '+');
1531             }
1532 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.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_multiply($$.c);$$.c=abc_coerce_a($$.c);
1536              $$.t = join_types($1.t, $3.t, '*');
1537             }
1538
1539 E : E "as" E
1540 E : E "is" E
1541 E : '(' E ')' {$$=$2;}
1542 E : '-' E {$$=$2;}
1543
1544 E : E '[' E ']' {
1545   $$.c = $1.c;
1546   $$.c = code_append($$.c, $3.c);
1547  
1548   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1549   $$.c = abc_getproperty2($$.c, &m);
1550 }
1551
1552 E : E "+=" E { 
1553                code_t*c = $3.c;
1554                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1555                 c=abc_add_i(c);
1556                } else {
1557                 c=abc_add(c);
1558                }
1559                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1560                
1561                $$.c = toreadwrite($1.c, c, 0);
1562                $$.t = $1.t;
1563               }
1564 E : E "-=" E { code_t*c = $3.c; 
1565                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1566                 c=abc_subtract_i(c);
1567                } else {
1568                 c=abc_subtract(c);
1569                }
1570                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1571                
1572                $$.c = toreadwrite($1.c, c, 0);
1573                $$.t = $1.t;
1574              }
1575 E : E '=' E { code_t*c = 0;
1576               c = code_append(c, $3.c);
1577               c = converttype(c, $3.t, $1.t);
1578               $$.c = toreadwrite($1.c, c, 1);
1579               $$.t = $1.t;
1580             }
1581
1582 // TODO: use inclocal where appropriate
1583 E : E "++" { code_t*c = 0;
1584              classinfo_t*type = $1.t;
1585              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1586                  c=abc_increment_i(c);
1587              } else {
1588                  c=abc_increment(c);
1589                  type = TYPE_NUMBER;
1590              }
1591              c=converttype(c, type, $1.t);
1592              $$.c = toreadwrite($1.c, c, 0);
1593              $$.t = $1.t;
1594            }
1595 E : E "--" { code_t*c = 0;
1596              classinfo_t*type = $1.t;
1597              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1598                  c=abc_increment_i(c);
1599              } else {
1600                  c=abc_increment(c);
1601                  type = TYPE_NUMBER;
1602              }
1603              c=converttype(c, type, $1.t);
1604              $$.c = toreadwrite($1.c, c, 0);
1605              $$.t = $1.t;
1606             }
1607
1608 E : "++" E { code_t*c = 0;
1609              classinfo_t*type = $2.t;
1610              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1611                  c=abc_increment_i(c);
1612              } else {
1613                  c=abc_increment(c);
1614                  type = TYPE_NUMBER;
1615              }
1616              c=converttype(c, type, $2.t);
1617              $$.c = toreadwrite($2.c, c, 0);
1618              $$.t = $2.t;
1619            }
1620
1621 E : E '.' T_IDENTIFIER
1622             {$$.c = $1.c;
1623              if($$.t) {
1624                  memberinfo_t*f = registry_findmember($$.t, $3->text);
1625
1626                  if(f && f->slot) {
1627                      $$.c = abc_getslot($$.c, f->slot);
1628                  } else {
1629                      namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
1630                      multiname_t m = {QNAME, &ns, 0, $3->text};
1631                      $$.c = abc_getproperty2($$.c, &m);
1632                  }
1633                  /* determine type */
1634                  if(f) {
1635                     if(f->kind == MEMBER_METHOD) {
1636                         $$.t = TYPE_FUNCTION(f);
1637                     } else {
1638                         $$.t = f->type;
1639                     }
1640                  } else {
1641                     $$.c = abc_coerce_a($$.c);
1642                     $$.t = registry_getanytype();
1643                  }
1644              } else {
1645                  namespace_t ns = {ACCESS_PACKAGE, ""};
1646                  multiname_t m = {QNAME, &ns, 0, $3->text};
1647                  $$.c = abc_getproperty2($$.c, &m);
1648                  $$.c = abc_coerce_a($$.c);
1649                  $$.t = registry_getanytype();
1650              }
1651             }
1652
1653 VAR_READ : T_IDENTIFIER {
1654     $$.t = 0;
1655     $$.c = 0;
1656     int i;
1657     memberinfo_t*f = 0;
1658     if((i = find_variable($1->text, &$$.t)) >= 0) {
1659         // $1 is a local variable
1660         $$.c = abc_getlocal($$.c, i);
1661     } else if((f = registry_findmember(state->clsinfo, $1->text))) {
1662         // $1 is a function in this class
1663         if(f->kind == MEMBER_METHOD) {
1664             $$.t = TYPE_FUNCTION(f);
1665         } else {
1666             $$.t = f->type;
1667         }
1668         if(f->slot>0) {
1669             $$.c = abc_getlocal_0($$.c);
1670             $$.c = abc_getslot($$.c, f->slot);
1671         } else {
1672             namespace_t ns = {state->clsinfo->access, ""};
1673             multiname_t m = {QNAME, &ns, 0, $1->text};
1674             $$.c = abc_getlocal_0($$.c);
1675             $$.c = abc_getproperty2($$.c, &m);
1676         }
1677     } else {
1678         // let the avm2 resolve $1 
1679         if(strcmp($1->text,"trace"))
1680         warning("Couldn't resolve %s, doing late binding", $1->text);
1681         state->late_binding = 1;
1682
1683         $$.t = 0;
1684         $$.c = abc_findpropstrict($$.c, $1->text);
1685         $$.c = abc_getproperty($$.c, $1->text);
1686     }
1687 }
1688
1689
1690 // ------------------------------------------------------------------------------
1691
1692
1693 TYPE : QNAME {$$=$1;}
1694      | '*'        {$$=registry_getanytype();}
1695      |  "String"  {$$=registry_getstringclass();}
1696      |  "int"     {$$=registry_getintclass();}
1697      |  "uint"    {$$=registry_getuintclass();}
1698      |  "Boolean" {$$=registry_getbooleanclass();}
1699      |  "Number"  {$$=registry_getnumberclass();}
1700
1701 MAYBETYPE: ':' TYPE {$$=$2;}
1702 MAYBETYPE:          {$$=0;}
1703
1704 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
1705 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1706                       MAYBETYPE
1707
1708 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1709 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1710 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1711
1712 //NAMESPACE :              {$$=empty_token();}
1713 //NAMESPACE : T_IDENTIFIER {$$=$1};
1714
1715 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1716                    //MULTINAME(m, registry_getintclass());
1717                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1718                    $$.t = TYPE_INT;
1719                   }
1720 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1721                     $$.t = TYPE_INT;
1722                    }
1723 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1724                   $$.t = TYPE_INT;
1725                  }
1726 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1727                    $$.t = TYPE_UINT;
1728                   }
1729 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1730                     $$.t = TYPE_FLOAT;
1731                    }
1732 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1733                      $$.t = TYPE_STRING;
1734                     }
1735 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1736                     $$.t = TYPE_BOOLEAN;
1737                    }
1738 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1739                      $$.t = TYPE_BOOLEAN;
1740                     }
1741 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1742                     $$.t = TYPE_NULL;
1743                    }
1744
1745 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1746
1747
1748 //VARIABLE : T_IDENTIFIER
1749 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1750 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1751 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1752 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1753 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1754
1755 GETSET : "get" {$$=$1;}
1756        | "set" {$$=$1;}
1757        |       {$$=empty_token();}
1758
1759 IDECLARATION : VARIABLE_DECLARATION
1760 IDECLARATION : FUNCTION_DECLARATION
1761
1762 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1763 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1764
1765 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1766 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1767
1768
1769 MAYBE_IDECLARATION_LIST : 
1770 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1771 IDECLARATION_LIST : IDECLARATION
1772 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1773
1774 // chapter 14
1775 // 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
1776 // syntactic keywords: each get set namespace include dynamic final native override static
1777