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 class_signature_t*class_signature;
45 class_signature_list_t*class_signature_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"
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 '.'
136 %type <code> CODEPIECE
137 %type <code> CODEBLOCK MAYBECODE
138 %type <token> PACKAGE_DECLARATION
139 %type <token> FUNCTION_DECLARATION
140 %type <code> VARIABLE_DECLARATION
141 %type <token> CLASS_DECLARATION
142 %type <token> NAMESPACE_DECLARATION
143 %type <token> INTERFACE_DECLARATION
144 %type <code> VOIDEXPRESSION
145 %type <value> EXPRESSION
146 %type <value> MAYBEEXPRESSION
149 %type <value> CONSTANT
150 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
151 %type <token> USE_NAMESPACE
152 %type <code> ASSIGNMENT FOR_INIT
154 %type <class_signature> MAYBETYPE
157 %type <param_list> PARAM_LIST
158 %type <param_list> MAYBE_PARAM_LIST
159 %type <token> MODIFIERS
160 %type <token> MODIFIER_LIST
161 %type <class_signature_list> IMPLEMENTS_LIST
162 %type <class_signature> EXTENDS
163 %type <class_signature_list> EXTENDS_LIST
164 %type <class_signature> PACKAGEANDCLASS
165 %type <class_signature_list> PACKAGEANDCLASS_LIST
166 %type <token> MULTILEVELIDENTIFIER
167 %type <class_signature> TYPE
169 //%type <token> VARIABLE
170 %type <value> VAR_READ
172 %type <token> X_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
220 static int yyerror(char*s)
222 syntaxerror("%s", s);
224 static token_t* concat2(token_t* t1, token_t* t2)
227 int l1 = strlen(t1->text);
228 int l2 = strlen(t2->text);
229 t->text = malloc(l1+l2+1);
230 memcpy(t->text , t1->text, l1);
231 memcpy(t->text+l1, t2->text, l2);
235 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
238 int l1 = strlen(t1->text);
239 int l2 = strlen(t2->text);
240 int l3 = strlen(t3->text);
241 t->text = malloc(l1+l2+l3+1);
242 memcpy(t->text , t1->text, l1);
243 memcpy(t->text+l1, t2->text, l2);
244 memcpy(t->text+l1+l2, t3->text, l3);
245 t->text[l1+l2+l3] = 0;
248 static char* concat3str(const char* t1, const char* t2, const char* t3)
253 char*text = malloc(l1+l2+l3+1);
254 memcpy(text , t1, l1);
255 memcpy(text+l1, t2, l2);
256 memcpy(text+l1+l2, t3, l3);
261 typedef struct _import {
265 DECLARE_LIST(import);
267 typedef struct _state {
275 /* code that needs to be executed at the start of
276 a method (like initializing local registers) */
281 import_list_t*wildcard_imports;
283 char has_own_imports;
293 static state_t* state = 0;
297 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
299 static state_list_t*state_stack=0;
301 static void new_state()
304 NEW(state_list_t, sl);
306 state_t*oldstate = state;
308 memcpy(s, state, sizeof(state_t)); //shallow copy
309 sl->next = state_stack;
312 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
315 s->imports = dict_new();
320 state->vars = array_new();
322 state->has_own_imports = 0;
324 static void state_has_imports()
326 state->wildcard_imports = list_clone(state->wildcard_imports);
327 state->imports = dict_clone(state->imports);
328 state->has_own_imports = 1;
331 static void old_state()
333 if(!state_stack || !state_stack->next)
334 syntaxerror("invalid nesting");
335 state_t*oldstate = state;
336 state_list_t*old = state_stack;
337 state_stack = state_stack->next;
339 state = state_stack->state;
340 /*if(state->initcode) {
341 printf("residual initcode\n");
342 code_dump(state->initcode, 0, 0, "", stdout);
344 if(oldstate->has_own_imports) {
345 list_free(oldstate->wildcard_imports);
346 dict_destroy(oldstate->imports);oldstate->imports=0;
348 state->initcode = code_append(state->initcode, oldstate->initcode);
350 void initialize_state()
354 state->file = abc_file_new();
355 state->file->flags &= ~ABCFILE_LAZY;
357 state->init = abc_initscript(state->file, 0, 0);
358 abc_method_body_t*m = state->init->method->body;
361 __ findpropstrict(m, "[package]::trace");
362 __ pushstring(m, "[entering global init function]");
363 __ callpropvoid(m, "[package]::trace", 1);
365 void* finalize_state()
367 if(state->level!=1) {
368 syntaxerror("unexpected end of file");
370 abc_method_body_t*m = state->init->method->body;
373 __ findpropstrict(m, "[package]::trace");
374 __ pushstring(m, "[leaving global init function]");
375 __ callpropvoid(m, "[package]::trace", 1);
381 static void startpackage(token_t*t)
384 syntaxerror("Packages can not be nested.");
387 char*name = t?t->text:"";
388 /*printf("entering package \"%s\"\n", name);*/
389 state->package = name;
391 static void endpackage()
393 /*printf("leaving package \"%s\"\n", state->package);*/
398 static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements, char interface)
401 syntaxerror("inner classes now allowed");
404 state->classname = name->text;
407 class_signature_list_t*mlist=0;
408 /*printf("entering class %s\n", name->text);
409 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
411 printf(" extends: %s.%s\n", extends->package, extends->name);
412 printf(" implements (%d): ", list_length(implements));
413 for(mlist=implements;mlist;mlist=mlist->next) {
414 printf("%s ", mlist->class_signature?mlist->class_signature->name:0);
419 char public=0,internal=0,final=0,sealed=1;
420 for(t=modifiers->tokens;t;t=t->next) {
421 if(t->token->type == KW_INTERNAL) {
422 /* the programmer is being explicit-
423 being internal is the default anyway */
425 } else if(t->token->type == KW_PUBLIC) {
427 } else if(t->token->type == KW_FINAL) {
430 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
434 syntaxerror("public and internal not supported at the same time.");
436 /* create the class name, together with the proper attributes */
440 if(!public && !state->package) {
441 access = ACCESS_PRIVATE; package = current_filename;
442 } else if(!public && state->package) {
443 access = ACCESS_PACKAGEINTERNAL; package = state->package;
444 } else if(state->package) {
445 access = ACCESS_PACKAGE; package = state->package;
447 syntaxerror("public classes only allowed inside a package");
450 if(registry_findclass(package, state->classname)) {
451 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
454 class_signature_t* classname = class_signature_register(access, package, state->classname);
456 MULTINAME(classname2,classname);
458 multiname_t*extends2 = sig2mname(extends);
460 state->cls = abc_class_new(state->file, &classname2, extends2);
461 if(final) abc_class_final(state->cls);
462 if(sealed) abc_class_sealed(state->cls);
463 if(interface) abc_class_interface(state->cls);
465 for(mlist=implements;mlist;mlist=mlist->next) {
466 MULTINAME(m, mlist->class_signature);
467 abc_class_add_interface(state->cls, &m);
470 /* now write the construction code for this class */
471 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
473 abc_method_body_t*m = state->init->method->body;
474 __ getglobalscope(m);
475 class_signature_t*s = extends;
480 //TODO: take a look at the current scope stack, maybe
481 // we can re-use something
486 multiname_t*s2 = sig2mname(s);
488 multiname_destroy(s2);
491 m->code = m->code->prev->prev; // invert
494 /* continue appending after last op end */
495 while(m->code && m->code->next) m->code = m->code->next;
497 /* TODO: if this is one of *our* classes, we can also
498 do a getglobalscope/getslot <nr> (which references
499 the init function's slots) */
501 __ getlex2(m, extends2);
503 __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
507 __ newclass(m,state->cls);
511 __ setslot(m, slotindex);
513 /* flash.display.MovieClip handling */
514 if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
515 if(state->package && state->package[0]) {
516 globalclass = concat3str(state->package, ".", state->classname);
518 globalclass = strdup(state->classname);
521 multiname_destroy(extends2);
524 static void endclass()
526 /*printf("leaving class %s\n", state->classname);*/
529 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
530 param_list_t*params, class_signature_t*type)
534 state->function = name->text;
536 /*printf("entering function %s\n", name->text);
538 printf(" namespace: %s\n", ns->text);
539 printf(" getset: %s\n", getset->text);
540 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
541 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
543 printf(" type: %s.%s\n", type->package, type->name);
547 syntaxerror("not able to start another method scope");
550 multiname_t*type2 = sig2mname(type);
552 if(!strcmp(state->classname,name->text)) {
553 state->m = abc_class_constructor(state->cls, type2, 0);
555 state->m = abc_class_method(state->cls, type2, name->text, 0);
558 for(p=params;p;p=p->next) {
559 multiname_t*m = sig2mname(p->param->type);
560 list_append(state->m->method->parameters, m);
563 /* state->vars is initialized by state_new */
564 array_append(state->vars, "this", 0);
565 for(p=params;p;p=p->next) {
566 array_append(state->vars, p->param->name, 0);
569 __ getlocal_0(state->m);
570 __ pushscope(state->m);
572 multiname_destroy(type2);
574 static void endfunction()
576 /*printf("leaving function %s\n", state->function);*/
577 __ returnvoid(state->m);
583 static token_t* empty_token()
591 void extend(token_t*list, token_t*add) {
592 list_append(list->tokens,add);
594 list->text = add->text;
596 void extend_s(token_t*list, char*seperator, token_t*add) {
597 list_append(list->tokens,add);
598 char*t1 = list->text;
604 list->text = malloc(l1+l2+l3+1);
605 strcpy(list->text, t1);
606 strcpy(list->text+l1, t2);
607 strcpy(list->text+l1+l2, t3);
608 list->text[l1+l2+l3]=0;
611 static int find_variable(char*name, class_signature_t**m)
613 state_list_t* s = state_stack;
615 int i = array_find(s->state->vars, name);
618 *m = array_getvalue(s->state->vars, i);
620 return i + s->state->local_var_base;
624 syntaxerror("undefined variable: %s", name);
626 static char variable_exists(char*name)
628 return array_contains(state->vars, name);
630 static int new_variable(char*name, class_signature_t*type)
632 return array_append(state->vars, name, type) + state->local_var_base;
634 code_t* killvars(code_t*c)
637 for(t=0;t<state->vars->num;t++) {
638 class_signature_t*type = array_getvalue(state->vars, t);
639 //do this always, otherwise register types don't match
640 //in the verifier when doing nested loops
641 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
642 c = abc_kill(c, t+state->local_var_base);
648 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
653 void breakjumpsto(code_t*c, code_t*jump)
658 if(c->opcode == OPCODE___BREAK__) {
659 c->opcode = OPCODE_JUMP;
666 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
668 return registry_getanytype(); // FIXME
670 code_t*converttype(code_t*c, class_signature_t*from, class_signature_t*to)
675 /*TODO: can omit this if from is zero? */
676 return abc_coerce_a(c);
678 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
679 MULTINAME(m, TYPE_UINT);
680 return abc_coerce2(c, &m);
682 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
683 MULTINAME(m, TYPE_INT);
684 return abc_coerce2(c, &m);
689 code_t*defaultvalue(code_t*c, class_signature_t*type)
691 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
692 c = abc_pushbyte(c, 0);
693 } else if(TYPE_IS_BOOLEAN(type)) {
694 c = abc_pushfalse(c);
706 /* ------------ code blocks / statements ---------------- */
710 MAYBECODE: CODE {$$=$1;}
711 MAYBECODE: {$$=code_new();}
713 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
714 CODE: CODEPIECE {$$=$1;}
716 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
717 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
718 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
719 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
720 CODEPIECE: ';' {$$=code_new();}
721 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
722 CODEPIECE: VOIDEXPRESSION {$$=$1}
723 CODEPIECE: FOR {$$=$1}
724 CODEPIECE: WHILE {$$=$1}
725 CODEPIECE: BREAK {$$=$1}
726 CODEPIECE: RETURN {$$=$1}
727 CODEPIECE: IF {$$=$1}
728 CODEPIECE: ASSIGNMENT {$$=$1}
729 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
730 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
731 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
733 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
734 CODEBLOCK : CODEPIECE ';' {$$=$1;}
735 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
737 /* ------------ functions --------------------------- */
739 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
740 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
741 if(!state->m) syntaxerror("internal error: undefined function");
742 state->initcode = abc_nop(state->initcode);
743 state->initcode = abc_nop(state->initcode);
744 state->initcode = abc_nop(state->initcode);
745 state->m->code = code_append(state->initcode, $11);state->initcode=0;
749 /* ------------ variables --------------------------- */
751 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
752 | {$$.c=abc_pushundefined(0);
756 VAR : "const" | "var"
757 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
758 if(variable_exists($2->text))
759 syntaxerror("Variable %s already defined", $2->text);
761 if(!is_subtype_of($4.t, $3)) {
762 syntaxerror("Can't convert %s to %s", $4.t->name,
766 int index = new_variable($2->text, $3);
769 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
771 $$ = converttype($$, $4.t, $3);
772 $$ = abc_setlocal($$, index);
774 $$ = defaultvalue(0, $3);
775 $$ = abc_setlocal($$, index);
778 /* push default value for type on stack */
779 state->initcode = defaultvalue(state->initcode, $3);
780 state->initcode = abc_setlocal(state->initcode, index);
782 /* only bother to actually set this variable if its syntax is either
787 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
789 $$ = abc_coerce_a($$);
790 $$ = abc_setlocal($$, index);
796 /* that's the default for a local register, anyway
798 state->initcode = abc_pushundefined(state->initcode);
799 state->initcode = abc_setlocal(state->initcode, index);
801 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
803 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
804 class_signature_t*type=0;
805 int i = find_variable($1->text, &type);
808 // convert to "any" type, the register is untyped
809 $$ = abc_coerce_a($$);
811 // TODO: convert ints to strings etc.
813 $$ = abc_setlocal($$, i);
816 /* ------------ control flow ------------------------- */
818 MAYBEELSE: %prec prec_none {$$ = code_new();}
819 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
820 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
822 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
823 $$ = state->initcode;state->initcode=0;
825 $$ = code_append($$, $4.c);
826 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
828 $$ = code_append($$, $6);
830 myjmp = $$ = abc_jump($$, 0);
832 myif->branch = $$ = abc_label($$);
834 $$ = code_append($$, $7);
835 myjmp->branch = $$ = abc_label($$);
838 $$ = killvars($$);old_state();
841 FOR_INIT : {$$=code_new();}
842 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
844 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
845 $$ = state->initcode;state->initcode=0;
847 $$ = code_append($$, $4);
848 code_t*loopstart = $$ = abc_label($$);
849 $$ = code_append($$, $6.c);
850 code_t*myif = $$ = abc_iffalse($$, 0);
851 $$ = code_append($$, $10);
852 $$ = code_append($$, $8);
853 $$ = abc_jump($$, loopstart);
854 code_t*out = $$ = abc_label($$);
855 breakjumpsto($$, out);
858 $$ = killvars($$);old_state();
861 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
862 $$ = state->initcode;state->initcode=0;
864 code_t*myjmp = $$ = abc_jump($$, 0);
865 code_t*loopstart = $$ = abc_label($$);
866 $$ = code_append($$, $6);
867 myjmp->branch = $$ = abc_label($$);
868 $$ = code_append($$, $4.c);
869 $$ = abc_iftrue($$, loopstart);
870 code_t*out = $$ = abc_label($$);
871 breakjumpsto($$, out);
873 $$ = killvars($$);old_state();
877 $$ = abc___break__(0);
880 /* ------------ packages and imports ---------------- */
882 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
883 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
885 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
886 PACKAGE: X_IDENTIFIER {$$=$1;}
888 IMPORT : "import" PACKAGE '.' X_IDENTIFIER {
889 class_signature_t*c = registry_findclass($2->text, $4->text);
891 syntaxerror("Couldn't import %s.%s\n", $2->text, $4->text);
893 dict_put(state->imports, $4->text, c);
896 IMPORT : "import" PACKAGE '.' '*' {
898 i->package = $2->text;
900 list_append(state->wildcard_imports, i);
904 /* ------------ classes and interfaces -------------- */
906 MODIFIERS : {$$=empty_token();}
907 MODIFIERS : MODIFIER_LIST {$$=$1}
908 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
909 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
910 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
912 EXTENDS : {$$=registry_getobjectclass();}
913 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
915 EXTENDS_LIST : {$$=list_new();}
916 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
918 IMPLEMENTS_LIST : {$$=list_new();}
919 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
921 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
922 EXTENDS IMPLEMENTS_LIST
923 '{' {startclass($1,$3,$4,$5, 0);}
924 MAYBE_DECLARATION_LIST
926 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
928 '{' {startclass($1,$3,0,$4,1);}
929 MAYBE_IDECLARATION_LIST
932 /* ------------- package + class ids --------------- */
934 PACKAGEANDCLASS : T_IDENTIFIER {
936 /* try current package */
937 $$ = registry_findclass(state->package, $1->text);
939 /* try explicit imports */
940 dictentry_t* e = dict_get_slot(state->imports, $1->text);
944 if(!strcmp(e->key, $1->text)) {
945 $$ = (class_signature_t*)e->data;
950 /* try package.* imports */
951 import_list_t*l = state->wildcard_imports;
955 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
956 $$ = registry_findclass(l->import->package, $1->text);
960 /* try global package */
962 $$ = registry_findclass("", $1->text);
965 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
967 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
968 $$ = registry_findclass($1->text, $3->text);
969 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
973 /* ----------function calls, constructor calls ------ */
975 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
976 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
978 MAYBE_EXPRESSION_LIST : {$$=0;}
979 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
980 EXPRESSION_LIST : EXPRESSION {$$=list_new();
981 typedcode_t*t = malloc(sizeof(typedcode_t));
984 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
985 typedcode_t*t = malloc(sizeof(typedcode_t));
989 NEW : "new" PACKAGEANDCLASS MAYBE_PARAM_VALUES {
992 $$.c = abc_findpropstrict2($$.c, &m);
993 typedcode_list_t*l = $3;
996 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1000 $$.c = abc_constructprop2($$.c, &m, len);
1004 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1005 /* TODO: use abc_call (for calling local variables),
1006 abc_callstatic (for calling own methods) */
1008 $$.c = abc_findpropstrict($$.c, $1->text);
1009 typedcode_list_t*l = $3;
1012 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1016 $$.c = abc_callproperty($$.c, $1->text, len);
1017 /* TODO: look up the functions's return value */
1021 RETURN: "return" %prec prec_none {
1022 $$ = abc_returnvoid(0);
1024 RETURN: "return" EXPRESSION {
1026 $$ = abc_returnvalue($$);
1029 TYPE : PACKAGEANDCLASS {$$=$1;}
1030 | '*' {$$=registry_getanytype();}
1031 | "String" {$$=registry_getstringclass();}
1032 | "int" {$$=registry_getintclass();}
1033 | "uint" {$$=registry_getuintclass();}
1034 | "Boolean" {$$=registry_getbooleanclass();}
1035 | "Number" {$$=registry_getnumberclass();}
1037 MAYBETYPE: ':' TYPE {$$=$2;}
1040 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
1041 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1044 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1045 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1046 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1048 //NAMESPACE : {$$=empty_token();}
1049 //NAMESPACE : T_IDENTIFIER {$$=$1};
1051 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1052 //MULTINAME(m, registry_getintclass());
1053 //$$.c = abc_coerce2($$.c, &m); // FIXME
1056 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1059 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1062 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1065 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1068 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1071 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1072 $$.t = TYPE_BOOLEAN;
1074 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1075 $$.t = TYPE_BOOLEAN;
1077 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1081 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1084 EXPRESSION : E %prec prec_none /*precedence below '-x'*/ {$$ = $1;}
1085 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
1088 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1090 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1094 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1095 $$.t = TYPE_BOOLEAN;
1097 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1098 $$.t = TYPE_BOOLEAN;
1100 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1101 $$.t = TYPE_BOOLEAN;
1103 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1104 $$.t = TYPE_BOOLEAN;
1106 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1107 $$.t = TYPE_BOOLEAN;
1109 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1110 $$.t = TYPE_BOOLEAN;
1112 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1113 $$.t = TYPE_BOOLEAN;
1116 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1118 $$.c = converttype($$.c, $1.t, $$.t);
1119 $$.c = abc_dup($$.c);
1120 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1121 $$.c = abc_pop($$.c);
1122 $$.c = code_append($$.c,$3.c);
1123 $$.c = converttype($$.c, $1.t, $$.t);
1124 code_t*label = $$.c = abc_label($$.c);
1125 jmp->branch = label;
1127 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1129 $$.c = converttype($$.c, $1.t, $$.t);
1130 $$.c = abc_dup($$.c);
1131 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1132 $$.c = abc_pop($$.c);
1133 $$.c = code_append($$.c,$3.c);
1134 $$.c = converttype($$.c, $1.t, $$.t);
1135 code_t*label = $$.c = abc_label($$.c);
1136 jmp->branch = label;
1139 E : '!' E {$$.c=$2.c;
1140 $$.c = abc_not($$.c);
1141 $$.t = TYPE_BOOLEAN;
1146 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1147 $$.t = join_types($1.t, $3.t, '+');
1149 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1150 $$.t = join_types($1.t, $3.t, '%');
1152 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1153 $$.t = join_types($1.t, $3.t, '*');
1158 E : '(' E ')' {$$=$2;}
1161 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1162 class_signature_t*type = join_types($1.type, $3.t, '+');
1163 $$.c=converttype($$.c, type, $1.type);
1164 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1167 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1168 class_signature_t*type = join_types($1.type, $3.t, '-');
1169 $$.c=converttype($$.c, type, $1.type);
1170 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1174 // TODO: use inclocal where appropriate
1175 E : LH "++" {$$.c = $1.read;
1176 class_signature_t*type = $1.type;
1177 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1178 $$.c=abc_increment_i($$.c);
1180 $$.c=abc_increment($$.c);
1183 $$.c=converttype($$.c, type, $1.type);
1184 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1187 E : LH "--" {$$.c = $1.read;
1188 class_signature_t*type = $1.type;
1189 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1190 $$.c=abc_decrement_i($$.c);
1192 $$.c=abc_decrement($$.c);
1195 $$.c=converttype($$.c, type, $1.type);
1196 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1201 int i = find_variable($1->text, &$$.type);
1202 $$.read = abc_getlocal(0, i);
1203 $$.write = abc_setlocal(0, i);
1207 VAR_READ : T_IDENTIFIER {
1208 int i = find_variable($1->text, &$$.t);
1209 $$.c = abc_getlocal(0, i);
1212 //VARIABLE : T_IDENTIFIER
1213 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1214 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1215 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1216 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1217 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1219 // keywords which also may be identifiers
1220 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1222 GETSET : "get" {$$=$1;}
1224 | {$$=empty_token();}
1226 MAYBE_PARAM_LIST: {$$=list_new();}
1227 MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
1228 PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1; list_append($$, $3);}
1229 PARAM_LIST: PARAM {$$ = list_new();list_append($$, $1);}
1230 PARAM: T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
1231 $$->name=$1->text;$$->type = $3;}
1232 PARAM: T_IDENTIFIER {$$ = malloc(sizeof(param_t));
1233 $$->name=$1->text;$$->type = TYPE_ANY;}
1235 DECLARATION : VARIABLE_DECLARATION
1236 DECLARATION : FUNCTION_DECLARATION
1238 IDECLARATION : VARIABLE_DECLARATION
1239 IDECLARATION : FUNCTION_DECLARATION
1241 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1242 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1244 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1245 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1247 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1248 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1250 MAYBE_DECLARATION_LIST :
1251 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1252 DECLARATION_LIST : DECLARATION
1253 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1255 MAYBE_IDECLARATION_LIST :
1256 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1257 IDECLARATION_LIST : IDECLARATION
1258 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1261 // 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
1262 // syntactic keywords: each get set namespace include dynamic final native override static