changed _type back to type_t, now that the #includes work again
[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     state->initcode = code_append(state->initcode, oldstate->initcode);
324 }
325 void initialize_state()
326 {
327     new_state();
328
329     state->file = abc_file_new();
330     state->file->flags &= ~ABCFILE_LAZY;
331     
332     state->init = abc_initscript(state->file, 0, 0);
333     abc_method_body_t*m = state->init->method->body;
334     __ getlocal_0(m);
335     __ pushscope(m);
336     __ findpropstrict(m, "[package]::trace");
337     __ pushstring(m, "[entering global init function]");
338     __ callpropvoid(m, "[package]::trace", 1);
339 }
340 void* finalize_state()
341 {
342     if(state->level!=1) {
343         syntaxerror("unexpected end of file");
344     }
345     abc_method_body_t*m = state->init->method->body;
346     //__ popscope(m);
347     
348     __ findpropstrict(m, "[package]::trace");
349     __ pushstring(m, "[leaving global init function]");
350     __ callpropvoid(m, "[package]::trace", 1);
351     __ returnvoid(m);
352     return state->file;
353 }
354
355
356 static void startpackage(token_t*t) 
357 {
358     if(state->package) {
359         syntaxerror("Packages can not be nested."); 
360     } 
361     new_state();
362     char*name = t?t->text:"";
363     /*printf("entering package \"%s\"\n", name);*/
364     state->package = name;
365 }
366 static void endpackage()
367 {
368     /*printf("leaving package \"%s\"\n", state->package);*/
369     old_state();
370 }
371
372 char*globalclass=0;
373 static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements)
374 {
375     if(state->cls) {
376         syntaxerror("inner classes now allowed"); 
377     }
378     new_state();
379     state->classname = name->text;
380
381     token_list_t*t=0;
382     class_signature_list_t*mlist=0;
383     /*printf("entering class %s\n", name->text);
384     printf("  modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
385     if(extends) 
386         printf("  extends: %s.%s\n", extends->package, extends->name);
387
388     printf("  implements (%d): ", list_length(implements));
389     for(mlist=implements;mlist;mlist=mlist->next)  {
390         printf("%s ", mlist->class_signature->name);
391     }
392     printf("\n");*/
393
394     char public=0,internal=0,final=0,sealed=1;
395     for(t=modifiers->tokens;t;t=t->next) {
396         if(t->token->type == KW_INTERNAL) {
397             /* the programmer is being explicit- 
398                being internal is the default anyway */
399             internal = 1;
400         } else if(t->token->type == KW_PUBLIC) {
401             public = 1;
402         } else if(t->token->type == KW_FINAL) {
403             final = 1;
404         } else {
405             syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
406         }
407     }
408     if(public&&internal)
409         syntaxerror("public and internal not supported at the same time.");
410
411     /* create the class name, together with the proper attributes */
412     int access=0;
413     char*package=0;
414
415     if(!public && !state->package) {
416         access = ACCESS_PRIVATE; package = current_filename;
417     } else if(!public && state->package) {
418         access = ACCESS_PACKAGEINTERNAL; package = state->package;
419     } else if(state->package) {
420         access = ACCESS_PACKAGE; package = state->package;
421     } else {
422         syntaxerror("public classes only allowed inside a package");
423     }
424
425     if(registry_findclass(package, state->classname)) {
426         syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
427     }
428     
429     class_signature_t* classname = class_signature_register(access, package, state->classname);
430
431     multiname_t*extends2 = sig2mname(extends);
432     multiname_t*classname2 = sig2mname(classname);
433
434     state->cls = abc_class_new(state->file, classname2, extends2);
435     if(final) abc_class_final(state->cls);
436     if(sealed) abc_class_sealed(state->cls);
437
438     for(mlist=implements;mlist;mlist=mlist->next) {
439         MULTINAME(m, mlist->class_signature);
440         abc_class_add_interface(state->cls, &m);
441     }
442
443     /* now write the construction code for this class */
444     int slotindex = abc_initscript_addClassTrait(state->init, classname2, state->cls);
445
446     abc_method_body_t*m = state->init->method->body;
447     __ getglobalscope(m);
448     class_signature_t*s = extends;
449
450     int count=0;
451     
452     while(s) {
453         //TODO: take a look at the current scope stack, maybe 
454         //      we can re-use something
455         s = s->superclass;
456         if(!s) 
457         break;
458        
459         multiname_t*s2 = sig2mname(s);
460         __ getlex2(m, s2);
461         multiname_destroy(s2);
462
463         __ pushscope(m);
464         m->code = m->code->prev->prev; // invert
465         count++;
466     }
467     /* continue appending after last op end */
468     while(m->code && m->code->next) m->code = m->code->next; 
469
470     /* TODO: if this is one of *our* classes, we can also 
471              do a getglobalscope/getslot <nr> (which references
472              the init function's slots) */
473     __ getlex2(m, extends2);
474     __ dup(m);
475     __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
476     __ newclass(m,state->cls);
477     while(count--) {
478         __ popscope(m);
479     }
480     __ setslot(m, slotindex);
481
482     /* flash.display.MovieClip handling */
483     if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
484         if(state->package && state->package[0]) {
485             globalclass = concat3str(state->package, ".", state->classname);
486         } else {
487             globalclass = strdup(state->classname);
488         }
489     }
490 }
491
492 static void endclass()
493 {
494     /*printf("leaving class %s\n", state->classname);*/
495     old_state();
496 }
497 static void addimport(token_t*t)
498 {
499     NEW(import_t,i);
500     i->path = t->text;
501     list_append(state->imports, i);
502 }
503 static void print_imports()
504 {
505     import_list_t*l = state->imports;
506     while(l) {
507         printf("  import %s\n", l->import->path);
508         l = l->next;
509     }
510 }
511 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
512                           token_t*params, class_signature_t*type)
513 {
514     token_list_t*t;
515     new_state();
516     state->function = name->text;
517     
518     /*printf("entering function %s\n", name->text);
519     if(ns)
520         printf("  namespace: %s\n", ns->text);
521     printf("  getset: %s\n", getset->text);
522     printf("  params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
523     printf("  mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
524     if(type)
525         printf("  type: %s.%s\n", type->package, type->name);
526     print_imports();*/
527     
528     if(state->m) {
529         syntaxerror("not able to start another method scope");
530     }
531
532     multiname_t*type2 = sig2mname(type);
533
534     if(!strcmp(state->classname,name->text)) {
535         state->m = abc_class_constructor(state->cls, type2, 0);
536     } else {
537         state->m = abc_class_method(state->cls, type2, name->text, 0);
538     }
539     array_append(state->vars, "this", 0);
540
541     __ getlocal_0(state->m);
542     __ pushscope(state->m);
543
544     multiname_destroy(type2);
545 }
546 static void endfunction()
547 {
548     printf("leaving function %s\n", state->function);
549     __ returnvoid(state->m);
550
551     old_state();
552 }
553 static token_t* empty_token()
554 {
555     NEW(token_t,t);
556     t->type=T_EMPTY;
557     t->text=0;
558     return t;
559 }
560
561 void extend(token_t*list, token_t*add) {
562     list_append(list->tokens,add);
563     if(!list->text)
564         list->text = add->text;
565 }
566 void extend_s(token_t*list, char*seperator, token_t*add) {
567     list_append(list->tokens,add);
568     char*t1 = list->text;
569     char*t2 = seperator;
570     char*t3 = add->text;
571     int l1 = strlen(t1);
572     int l2 = strlen(t2);
573     int l3 = strlen(t3);
574     list->text = malloc(l1+l2+l3+1);
575     strcpy(list->text, t1);
576     strcpy(list->text+l1, t2);
577     strcpy(list->text+l1+l2, t3);
578     list->text[l1+l2+l3]=0;
579 }
580
581 int find_variable(char*name, class_signature_t**m)
582 {
583     state_list_t* s = state_stack;
584     while(s) {
585         int i = array_find(s->state->vars, name);
586         if(i>=0) {
587             if(m) {
588                 *m = array_getvalue(s->state->vars, i);
589             }
590             return i + s->state->local_var_base;
591         }
592         s = s->next;
593     }
594     syntaxerror("undefined variable: %s", name);
595 }
596
597 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
598 {
599     return registry_getanytype(); // FIXME
600 }
601 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
602 {
603     return 1; // FIXME
604 }
605
606 #define TYPE_ANY                  registry_getanytype()
607 #define TYPE_IS_ANY(t)    ((t) == registry_getanytype())
608 #define TYPE_INT                  registry_getintclass()
609 #define TYPE_IS_INT(t)    ((t) == registry_getintclass())
610 #define TYPE_UINT                 registry_getuintclass()
611 #define TYPE_IS_UINT(t)   ((t) == registry_getuintclass())
612 #define TYPE_FLOAT                registry_getnumberclass()
613 #define TYPE_IS_FLOAT(t)  ((t) == registry_getnumberclass())
614 #define TYPE_BOOLEAN              registry_getbooleanclass()
615 #define TYPE_IS_BOOLEAN(t)((t) == registry_getbooleanclass())
616 #define TYPE_STRING               registry_getstringclass()
617 #define TYPE_IS_STRING(t) ((t) == registry_getstringclass())
618 #define TYPE_NULL                 registry_getnullclass()
619 #define TYPE_IS_NULL(t)   ((t) == registry_getnullclass())
620
621 %}
622
623
624 %%
625
626 /* ------------ code blocks / statements ---------------- */
627
628 PROGRAM: MAYBECODE
629
630 MAYBECODE: CODE {$$=$1;}
631 MAYBECODE:      {$$=code_new();}
632
633 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
634 CODE: CODEPIECE {$$=$1;}
635
636 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
637 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
638 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
639 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
640 CODEPIECE: ';'                   {$$=code_new();}
641 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
642 CODEPIECE: VOIDEXPRESSION        {$$=$1}
643 CODEPIECE: FOR                   {$$=$1}
644 CODEPIECE: WHILE                 {$$=$1}
645 CODEPIECE: BREAK                 {$$=$1}
646 CODEPIECE: IF                    {$$=$1}
647 CODEPIECE: ASSIGNMENT            {$$=$1}
648 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
649 CODEPIECE: FUNCTION_DECLARATION  {/*TODO*/$$=code_new();}
650 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
651
652 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
653 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
654 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
655
656 /* ------------ functions --------------------------- */
657
658 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
659                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
660     if(!state->m) syntaxerror("internal error: undefined function");
661     state->m->code = code_append(state->initcode, $11);state->initcode=0;
662     endfunction()
663 }
664
665 /* ------------ variables --------------------------- */
666
667 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
668                 |                {$$.c=abc_pushundefined(0);
669                                   $$.t=TYPE_ANY;
670                                  }
671
672 VAR : "const" | "var"
673 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
674     if(array_contains(state->vars, $2->text))
675         syntaxerror("Variable %s already defined", $2->text);
676     $$ = $4.c;
677    
678     if(!is_subtype_of($4.t, $3)) {
679         syntaxerror("Can't convert %s to %s", $4.t->name, 
680                                               $3->name);
681     }
682
683     int index = array_append(state->vars, $2->text, $3) + state->local_var_base;
684     $$ = abc_setlocal($$, index);
685
686     if($3) {
687         if(TYPE_IS_INT($3) || TYPE_IS_UINT($3) || TYPE_IS_FLOAT($3)) {
688             state->initcode = abc_pushbyte(state->initcode, 32);
689         } else if(TYPE_IS_BOOLEAN($3)) {
690             state->initcode = abc_pushfalse(state->initcode);
691         } else {
692             state->initcode = abc_pushnull(state->initcode);
693         }
694         state->initcode = abc_setlocal(state->initcode, index);
695     } /*else {
696         // that's the default for a local register, anyway
697         state->initcode = abc_pushundefined(state->initcode);
698         state->initcode = abc_setlocal(state->initcode, index);
699     }*/
700     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t->name);
701 }
702 ASSIGNMENT :           T_IDENTIFIER '=' EXPRESSION {
703     class_signature_t*type=0;
704     int i = find_variable($1->text, &type);
705     $$ = $3.c;
706     if(!type && $3.t) {
707         // convert to "any" type, the register is untyped
708         $$ = abc_coerce_a($$);
709     } else {
710         // TODO: convert ints to strings etc.
711     }
712     $$ = abc_setlocal($$, i);
713 }
714
715 /* ------------ control flow ------------------------- */
716
717 MAYBEELSE:  %prec prec_none {$$ = code_new();}
718 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
719 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
720
721 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
722     $$=$4.c;
723     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
724    
725     $$ = code_append($$, $6);
726     if($7) {
727         myjmp = $$ = abc_jump($$, 0);
728     }
729     myif->branch = $$ = abc_label($$);
730     if($7) {
731         $$ = code_append($$, $7);
732         myjmp->branch = $$ = abc_label($$);
733     }
734     old_state();
735 }
736
737 FOR_INIT : {$$=code_new();}
738 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
739
740 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
741     $$ = $4;
742     code_t*loopstart = $$ = abc_label($$);
743     $$ = code_append($$, $6.c);
744     code_t*myif = $$ = abc_iffalse($$, 0);
745     $$ = code_append($$, $10);
746     $$ = code_append($$, $8);
747     $$ = abc_jump($$, loopstart);
748     $$ = abc_label($$);
749     myif->branch = $$;
750     old_state();
751 }
752
753 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
754     code_t*myjmp = $$ = abc_jump(0, 0);
755     code_t*loopstart = $$ = abc_label($$);
756     $$ = code_append($$, $6);
757     myjmp->branch = $$ = abc_label($$);
758     $$ = code_append($$, $4.c);
759     $$ = abc_iftrue($$, loopstart);
760     old_state();
761 }
762
763 BREAK : "break" {
764     $$ = abc___break__(0);
765 }
766
767 /* ------------ packages and imports ---------------- */
768
769 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
770 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
771
772 IMPORT : "import" PACKAGESPEC {addimport($2);}
773
774 TYPE : PACKAGEANDCLASS {$$=$1;}
775      | '*'        {$$=registry_getanytype();}
776      |  "String"  {$$=registry_getstringclass();}
777      |  "int"     {$$=registry_getintclass();}
778      |  "uint"    {$$=registry_getuintclass();}
779      |  "Boolean" {$$=registry_getbooleanclass();}
780      |  "Number"  {$$=registry_getnumberclass();}
781
782 MAYBETYPE: ':' TYPE {$$=$2;}
783 MAYBETYPE:          {$$=0;}
784
785 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
786 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')' 
787                       MAYBETYPE
788
789 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
790 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
791 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
792
793 //NAMESPACE :              {$$=empty_token();}
794 //NAMESPACE : T_IDENTIFIER {$$=$1};
795
796 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
797                    MULTINAME(m, registry_getintclass());
798                    $$.c = abc_coerce2($$.c, &m); // FIXME
799                    $$.t = TYPE_INT;
800                   }
801 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
802                     $$.t = TYPE_INT;
803                    }
804 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
805                   $$.t = TYPE_INT;
806                  }
807 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
808                    $$.t = TYPE_UINT;
809                   }
810 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
811                     $$.t = TYPE_FLOAT;
812                    }
813 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
814                      $$.t = TYPE_STRING;
815                     }
816 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
817                     $$.t = TYPE_BOOLEAN;
818                    }
819 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
820                      $$.t = TYPE_BOOLEAN;
821                     }
822 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
823                     $$.t = TYPE_NULL;
824                    }
825
826 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
827
828
829 EXPRESSION : E %prec prec_none  /*precendence below '-x'*/ {$$ = $1;}
830 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
831
832 E : CONSTANT
833 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
834 E : NEW                         {$$.c = abc_pushundefined(0); /* FIXME */
835                                  $$.t = TYPE_ANY;
836                                 }
837 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
838                                  $$.t = TYPE_ANY;
839                                 }
840 E : FUNCTIONCALL
841 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
842              $$.t = TYPE_BOOLEAN;
843             }
844 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
845              $$.t = TYPE_BOOLEAN;
846             }
847 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
848               $$.t = TYPE_BOOLEAN;
849              }
850 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
851               $$.t = TYPE_BOOLEAN;
852              }
853 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
854               $$.t = TYPE_BOOLEAN;
855              }
856 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
857               $$.t = TYPE_BOOLEAN;
858              }
859 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
860               $$.t = TYPE_BOOLEAN;
861              }
862
863 E : E '-' E
864 E : E '/' E
865 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
866              $$.t = join_types($1.t, $3.t, '+');
867             }
868 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
869              $$.t = join_types($1.t, $3.t, '%');
870             }
871 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
872              $$.t = join_types($1.t, $3.t, '*');
873             }
874
875 E : E "as" TYPE
876 E : E "is" TYPE
877 E : '(' E ')' {$$=$2;}
878 E : '-' E {$$=$2;}
879
880 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
881                MULTINAME(m, registry_getintclass());
882                $$.c=abc_coerce2($$.c, &m); // FIXME
883                $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
884                $$.t = $1.type;
885               }
886 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
887                MULTINAME(m, registry_getintclass());
888                $$.c=abc_coerce2($$.c, &m); // FIXME
889                $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
890                $$.t = $1.type;
891               }
892
893 // TODO: use inclocal where appropriate
894 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
895              MULTINAME(m, registry_getintclass());
896              $$.c=abc_coerce2($$.c, &m); //FIXME
897              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
898              $$.t = $1.type;
899             }
900 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
901              MULTINAME(m, registry_getintclass());
902              $$.c=abc_coerce2($$.c, &m); //FIXME
903              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
904              $$.t = $1.type;
905             }
906
907 LH: T_IDENTIFIER {
908   int i = find_variable($1->text, &$$.type);
909   $$.read = abc_getlocal(0, i);
910   $$.write = abc_setlocal(0, i);
911 }
912
913 NEW : "new" T_IDENTIFIER                         {$$.c=0;$$.t=0;/*FIXME*/}
914     | "new" T_IDENTIFIER '(' ')'                 {$$.c=0;$$.t=0;/*FIXME*/}
915     | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
916
917 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
918         /* TODO: use abc_call (for calling local variables),
919                  abc_callstatic (for calling own methods) */
920         $$.c = code_new();
921         $$.c = abc_findpropstrict($$.c, $1->text);
922         typedcode_list_t*l = $3;
923         // push parameters on stack
924         int len = 0;
925         while(l) {
926             $$.c = code_append($$.c, l->typedcode.c);
927             l = l->nxt;
928             len ++;
929         }
930         $$.c = abc_callproperty($$.c, $1->text, len);
931 }
932
933 MAYBE_EXPRESSION_LIST : {$$=0;}
934 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
935 EXPRESSION_LIST : EXPRESSION                     {$$=malloc(sizeof(typedcode_list_t));
936                                                   $$->nxt = 0;
937                                                   $$->typedcode = $1;}
938 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
939                                                   $$->nxt = $1;
940                                                   $$->typedcode = $3;
941                                                  }
942
943 VAR_READ : T_IDENTIFIER {
944         int i = find_variable($1->text, &$$.t);
945         $$.c = abc_getlocal(0, i);
946 }
947
948 //VARIABLE : T_IDENTIFIER
949 //VARIABLE : VARIABLE '.' T_IDENTIFIER
950 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
951 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
952 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
953 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
954
955 // keywords which also may be identifiers
956 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
957
958 PACKAGESPEC : PACKAGESPEC '.' PACKAGESPEC {if($1->text[0]=='*') syntaxerror("wildcard in the middle of path");
959                                            $$ = concat3($1,$2,$3);}
960 PACKAGESPEC : X_IDENTIFIER                {$$=$1;}
961 PACKAGESPEC : '*'                         {$$=$1;}
962
963 GETSET : "get" {$$=$1;}
964        | "set" {$$=$1;}
965        |       {$$=empty_token();}
966
967 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER EXTENDS IMPLEMENTS_LIST '{' {startclass($1,$3,$4,$5);} MAYBE_DECLARATION_LIST '}' {endclass();}
968 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER EXTENDS_LIST '{' MAYBE_IDECLARATION_LIST '}'
969
970 PARAMS: {$$=empty_token();}
971 PARAMS: PARAM_LIST {$$=$1;}
972 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
973 PARAM_LIST: PARAM                {$$=empty_token();extend($$,$1);}
974 PARAM:  T_IDENTIFIER ':' TYPE {$$=$1;}
975
976 MODIFIERS : {$$=empty_token();}
977 MODIFIERS : MODIFIER_LIST {$$=$1}
978 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
979 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
980 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
981
982 DECLARATION : VARIABLE_DECLARATION
983 DECLARATION : FUNCTION_DECLARATION
984
985 IDECLARATION : VARIABLE_DECLARATION
986 IDECLARATION : FUNCTION_DECLARATION
987
988 IMPLEMENTS_LIST : {$$=list_new();}
989 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
990
991 EXTENDS : {$$=registry_getobjectclass();}
992 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
993
994 EXTENDS_LIST : {$$=list_new();}
995 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
996
997 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
998 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
999
1000 PACKAGEANDCLASS : T_IDENTIFIER {$$ = registry_findclass(state->package, $1->text);}
1001 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {$$ = registry_findclass($1->text, $3->text);}
1002 PACKAGE : X_IDENTIFIER
1003 PACKAGE : PACKAGE '.' X_IDENTIFIER {$$=$1;extend_s($$,".",$3);}
1004
1005 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1006 MULTILEVELIDENTIFIER : T_IDENTIFIER                 {$$=$1;extend($$,$1)};
1007
1008 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1009 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1010
1011 MAYBE_DECLARATION_LIST : 
1012 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1013 DECLARATION_LIST : DECLARATION
1014 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1015
1016 MAYBE_IDECLARATION_LIST : 
1017 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1018 IDECLARATION_LIST : IDECLARATION
1019 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1020
1021 // chapter 14
1022 // 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
1023 // syntactic keywords: each get set namespace include dynamic final native override static
1024