added missing type conversions
[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     if(!to) {
649         /*TODO: can omit this if from is zero? */
650         return abc_coerce_a(c);
651     }
652     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
653         MULTINAME(m, TYPE_UINT);
654         return abc_coerce2(c, &m);
655     }
656     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
657         MULTINAME(m, TYPE_INT);
658         return abc_coerce2(c, &m);
659     }
660     return c;
661 }
662
663 code_t*defaultvalue(code_t*c, class_signature_t*type)
664 {
665     if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
666        c = abc_pushbyte(c, 0);
667     } else if(TYPE_IS_BOOLEAN(type)) {
668        c = abc_pushfalse(c);
669     } else {
670        c = abc_pushnull(c);
671     }
672     return c;
673 }
674
675 %}
676
677
678 %%
679
680 /* ------------ code blocks / statements ---------------- */
681
682 PROGRAM: MAYBECODE
683
684 MAYBECODE: CODE {$$=$1;}
685 MAYBECODE:      {$$=code_new();}
686
687 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
688 CODE: CODEPIECE {$$=$1;}
689
690 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
691 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
692 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
693 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
694 CODEPIECE: ';'                   {$$=code_new();}
695 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
696 CODEPIECE: VOIDEXPRESSION        {$$=$1}
697 CODEPIECE: FOR                   {$$=$1}
698 CODEPIECE: WHILE                 {$$=$1}
699 CODEPIECE: BREAK                 {$$=$1}
700 CODEPIECE: IF                    {$$=$1}
701 CODEPIECE: ASSIGNMENT            {$$=$1}
702 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
703 CODEPIECE: FUNCTION_DECLARATION  {/*TODO*/$$=code_new();}
704 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
705
706 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
707 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
708 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
709
710 /* ------------ functions --------------------------- */
711
712 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
713                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
714     if(!state->m) syntaxerror("internal error: undefined function");
715     state->initcode = abc_nop(state->initcode);
716     state->initcode = abc_nop(state->initcode);
717     state->initcode = abc_nop(state->initcode);
718     state->m->code = code_append(state->initcode, $11);state->initcode=0;
719     endfunction()
720 }
721
722 /* ------------ variables --------------------------- */
723
724 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
725                 |                {$$.c=abc_pushundefined(0);
726                                   $$.t=TYPE_ANY;
727                                  }
728
729 VAR : "const" | "var"
730 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
731     if(variable_exists($2->text))
732         syntaxerror("Variable %s already defined", $2->text);
733    
734     if(!is_subtype_of($4.t, $3)) {
735         syntaxerror("Can't convert %s to %s", $4.t->name, 
736                                               $3->name);
737     }
738
739     int index = new_variable($2->text, $3);
740     
741     if($3) {
742         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
743             $$ = $4.c;
744             $$ = converttype($$, $4.t, $3);
745             $$ = abc_setlocal($$, index);
746         } else {
747             $$ = defaultvalue(0, $3);
748             $$ = abc_setlocal($$, index);
749         }
750
751         /* push default value for type on stack */
752         state->initcode = defaultvalue(state->initcode, $3);
753         state->initcode = abc_setlocal(state->initcode, index);
754     } else {
755         /* only bother to actually set this variable if its syntax is either
756             var x:type;
757            or
758             var x=expr;
759         */
760         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
761             $$ = $4.c;
762             $$ = abc_coerce_a($$);
763             $$ = abc_setlocal($$, index);
764         } else {
765             $$ = code_new();
766         }
767     }
768     
769     /* that's the default for a local register, anyway
770         else {
771         state->initcode = abc_pushundefined(state->initcode);
772         state->initcode = abc_setlocal(state->initcode, index);
773     }*/
774     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
775 }
776 ASSIGNMENT :           T_IDENTIFIER '=' EXPRESSION {
777     class_signature_t*type=0;
778     int i = find_variable($1->text, &type);
779     $$ = $3.c;
780     if(!type && $3.t) {
781         // convert to "any" type, the register is untyped
782         $$ = abc_coerce_a($$);
783     } else {
784         // TODO: convert ints to strings etc.
785     }
786     $$ = abc_setlocal($$, i);
787 }
788
789 /* ------------ control flow ------------------------- */
790
791 MAYBEELSE:  %prec prec_none {$$ = code_new();}
792 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
793 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
794
795 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
796     $$ = state->initcode;state->initcode=0;
797
798     $$ = code_append($$, $4.c);
799     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
800    
801     $$ = code_append($$, $6);
802     if($7) {
803         myjmp = $$ = abc_jump($$, 0);
804     }
805     myif->branch = $$ = abc_label($$);
806     if($7) {
807         $$ = code_append($$, $7);
808         myjmp->branch = $$ = abc_label($$);
809     }
810     
811     $$ = killvars($$);old_state();
812 }
813
814 FOR_INIT : {$$=code_new();}
815 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
816
817 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
818     $$ = state->initcode;state->initcode=0;
819
820     $$ = code_append($$, $4);
821     code_t*loopstart = $$ = abc_label($$);
822     $$ = code_append($$, $6.c);
823     code_t*myif = $$ = abc_iffalse($$, 0);
824     $$ = code_append($$, $10);
825     $$ = code_append($$, $8);
826     $$ = abc_jump($$, loopstart);
827     code_t*out = $$ = abc_label($$);
828     breakjumpsto($$, out);
829     myif->branch = out;
830
831     $$ = killvars($$);old_state();
832 }
833
834 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
835     $$ = state->initcode;state->initcode=0;
836
837     code_t*myjmp = $$ = abc_jump($$, 0);
838     code_t*loopstart = $$ = abc_label($$);
839     $$ = code_append($$, $6);
840     myjmp->branch = $$ = abc_label($$);
841     $$ = code_append($$, $4.c);
842     $$ = abc_iftrue($$, loopstart);
843     code_t*out = $$ = abc_label($$);
844     breakjumpsto($$, out);
845
846     $$ = killvars($$);old_state();
847 }
848
849 BREAK : "break" {
850     $$ = abc___break__(0);
851 }
852
853 /* ------------ packages and imports ---------------- */
854
855 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
856 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
857
858 IMPORT : "import" PACKAGESPEC {addimport($2);}
859
860 TYPE : PACKAGEANDCLASS {$$=$1;}
861      | '*'        {$$=registry_getanytype();}
862      |  "String"  {$$=registry_getstringclass();}
863      |  "int"     {$$=registry_getintclass();}
864      |  "uint"    {$$=registry_getuintclass();}
865      |  "Boolean" {$$=registry_getbooleanclass();}
866      |  "Number"  {$$=registry_getnumberclass();}
867
868 MAYBETYPE: ':' TYPE {$$=$2;}
869 MAYBETYPE:          {$$=0;}
870
871 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
872 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
873                       MAYBETYPE
874
875 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
876 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
877 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
878
879 //NAMESPACE :              {$$=empty_token();}
880 //NAMESPACE : T_IDENTIFIER {$$=$1};
881
882 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
883                    //MULTINAME(m, registry_getintclass());
884                    //$$.c = abc_coerce2($$.c, &m); // FIXME
885                    $$.t = TYPE_INT;
886                   }
887 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
888                     $$.t = TYPE_INT;
889                    }
890 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
891                   $$.t = TYPE_INT;
892                  }
893 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
894                    $$.t = TYPE_UINT;
895                   }
896 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
897                     $$.t = TYPE_FLOAT;
898                    }
899 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
900                      $$.t = TYPE_STRING;
901                     }
902 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
903                     $$.t = TYPE_BOOLEAN;
904                    }
905 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
906                      $$.t = TYPE_BOOLEAN;
907                     }
908 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
909                     $$.t = TYPE_NULL;
910                    }
911
912 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
913
914
915 EXPRESSION : E %prec prec_none  /*precendence below '-x'*/ {$$ = $1;}
916 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
917
918 E : CONSTANT
919 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
920 E : NEW                         {$$.c = abc_pushundefined(0); /* FIXME */
921                                  $$.t = TYPE_ANY;
922                                 }
923 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
924                                  $$.t = TYPE_ANY;
925                                 }
926 E : FUNCTIONCALL
927 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
928              $$.t = TYPE_BOOLEAN;
929             }
930 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
931              $$.t = TYPE_BOOLEAN;
932             }
933 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
934               $$.t = TYPE_BOOLEAN;
935              }
936 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
937               $$.t = TYPE_BOOLEAN;
938              }
939 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
940               $$.t = TYPE_BOOLEAN;
941              }
942 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
943               $$.t = TYPE_BOOLEAN;
944              }
945 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
946               $$.t = TYPE_BOOLEAN;
947              }
948
949 E : E '-' E
950 E : E '/' E
951 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
952              $$.t = join_types($1.t, $3.t, '+');
953             }
954 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
955              $$.t = join_types($1.t, $3.t, '%');
956             }
957 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
958              $$.t = join_types($1.t, $3.t, '*');
959             }
960
961 E : E "as" TYPE
962 E : E "is" TYPE
963 E : '(' E ')' {$$=$2;}
964 E : '-' E {$$=$2;}
965
966 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
967                class_signature_t*type = join_types($1.type, $3.t, '+');
968                $$.c=converttype($$.c, type, $1.type);
969                $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
970                $$.t = $1.type;
971               }
972 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
973                class_signature_t*type = join_types($1.type, $3.t, '-');
974                $$.c=converttype($$.c, type, $1.type);
975                $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
976                $$.t = $1.type;
977               }
978
979 // TODO: use inclocal where appropriate
980 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
981              class_signature_t*type = $1.type;
982              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
983              $$.c=converttype($$.c, type, $1.type);
984              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
985              $$.t = $1.type;
986             }
987 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
988              class_signature_t*type = $1.type;
989              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
990              $$.c=converttype($$.c, 0, $1.type);
991              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
992              $$.t = $1.type;
993             }
994
995 LH: T_IDENTIFIER {
996   int i = find_variable($1->text, &$$.type);
997   $$.read = abc_getlocal(0, i);
998   $$.write = abc_setlocal(0, i);
999 }
1000
1001 NEW : "new" T_IDENTIFIER                         {$$.c=0;$$.t=0;/*FIXME*/}
1002     | "new" T_IDENTIFIER '(' ')'                 {$$.c=0;$$.t=0;/*FIXME*/}
1003     | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
1004
1005 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1006         /* TODO: use abc_call (for calling local variables),
1007                  abc_callstatic (for calling own methods) */
1008         $$.c = code_new();
1009         $$.c = abc_findpropstrict($$.c, $1->text);
1010         typedcode_list_t*l = $3;
1011         // push parameters on stack
1012         int len = 0;
1013         while(l) {
1014             $$.c = code_append($$.c, l->typedcode.c);
1015             l = l->nxt;
1016             len ++;
1017         }
1018         $$.c = abc_callproperty($$.c, $1->text, len);
1019 }
1020
1021 MAYBE_EXPRESSION_LIST : {$$=0;}
1022 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1023 EXPRESSION_LIST : EXPRESSION                     {$$=malloc(sizeof(typedcode_list_t));
1024                                                   $$->nxt = 0;
1025                                                   $$->typedcode = $1;}
1026 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1027                                                   $$->nxt = $1;
1028                                                   $$->typedcode = $3;
1029                                                  }
1030
1031 VAR_READ : T_IDENTIFIER {
1032         int i = find_variable($1->text, &$$.t);
1033         $$.c = abc_getlocal(0, i);
1034 }
1035
1036 //VARIABLE : T_IDENTIFIER
1037 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1038 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1039 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1040 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1041 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1042
1043 // keywords which also may be identifiers
1044 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1045
1046 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
1047                                            $$ = concat3($1,$2,$3);}
1048 PACKAGESPEC : X_IDENTIFIER                {$$=$1;}
1049 PACKAGESPEC : '*'                         {$$=$1;}
1050
1051 GETSET : "get" {$$=$1;}
1052        | "set" {$$=$1;}
1053        |       {$$=empty_token();}
1054
1055 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
1056 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
1057
1058 PARAMS: {$$=empty_token();}
1059 PARAMS: PARAM_LIST {$$=$1;}
1060 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
1061 PARAM_LIST: PARAM                {$$=empty_token();extend($$,$1);}
1062 PARAM:  T_IDENTIFIER ':' TYPE {$$=$1;}
1063
1064 MODIFIERS : {$$=empty_token();}
1065 MODIFIERS : MODIFIER_LIST {$$=$1}
1066 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
1067 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
1068 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
1069
1070 DECLARATION : VARIABLE_DECLARATION
1071 DECLARATION : FUNCTION_DECLARATION
1072
1073 IDECLARATION : VARIABLE_DECLARATION
1074 IDECLARATION : FUNCTION_DECLARATION
1075
1076 IMPLEMENTS_LIST : {$$=list_new();}
1077 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
1078
1079 EXTENDS : {$$=registry_getobjectclass();}
1080 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
1081
1082 EXTENDS_LIST : {$$=list_new();}
1083 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
1084
1085 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1086 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1087
1088 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
1089 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
1090 PACKAGE : X_IDENTIFIER
1091 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
1092
1093 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1094 MULTILEVELIDENTIFIER : T_IDENTIFIER                 {$$=$1;extend($$,$1)};
1095
1096 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1097 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1098
1099 MAYBE_DECLARATION_LIST : 
1100 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1101 DECLARATION_LIST : DECLARATION
1102 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1103
1104 MAYBE_IDECLARATION_LIST : 
1105 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1106 IDECLARATION_LIST : IDECLARATION
1107 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1108
1109 // chapter 14
1110 // 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
1111 // syntactic keywords: each get set namespace include dynamic final native override static
1112