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