implemented new()
[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(!to) {
670         /*TODO: can omit this if from is zero? */
671         return abc_coerce_a(c);
672     }
673     if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
674         MULTINAME(m, TYPE_UINT);
675         return abc_coerce2(c, &m);
676     }
677     if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
678         MULTINAME(m, TYPE_INT);
679         return abc_coerce2(c, &m);
680     }
681     return c;
682 }
683
684 code_t*defaultvalue(code_t*c, class_signature_t*type)
685 {
686     if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
687        c = abc_pushbyte(c, 0);
688     } else if(TYPE_IS_BOOLEAN(type)) {
689        c = abc_pushfalse(c);
690     } else {
691        c = abc_pushnull(c);
692     }
693     return c;
694 }
695
696 %}
697
698
699 %%
700
701 /* ------------ code blocks / statements ---------------- */
702
703 PROGRAM: MAYBECODE
704
705 MAYBECODE: CODE {$$=$1;}
706 MAYBECODE:      {$$=code_new();}
707
708 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
709 CODE: CODEPIECE {$$=$1;}
710
711 CODEPIECE: PACKAGE_DECLARATION   {$$=code_new();/*enters a scope*/}
712 CODEPIECE: CLASS_DECLARATION     {$$=code_new();/*enters a scope*/}
713 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
714 CODEPIECE: IMPORT                {$$=code_new();/*adds imports to current scope*/}
715 CODEPIECE: ';'                   {$$=code_new();}
716 CODEPIECE: VARIABLE_DECLARATION  {$$=$1}
717 CODEPIECE: VOIDEXPRESSION        {$$=$1}
718 CODEPIECE: FOR                   {$$=$1}
719 CODEPIECE: WHILE                 {$$=$1}
720 CODEPIECE: BREAK                 {$$=$1}
721 CODEPIECE: IF                    {$$=$1}
722 CODEPIECE: ASSIGNMENT            {$$=$1}
723 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
724 CODEPIECE: FUNCTION_DECLARATION  {/*TODO*/$$=code_new();}
725 CODEPIECE: USE_NAMESPACE         {/*TODO*/$$=code_new();}
726
727 CODEBLOCK :  '{' MAYBECODE '}' {$$=$2;}
728 CODEBLOCK :  CODEPIECE ';'             {$$=$1;}
729 CODEBLOCK :  CODEPIECE %prec below_semicolon {$$=$1;}
730
731 /* ------------ functions --------------------------- */
732
733 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
734                       MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
735     if(!state->m) syntaxerror("internal error: undefined function");
736     state->initcode = abc_nop(state->initcode);
737     state->initcode = abc_nop(state->initcode);
738     state->initcode = abc_nop(state->initcode);
739     state->m->code = code_append(state->initcode, $11);state->initcode=0;
740     endfunction()
741 }
742
743 /* ------------ variables --------------------------- */
744
745 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
746                 |                {$$.c=abc_pushundefined(0);
747                                   $$.t=TYPE_ANY;
748                                  }
749
750 VAR : "const" | "var"
751 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
752     if(variable_exists($2->text))
753         syntaxerror("Variable %s already defined", $2->text);
754    
755     if(!is_subtype_of($4.t, $3)) {
756         syntaxerror("Can't convert %s to %s", $4.t->name, 
757                                               $3->name);
758     }
759
760     int index = new_variable($2->text, $3);
761     
762     if($3) {
763         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
764             $$ = $4.c;
765             $$ = converttype($$, $4.t, $3);
766             $$ = abc_setlocal($$, index);
767         } else {
768             $$ = defaultvalue(0, $3);
769             $$ = abc_setlocal($$, index);
770         }
771
772         /* push default value for type on stack */
773         state->initcode = defaultvalue(state->initcode, $3);
774         state->initcode = abc_setlocal(state->initcode, index);
775     } else {
776         /* only bother to actually set this variable if its syntax is either
777             var x:type;
778            or
779             var x=expr;
780         */
781         if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
782             $$ = $4.c;
783             $$ = abc_coerce_a($$);
784             $$ = abc_setlocal($$, index);
785         } else {
786             $$ = code_new();
787         }
788     }
789     
790     /* that's the default for a local register, anyway
791         else {
792         state->initcode = abc_pushundefined(state->initcode);
793         state->initcode = abc_setlocal(state->initcode, index);
794     }*/
795     printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
796 }
797 ASSIGNMENT :           T_IDENTIFIER '=' EXPRESSION {
798     class_signature_t*type=0;
799     int i = find_variable($1->text, &type);
800     $$ = $3.c;
801     if(!type && $3.t) {
802         // convert to "any" type, the register is untyped
803         $$ = abc_coerce_a($$);
804     } else {
805         // TODO: convert ints to strings etc.
806     }
807     $$ = abc_setlocal($$, i);
808 }
809
810 /* ------------ control flow ------------------------- */
811
812 MAYBEELSE:  %prec prec_none {$$ = code_new();}
813 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
814 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
815
816 IF  : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
817     $$ = state->initcode;state->initcode=0;
818
819     $$ = code_append($$, $4.c);
820     code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
821    
822     $$ = code_append($$, $6);
823     if($7) {
824         myjmp = $$ = abc_jump($$, 0);
825     }
826     myif->branch = $$ = abc_label($$);
827     if($7) {
828         $$ = code_append($$, $7);
829         myjmp->branch = $$ = abc_label($$);
830     }
831     
832     $$ = killvars($$);old_state();
833 }
834
835 FOR_INIT : {$$=code_new();}
836 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
837
838 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
839     $$ = state->initcode;state->initcode=0;
840
841     $$ = code_append($$, $4);
842     code_t*loopstart = $$ = abc_label($$);
843     $$ = code_append($$, $6.c);
844     code_t*myif = $$ = abc_iffalse($$, 0);
845     $$ = code_append($$, $10);
846     $$ = code_append($$, $8);
847     $$ = abc_jump($$, loopstart);
848     code_t*out = $$ = abc_label($$);
849     breakjumpsto($$, out);
850     myif->branch = out;
851
852     $$ = killvars($$);old_state();
853 }
854
855 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
856     $$ = state->initcode;state->initcode=0;
857
858     code_t*myjmp = $$ = abc_jump($$, 0);
859     code_t*loopstart = $$ = abc_label($$);
860     $$ = code_append($$, $6);
861     myjmp->branch = $$ = abc_label($$);
862     $$ = code_append($$, $4.c);
863     $$ = abc_iftrue($$, loopstart);
864     code_t*out = $$ = abc_label($$);
865     breakjumpsto($$, out);
866
867     $$ = killvars($$);old_state();
868 }
869
870 BREAK : "break" {
871     $$ = abc___break__(0);
872 }
873
874 /* ------------ packages and imports ---------------- */
875
876 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
877 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
878
879 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
880 PACKAGE: X_IDENTIFIER             {$$=$1;}
881
882 IMPORT : "import" PACKAGE '.' X_IDENTIFIER {
883        class_signature_t*c = registry_findclass($2->text, $4->text);
884        if(!c) 
885             syntaxerror("Couldn't import %s.%s\n", $2->text, $4->text);
886        state_has_imports();
887        dict_put(state->imports, $4->text, c);
888        $$=0;
889 }
890 IMPORT : "import" PACKAGE '.' '*' {
891        NEW(import_t,i);
892        i->package = $2->text;
893        state_has_imports();
894        list_append(state->wildcard_imports, i);
895        $$=0;
896 }
897
898 /* ------------ classes and interfaces -------------- */
899
900 MODIFIERS : {$$=empty_token();}
901 MODIFIERS : MODIFIER_LIST {$$=$1}
902 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
903 MODIFIER_LIST : MODIFIER               {$$=empty_token();extend($$,$1);}
904 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
905
906 EXTENDS : {$$=registry_getobjectclass();}
907 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
908
909 EXTENDS_LIST : {$$=list_new();}
910 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
911
912 IMPLEMENTS_LIST : {$$=list_new();}
913 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
914
915 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER 
916                               EXTENDS IMPLEMENTS_LIST 
917                               '{' {startclass($1,$3,$4,$5, 0);} 
918                               MAYBE_DECLARATION_LIST 
919                               '}' {endclass();}
920 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER 
921                               EXTENDS_LIST 
922                               '{' {startclass($1,$3,0,$4,1);}
923                               MAYBE_IDECLARATION_LIST 
924                               '}' {endclass();}
925
926 TYPE : PACKAGEANDCLASS {$$=$1;}
927      | '*'        {$$=registry_getanytype();}
928      |  "String"  {$$=registry_getstringclass();}
929      |  "int"     {$$=registry_getintclass();}
930      |  "uint"    {$$=registry_getuintclass();}
931      |  "Boolean" {$$=registry_getbooleanclass();}
932      |  "Number"  {$$=registry_getnumberclass();}
933
934 MAYBETYPE: ':' TYPE {$$=$2;}
935 MAYBETYPE:          {$$=0;}
936
937 //FUNCTION_HEADER:      NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')' 
938 FUNCTION_HEADER:      MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')' 
939                       MAYBETYPE
940
941 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
942 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
943 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
944
945 //NAMESPACE :              {$$=empty_token();}
946 //NAMESPACE : T_IDENTIFIER {$$=$1};
947
948 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
949                    //MULTINAME(m, registry_getintclass());
950                    //$$.c = abc_coerce2($$.c, &m); // FIXME
951                    $$.t = TYPE_INT;
952                   }
953 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
954                     $$.t = TYPE_INT;
955                    }
956 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
957                   $$.t = TYPE_INT;
958                  }
959 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
960                    $$.t = TYPE_UINT;
961                   }
962 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
963                     $$.t = TYPE_FLOAT;
964                    }
965 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
966                      $$.t = TYPE_STRING;
967                     }
968 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
969                     $$.t = TYPE_BOOLEAN;
970                    }
971 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
972                      $$.t = TYPE_BOOLEAN;
973                     }
974 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
975                     $$.t = TYPE_NULL;
976                    }
977
978 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
979
980
981 EXPRESSION : E %prec prec_none  /*precendence below '-x'*/ {$$ = $1;}
982 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
983
984 E : CONSTANT
985 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
986 E : NEW                         {$$ = $1;}
987 E : T_REGEXP                    {$$.c = abc_pushundefined(0); /* FIXME */
988                                  $$.t = TYPE_ANY;
989                                 }
990 E : FUNCTIONCALL
991 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
992              $$.t = TYPE_BOOLEAN;
993             }
994 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
995              $$.t = TYPE_BOOLEAN;
996             }
997 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
998               $$.t = TYPE_BOOLEAN;
999              }
1000 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1001               $$.t = TYPE_BOOLEAN;
1002              }
1003 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1004               $$.t = TYPE_BOOLEAN;
1005              }
1006 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1007               $$.t = TYPE_BOOLEAN;
1008              }
1009 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1010               $$.t = TYPE_BOOLEAN;
1011              }
1012
1013 E : E "||" E {$$.c = $1.c;
1014               $$.c=abc_dup($$.c);
1015               code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1016               $$.c=abc_pop($$.c);
1017               $$.c = code_append($$.c,$3.c);
1018               code_t*label = $$.c = abc_label($$.c);
1019               jmp->branch = label;
1020               $$.t = join_types($1.t, $3.t, 'O');
1021              }
1022 E : E "&&" E {$$.c = $1.c;
1023               $$.c=abc_dup($$.c);
1024               code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1025               $$.c=abc_pop($$.c);
1026               $$.c = code_append($$.c,$3.c);
1027               code_t*label = $$.c = abc_label($$.c);
1028               jmp->branch = label;
1029               $$.t = join_types($1.t, $3.t, 'A');
1030              }
1031
1032 E : '!' E    {$$.c=$2.c;
1033               $$.c = abc_not($$.c);
1034               $$.t = TYPE_BOOLEAN;
1035              }
1036
1037 E : E '-' E
1038 E : E '/' E
1039 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1040              $$.t = join_types($1.t, $3.t, '+');
1041             }
1042 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1043              $$.t = join_types($1.t, $3.t, '%');
1044             }
1045 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1046              $$.t = join_types($1.t, $3.t, '*');
1047             }
1048
1049 E : E "as" TYPE
1050 E : E "is" TYPE
1051 E : '(' E ')' {$$=$2;}
1052 E : '-' E {$$=$2;}
1053
1054 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1055                class_signature_t*type = join_types($1.type, $3.t, '+');
1056                $$.c=converttype($$.c, type, $1.type);
1057                $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1058                $$.t = $1.type;
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
1067 // TODO: use inclocal where appropriate
1068 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
1069              class_signature_t*type = $1.type;
1070              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1071              $$.c=converttype($$.c, type, $1.type);
1072              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1073              $$.t = $1.type;
1074             }
1075 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
1076              class_signature_t*type = $1.type;
1077              if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1078              $$.c=converttype($$.c, 0, $1.type);
1079              $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1080              $$.t = $1.type;
1081             }
1082
1083 LH: T_IDENTIFIER {
1084   int i = find_variable($1->text, &$$.type);
1085   $$.read = abc_getlocal(0, i);
1086   $$.write = abc_setlocal(0, i);
1087 }
1088
1089 MAYBE_PARAM_VALUES :  %prec prec_none {$$=0;}
1090 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1091
1092 NEW : "new" PACKAGEANDCLASS MAYBE_PARAM_VALUES {
1093     MULTINAME(m, $2);
1094     $$.c = code_new();
1095     $$.c = abc_findpropstrict2($$.c, &m);
1096     typedcode_list_t*l = $3;
1097     int len = 0;
1098     while(l) {
1099         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1100         l = l->next;
1101         len ++;
1102     }
1103     $$.c = abc_constructprop2($$.c, &m, len);
1104     $$.t = $2;
1105 }
1106
1107 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1108     /* TODO: use abc_call (for calling local variables),
1109              abc_callstatic (for calling own methods) */
1110     $$.c = code_new();
1111     $$.c = abc_findpropstrict($$.c, $1->text);
1112     typedcode_list_t*l = $3;
1113     int len = 0;
1114     while(l) {
1115         $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1116         l = l->next;
1117         len ++;
1118     }
1119     $$.c = abc_callproperty($$.c, $1->text, len);
1120     /* TODO: look up the functions's return value */
1121     $$.t = TYPE_ANY;
1122 }
1123
1124 MAYBE_EXPRESSION_LIST : {$$=0;}
1125 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1126 EXPRESSION_LIST : EXPRESSION                     {$$=list_new();
1127                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1128                                                   *t = $1;
1129                                                   list_append($$, t);}
1130 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
1131                                                   typedcode_t*t = malloc(sizeof(typedcode_t));
1132                                                   *t = $3;
1133                                                   list_append($$, t);}
1134
1135 VAR_READ : T_IDENTIFIER {
1136     int i = find_variable($1->text, &$$.t);
1137     $$.c = abc_getlocal(0, i);
1138 }
1139
1140 //VARIABLE : T_IDENTIFIER
1141 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1142 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1143 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1144 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1145 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1146
1147 // keywords which also may be identifiers
1148 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1149
1150 GETSET : "get" {$$=$1;}
1151        | "set" {$$=$1;}
1152        |       {$$=empty_token();}
1153
1154 MAYBE_PARAM_LIST: {$$=list_new();}
1155 MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
1156 PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1;         list_append($$, $3);}
1157 PARAM_LIST: PARAM                {$$ = list_new();list_append($$, $1);}
1158 PARAM:  T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
1159                                $$->name=$1->text;$$->type = $3;}
1160 PARAM:  T_IDENTIFIER          {$$ = malloc(sizeof(param_t));
1161                                $$->name=$1->text;$$->type = TYPE_ANY;}
1162
1163 DECLARATION : VARIABLE_DECLARATION
1164 DECLARATION : FUNCTION_DECLARATION
1165
1166 IDECLARATION : VARIABLE_DECLARATION
1167 IDECLARATION : FUNCTION_DECLARATION
1168
1169 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1170 //IDENTIFIER_LIST : T_IDENTIFIER                     {$$=empty_token();extend($$,$1);}
1171
1172 PACKAGEANDCLASS : T_IDENTIFIER {
1173
1174     /* try current package */
1175     $$ = registry_findclass(state->package, $1->text);
1176
1177     /* try explicit imports */
1178     dictentry_t* e = dict_get_slot(state->imports, $1->text);
1179     while(e) {
1180         if($$)
1181             break;
1182         if(!strcmp(e->key, $1->text)) {
1183             $$ = (class_signature_t*)e->data;
1184         }
1185         e = e->next;
1186     }
1187
1188     /* try package.* imports */
1189     import_list_t*l = state->wildcard_imports;
1190     while(l) {
1191         if($$)
1192             break;
1193         //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1194         $$ = registry_findclass(l->import->package, $1->text);
1195         l = l->next;
1196     }
1197
1198     /* try global package */
1199     if(!$$) {
1200         $$ = registry_findclass("", $1->text);
1201     }
1202
1203     if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1204 }
1205 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1206     $$ = registry_findclass($1->text, $3->text);
1207     if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1208 }
1209
1210
1211 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1212 MULTILEVELIDENTIFIER : T_IDENTIFIER                 {$$=$1;extend($$,$1)};
1213
1214 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1215 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1216
1217 MAYBE_DECLARATION_LIST : 
1218 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1219 DECLARATION_LIST : DECLARATION
1220 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1221
1222 MAYBE_IDECLARATION_LIST : 
1223 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1224 IDECLARATION_LIST : IDECLARATION
1225 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1226
1227 // chapter 14
1228 // 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
1229 // syntactic keywords: each get set namespace include dynamic final native override static
1230