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