fixed opcodes
[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     class_signature_t*class_signature;
45     class_signature_list_t*class_signature_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     writeable_t writeable;
54     char*string;
55 }
56
57
58 %token<token> T_IDENTIFIER
59 %token<string> T_STRING
60 %token<token> T_REGEXP
61 %token<token> T_EMPTY
62 %token<number_int> T_INT
63 %token<number_uint> T_UINT
64 %token<number_uint> T_BYTE
65 %token<number_uint> T_SHORT
66 %token<number_float> T_FLOAT
67
68 %token<token> KW_IMPLEMENTS
69 %token<token> KW_NAMESPACE "namespace"
70 %token<token> KW_PACKAGE "package"
71 %token<token> KW_PROTECTED
72 %token<token> KW_PUBLIC
73 %token<token> KW_PRIVATE
74 %token<token> KW_USE "use"
75 %token<token> KW_INTERNAL
76 %token<token> KW_NEW "new"
77 %token<token> KW_NATIVE
78 %token<token> KW_FUNCTION "function"
79 %token<token> KW_FOR "for"
80 %token<token> KW_CLASS "class"
81 %token<token> KW_CONST "const"
82 %token<token> KW_SET "set"
83 %token<token> KW_STATIC
84 %token<token> KW_IMPORT "import"
85 %token<token> KW_INTERFACE "interface"
86 %token<token> KW_NULL
87 %token<token> KW_VAR "var"
88 %token<token> KW_DYNAMIC
89 %token<token> KW_OVERRIDE
90 %token<token> KW_FINAL
91 %token<token> KW_GET "get"
92 %token<token> KW_EXTENDS
93 %token<token> KW_FALSE "false"
94 %token<token> KW_TRUE "true"
95 %token<token> KW_BOOLEAN "Boolean"
96 %token<token> KW_UINT "uint"
97 %token<token> KW_INT "int"
98 %token<token> KW_WHILE "while"
99 %token<token> KW_NUMBER "Number"
100 %token<token> KW_STRING "String"
101 %token<token> KW_IF "if"
102 %token<token> KW_ELSE  "else"
103 %token<token> KW_BREAK   "break"
104 %token<token> KW_IS "is"
105 %token<token> KW_AS "as"
106
107 %token<token> T_EQEQ "=="
108 %token<token> T_EQEQEQ "==="
109 %token<token> T_NE "!="
110 %token<token> T_LE "<="
111 %token<token> T_GE ">="
112 %token<token> T_DIVBY "/=" 
113 %token<token> T_MODBY "%="
114 %token<token> T_PLUSBY "+=" 
115 %token<token> T_MINUSBY "-="
116 %token<token> T_SHRBY ">>="
117 %token<token> T_SHLBY "<<="
118 %token<token> T_USHRBY ">>>="
119 %token<token> T_OROR "||"
120 %token<token> T_ANDAND "&&"
121 %token<token> T_COLONCOLON "::"
122 %token<token> T_MINUSMINUS "--"
123 %token<token> T_PLUSPLUS "++"
124 %token<token> T_DOTDOT ".."
125 %token<token> T_SHL "<<"
126 %token<token> T_USHR ">>>"
127 %token<token> T_SHR ">>"
128 %token<token> T_SEMICOLON ';'
129 %token<token> T_STAR '*'
130 %token<token> T_DOT '.'
131
132 %type <code> CODE
133 %type <code> CODEPIECE
134 %type <code> CODEBLOCK MAYBECODE
135 %type <token> PACKAGE_DECLARATION
136 %type <token> FUNCTION_DECLARATION
137 %type <code> VARIABLE_DECLARATION
138 %type <token> CLASS_DECLARATION
139 %type <token> NAMESPACE_DECLARATION
140 %type <token> INTERFACE_DECLARATION
141 %type <code> VOIDEXPRESSION
142 %type <value> EXPRESSION
143 %type <value> MAYBEEXPRESSION
144 %type <value> E
145 %type <writeable> LH
146 %type <value> CONSTANT
147 %type <code> FOR IF WHILE MAYBEELSE BREAK
148 %type <token> USE_NAMESPACE
149 %type <code> ASSIGNMENT FOR_INIT
150 %type <token> IMPORT
151 %type <class_signature> MAYBETYPE
152 %type <token> PACKAGESPEC
153 %type <token> GETSET
154 %type <token> PARAM
155 %type <token> PARAMS
156 %type <token> PARAM_LIST
157 %type <token> MODIFIERS
158 %type <token> MODIFIER_LIST
159 %type <class_signature_list> IMPLEMENTS_LIST
160 %type <class_signature> EXTENDS
161 %type <class_signature_list> EXTENDS_LIST
162 %type <class_signature> PACKAGEANDCLASS
163 %type <class_signature_list> PACKAGEANDCLASS_LIST
164 %type <token> MULTILEVELIDENTIFIER
165 %type <class_signature> TYPE
166 %type <token> VAR
167 //%type <token> VARIABLE
168 %type <value> VAR_READ
169 %type <value> NEW
170 %type <token> X_IDENTIFIER
171 %type <token> MODIFIER
172 %type <token> PACKAGE
173 %type <value> FUNCTIONCALL
174 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST
175
176 // precendence: 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 '-'
195 %left '+'
196 %left "<<"
197 %left ">>>"
198 %left ">>"
199 %left '%'
200 %left '/'
201 %left '*'
202 %left '!'
203 %left '~'
204 %left "--" "++"
205 %left '['
206 %nonassoc "as"
207 %left '.' ".." "::"
208 %nonassoc T_IDENTIFIER
209 %left below_semicolon
210 %left ';'
211 %nonassoc "else"
212 %left '('
213 %left prec_highest
214
215      
216 %{
217
218 static int yyerror(char*s)
219 {
220    syntaxerror("%s", s); 
221 }
222 static token_t* concat2(token_t* t1, token_t* t2)
223 {
224     NEW(token_t,t);
225     int l1 = strlen(t1->text);
226     int l2 = strlen(t2->text);
227     t->text = malloc(l1+l2+1);
228     memcpy(t->text   , t1->text, l1);
229     memcpy(t->text+l1, t2->text, l2);
230     t->text[l1+l2] = 0;
231     return t;
232 }
233 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
234 {
235     NEW(token_t,t);
236     int l1 = strlen(t1->text);
237     int l2 = strlen(t2->text);
238     int l3 = strlen(t3->text);
239     t->text = malloc(l1+l2+l3+1);
240     memcpy(t->text   , t1->text, l1);
241     memcpy(t->text+l1, t2->text, l2);
242     memcpy(t->text+l1+l2, t3->text, l3);
243     t->text[l1+l2+l3] = 0;
244     return t;
245 }
246 static char* concat3str(const char* t1, const char* t2, const char* t3)
247 {
248     int l1 = strlen(t1);
249     int l2 = strlen(t2);
250     int l3 = strlen(t3);
251     char*text = malloc(l1+l2+l3+1);
252     memcpy(text   , t1, l1);
253     memcpy(text+l1, t2, l2);
254     memcpy(text+l1+l2, t3, l3);
255     text[l1+l2+l3] = 0;
256     return text;
257 }
258
259 typedef struct _import {
260     char*path;
261 } import_t;
262
263 DECLARE_LIST(import);
264
265 typedef struct _state {
266     abc_file_t*file;
267     abc_script_t*init;
268
269     int level;
270
271     char*package;     
272     char*function;
273     /* code that needs to be executed at the start of
274        a method (like initializing local registers) */
275     code_t*initcode;
276
277     abc_method_body_t*m;
278     import_list_t*imports;
279    
280     /* class data */
281     char*classname;
282     abc_class_t*cls;
283
284     array_t*vars;
285     int local_var_base;
286 } state_t;
287
288 static state_t* state = 0;
289
290 DECLARE_LIST(state);
291
292 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
293
294 static state_list_t*state_stack=0;
295
296 static void new_state()
297 {
298     NEW(state_t, s);
299     NEW(state_list_t, sl);
300
301     state_t*oldstate = state;
302     if(state)
303         memcpy(s, state, sizeof(state_t)); //shallow copy
304     sl->next = state_stack;
305     sl->state = s;
306     if(oldstate)
307         s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
308     state_stack = sl;
309     state = s;
310     state->level++;
311     state->vars = array_new();
312     state->initcode = 0;
313 }
314 static void old_state()
315 {
316     if(!state_stack || !state_stack->next)
317         syntaxerror("invalid nesting");
318     state_t*oldstate = state;
319     state_list_t*old = state_stack;
320     state_stack = state_stack->next;
321     free(old);
322     state = state_stack->state;
323     /*if(state->initcode) {
324         printf("residual initcode\n");
325         code_dump(state->initcode, 0, 0, "", stdout);
326     }*/
327     state->initcode = code_append(state->initcode, oldstate->initcode);
328 }
329 void initialize_state()
330 {
331     new_state();
332
333     state->file = abc_file_new();
334     state->file->flags &= ~ABCFILE_LAZY;
335     
336     state->init = abc_initscript(state->file, 0, 0);
337     abc_method_body_t*m = state->init->method->body;
338     __ getlocal_0(m);
339     __ pushscope(m);
340     __ findpropstrict(m, "[package]::trace");
341     __ pushstring(m, "[entering global init function]");
342     __ callpropvoid(m, "[package]::trace", 1);
343 }
344 void* finalize_state()
345 {
346     if(state->level!=1) {
347         syntaxerror("unexpected end of file");
348     }
349     abc_method_body_t*m = state->init->method->body;
350     //__ popscope(m);
351     
352     __ findpropstrict(m, "[package]::trace");
353     __ pushstring(m, "[leaving global init function]");
354     __ callpropvoid(m, "[package]::trace", 1);
355     __ returnvoid(m);
356     return state->file;
357 }
358
359
360 static void startpackage(token_t*t) 
361 {
362     if(state->package) {
363         syntaxerror("Packages can not be nested."); 
364     } 
365     new_state();
366     char*name = t?t->text:"";
367     /*printf("entering package \"%s\"\n", name);*/
368     state->package = name;
369 }
370 static void endpackage()
371 {
372     /*printf("leaving package \"%s\"\n", state->package);*/
373     old_state();
374 }
375
376 char*globalclass=0;
377 static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements)
378 {
379     if(state->cls) {
380         syntaxerror("inner classes now allowed"); 
381     }
382     new_state();
383     state->classname = name->text;
384
385     token_list_t*t=0;
386     class_signature_list_t*mlist=0;
387     /*printf("entering class %s\n", name->text);
388     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
389     if(extends) 
390         printf("  extends: %s.%s\n", extends->package, extends->name);
391
392     printf("  implements (%d): ", list_length(implements));
393     for(mlist=implements;mlist;mlist=mlist->next)  {
394         printf("%s ", mlist->class_signature->name);
395     }
396     printf("\n");*/
397
398     char public=0,internal=0,final=0,sealed=1;
399     for(t=modifiers->tokens;t;t=t->next) {
400         if(t->token->type == KW_INTERNAL) {
401             /* the programmer is being explicit- 
402                being internal is the default anyway */
403             internal = 1;
404         } else if(t->token->type == KW_PUBLIC) {
405             public = 1;
406         } else if(t->token->type == KW_FINAL) {
407             final = 1;
408         } else {
409             syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
410         }
411     }
412     if(public&&internal)
413         syntaxerror("public and internal not supported at the same time.");
414
415     /* create the class name, together with the proper attributes */
416     int access=0;
417     char*package=0;
418
419     if(!public && !state->package) {
420         access = ACCESS_PRIVATE; package = current_filename;
421     } else if(!public && state->package) {
422         access = ACCESS_PACKAGEINTERNAL; package = state->package;
423     } else if(state->package) {
424         access = ACCESS_PACKAGE; package = state->package;
425     } else {
426         syntaxerror("public classes only allowed inside a package");
427     }
428
429     if(registry_findclass(package, state->classname)) {
430         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
431     }
432     
433     class_signature_t* classname = class_signature_register(access, package, state->classname);
434
435     multiname_t*extends2 = sig2mname(extends);
436     multiname_t*classname2 = sig2mname(classname);
437
438     state->cls = abc_class_new(state->file, classname2, extends2);
439     if(final) abc_class_final(state->cls);
440     if(sealed) abc_class_sealed(state->cls);
441
442     for(mlist=implements;mlist;mlist=mlist->next) {
443         MULTINAME(m, mlist->class_signature);
444         abc_class_add_interface(state->cls, &m);
445     }
446
447     /* now write the construction code for this class */
448     int slotindex = abc_initscript_addClassTrait(state->init, classname2, state->cls);
449
450     abc_method_body_t*m = state->init->method->body;
451     __ getglobalscope(m);
452     class_signature_t*s = extends;
453
454     int count=0;
455     
456     while(s) {
457         //TODO: take a look at the current scope stack, maybe 
458         //      we can re-use something
459         s = s->superclass;
460         if(!s) 
461         break;
462        
463         multiname_t*s2 = sig2mname(s);
464         __ getlex2(m, s2);
465         multiname_destroy(s2);
466
467         __ pushscope(m);
468         m->code = m->code->prev->prev; // invert
469         count++;
470     }
471     /* continue appending after last op end */
472     while(m->code && m->code->next) m->code = m->code->next; 
473
474     /* TODO: if this is one of *our* classes, we can also 
475              do a getglobalscope/getslot <nr> (which references
476              the init function's slots) */
477     __ getlex2(m, extends2);
478     __ dup(m);
479     __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
480     __ newclass(m,state->cls);
481     while(count--) {
482         __ popscope(m);
483     }
484     __ setslot(m, slotindex);
485
486     /* flash.display.MovieClip handling */
487     if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
488         if(state->package && state->package[0]) {
489             globalclass = concat3str(state->package, ".", state->classname);
490         } else {
491             globalclass = strdup(state->classname);
492         }
493     }
494 }
495
496 static void endclass()
497 {
498     /*printf("leaving class %s\n", state->classname);*/
499     old_state();
500 }
501 static void addimport(token_t*t)
502 {
503     NEW(import_t,i);
504     i->path = t->text;
505     list_append(state->imports, i);
506 }
507 static void print_imports()
508 {
509     import_list_t*l = state->imports;
510     while(l) {
511         printf("  import %s\n", l->import->path);
512         l = l->next;
513     }
514 }
515 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
516                           token_t*params, class_signature_t*type)
517 {
518     token_list_t*t;
519     new_state();
520     state->function = name->text;
521     
522     /*printf("entering function %s\n", name->text);
523     if(ns)
524         printf("  namespace: %s\n", ns->text);
525     printf("  getset: %s\n", getset->text);
526     printf("  params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
527     printf("  mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
528     if(type)
529         printf("  type: %s.%s\n", type->package, type->name);
530     print_imports();*/
531     
532     if(state->m) {
533         syntaxerror("not able to start another method scope");
534     }
535
536     multiname_t*type2 = sig2mname(type);
537
538     if(!strcmp(state->classname,name->text)) {
539         state->m = abc_class_constructor(state->cls, type2, 0);
540     } else {
541         state->m = abc_class_method(state->cls, type2, name->text, 0);
542     }
543     /* state->vars is initialized by state_new */
544     array_append(state->vars, "this", 0);
545
546     __ getlocal_0(state->m);
547     __ pushscope(state->m);
548
549     multiname_destroy(type2);
550 }
551 static void endfunction()
552 {
553     /*printf("leaving function %s\n", state->function);*/
554     __ returnvoid(state->m);
555
556     old_state();
557 }
558
559
560 static token_t* empty_token()
561 {
562     NEW(token_t,t);
563     t->type=T_EMPTY;
564     t->text=0;
565     return t;
566 }
567
568 void extend(token_t*list, token_t*add) {
569     list_append(list->tokens,add);
570     if(!list->text)
571         list->text = add->text;
572 }
573 void extend_s(token_t*list, char*seperator, token_t*add) {
574     list_append(list->tokens,add);
575     char*t1 = list->text;
576     char*t2 = seperator;
577     char*t3 = add->text;
578     int l1 = strlen(t1);
579     int l2 = strlen(t2);
580     int l3 = strlen(t3);
581     list->text = malloc(l1+l2+l3+1);
582     strcpy(list->text, t1);
583     strcpy(list->text+l1, t2);
584     strcpy(list->text+l1+l2, t3);
585     list->text[l1+l2+l3]=0;
586 }
587
588 static int find_variable(char*name, class_signature_t**m)
589 {
590     state_list_t* s = state_stack;
591     while(s) {
592         int i = array_find(s->state->vars, name);
593         if(i>=0) {
594             if(m) {
595                 *m = array_getvalue(s->state->vars, i);
596             }
597             return i + s->state->local_var_base;
598         }
599         s = s->next;
600     }
601     syntaxerror("undefined variable: %s", name);
602
603 static char variable_exists(char*name) 
604 {
605     return array_contains(state->vars, name);
606 }
607 static int new_variable(char*name, class_signature_t*type)
608 {
609     return array_append(state->vars, name, type) + state->local_var_base;
610 }
611 code_t* killvars(code_t*c) 
612 {
613     int t;
614     for(t=0;t<state->vars->num;t++) {
615         class_signature_t*type = array_getvalue(state->vars, t);
616         //do this always, otherwise register types don't match
617         //in the verifier when doing nested loops
618         //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
619             c = abc_kill(c, t+state->local_var_base);
620         //}
621     }
622     return c;
623 }
624
625 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
626 {
627     return registry_getanytype(); // FIXME
628 }
629 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
630 {
631     return 1; // FIXME
632 }
633
634 void breakjumpsto(code_t*c, code_t*jump) 
635 {
636     while(c->prev) 
637         c=c->prev;
638     while(c) {
639         if(c->opcode == OPCODE___BREAK__) {
640             c->opcode = OPCODE_JUMP;
641             c->branch = jump;
642         }
643         c = c->next;
644     }
645 }
646 code_t*converttype(code_t*c, class_signature_t*from, class_signature_t*to)
647 {
648     /* TODO */
649     return abc_nop(c);
650 }
651
652 code_t*defaultvalue(code_t*c, class_signature_t*type)
653 {
654     if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
655        c = abc_pushbyte(c, 0);
656     } else if(TYPE_IS_BOOLEAN(type)) {
657        c = abc_pushfalse(c);
658     } else {
659        c = abc_pushnull(c);
660     }
661     return c;
662 }
663
664 %}
665
666
667 %%
668
669 /* ------------ code blocks / statements ---------------- */
670
671 PROGRAM: MAYBECODE
672
673 MAYBECODE: CODE {$$=$1;}
674 MAYBECODE:      {$$=code_new();}
675
676 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
677 CODE: CODEPIECE {$$=$1;}
678
679 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
680 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
681 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
682 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
683 CODEPIECE: ';'                   {$$=code_new();}
684 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
685 CODEPIECE: VOIDEXPRESSION        {$$=$1}
686 CODEPIECE: FOR                   {$$=$1}
687 CODEPIECE: WHILE                 {$$=$1}
688 CODEPIECE: BREAK                 {$$=$1}
689 CODEPIECE: IF                    {$$=$1}
690 CODEPIECE: ASSIGNMENT            {$$=$1}
691 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
692 CODEPIECE: FUNCTION_DECLARATION  {/*TODO*/$$=code_new();}
693 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
694
695 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
696 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
697 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
698
699 /* ------------ functions --------------------------- */
700
701 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
702                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
703     if(!state->m) syntaxerror("internal error: undefined function");
704     state->initcode = abc_nop(state->initcode);
705     state->initcode = abc_nop(state->initcode);
706     state->initcode = abc_nop(state->initcode);
707     state->m->code = code_append(state->initcode, $11);state->initcode=0;
708     endfunction()
709 }
710
711 /* ------------ variables --------------------------- */
712
713 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
714                 |                {$$.c=abc_pushundefined(0);
715                                   $$.t=TYPE_ANY;
716                                  }
717
718 VAR : "const" | "var"
719 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
720     if(variable_exists($2->text))
721         syntaxerror("Variable %s already defined", $2->text);
722    
723     if(!is_subtype_of($4.t, $3)) {
724         syntaxerror("Can't convert %s to %s", $4.t->name, 
725                                               $3->name);
726     }
727
728     int index = new_variable($2->text, $3);
729     
730     if($3) {
731         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
732             $$ = $4.c;
733             $$ = converttype($$, $4.t, $3);
734             $$ = abc_setlocal($$, index);
735         } else {
736             $$ = defaultvalue(0, $3);
737             $$ = abc_setlocal($$, index);
738         }
739
740         /* push default value for type on stack */
741         state->initcode = defaultvalue(state->initcode, $3);
742         state->initcode = abc_setlocal(state->initcode, index);
743     } else {
744         /* only bother to actually set this variable if its syntax is either
745             var x:type;
746            or
747             var x=expr;
748         */
749         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
750             $$ = $4.c;
751             $$ = abc_coerce_a($$);
752             $$ = abc_setlocal($$, index);
753         } else {
754             $$ = code_new();
755         }
756     }
757     
758     /* that's the default for a local register, anyway
759         else {
760         state->initcode = abc_pushundefined(state->initcode);
761         state->initcode = abc_setlocal(state->initcode, index);
762     }*/
763     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
764 }
765 ASSIGNMENT :           T_IDENTIFIER '=' EXPRESSION {
766     class_signature_t*type=0;
767     int i = find_variable($1->text, &type);
768     $$ = $3.c;
769     if(!type && $3.t) {
770         // convert to "any" type, the register is untyped
771         $$ = abc_coerce_a($$);
772     } else {
773         // TODO: convert ints to strings etc.
774     }
775     $$ = abc_setlocal($$, i);
776 }
777
778 /* ------------ control flow ------------------------- */
779
780 MAYBEELSE:  %prec prec_none {$$ = code_new();}
781 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
782 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
783
784 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
785     $$ = state->initcode;state->initcode=0;
786
787     $$ = code_append($$, $4.c);
788     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
789    
790     $$ = code_append($$, $6);
791     if($7) {
792         myjmp = $$ = abc_jump($$, 0);
793     }
794     myif->branch = $$ = abc_label($$);
795     if($7) {
796         $$ = code_append($$, $7);
797         myjmp->branch = $$ = abc_label($$);
798     }
799     
800     $$ = killvars($$);old_state();
801 }
802
803 FOR_INIT : {$$=code_new();}
804 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
805
806 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
807     code_append($$, state->initcode);state->initcode=0;
808
809     $$ = code_append($$, $4);
810     code_t*loopstart = $$ = abc_label($$);
811     $$ = code_append($$, $6.c);
812     code_t*myif = $$ = abc_iffalse($$, 0);
813     $$ = code_append($$, $10);
814     $$ = code_append($$, $8);
815     $$ = abc_jump($$, loopstart);
816     code_t*out = $$ = abc_label($$);
817     breakjumpsto($$, out);
818     myif->branch = out;
819
820     $$ = killvars($$);old_state();
821 }
822
823 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
824     $$ = state->initcode;state->initcode=0;
825
826     code_t*myjmp = $$ = abc_jump($$, 0);
827     code_t*loopstart = $$ = abc_label($$);
828     $$ = code_append($$, $6);
829     myjmp->branch = $$ = abc_label($$);
830     $$ = code_append($$, $4.c);
831     $$ = abc_iftrue($$, loopstart);
832     code_t*out = $$ = abc_label($$);
833     breakjumpsto($$, out);
834
835     $$ = killvars($$);old_state();
836 }
837
838 BREAK : "break" {
839     $$ = abc___break__(0);
840 }
841
842 /* ------------ packages and imports ---------------- */
843
844 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
845 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
846
847 IMPORT : "import" PACKAGESPEC {addimport($2);}
848
849 TYPE : PACKAGEANDCLASS {$$=$1;}
850      | '*'        {$$=registry_getanytype();}
851      |  "String"  {$$=registry_getstringclass();}
852      |  "int"     {$$=registry_getintclass();}
853      |  "uint"    {$$=registry_getuintclass();}
854      |  "Boolean" {$$=registry_getbooleanclass();}
855      |  "Number"  {$$=registry_getnumberclass();}
856
857 MAYBETYPE: ':' TYPE {$$=$2;}
858 MAYBETYPE:          {$$=0;}
859
860 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
861 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
862                       MAYBETYPE
863
864 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
865 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
866 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
867
868 //NAMESPACE :              {$$=empty_token();}
869 //NAMESPACE : T_IDENTIFIER {$$=$1};
870
871 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
872                    //MULTINAME(m, registry_getintclass());
873                    //$$.c = abc_coerce2($$.c, &m); // FIXME
874                    $$.t = TYPE_INT;
875                   }
876 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
877                     $$.t = TYPE_INT;
878                    }
879 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
880                   $$.t = TYPE_INT;
881                  }
882 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
883                    $$.t = TYPE_UINT;
884                   }
885 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
886                     $$.t = TYPE_FLOAT;
887                    }
888 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
889                      $$.t = TYPE_STRING;
890                     }
891 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
892                     $$.t = TYPE_BOOLEAN;
893                    }
894 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
895                      $$.t = TYPE_BOOLEAN;
896                     }
897 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
898                     $$.t = TYPE_NULL;
899                    }
900
901 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
902
903
904 EXPRESSION : E %prec prec_none  /*precendence below '-x'*/ {$$ = $1;}
905 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
906
907 E : CONSTANT
908 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
909 E : NEW                         {$$.c = abc_pushundefined(0); /* FIXME */
910                                  $$.t = TYPE_ANY;
911                                 }
912 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
913                                  $$.t = TYPE_ANY;
914                                 }
915 E : FUNCTIONCALL
916 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
917              $$.t = TYPE_BOOLEAN;
918             }
919 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
920              $$.t = TYPE_BOOLEAN;
921             }
922 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
923               $$.t = TYPE_BOOLEAN;
924              }
925 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
926               $$.t = TYPE_BOOLEAN;
927              }
928 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
929               $$.t = TYPE_BOOLEAN;
930              }
931 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
932               $$.t = TYPE_BOOLEAN;
933              }
934 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
935               $$.t = TYPE_BOOLEAN;
936              }
937
938 E : E '-' E
939 E : E '/' E
940 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
941              $$.t = join_types($1.t, $3.t, '+');
942             }
943 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
944              $$.t = join_types($1.t, $3.t, '%');
945             }
946 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
947              $$.t = join_types($1.t, $3.t, '*');
948             }
949
950 E : E "as" TYPE
951 E : E "is" TYPE
952 E : '(' E ')' {$$=$2;}
953 E : '-' E {$$=$2;}
954
955 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
956                MULTINAME(m, registry_getintclass());
957                $$.c=abc_coerce2($$.c, &m); // FIXME
958                $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
959                $$.t = $1.type;
960               }
961 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
962                MULTINAME(m, registry_getintclass());
963                $$.c=abc_coerce2($$.c, &m); // FIXME
964                $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
965                $$.t = $1.type;
966               }
967
968 // TODO: use inclocal where appropriate
969 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
970              MULTINAME(m, registry_getintclass());
971              $$.c=abc_coerce2($$.c, &m); //FIXME
972              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
973              $$.t = $1.type;
974             }
975 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
976              MULTINAME(m, registry_getintclass());
977              $$.c=abc_coerce2($$.c, &m); //FIXME
978              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
979              $$.t = $1.type;
980             }
981
982 LH: T_IDENTIFIER {
983   int i = find_variable($1->text, &$$.type);
984   $$.read = abc_getlocal(0, i);
985   $$.write = abc_setlocal(0, i);
986 }
987
988 NEW : "new" T_IDENTIFIER                         {$$.c=0;$$.t=0;/*FIXME*/}
989     | "new" T_IDENTIFIER '(' ')'                 {$$.c=0;$$.t=0;/*FIXME*/}
990     | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
991
992 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
993         /* TODO: use abc_call (for calling local variables),
994                  abc_callstatic (for calling own methods) */
995         $$.c = code_new();
996         $$.c = abc_findpropstrict($$.c, $1->text);
997         typedcode_list_t*l = $3;
998         // push parameters on stack
999         int len = 0;
1000         while(l) {
1001             $$.c = code_append($$.c, l->typedcode.c);
1002             l = l->nxt;
1003             len ++;
1004         }
1005         $$.c = abc_callproperty($$.c, $1->text, len);
1006 }
1007
1008 MAYBE_EXPRESSION_LIST : {$$=0;}
1009 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1010 EXPRESSION_LIST : EXPRESSION                     {$$=malloc(sizeof(typedcode_list_t));
1011                                                   $$->nxt = 0;
1012                                                   $$->typedcode = $1;}
1013 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1014                                                   $$->nxt = $1;
1015                                                   $$->typedcode = $3;
1016                                                  }
1017
1018 VAR_READ : T_IDENTIFIER {
1019         int i = find_variable($1->text, &$$.t);
1020         $$.c = abc_getlocal(0, i);
1021 }
1022
1023 //VARIABLE : T_IDENTIFIER
1024 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1025 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1026 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1027 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1028 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1029
1030 // keywords which also may be identifiers
1031 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1032
1033 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
1034                                            $$ = concat3($1,$2,$3);}
1035 PACKAGESPEC : X_IDENTIFIER                {$$=$1;}
1036 PACKAGESPEC : '*'                         {$$=$1;}
1037
1038 GETSET : "get" {$$=$1;}
1039        | "set" {$$=$1;}
1040        |       {$$=empty_token();}
1041
1042 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
1043 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
1044
1045 PARAMS: {$$=empty_token();}
1046 PARAMS: PARAM_LIST {$$=$1;}
1047 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
1048 PARAM_LIST: PARAM                {$$=empty_token();extend($$,$1);}
1049 PARAM:  T_IDENTIFIER ':' TYPE {$$=$1;}
1050
1051 MODIFIERS : {$$=empty_token();}
1052 MODIFIERS : MODIFIER_LIST {$$=$1}
1053 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1054 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
1055 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1056
1057 DECLARATION : VARIABLE_DECLARATION
1058 DECLARATION : FUNCTION_DECLARATION
1059
1060 IDECLARATION : VARIABLE_DECLARATION
1061 IDECLARATION : FUNCTION_DECLARATION
1062
1063 IMPLEMENTS_LIST : {$$=list_new();}
1064 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
1065
1066 EXTENDS : {$$=registry_getobjectclass();}
1067 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
1068
1069 EXTENDS_LIST : {$$=list_new();}
1070 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
1071
1072 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1073 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1074
1075 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
1076 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
1077 PACKAGE : X_IDENTIFIER
1078 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
1079
1080 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1081 MULTILEVELIDENTIFIER : T_IDENTIFIER                 {$$=$1;extend($$,$1)};
1082
1083 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1084 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1085
1086 MAYBE_DECLARATION_LIST : 
1087 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1088 DECLARATION_LIST : DECLARATION
1089 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1090
1091 MAYBE_IDECLARATION_LIST : 
1092 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1093 IDECLARATION_LIST : IDECLARATION
1094 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1095
1096 // chapter 14
1097 // 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
1098 // syntactic keywords: each get set namespace include dynamic final native override static
1099