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