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