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