reworked left-hand expressions
[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     abc_method_body_t*m = state->init->method->body;
369     __ getlocal_0(m);
370     __ pushscope(m);
371     __ findpropstrict(m, "[package]::trace");
372     __ pushstring(m, "[entering global init function]");
373     __ callpropvoid(m, "[package]::trace", 1);
374 }
375 void* finalize_state()
376 {
377     if(state->level!=1) {
378         syntaxerror("unexpected end of file");
379     }
380     abc_method_body_t*m = state->init->method->body;
381     //__ popscope(m);
382     
383     __ findpropstrict(m, "[package]::trace");
384     __ pushstring(m, "[leaving global init function]");
385     __ callpropvoid(m, "[package]::trace", 1);
386     __ returnvoid(m);
387     return state->file;
388 }
389
390
391 static void startpackage(token_t*t) 
392 {
393     if(state->package) {
394         syntaxerror("Packages can not be nested."); 
395     } 
396     new_state();
397     char*name = t?t->text:"";
398     /*printf("entering package \"%s\"\n", name);*/
399     state->package = name;
400 }
401 static void endpackage()
402 {
403     /*printf("leaving package \"%s\"\n", state->package);*/
404     old_state();
405 }
406
407 char*globalclass=0;
408 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
409 {
410     if(state->cls) {
411         syntaxerror("inner classes now allowed"); 
412     }
413     new_state();
414     char*classname = name->text;
415
416     token_list_t*t=0;
417     classinfo_list_t*mlist=0;
418     /*printf("entering class %s\n", name->text);
419     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
420     if(extends) 
421         printf("  extends: %s.%s\n", extends->package, extends->name);
422     printf("  implements (%d): ", list_length(implements));
423     for(mlist=implements;mlist;mlist=mlist->next)  {
424         printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
425     }
426     printf("\n");
427     */
428
429     char public=0,internal=0,final=0,sealed=1;
430     for(t=modifiers->tokens;t;t=t->next) {
431         if(t->token->type == KW_INTERNAL) {
432             /* the programmer is being explicit- 
433                being internal is the default anyway */
434             internal = 1;
435         } else if(t->token->type == KW_PUBLIC) {
436             public = 1;
437         } else if(t->token->type == KW_FINAL) {
438             final = 1;
439         } else {
440             syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
441         }
442     }
443     if(public&&internal)
444         syntaxerror("public and internal not supported at the same time.");
445
446     /* create the class name, together with the proper attributes */
447     int access=0;
448     char*package=0;
449
450     if(!public && !state->package) {
451         access = ACCESS_PRIVATE; package = current_filename;
452     } else if(!public && state->package) {
453         access = ACCESS_PACKAGEINTERNAL; package = state->package;
454     } else if(state->package) {
455         access = ACCESS_PACKAGE; package = state->package;
456     } else {
457         syntaxerror("public classes only allowed inside a package");
458     }
459
460     if(registry_findclass(package, classname)) {
461         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, classname);
462     }
463     
464     state->clsinfo = classinfo_register(access, package, classname);
465
466     MULTINAME(classname2,state->clsinfo);
467     
468     multiname_t*extends2 = sig2mname(extends);
469
470     /*if(extends) {
471         state->cls_init = abc_getlocal_0(state->cls_init);
472         state->cls_init = abc_constructsuper(state->cls_init, 0);
473     }*/
474
475     state->cls = abc_class_new(state->file, &classname2, extends2);
476     if(final) abc_class_final(state->cls);
477     if(sealed) abc_class_sealed(state->cls);
478     if(interface) abc_class_interface(state->cls);
479
480     for(mlist=implements;mlist;mlist=mlist->next) {
481         MULTINAME(m, mlist->classinfo);
482         abc_class_add_interface(state->cls, &m);
483     }
484
485     /* now write the construction code for this class */
486     int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
487
488     abc_method_body_t*m = state->init->method->body;
489     __ getglobalscope(m);
490     classinfo_t*s = extends;
491
492     int count=0;
493     
494     while(s) {
495         //TODO: take a look at the current scope stack, maybe 
496         //      we can re-use something
497         s = s->superclass;
498         if(!s) 
499         break;
500        
501         multiname_t*s2 = sig2mname(s);
502         __ getlex2(m, s2);
503         multiname_destroy(s2);
504
505         __ pushscope(m); count++;
506         m->code = m->code->prev->prev; // invert
507     }
508     /* continue appending after last op end */
509     while(m->code && m->code->next) m->code = m->code->next; 
510
511     /* TODO: if this is one of *our* classes, we can also 
512              do a getglobalscope/getslot <nr> (which references
513              the init function's slots) */
514     if(extends2) {
515         __ getlex2(m, extends2);
516         __ dup(m);
517         /* notice: we get a Verify Error #1107 if the top elemnt on the scope
518            stack is not the superclass */
519         __ pushscope(m);count++;
520     } else {
521         __ pushnull(m);
522         /* notice: we get a verify error #1107 if the top element on the scope 
523            stack is not the global object */
524         __ getlocal_0(m);
525         __ pushscope(m);count++;
526     }
527     __ newclass(m,state->cls);
528     while(count--) {
529         __ popscope(m);
530     }
531     __ setslot(m, slotindex);
532
533     /* flash.display.MovieClip handling */
534     if(!globalclass && public && classinfo_equals(registry_getMovieClip(),extends)) {
535         if(state->package && state->package[0]) {
536             globalclass = concat3str(state->package, ".", classname);
537         } else {
538             globalclass = strdup(classname);
539         }
540     }
541     multiname_destroy(extends2);
542 }
543
544 static void endclass()
545 {
546     if(state->cls_init) {
547         if(!state->cls->constructor) {
548             abc_method_body_t*m = abc_class_constructor(state->cls, 0, 0);
549             m->code = code_append(m->code, state->cls_init);
550             m->code = abc_returnvoid(m->code);
551         } else {
552             code_t*c = state->cls->constructor->body->code;
553             c = code_append(state->cls_init, c);
554             state->cls->constructor->body->code = c;
555
556         }
557     }
558     if(state->cls_static_init) {
559         if(!state->cls->static_constructor) {
560             abc_method_body_t*m = abc_class_staticconstructor(state->cls, 0, 0);
561             m->code = state->cls_static_init;
562         } else {
563             state->cls->static_constructor->body->code = 
564                 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
565         }
566     }
567
568     old_state();
569 }
570 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
571                           param_list_t*params, classinfo_t*type)
572 {
573     token_list_t*t;
574     new_state();
575     state->function = name->text;
576     
577     if(state->m) {
578         syntaxerror("not able to start another method scope");
579     }
580
581     multiname_t*type2 = sig2mname(type);
582     if(!strcmp(state->clsinfo->name,name->text)) {
583         state->m = abc_class_constructor(state->cls, type2, 0);
584     } else {
585         state->minfo = memberinfo_register(state->clsinfo, name->text, MEMBER_METHOD);
586         state->m = abc_class_method(state->cls, type2, name->text, 0);
587         state->minfo->slot = state->m->method->trait->slot_id;
588     }
589     if(getset->type == KW_GET) {
590         state->m->method->trait->kind = TRAIT_GETTER;
591     }
592     if(getset->type == KW_SET) {
593         state->m->method->trait->kind = TRAIT_SETTER;
594     }
595
596     param_list_t*p;
597     for(p=params;p;p=p->next) {
598         multiname_t*m = sig2mname(p->param->type);
599         list_append(state->m->method->parameters, m);
600     }
601
602     /* state->vars is initialized by state_new */
603     array_append(state->vars, "this", 0);
604     for(p=params;p;p=p->next) {
605         array_append(state->vars, p->param->name, 0);
606     }
607 }
608 static void endfunction(code_t*body)
609 {
610     code_t*c = 0;
611     if(state->late_binding) {
612         c = abc_getlocal_0(c);
613         c = abc_pushscope(c);
614     }
615     c = code_append(c, state->initcode);
616     c = code_append(c, body);
617     c = abc_returnvoid(c);
618
619     if(state->m->code) syntaxerror("internal error");
620     state->m->code = c;
621     old_state();
622 }
623
624
625 static token_t* empty_token()
626 {
627     NEW(token_t,t);
628     t->type=T_EMPTY;
629     t->text=0;
630     return t;
631 }
632
633 void extend(token_t*list, token_t*add) {
634     list_append(list->tokens,add);
635     if(!list->text)
636         list->text = add->text;
637 }
638 void extend_s(token_t*list, char*seperator, token_t*add) {
639     list_append(list->tokens,add);
640     char*t1 = list->text;
641     char*t2 = seperator;
642     char*t3 = add->text;
643     int l1 = strlen(t1);
644     int l2 = strlen(t2);
645     int l3 = strlen(t3);
646     list->text = malloc(l1+l2+l3+1);
647     strcpy(list->text, t1);
648     strcpy(list->text+l1, t2);
649     strcpy(list->text+l1+l2, t3);
650     list->text[l1+l2+l3]=0;
651 }
652
653 static int find_variable(char*name, classinfo_t**m)
654 {
655     state_list_t* s = state_stack;
656     while(s) {
657         int i = array_find(s->state->vars, name);
658         if(i>=0) {
659             if(m) {
660                 *m = array_getvalue(s->state->vars, i);
661             }
662             return i + s->state->local_var_base;
663         }
664         s = s->next;
665     }
666     return -1;
667
668 static int find_variable_safe(char*name, classinfo_t**m)
669 {
670     int i = find_variable(name, m);
671     if(i<0)
672         syntaxerror("undefined variable: %s", name);
673     return i;
674 }
675 static char variable_exists(char*name) 
676 {
677     return array_contains(state->vars, name);
678 }
679 static int new_variable(char*name, classinfo_t*type)
680 {
681     return array_append(state->vars, name, type) + state->local_var_base;
682 }
683 #define TEMPVARNAME "__as3_temp__"
684 static int gettempvar()
685 {
686     int i = find_variable(TEMPVARNAME, 0);
687     if(i<0) {
688         return new_variable(TEMPVARNAME, 0);
689     } else {
690         return i;
691     }
692 }
693
694 code_t* killvars(code_t*c) 
695 {
696     int t;
697     for(t=0;t<state->vars->num;t++) {
698         classinfo_t*type = array_getvalue(state->vars, t);
699         //do this always, otherwise register types don't match
700         //in the verifier when doing nested loops
701         //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
702             c = abc_kill(c, t+state->local_var_base);
703         //}
704     }
705     return c;
706 }
707
708 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
709 {
710     return 1; // FIXME
711 }
712
713 void breakjumpsto(code_t*c, code_t*jump) 
714 {
715     while(c->prev) 
716         c=c->prev;
717     while(c) {
718         if(c->opcode == OPCODE___BREAK__) {
719             c->opcode = OPCODE_JUMP;
720             c->branch = jump;
721         }
722         c = c->next;
723     }
724 }
725
726 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
727 {
728     return registry_getanytype(); // FIXME
729 }
730 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
731 {
732     if(from==to)
733         return c;
734     if(!to) {
735         /*TODO: can omit this if from is zero? */
736         return abc_coerce_a(c);
737     }
738     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
739         MULTINAME(m, TYPE_UINT);
740         return abc_coerce2(c, &m);
741     }
742     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
743         MULTINAME(m, TYPE_INT);
744         return abc_coerce2(c, &m);
745     }
746     return c;
747 }
748
749 code_t*defaultvalue(code_t*c, classinfo_t*type)
750 {
751     if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
752        c = abc_pushbyte(c, 0);
753     } else if(TYPE_IS_BOOLEAN(type)) {
754        c = abc_pushfalse(c);
755     } else {
756        c = abc_pushnull(c);
757     }
758     return c;
759 }
760
761 char is_pushundefined(code_t*c)
762 {
763     return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
764 }
765
766 static code_t* toreadwrite(code_t*in, code_t*middlepart)
767 {
768     /* converts this:
769
770        [prefix code] [read instruction]
771
772        to this:
773
774        [prefix code] ([dup]) [read instruction] [setvar] [middlepart] [write instruction] [getvar]
775     */
776     
777     if(in->next)
778         syntaxerror("internal error");
779
780     int temp = gettempvar();
781
782     /* chop off read instruction */
783     code_t*prefix = in;
784     code_t*r = in;
785     if(r->prev) {
786         prefix = r->prev;r->prev = 0;
787         prefix->next=0;
788     } else {
789         prefix = 0;
790     }
791
792     /* generate the write instruction, and maybe append a dup to the prefix code */
793     code_t* write = abc_nop(middlepart);
794     if(r->opcode == OPCODE_GETPROPERTY) {
795         write->opcode = OPCODE_SETPROPERTY;
796         multiname_t*m = (multiname_t*)r->data[0];
797         write->data[0] = multiname_clone(m);
798         if(m->type != QNAME)
799             syntaxerror("illegal lvalue: can't assign a value to this expression (not a qname)");
800         prefix = abc_dup(prefix); // we need the object, too
801     } else if(r->opcode == OPCODE_GETSLOT) {
802         write->opcode = OPCODE_SETSLOT;
803         write->data[0] = r->data[0];
804         prefix = abc_dup(prefix); // we need the object, too
805     } else if(r->opcode == OPCODE_GETLOCAL) { 
806         write->opcode = OPCODE_SETLOCAL;
807         write->data[0] = r->data[0];
808     } else if(r->opcode == OPCODE_GETLOCAL_0) { 
809         write->opcode = OPCODE_SETLOCAL_0;
810     } else if(r->opcode == OPCODE_GETLOCAL_1) { 
811         write->opcode = OPCODE_SETLOCAL_1;
812     } else if(r->opcode == OPCODE_GETLOCAL_2) { 
813         write->opcode = OPCODE_SETLOCAL_2;
814     } else if(r->opcode == OPCODE_GETLOCAL_3) { 
815         write->opcode = OPCODE_SETLOCAL_3;
816     } else {
817         code_dump(r, 0, 0, "", stdout);
818         syntaxerror("illegal lvalue: can't assign a value to this expression");
819     }
820     code_t* c = prefix;
821     c = code_append(c, r);
822
823     c = abc_dup(c);
824     c = abc_setlocal(c, temp);
825     c = code_append(c, middlepart);
826     c = abc_getlocal(c, temp);
827     c = abc_kill(c, temp);
828
829     return c;
830 }
831
832
833 %}
834
835
836 %%
837
838 /* ------------ code blocks / statements ---------------- */
839
840 PROGRAM: MAYBECODE
841
842 MAYBECODE: CODE {$$=$1;}
843 MAYBECODE:      {$$=code_new();}
844
845 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
846 CODE: CODEPIECE {$$=$1;}
847
848 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
849 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
850 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
851 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
852 CODEPIECE: ';'                   {$$=code_new();}
853 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
854 CODEPIECE: VOIDEXPRESSION        {$$=$1}
855 CODEPIECE: FOR                   {$$=$1}
856 CODEPIECE: WHILE                 {$$=$1}
857 CODEPIECE: BREAK                 {$$=$1}
858 CODEPIECE: RETURN                {$$=$1}
859 CODEPIECE: IF                    {$$=$1}
860 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
861 CODEPIECE: FUNCTION_DECLARATION  {/*TODO*/$$=code_new();}
862 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
863
864 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
865 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
866 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
867
868 /* ------------ variables --------------------------- */
869
870 MAYBEEXPRESSION : '=' NONCOMMAEXPRESSION {$$=$2;}
871                 |                {$$.c=abc_pushundefined(0);
872                                   $$.t=TYPE_ANY;
873                                  }
874
875 VAR : "const" | "var"
876 VARIABLE_DECLARATION : VAR VARIABLE_LIST {$$=$2;}
877
878 VARIABLE_LIST: ONE_VARIABLE                   {$$ = $1;}
879 VARIABLE_LIST: VARIABLE_LIST ',' ONE_VARIABLE {$$ = code_append($1, $3);}
880
881 ONE_VARIABLE: {} T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION
882 {
883     if(variable_exists($2->text))
884         syntaxerror("Variable %s already defined", $2->text);
885    
886     if(!is_subtype_of($4.t, $3)) {
887         syntaxerror("Can't convert %s to %s", $4.t->name, 
888                                               $3->name);
889     }
890
891     int index = new_variable($2->text, $3);
892     
893     if($3) {
894         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
895             $$ = $4.c;
896             $$ = converttype($$, $4.t, $3);
897             $$ = abc_setlocal($$, index);
898         } else {
899             $$ = defaultvalue(0, $3);
900             $$ = abc_setlocal($$, index);
901         }
902
903         /* push default value for type on stack */
904         state->initcode = defaultvalue(state->initcode, $3);
905         state->initcode = abc_setlocal(state->initcode, index);
906     } else {
907         /* only bother to actually set this variable if its syntax is either
908             var x:type;
909            or
910             var x=expr;
911         */
912         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
913             $$ = $4.c;
914             $$ = abc_coerce_a($$);
915             $$ = abc_setlocal($$, index);
916         } else {
917             $$ = code_new();
918         }
919     }
920     
921     /* that's the default for a local register, anyway
922         else {
923         state->initcode = abc_pushundefined(state->initcode);
924         state->initcode = abc_setlocal(state->initcode, index);
925     }*/
926     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
927 }
928
929 /* ------------ control flow ------------------------- */
930
931 MAYBEELSE:  %prec prec_none {$$ = code_new();}
932 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
933 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
934
935 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
936     $$ = state->initcode;state->initcode=0;
937
938     $$ = code_append($$, $4.c);
939     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
940    
941     $$ = code_append($$, $6);
942     if($7) {
943         myjmp = $$ = abc_jump($$, 0);
944     }
945     myif->branch = $$ = abc_label($$);
946     if($7) {
947         $$ = code_append($$, $7);
948         myjmp->branch = $$ = abc_label($$);
949     }
950     
951     $$ = killvars($$);old_state();
952 }
953
954 FOR_INIT : {$$=code_new();}
955 FOR_INIT : VARIABLE_DECLARATION
956 FOR_INIT : VOIDEXPRESSION
957
958 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
959     $$ = state->initcode;state->initcode=0;
960
961     $$ = code_append($$, $4);
962     code_t*loopstart = $$ = abc_label($$);
963     $$ = code_append($$, $6.c);
964     code_t*myif = $$ = abc_iffalse($$, 0);
965     $$ = code_append($$, $10);
966     $$ = code_append($$, $8);
967     $$ = abc_jump($$, loopstart);
968     code_t*out = $$ = abc_label($$);
969     breakjumpsto($$, out);
970     myif->branch = out;
971
972     $$ = killvars($$);old_state();
973 }
974
975 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
976     $$ = state->initcode;state->initcode=0;
977
978     code_t*myjmp = $$ = abc_jump($$, 0);
979     code_t*loopstart = $$ = abc_label($$);
980     $$ = code_append($$, $6);
981     myjmp->branch = $$ = abc_label($$);
982     $$ = code_append($$, $4.c);
983     $$ = abc_iftrue($$, loopstart);
984     code_t*out = $$ = abc_label($$);
985     breakjumpsto($$, out);
986
987     $$ = killvars($$);old_state();
988 }
989
990 BREAK : "break" {
991     $$ = abc___break__(0);
992 }
993
994 /* ------------ packages and imports ---------------- */
995
996 X_IDENTIFIER: T_IDENTIFIER
997             | "package"
998
999 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
1000 PACKAGE: X_IDENTIFIER             {$$=$1;}
1001
1002 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
1003 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
1004
1005 IMPORT : "import" QNAME {
1006        classinfo_t*c = $2;
1007        if(!c) 
1008             syntaxerror("Couldn't import class\n");
1009        state_has_imports();
1010        dict_put(state->imports, c->name, c);
1011        $$=0;
1012 }
1013 IMPORT : "import" PACKAGE '.' '*' {
1014        NEW(import_t,i);
1015        i->package = $2->text;
1016        state_has_imports();
1017        list_append(state->wildcard_imports, i);
1018        $$=0;
1019 }
1020
1021 /* ------------ classes and interfaces (header) -------------- */
1022
1023 MODIFIERS : {$$=empty_token();}
1024 MODIFIERS : MODIFIER_LIST {$$=$1}
1025 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1026 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
1027 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1028
1029 EXTENDS : {$$=registry_getobjectclass();}
1030 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
1031
1032 EXTENDS_LIST : {$$=list_new();}
1033 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
1034
1035 IMPLEMENTS_LIST : {$$=list_new();}
1036 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
1037
1038 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER 
1039                               EXTENDS IMPLEMENTS_LIST 
1040                               '{' {startclass($1,$3,$4,$5, 0);} 
1041                               MAYBE_DECLARATION_LIST 
1042                               '}' {endclass();}
1043
1044 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER 
1045                               EXTENDS_LIST 
1046                               '{' {startclass($1,$3,0,$4,1);}
1047                               MAYBE_IDECLARATION_LIST 
1048                               '}' {endclass();}
1049
1050 /* ------------ classes and interfaces (body) -------------- */
1051
1052 MAYBE_DECLARATION_LIST : 
1053 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1054 DECLARATION_LIST : DECLARATION
1055 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1056 DECLARATION : ';'
1057 DECLARATION : SLOT_DECLARATION
1058 DECLARATION : FUNCTION_DECLARATION
1059
1060 VARCONST: "var" | "const"
1061 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
1062
1063     memberinfo_t* info = memberinfo_register(state->clsinfo, $3->text, MEMBER_SLOT);
1064     info->type = $4;
1065
1066     trait_t*t=0;
1067     if($4) {
1068         MULTINAME(m, $4);
1069         t=abc_class_slot(state->cls, $3->text, &m);
1070     } else {
1071         t=abc_class_slot(state->cls, $3->text, 0);
1072     }
1073     if($2->type==KW_CONST) {
1074         t->kind= TRAIT_CONST;
1075     }
1076     info->slot = t->slot_id;
1077     if($5.c && !is_pushundefined($5.c)) {
1078         code_t*c = 0;
1079         c = abc_getlocal_0(c);
1080         c = code_append(c, $5.c);
1081         c = converttype(c, $5.t, $4);
1082         c = abc_setslot(c, t->slot_id);
1083         //c = abc_setproperty(c, $3->text); 
1084         state->cls_init = code_append(state->cls_init, c);
1085     }
1086 }
1087
1088 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1089                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' 
1090 {
1091     if(!state->m) syntaxerror("internal error: undefined function");
1092     endfunction($11);
1093 }
1094
1095 /* ------------- package + class ids --------------- */
1096
1097 CLASS: T_IDENTIFIER {
1098
1099     /* try current package */
1100     $$ = registry_findclass(state->package, $1->text);
1101
1102     /* try explicit imports */
1103     dictentry_t* e = dict_get_slot(state->imports, $1->text);
1104     while(e) {
1105         if($$)
1106             break;
1107         if(!strcmp(e->key, $1->text)) {
1108             $$ = (classinfo_t*)e->data;
1109         }
1110         e = e->next;
1111     }
1112
1113     /* try package.* imports */
1114     import_list_t*l = state->wildcard_imports;
1115     while(l) {
1116         if($$)
1117             break;
1118         //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1119         $$ = registry_findclass(l->import->package, $1->text);
1120         l = l->next;
1121     }
1122
1123     /* try global package */
1124     if(!$$) {
1125         $$ = registry_findclass("", $1->text);
1126     }
1127
1128     if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1129 }
1130
1131 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1132     $$ = registry_findclass($1->text, $3->text);
1133     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1134 }
1135
1136 QNAME: PACKAGEANDCLASS
1137      | CLASS
1138
1139
1140 /* ----------function calls, constructor calls ------ */
1141
1142 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1143 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1144
1145 MAYBE_EXPRESSION_LIST : {$$=0;}
1146 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1147 EXPRESSION_LIST : NONCOMMAEXPRESSION             {$$=list_new();
1148                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1149                                                   *t = $1;
1150                                                   list_append($$, t);}
1151 EXPRESSION_LIST : EXPRESSION_LIST ',' NONCOMMAEXPRESSION {$$=$1;
1152                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1153                                                   *t = $3;
1154                                                   list_append($$, t);}
1155
1156 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1157     MULTINAME(m, $2);
1158     $$.c = code_new();
1159
1160     /* TODO: why do we have to *find* our own classes? */
1161     $$.c = abc_findpropstrict2($$.c, &m);
1162
1163     typedcode_list_t*l = $3;
1164     int len = 0;
1165     while(l) {
1166         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1167         l = l->next;
1168         len ++;
1169     }
1170     $$.c = abc_constructprop2($$.c, &m, len);
1171     $$.t = $2;
1172 }
1173
1174 /* TODO: use abc_call (for calling local variables),
1175          abc_callstatic (for calling own methods) 
1176          call (for closures)
1177 */
1178 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1179     typedcode_list_t*l = $3;
1180     int len = 0;
1181     code_t*paramcode = 0;
1182     while(l) {
1183         paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1184         l = l->next;
1185         len ++;
1186     }
1187
1188     $$.c = $1.c;
1189     if($$.c->opcode == OPCODE_GETPROPERTY) {
1190         multiname_t*name = multiname_clone($$.c->data[0]);
1191         $$.c = code_cutlast($$.c);
1192         $$.c = code_append($$.c, paramcode);
1193         $$.c = abc_callproperty2($$.c, name, len);
1194     } else if($$.c->opcode == OPCODE_GETSLOT) {
1195         int slot = (int)(ptroff_t)$$.c->data[0];
1196         trait_t*t = abc_class_find_slotid(state->cls,slot);//FIXME
1197         if(t->kind!=TRAIT_METHOD) {syntaxerror("not a function");}
1198         
1199         abc_method_t*m = t->method;
1200         $$.c = code_cutlast($$.c);
1201         $$.c = code_append($$.c, paramcode);
1202
1203         //$$.c = abc_callmethod($$.c, m, len); //#1051 illegal early access binding
1204         $$.c = abc_callproperty2($$.c, t->name, len);
1205     } else {
1206         int i = find_variable_safe("this", 0);
1207         $$.c = abc_getlocal($$.c, i);
1208         $$.c = code_append($$.c, paramcode);
1209         $$.c = abc_call($$.c, len);
1210     }
1211     /* TODO: look up the functions's return value */
1212     $$.t = TYPE_ANY;
1213 }
1214
1215 RETURN: "return" %prec prec_none {
1216     $$ = abc_returnvoid(0);
1217 }
1218 RETURN: "return" EXPRESSION {
1219     $$ = $2.c;
1220     $$ = abc_returnvalue($$);
1221 }
1222 // ----------------------- expression types -------------------------------------
1223
1224 NONCOMMAEXPRESSION : E        %prec prec_belowminus {$$=$1;}
1225 EXPRESSION : E                %prec prec_belowminus {$$ = $1;}
1226 EXPRESSION : EXPRESSION ',' E %prec prec_belowminus {
1227     $$.c = $1.c;
1228     $$.c = abc_pop($$.c);
1229     $$.c = code_append($$.c,$3.c);
1230     $$.t = $3.t;
1231 }
1232 VOIDEXPRESSION : EXPRESSION %prec prec_belowminus {$$=abc_pop($1.c);}
1233
1234 // ----------------------- expression evaluation -------------------------------------
1235
1236 E : CONSTANT
1237 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1238 E : NEW                         {$$ = $1;}
1239 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
1240                                  $$.t = TYPE_ANY;
1241                                 }
1242 E : FUNCTIONCALL
1243 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1244              $$.t = TYPE_BOOLEAN;
1245             }
1246 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1247              $$.t = TYPE_BOOLEAN;
1248             }
1249 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1250               $$.t = TYPE_BOOLEAN;
1251              }
1252 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1253               $$.t = TYPE_BOOLEAN;
1254              }
1255 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1256               $$.t = TYPE_BOOLEAN;
1257              }
1258 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1259               $$.t = TYPE_BOOLEAN;
1260              }
1261 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1262               $$.t = TYPE_BOOLEAN;
1263              }
1264
1265 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1266               $$.c = $1.c;
1267               $$.c = converttype($$.c, $1.t, $$.t);
1268               $$.c = abc_dup($$.c);
1269               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1270               $$.c = abc_pop($$.c);
1271               $$.c = code_append($$.c,$3.c);
1272               $$.c = converttype($$.c, $1.t, $$.t);
1273               code_t*label = $$.c = abc_label($$.c);
1274               jmp->branch = label;
1275              }
1276 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1277               $$.c = $1.c;
1278               $$.c = converttype($$.c, $1.t, $$.t);
1279               $$.c = abc_dup($$.c);
1280               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1281               $$.c = abc_pop($$.c);
1282               $$.c = code_append($$.c,$3.c);
1283               $$.c = converttype($$.c, $1.t, $$.t);
1284               code_t*label = $$.c = abc_label($$.c);
1285               jmp->branch = label;              
1286              }
1287
1288 E : E '.' T_IDENTIFIER
1289             {$$.c = $1.c;
1290              if($$.t) {
1291                  //namespace_t ns = {$$.t->access, (char*)$$.t->package};
1292                  namespace_t ns = {$$.t->access, ""};
1293                  multiname_t m = {QNAME, &ns, 0, $3->text};
1294                  $$.c = abc_getproperty2($$.c, &m);
1295                 /* FIXME: get type of ($1.t).$3 */
1296                  $$.t = registry_getanytype();
1297              } else {
1298                  namespace_t ns = {ACCESS_PACKAGE, ""};
1299                  multiname_t m = {QNAME, &ns, 0, $3->text};
1300                  $$.c = abc_getproperty2($$.c, &m);
1301                  $$.t = registry_getanytype();
1302              }
1303             }
1304
1305 E : '!' E    {$$.c=$2.c;
1306               $$.c = abc_not($$.c);
1307               $$.t = TYPE_BOOLEAN;
1308              }
1309
1310 E : E '-' E
1311 E : E '/' E
1312 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1313              $$.t = join_types($1.t, $3.t, '+');
1314             }
1315 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1316              $$.t = join_types($1.t, $3.t, '%');
1317             }
1318 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1319              $$.t = join_types($1.t, $3.t, '*');
1320             }
1321
1322 E : E "as" E
1323 E : E "is" E
1324 E : '(' E ')' {$$=$2;}
1325 E : '-' E {$$=$2;}
1326
1327 E : E "+=" E { 
1328                code_t*c = $3.c;
1329                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1330                 c=abc_add_i(c);
1331                } else {
1332                 c=abc_add(c);
1333                }
1334                c=converttype(c, join_types($1.t, $3.t, '+'), $1.t);
1335                
1336                $$.c = toreadwrite($1.c, c);
1337                $$.t = $1.t;
1338               }
1339 E : E "-=" E { code_t*c = $3.c; 
1340                if(TYPE_IS_INT($3.t) || TYPE_IS_UINT($3.t)) {
1341                 c=abc_subtract_i(c);
1342                } else {
1343                 c=abc_subtract(c);
1344                }
1345                c=converttype(c, join_types($1.t, $3.t, '-'), $1.t);
1346                
1347                $$.c = toreadwrite($1.c, c);
1348                $$.t = $1.t;
1349              }
1350 E : E '=' E { code_t*c = 0;
1351               c = abc_pop(c);
1352               c = code_append(c, $3.c);
1353               c = converttype(c, $3.t, $1.t);
1354               $$.c = toreadwrite($1.c, c);
1355               $$.t = $1.t;
1356             }
1357
1358 // TODO: use inclocal where appropriate
1359 E : E "++" { code_t*c = 0;
1360              classinfo_t*type = $1.t;
1361              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1362                  c=abc_increment_i(c);
1363              } else {
1364                  c=abc_increment(c);
1365                  type = TYPE_NUMBER;
1366              }
1367              c=converttype(c, type, $1.t);
1368              $$.c = toreadwrite($1.c, c);
1369              $$.t = $1.t;
1370            }
1371 E : E "--" { code_t*c = 0;
1372              classinfo_t*type = $1.t;
1373              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1374                  c=abc_increment_i(c);
1375              } else {
1376                  c=abc_increment(c);
1377                  type = TYPE_NUMBER;
1378              }
1379              c=converttype(c, type, $1.t);
1380              $$.c = toreadwrite($1.c, c);
1381              $$.t = $1.t;
1382             }
1383
1384 VAR_READ : T_IDENTIFIER {
1385     $$.t = 0;
1386     $$.c = 0;
1387     int i;
1388     memberinfo_t*m;
1389     if((i = find_variable($1->text, &$$.t)) >= 0) {
1390         $$.c = abc_getlocal($$.c, i);
1391     } else if((m = registry_findmember(state->clsinfo, $1->text))) {
1392         $$.t = m->type;
1393         if(m->slot>0) {
1394             $$.c = abc_getlocal_0($$.c);
1395             $$.c = abc_getslot($$.c, m->slot);
1396         } else {
1397             $$.c = abc_getlocal_0($$.c);
1398             $$.c = abc_getproperty($$.c, $1->text);
1399         }
1400     } else {
1401         warning("Couldn't resolve %s, doing late binding", $1->text);
1402         state->late_binding = 1;
1403
1404         $$.t = 0;
1405         $$.c = abc_findpropstrict($$.c, $1->text);
1406         $$.c = abc_getproperty($$.c, $1->text);
1407     }
1408 }
1409
1410
1411 // ------------------------------------------------------------------------------
1412
1413
1414 TYPE : QNAME {$$=$1;}
1415      | '*'        {$$=registry_getanytype();}
1416      |  "String"  {$$=registry_getstringclass();}
1417      |  "int"     {$$=registry_getintclass();}
1418      |  "uint"    {$$=registry_getuintclass();}
1419      |  "Boolean" {$$=registry_getbooleanclass();}
1420      |  "Number"  {$$=registry_getnumberclass();}
1421
1422 MAYBETYPE: ':' TYPE {$$=$2;}
1423 MAYBETYPE:          {$$=0;}
1424
1425 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
1426 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
1427                       MAYBETYPE
1428
1429 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1430 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1431 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1432
1433 //NAMESPACE :              {$$=empty_token();}
1434 //NAMESPACE : T_IDENTIFIER {$$=$1};
1435
1436 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1437                    //MULTINAME(m, registry_getintclass());
1438                    //$$.c = abc_coerce2($$.c, &m); // FIXME
1439                    $$.t = TYPE_INT;
1440                   }
1441 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1442                     $$.t = TYPE_INT;
1443                    }
1444 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1445                   $$.t = TYPE_INT;
1446                  }
1447 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1448                    $$.t = TYPE_UINT;
1449                   }
1450 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1451                     $$.t = TYPE_FLOAT;
1452                    }
1453 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1454                      $$.t = TYPE_STRING;
1455                     }
1456 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1457                     $$.t = TYPE_BOOLEAN;
1458                    }
1459 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1460                      $$.t = TYPE_BOOLEAN;
1461                     }
1462 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1463                     $$.t = TYPE_NULL;
1464                    }
1465
1466 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1467
1468
1469 //VARIABLE : T_IDENTIFIER
1470 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1471 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1472 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1473 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1474 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1475
1476 GETSET : "get" {$$=$1;}
1477        | "set" {$$=$1;}
1478        |       {$$=empty_token();}
1479
1480 MAYBE_PARAM_LIST: {$$=list_new();}
1481 MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
1482 PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1;         list_append($$, $3);}
1483 PARAM_LIST: PARAM                {$$ = list_new();list_append($$, $1);}
1484 PARAM:  T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
1485                                $$->name=$1->text;$$->type = $3;}
1486 PARAM:  T_IDENTIFIER          {$$ = malloc(sizeof(param_t));
1487                                $$->name=$1->text;$$->type = TYPE_ANY;}
1488
1489 IDECLARATION : VARIABLE_DECLARATION
1490 IDECLARATION : FUNCTION_DECLARATION
1491
1492 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1493 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1494
1495 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1496 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1497
1498
1499 MAYBE_IDECLARATION_LIST : 
1500 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1501 IDECLARATION_LIST : IDECLARATION
1502 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1503
1504 // chapter 14
1505 // 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
1506 // syntactic keywords: each get set namespace include dynamic final native override static
1507