44c94b3e2230175fde3472dda3ea37eb876e75a0
[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     string_t str;
56     constant_t*constant;
57 }
58
59
60 %token<token> T_IDENTIFIER
61 %token<str> 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_string2($1.str,$1.len);}
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;
1306      $$->type = TYPE_ANY;
1307      $$->value = $2;
1308 }
1309
1310 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1311                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,&$6,$8)} MAYBECODE '}' 
1312 {
1313     if(!state->m) syntaxerror("internal error: undefined function");
1314     endfunction($11);
1315 }
1316
1317 /* ------------- package + class ids --------------- */
1318
1319 CLASS: T_IDENTIFIER {
1320
1321     /* try current package */
1322     $$ = registry_findclass(state->package, $1->text);
1323
1324     /* try explicit imports */
1325     dictentry_t* e = dict_get_slot(state->imports, $1->text);
1326     while(e) {
1327         if($$)
1328             break;
1329         if(!strcmp(e->key, $1->text)) {
1330             $$ = (classinfo_t*)e->data;
1331         }
1332         e = e->next;
1333     }
1334
1335     /* try package.* imports */
1336     import_list_t*l = state->wildcard_imports;
1337     while(l) {
1338         if($$)
1339             break;
1340         //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1341         $$ = registry_findclass(l->import->package, $1->text);
1342         l = l->next;
1343     }
1344
1345     /* try global package */
1346     if(!$$) {
1347         $$ = registry_findclass("", $1->text);
1348     }
1349
1350     if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1351 }
1352
1353 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1354     $$ = registry_findclass($1->text, $3->text);
1355     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1356 }
1357
1358 QNAME: PACKAGEANDCLASS
1359      | CLASS
1360
1361
1362 /* ----------function calls, constructor calls ------ */
1363
1364 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1365 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1366
1367 MAYBE_EXPRESSION_LIST : {$$=0;}
1368 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1369 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1370                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1371                                                   *t = $1;
1372                                                   list_append($$, t);}
1373 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1374                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1375                                                   *t = $3;
1376                                                   list_append($$, t);}
1377
1378 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1379     MULTINAME(m, $2);
1380     $$.c = code_new();
1381
1382     /* TODO: why do we have to *find* our own classes? */
1383     $$.c = abc_findpropstrict2($$.c, &m);
1384
1385     typedcode_list_t*l = $3;
1386     int len = 0;
1387     while(l) {
1388         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1389         l = l->next;
1390         len ++;
1391     }
1392     $$.c = abc_constructprop2($$.c, &m, len);
1393     $$.t = $2;
1394 }
1395
1396 /* TODO: use abc_call (for calling local variables),
1397          abc_callstatic (for calling own methods) 
1398          call (for closures)
1399 */
1400 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1401     typedcode_list_t*l = $3;
1402     int len = 0;
1403     code_t*paramcode = 0;
1404     while(l) {
1405         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1406         l = l->next;
1407         len ++;
1408     }
1409        
1410     $$.c = $1.c;
1411     if($$.c->opcode == OPCODE_COERCE_A) {
1412         $$.c = code_cutlast($$.c);
1413     }
1414
1415     $$.t = TYPE_ANY;
1416     multiname_t*name = 0;
1417     if($$.c->opcode == OPCODE_GETPROPERTY) {
1418         name = multiname_clone($$.c->data[0]);
1419         $$.c = code_cutlast($$.c);
1420         $$.c = code_append($$.c, paramcode);
1421         $$.c = abc_callproperty2($$.c, name, len);
1422     } else if($$.c->opcode == OPCODE_GETSLOT) {
1423         int slot = (int)(ptroff_t)$$.c->data[0];
1424         trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1425         if(t->kind!=TRAIT_METHOD) {
1426             //flash allows to assign closures to members.
1427             //syntaxerror("not a function");
1428         }
1429         name = t->name;
1430         $$.c = code_cutlast($$.c);
1431         $$.c = code_append($$.c, paramcode);
1432         //$$.c = abc_callmethod($$.c, t->method, len); //#1051 illegal early access binding
1433         $$.c = abc_callproperty2($$.c, name, len);
1434     } else {
1435         $$.c = abc_getlocal_0($$.c);
1436         $$.c = code_append($$.c, paramcode);
1437         $$.c = abc_call($$.c, len);
1438     }
1439    
1440     memberinfo_t*f = 0;
1441    
1442     if(TYPE_IS_FUNCTION($1.t) &&
1443        (f = registry_findmember($1.t, "call"))) {
1444         $$.t = f->return_type;
1445     } else {
1446         $$.c = abc_coerce_a($$.c);
1447         $$.t = TYPE_ANY;
1448     }
1449 }
1450
1451 RETURN: "return" %prec prec_none {
1452     $$ = abc_returnvoid(0);
1453 }
1454 RETURN: "return" EXPRESSION {
1455     $$ = $2.c;
1456     $$ = abc_returnvalue($$);
1457 }
1458 // ----------------------- expression types -------------------------------------
1459
1460 NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
1461 EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
1462 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1463     $$.c = $1.c;
1464     $$.c = cut_last_push($$.c);
1465     $$.c = code_append($$.c,$3.c);
1466     $$.t = $3.t;
1467 }
1468 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=cut_last_push($1.c);}
1469
1470 // ----------------------- expression evaluation -------------------------------------
1471
1472 E : CONSTANT
1473 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1474 E : NEW                         {$$ = $1;}
1475 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1476                                  $$.t = TYPE_ANY;
1477                                 }
1478 E : FUNCTIONCALL
1479 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1480              $$.t = TYPE_BOOLEAN;
1481             }
1482 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1483              $$.t = TYPE_BOOLEAN;
1484             }
1485 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1486               $$.t = TYPE_BOOLEAN;
1487              }
1488 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1489               $$.t = TYPE_BOOLEAN;
1490              }
1491 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1492               $$.t = TYPE_BOOLEAN;
1493              }
1494 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1495               $$.t = TYPE_BOOLEAN;
1496              }
1497 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1498               $$.t = TYPE_BOOLEAN;
1499              }
1500
1501 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1502               $$.c = $1.c;
1503               $$.c = converttype($$.c, $1.t, $$.t);
1504               $$.c = abc_dup($$.c);
1505               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1506               $$.c = cut_last_push($$.c);
1507               $$.c = code_append($$.c,$3.c);
1508               $$.c = converttype($$.c, $3.t, $$.t);
1509               code_t*label = $$.c = abc_label($$.c);
1510               jmp->branch = label;
1511              }
1512 E : E "&&" E {
1513               $$.t = join_types($1.t, $3.t, 'A');
1514               /*printf("%08x:\n",$1.t);
1515               code_dump($1.c, 0, 0, "", stdout);
1516               printf("%08x:\n",$3.t);
1517               code_dump($3.c, 0, 0, "", stdout);
1518               printf("joining %08x and %08x to %08x\n", $1.t, $3.t, $$.t);*/
1519               $$.c = $1.c;
1520               $$.c = converttype($$.c, $1.t, $$.t);
1521               $$.c = abc_dup($$.c);
1522               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1523               $$.c = cut_last_push($$.c);
1524               $$.c = code_append($$.c,$3.c);
1525               $$.c = converttype($$.c, $3.t, $$.t);
1526               code_t*label = $$.c = abc_label($$.c);
1527               jmp->branch = label;              
1528              }
1529
1530 E : '!' E    {$$.c=$2.c;
1531               $$.c = abc_not($$.c);
1532               $$.t = TYPE_BOOLEAN;
1533              }
1534
1535 E : E '-' E
1536 E : E '/' E
1537 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1538              $$.t = join_types($1.t, $3.t, '+');
1539             }
1540 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1541              $$.t = join_types($1.t, $3.t, '%');
1542             }
1543 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1544              $$.t = join_types($1.t, $3.t, '*');
1545             }
1546
1547 E : E "as" E
1548 E : E "is" E
1549 E : '(' E ')' {$$=$2;}
1550 E : '-' E {$$=$2;}
1551
1552 E : E '[' E ']' {
1553   $$.c = $1.c;
1554   $$.c = code_append($$.c, $3.c);
1555  
1556   MULTINAME_LATE(m, $1.t?$1.t->access:ACCESS_PACKAGE, "");
1557   $$.c = abc_getproperty2($$.c, &m);
1558 }
1559
1560 E : E "*=" E { 
1561                code_t*c = $3.c;
1562                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1563                 c=abc_multiply_i(c);
1564                } else {
1565                 c=abc_multiply(c);
1566                }
1567                c=converttype(c, join_types($1.t, $3.t, '*'), $1.t);
1568                $$.c = toreadwrite($1.c, c, 0, 0);
1569                $$.t = $1.t;
1570               }
1571 E : E "%=" E { 
1572                code_t*c = abc_modulo($3.c);
1573                c=converttype(c, join_types($1.t, $3.t, '%'), $1.t);
1574                $$.c = toreadwrite($1.c, c, 0, 0);
1575                $$.t = $1.t;
1576               }
1577 E : E "<<=" E { 
1578                code_t*c = abc_lshift($3.c);
1579                c=converttype(c, join_types($1.t, $3.t, '<'), $1.t);
1580                $$.c = toreadwrite($1.c, c, 0, 0);
1581                $$.t = $1.t;
1582               }
1583 E : E ">>=" E { 
1584                code_t*c = abc_rshift($3.c);
1585                c=converttype(c, join_types($1.t, $3.t, '>'), $1.t);
1586                $$.c = toreadwrite($1.c, c, 0, 0);
1587                $$.t = $1.t;
1588               }
1589 E : E ">>>=" E { 
1590                code_t*c = abc_urshift($3.c);
1591                c=converttype(c, join_types($1.t, $3.t, 'U'), $1.t);
1592                $$.c = toreadwrite($1.c, c, 0, 0);
1593                $$.t = $1.t;
1594               }
1595 E : E "/=" E { 
1596                code_t*c = abc_divide($3.c);
1597                c=converttype(c, join_types($1.t, $3.t, '/'), $1.t);
1598                $$.c = toreadwrite($1.c, c, 0, 0);
1599                $$.t = $1.t;
1600               }
1601 E : E "+=" E { 
1602                code_t*c = $3.c;
1603                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1604                 c=abc_add_i(c);
1605                } else {
1606                 c=abc_add(c);
1607                }
1608                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1609                
1610                $$.c = toreadwrite($1.c, c, 0, 0);
1611                $$.t = $1.t;
1612               }
1613 E : E "-=" E { code_t*c = $3.c; 
1614                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1615                 c=abc_subtract_i(c);
1616                } else {
1617                 c=abc_subtract(c);
1618                }
1619                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1620                
1621                $$.c = toreadwrite($1.c, c, 0, 0);
1622                $$.t = $1.t;
1623              }
1624 E : E '=' E { code_t*c = 0;
1625               c = code_append(c, $3.c);
1626               c = converttype(c, $3.t, $1.t);
1627               $$.c = toreadwrite($1.c, c, 1, 0);
1628               $$.t = $1.t;
1629             }
1630
1631 // TODO: use inclocal where appropriate
1632 E : E "++" { code_t*c = 0;
1633              classinfo_t*type = $1.t;
1634              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1635                  c=abc_increment_i(c);
1636              } else {
1637                  c=abc_increment(c);
1638                  type = TYPE_NUMBER;
1639              }
1640              c=converttype(c, type, $1.t);
1641              $$.c = toreadwrite($1.c, c, 0, 1);
1642              $$.t = $1.t;
1643            }
1644 E : E "--" { code_t*c = 0;
1645              classinfo_t*type = $1.t;
1646              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1647                  c=abc_decrement_i(c);
1648              } else {
1649                  c=abc_decrement(c);
1650                  type = TYPE_NUMBER;
1651              }
1652              c=converttype(c, type, $1.t);
1653              $$.c = toreadwrite($1.c, c, 0, 1);
1654              $$.t = $1.t;
1655             }
1656
1657 E : "++" E { code_t*c = 0;
1658              classinfo_t*type = $2.t;
1659              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1660                  c=abc_increment_i(c);
1661              } else {
1662                  c=abc_increment(c);
1663                  type = TYPE_NUMBER;
1664              }
1665              c=converttype(c, type, $2.t);
1666              $$.c = toreadwrite($2.c, c, 0, 0);
1667              $$.t = $2.t;
1668            }
1669
1670 E : "--" E { code_t*c = 0;
1671              classinfo_t*type = $2.t;
1672              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1673                  c=abc_decrement_i(c);
1674              } else {
1675                  c=abc_decrement(c);
1676                  type = TYPE_NUMBER;
1677              }
1678              c=converttype(c, type, $2.t);
1679              $$.c = toreadwrite($2.c, c, 0, 0);
1680              $$.t = $2.t;
1681            }
1682
1683 E : E '.' T_IDENTIFIER
1684             {$$.c = $1.c;
1685              if($$.t) {
1686                  memberinfo_t*f = registry_findmember($$.t, $3->text);
1687
1688                  if(f && f->slot) {
1689                      $$.c = abc_getslot($$.c, f->slot);
1690                  } else {
1691                      namespace_t ns = {$$.t->access, ""}; // needs to be "", not $$.t->package
1692                      multiname_t m = {QNAME, &ns, 0, $3->text};
1693                      $$.c = abc_getproperty2($$.c, &m);
1694                  }
1695                  /* determine type */
1696                  if(f) {
1697                     if(f->kind == MEMBER_METHOD) {
1698                         $$.t = TYPE_FUNCTION(f);
1699                     } else {
1700                         $$.t = f->type;
1701                     }
1702                  } else {
1703                     $$.c = abc_coerce_a($$.c);
1704                     $$.t = registry_getanytype();
1705                  }
1706              } else {
1707                  namespace_t ns = {ACCESS_PACKAGE, ""};
1708                  multiname_t m = {QNAME, &ns, 0, $3->text};
1709                  $$.c = abc_getproperty2($$.c, &m);
1710                  $$.c = abc_coerce_a($$.c);
1711                  $$.t = registry_getanytype();
1712              }
1713             }
1714
1715 VAR_READ : T_IDENTIFIER {
1716     $$.t = 0;
1717     $$.c = 0;
1718     int i;
1719     memberinfo_t*f = 0;
1720     if((i = find_variable($1->text, &$$.t)) >= 0) {
1721         // $1 is a local variable
1722         $$.c = abc_getlocal($$.c, i);
1723     } else if((f = registry_findmember(state->clsinfo, $1->text))) {
1724         // $1 is a function in this class
1725         if(f->kind == MEMBER_METHOD) {
1726             $$.t = TYPE_FUNCTION(f);
1727         } else {
1728             $$.t = f->type;
1729         }
1730         if(f->slot>0) {
1731             $$.c = abc_getlocal_0($$.c);
1732             $$.c = abc_getslot($$.c, f->slot);
1733         } else {
1734             namespace_t ns = {state->clsinfo->access, ""};
1735             multiname_t m = {QNAME, &ns, 0, $1->text};
1736             $$.c = abc_getlocal_0($$.c);
1737             $$.c = abc_getproperty2($$.c, &m);
1738         }
1739     } else {
1740         // let the avm2 resolve $1 
1741         if(strcmp($1->text,"trace"))
1742         warning("Couldn't resolve %s, doing late binding", $1->text);
1743         state->late_binding = 1;
1744
1745         $$.t = 0;
1746         $$.c = abc_findpropstrict($$.c, $1->text);
1747         $$.c = abc_getproperty($$.c, $1->text);
1748     }
1749 }
1750
1751
1752 // ------------------------------------------------------------------------------
1753
1754
1755 TYPE : QNAME {$$=$1;}
1756      | '*'        {$$=registry_getanytype();}
1757      |  "String"  {$$=registry_getstringclass();}
1758      |  "int"     {$$=registry_getintclass();}
1759      |  "uint"    {$$=registry_getuintclass();}
1760      |  "Boolean" {$$=registry_getbooleanclass();}
1761      |  "Number"  {$$=registry_getnumberclass();}
1762
1763 MAYBETYPE: ':' TYPE {$$=$2;}
1764 MAYBETYPE:          {$$=0;}
1765
1766 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
1767 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1768                       MAYBETYPE
1769
1770 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1771 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1772 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1773
1774 //NAMESPACE :              {$$=empty_token();}
1775 //NAMESPACE : T_IDENTIFIER {$$=$1};
1776
1777 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1778                    //MULTINAME(m, registry_getintclass());
1779                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1780                    $$.t = TYPE_INT;
1781                   }
1782 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1783                     $$.t = TYPE_INT;
1784                    }
1785 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1786                   $$.t = TYPE_INT;
1787                  }
1788 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1789                    $$.t = TYPE_UINT;
1790                   }
1791 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1792                     $$.t = TYPE_FLOAT;
1793                    }
1794 CONSTANT : T_STRING {$$.c = abc_pushstring2(0, &$1);
1795                      $$.t = TYPE_STRING;
1796                     }
1797 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1798                     $$.t = TYPE_BOOLEAN;
1799                    }
1800 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1801                      $$.t = TYPE_BOOLEAN;
1802                     }
1803 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1804                     $$.t = TYPE_NULL;
1805                    }
1806
1807 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1808
1809
1810 //VARIABLE : T_IDENTIFIER
1811 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1812 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1813 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1814 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1815 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1816
1817 GETSET : "get" {$$=$1;}
1818        | "set" {$$=$1;}
1819        |       {$$=empty_token();}
1820
1821 IDECLARATION : VARIABLE_DECLARATION
1822 IDECLARATION : FUNCTION_DECLARATION
1823
1824 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1825 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1826
1827 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1828 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1829
1830
1831 MAYBE_IDECLARATION_LIST : 
1832 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1833 IDECLARATION_LIST : IDECLARATION
1834 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1835
1836 // chapter 14
1837 // 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
1838 // syntactic keywords: each get set namespace include dynamic final native override static
1839