3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
30 #include "tokenizer.h"
44 classinfo_t*classinfo;
45 classinfo_list_t*classinfo_list;
48 unsigned int number_uint;
52 typedcode_list_t*value_list;
54 param_list_t* param_list;
55 writeable_t writeable;
60 %token<token> T_IDENTIFIER
61 %token<string> T_STRING
62 %token<token> T_REGEXP
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
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"
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 '.'
135 %type <token> X_IDENTIFIER VARCONST
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
150 %type <value> CONSTANT
151 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
152 %type <token> USE_NAMESPACE
153 %type <code> ASSIGNMENT FOR_INIT
155 %type <classinfo> MAYBETYPE
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
169 //%type <token> VARIABLE
170 %type <value> VAR_READ
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
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
194 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
210 %nonassoc T_IDENTIFIER
211 %left below_semicolon
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"
226 static int yyerror(char*s)
228 syntaxerror("%s", s);
230 static token_t* concat2(token_t* t1, token_t* t2)
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);
241 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
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;
254 static char* concat3str(const char* t1, const char* t2, const char* 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);
267 typedef struct _import {
271 DECLARE_LIST(import);
273 typedef struct _state {
281 /* code that needs to be executed at the start of
282 a method (like initializing local registers) */
287 import_list_t*wildcard_imports;
289 char has_own_imports;
295 code_t*cls_static_init;
301 static state_t* state = 0;
305 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
307 static state_list_t*state_stack=0;
309 static void new_state()
312 NEW(state_list_t, sl);
314 state_t*oldstate = state;
316 memcpy(s, state, sizeof(state_t)); //shallow copy
317 sl->next = state_stack;
320 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
323 s->imports = dict_new();
328 state->vars = array_new();
330 state->has_own_imports = 0;
332 static void state_has_imports()
334 state->wildcard_imports = list_clone(state->wildcard_imports);
335 state->imports = dict_clone(state->imports);
336 state->has_own_imports = 1;
339 static void old_state()
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;
347 state = state_stack->state;
348 /*if(state->initcode) {
349 printf("residual initcode\n");
350 code_dump(state->initcode, 0, 0, "", stdout);
352 if(oldstate->has_own_imports) {
353 list_free(oldstate->wildcard_imports);
354 dict_destroy(oldstate->imports);oldstate->imports=0;
356 state->initcode = code_append(state->initcode, oldstate->initcode);
358 void initialize_state()
362 state->file = abc_file_new();
363 state->file->flags &= ~ABCFILE_LAZY;
365 state->init = abc_initscript(state->file, 0, 0);
366 abc_method_body_t*m = state->init->method->body;
369 __ findpropstrict(m, "[package]::trace");
370 __ pushstring(m, "[entering global init function]");
371 __ callpropvoid(m, "[package]::trace", 1);
373 void* finalize_state()
375 if(state->level!=1) {
376 syntaxerror("unexpected end of file");
378 abc_method_body_t*m = state->init->method->body;
381 __ findpropstrict(m, "[package]::trace");
382 __ pushstring(m, "[leaving global init function]");
383 __ callpropvoid(m, "[package]::trace", 1);
389 static void startpackage(token_t*t)
392 syntaxerror("Packages can not be nested.");
395 char*name = t?t->text:"";
396 /*printf("entering package \"%s\"\n", name);*/
397 state->package = name;
399 static void endpackage()
401 /*printf("leaving package \"%s\"\n", state->package);*/
406 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
409 syntaxerror("inner classes now allowed");
412 state->classname = name->text;
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");
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);
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 */
433 } else if(t->token->type == KW_PUBLIC) {
435 } else if(t->token->type == KW_FINAL) {
438 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
442 syntaxerror("public and internal not supported at the same time.");
444 /* create the class name, together with the proper attributes */
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;
455 syntaxerror("public classes only allowed inside a package");
458 if(registry_findclass(package, state->classname)) {
459 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
462 classinfo_t* classname = classinfo_register(access, package, state->classname);
464 MULTINAME(classname2,classname);
466 multiname_t*extends2 = sig2mname(extends);
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);
473 for(mlist=implements;mlist;mlist=mlist->next) {
474 MULTINAME(m, mlist->classinfo);
475 abc_class_add_interface(state->cls, &m);
478 /* now write the construction code for this class */
479 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
481 abc_method_body_t*m = state->init->method->body;
482 __ getglobalscope(m);
483 classinfo_t*s = extends;
488 //TODO: take a look at the current scope stack, maybe
489 // we can re-use something
494 multiname_t*s2 = sig2mname(s);
496 multiname_destroy(s2);
498 __ pushscope(m); count++;
499 m->code = m->code->prev->prev; // invert
501 /* continue appending after last op end */
502 while(m->code && m->code->next) m->code = m->code->next;
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) */
508 __ getlex2(m, extends2);
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++;
515 /* notice: we get a verify error #1107 if the top element on the scope
516 stack is not the global object */
518 __ pushscope(m);count++;
520 __ newclass(m,state->cls);
524 __ setslot(m, slotindex);
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);
531 globalclass = strdup(state->classname);
534 multiname_destroy(extends2);
537 static void endclass()
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;
544 state->cls->constructor->body->code =
545 code_append(state->cls_init, state->cls->constructor->body->code);
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;
553 state->cls->static_constructor->body->code =
554 code_append(state->cls_static_init, state->cls->static_constructor->body->code);
560 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
561 param_list_t*params, classinfo_t*type)
565 state->function = name->text;
567 /*printf("entering function %s\n", name->text);
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");
574 printf(" type: %s.%s\n", type->package, type->name);
578 syntaxerror("not able to start another method scope");
581 multiname_t*type2 = sig2mname(type);
582 if(!strcmp(state->classname,name->text)) {
583 state->m = abc_class_constructor(state->cls, type2, 0);
585 state->m = abc_class_method(state->cls, type2, name->text, 0);
588 for(p=params;p;p=p->next) {
589 multiname_t*m = sig2mname(p->param->type);
590 list_append(state->m->method->parameters, m);
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);
599 __ getlocal_0(state->m);
600 __ pushscope(state->m);
602 static void endfunction()
604 /*printf("leaving function %s\n", state->function);*/
605 __ returnvoid(state->m);
611 static token_t* empty_token()
619 void extend(token_t*list, token_t*add) {
620 list_append(list->tokens,add);
622 list->text = add->text;
624 void extend_s(token_t*list, char*seperator, token_t*add) {
625 list_append(list->tokens,add);
626 char*t1 = list->text;
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;
639 static int find_variable(char*name, classinfo_t**m)
641 state_list_t* s = state_stack;
643 int i = array_find(s->state->vars, name);
646 *m = array_getvalue(s->state->vars, i);
648 return i + s->state->local_var_base;
654 static int find_variable_safe(char*name, classinfo_t**m)
656 int i = find_variable(name, m);
658 syntaxerror("undefined variable: %s", name);
661 static char variable_exists(char*name)
663 return array_contains(state->vars, name);
665 static int new_variable(char*name, classinfo_t*type)
667 return array_append(state->vars, name, type) + state->local_var_base;
669 code_t* killvars(code_t*c)
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);
683 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
688 void breakjumpsto(code_t*c, code_t*jump)
693 if(c->opcode == OPCODE___BREAK__) {
694 c->opcode = OPCODE_JUMP;
701 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
703 return registry_getanytype(); // FIXME
705 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
710 /*TODO: can omit this if from is zero? */
711 return abc_coerce_a(c);
713 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
714 MULTINAME(m, TYPE_UINT);
715 return abc_coerce2(c, &m);
717 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
718 MULTINAME(m, TYPE_INT);
719 return abc_coerce2(c, &m);
724 code_t*defaultvalue(code_t*c, classinfo_t*type)
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);
736 char is_pushundefined(code_t*c)
738 return (c && !c->prev && !c->next && c->opcode == OPCODE_PUSHUNDEFINED);
746 /* ------------ code blocks / statements ---------------- */
750 MAYBECODE: CODE {$$=$1;}
751 MAYBECODE: {$$=code_new();}
753 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
754 CODE: CODEPIECE {$$=$1;}
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();}
773 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
774 CODEBLOCK : CODEPIECE ';' {$$=$1;}
775 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
777 /* ------------ variables --------------------------- */
779 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
780 | {$$.c=abc_pushundefined(0);
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);
789 if(!is_subtype_of($4.t, $3)) {
790 syntaxerror("Can't convert %s to %s", $4.t->name,
794 int index = new_variable($2->text, $3);
797 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
799 $$ = converttype($$, $4.t, $3);
800 $$ = abc_setlocal($$, index);
802 $$ = defaultvalue(0, $3);
803 $$ = abc_setlocal($$, index);
806 /* push default value for type on stack */
807 state->initcode = defaultvalue(state->initcode, $3);
808 state->initcode = abc_setlocal(state->initcode, index);
810 /* only bother to actually set this variable if its syntax is either
815 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
817 $$ = abc_coerce_a($$);
818 $$ = abc_setlocal($$, index);
824 /* that's the default for a local register, anyway
826 state->initcode = abc_pushundefined(state->initcode);
827 state->initcode = abc_setlocal(state->initcode, index);
829 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
831 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
833 int i = find_variable_safe($1->text, &type);
836 // convert to "any" type, the register is untyped
837 $$ = abc_coerce_a($$);
839 // TODO: convert ints to strings etc.
841 $$ = abc_setlocal($$, i);
844 /* ------------ control flow ------------------------- */
846 MAYBEELSE: %prec prec_none {$$ = code_new();}
847 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
848 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
850 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
851 $$ = state->initcode;state->initcode=0;
853 $$ = code_append($$, $4.c);
854 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
856 $$ = code_append($$, $6);
858 myjmp = $$ = abc_jump($$, 0);
860 myif->branch = $$ = abc_label($$);
862 $$ = code_append($$, $7);
863 myjmp->branch = $$ = abc_label($$);
866 $$ = killvars($$);old_state();
869 FOR_INIT : {$$=code_new();}
870 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
872 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
873 $$ = state->initcode;state->initcode=0;
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);
886 $$ = killvars($$);old_state();
889 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
890 $$ = state->initcode;state->initcode=0;
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);
901 $$ = killvars($$);old_state();
905 $$ = abc___break__(0);
908 /* ------------ packages and imports ---------------- */
910 X_IDENTIFIER: T_IDENTIFIER
913 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
914 PACKAGE: X_IDENTIFIER {$$=$1;}
916 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
917 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
919 IMPORT : "import" QNAME {
922 syntaxerror("Couldn't import class\n");
924 dict_put(state->imports, c->name, c);
927 IMPORT : "import" PACKAGE '.' '*' {
929 i->package = $2->text;
931 list_append(state->wildcard_imports, i);
935 /* ------------ classes and interfaces (header) -------------- */
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
943 EXTENDS : {$$=registry_getobjectclass();}
944 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
946 EXTENDS_LIST : {$$=list_new();}
947 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
949 IMPLEMENTS_LIST : {$$=list_new();}
950 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
952 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
953 EXTENDS IMPLEMENTS_LIST
954 '{' {startclass($1,$3,$4,$5, 0);}
955 MAYBE_DECLARATION_LIST
958 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
960 '{' {startclass($1,$3,0,$4,1);}
961 MAYBE_IDECLARATION_LIST
964 /* ------------ classes and interfaces (body) -------------- */
966 MAYBE_DECLARATION_LIST :
967 MAYBE_DECLARATION_LIST : DECLARATION_LIST
968 DECLARATION_LIST : DECLARATION
969 DECLARATION_LIST : DECLARATION_LIST DECLARATION
971 DECLARATION : SLOT_DECLARATION
972 DECLARATION : FUNCTION_DECLARATION
974 VARCONST: "var" | "const"
975 SLOT_DECLARATION: MODIFIERS VARCONST T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
979 t=abc_class_slot(state->cls, $3->text, &m);
981 t=abc_class_slot(state->cls, $3->text, 0);
983 if($2->type==KW_CONST) {
984 t->kind= TRAIT_CONST;
986 if($5.c && !is_pushundefined($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);
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;
1002 /* ------------- package + class ids --------------- */
1004 CLASS: T_IDENTIFIER {
1006 /* try current package */
1007 $$ = registry_findclass(state->package, $1->text);
1009 /* try explicit imports */
1010 dictentry_t* e = dict_get_slot(state->imports, $1->text);
1014 if(!strcmp(e->key, $1->text)) {
1015 $$ = (classinfo_t*)e->data;
1020 /* try package.* imports */
1021 import_list_t*l = state->wildcard_imports;
1025 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1026 $$ = registry_findclass(l->import->package, $1->text);
1030 /* try global package */
1032 $$ = registry_findclass("", $1->text);
1035 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
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);
1043 QNAME: PACKAGEANDCLASS
1047 /* ----------function calls, constructor calls ------ */
1049 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1050 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
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));
1057 list_append($$, t);}
1058 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
1059 typedcode_t*t = malloc(sizeof(typedcode_t));
1061 list_append($$, t);}
1063 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1066 $$.c = abc_findpropstrict2($$.c, &m);
1067 typedcode_list_t*l = $3;
1070 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1074 $$.c = abc_constructprop2($$.c, &m, len);
1078 /* TODO: use abc_call (for calling local variables),
1079 abc_callstatic (for calling own methods)
1082 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1083 typedcode_list_t*l = $3;
1085 code_t*paramcode = 0;
1087 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
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);
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);
1104 /* TODO: look up the functions's return value */
1108 RETURN: "return" %prec prec_none {
1109 $$ = abc_returnvoid(0);
1111 RETURN: "return" EXPRESSION {
1113 $$ = abc_returnvalue($$);
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();}
1124 MAYBETYPE: ':' TYPE {$$=$2;}
1127 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
1128 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
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
1135 //NAMESPACE : {$$=empty_token();}
1136 //NAMESPACE : T_IDENTIFIER {$$=$1};
1138 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1139 //MULTINAME(m, registry_getintclass());
1140 //$$.c = abc_coerce2($$.c, &m); // FIXME
1143 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1146 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1149 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1152 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1155 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1158 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1159 $$.t = TYPE_BOOLEAN;
1161 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1162 $$.t = TYPE_BOOLEAN;
1164 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1168 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1171 EXPRESSION : E %prec prec_none /*precedence below '-x'*/ {$$ = $1;}
1172 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
1175 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1177 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1181 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1182 $$.t = TYPE_BOOLEAN;
1184 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1185 $$.t = TYPE_BOOLEAN;
1187 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1188 $$.t = TYPE_BOOLEAN;
1190 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1191 $$.t = TYPE_BOOLEAN;
1193 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1194 $$.t = TYPE_BOOLEAN;
1196 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1197 $$.t = TYPE_BOOLEAN;
1199 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1200 $$.t = TYPE_BOOLEAN;
1203 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
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;
1214 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
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;
1226 E : E '.' T_IDENTIFIER
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();
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();
1242 E : '!' E {$$.c=$2.c;
1243 $$.c = abc_not($$.c);
1244 $$.t = TYPE_BOOLEAN;
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, '+');
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, '%');
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, '*');
1261 E : '(' E ')' {$$=$2;}
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);
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);
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);
1283 $$.c=abc_increment($$.c);
1286 $$.c=converttype($$.c, type, $1.type);
1287 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
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);
1295 $$.c=abc_decrement($$.c);
1298 $$.c=converttype($$.c, type, $1.type);
1299 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
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;
1320 syntaxerror("illegal lvalue: can't assign a value to this expression");
1326 int i = find_variable_safe($1->text, &$$.type);
1327 $$.read = abc_getlocal(0, i);
1328 $$.write = abc_setlocal(0, i);
1332 VAR_READ : T_IDENTIFIER {
1335 int i = find_variable($1->text, &$$.t);
1337 $$.c = abc_getlocal($$.c, i);
1340 $$.c = abc_findpropstrict($$.c, $1->text);
1341 $$.c = abc_getproperty($$.c, $1->text);
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
1352 GETSET : "get" {$$=$1;}
1354 | {$$=empty_token();}
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;}
1365 IDECLARATION : VARIABLE_DECLARATION
1366 IDECLARATION : FUNCTION_DECLARATION
1368 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1369 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1371 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1372 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1375 MAYBE_IDECLARATION_LIST :
1376 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1377 IDECLARATION_LIST : IDECLARATION
1378 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
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