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