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