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);
490 __ pushscope(m); count++;
491 m->code = m->code->prev->prev; // invert
493 /* continue appending after last op end */
494 while(m->code && m->code->next) m->code = m->code->next;
496 /* TODO: if this is one of *our* classes, we can also
497 do a getglobalscope/getslot <nr> (which references
498 the init function's slots) */
500 __ getlex2(m, extends2);
502 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
503 stack is not the superclass */
504 __ pushscope(m);count++;
507 /* notice: we get a verify error #1107 if the top element on the scope
508 stack is not the global object */
510 __ pushscope(m);count++;
512 __ newclass(m,state->cls);
516 __ setslot(m, slotindex);
518 /* flash.display.MovieClip handling */
519 if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
520 if(state->package && state->package[0]) {
521 globalclass = concat3str(state->package, ".", state->classname);
523 globalclass = strdup(state->classname);
526 multiname_destroy(extends2);
529 static void endclass()
531 /*printf("leaving class %s\n", state->classname);*/
534 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
535 param_list_t*params, class_signature_t*type)
539 state->function = name->text;
541 /*printf("entering function %s\n", name->text);
543 printf(" namespace: %s\n", ns->text);
544 printf(" getset: %s\n", getset->text);
545 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
546 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
548 printf(" type: %s.%s\n", type->package, type->name);
552 syntaxerror("not able to start another method scope");
555 multiname_t*type2 = sig2mname(type);
557 if(!strcmp(state->classname,name->text)) {
558 state->m = abc_class_constructor(state->cls, type2, 0);
560 state->m = abc_class_method(state->cls, type2, name->text, 0);
563 for(p=params;p;p=p->next) {
564 multiname_t*m = sig2mname(p->param->type);
565 list_append(state->m->method->parameters, m);
568 /* state->vars is initialized by state_new */
569 array_append(state->vars, "this", 0);
570 for(p=params;p;p=p->next) {
571 array_append(state->vars, p->param->name, 0);
574 __ getlocal_0(state->m);
575 __ pushscope(state->m);
577 multiname_destroy(type2);
579 static void endfunction()
581 /*printf("leaving function %s\n", state->function);*/
582 __ returnvoid(state->m);
588 static token_t* empty_token()
596 void extend(token_t*list, token_t*add) {
597 list_append(list->tokens,add);
599 list->text = add->text;
601 void extend_s(token_t*list, char*seperator, token_t*add) {
602 list_append(list->tokens,add);
603 char*t1 = list->text;
609 list->text = malloc(l1+l2+l3+1);
610 strcpy(list->text, t1);
611 strcpy(list->text+l1, t2);
612 strcpy(list->text+l1+l2, t3);
613 list->text[l1+l2+l3]=0;
616 static int find_variable(char*name, class_signature_t**m)
618 state_list_t* s = state_stack;
620 int i = array_find(s->state->vars, name);
623 *m = array_getvalue(s->state->vars, i);
625 return i + s->state->local_var_base;
629 syntaxerror("undefined variable: %s", name);
631 static char variable_exists(char*name)
633 return array_contains(state->vars, name);
635 static int new_variable(char*name, class_signature_t*type)
637 return array_append(state->vars, name, type) + state->local_var_base;
639 code_t* killvars(code_t*c)
642 for(t=0;t<state->vars->num;t++) {
643 class_signature_t*type = array_getvalue(state->vars, t);
644 //do this always, otherwise register types don't match
645 //in the verifier when doing nested loops
646 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
647 c = abc_kill(c, t+state->local_var_base);
653 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
658 void breakjumpsto(code_t*c, code_t*jump)
663 if(c->opcode == OPCODE___BREAK__) {
664 c->opcode = OPCODE_JUMP;
671 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
673 return registry_getanytype(); // FIXME
675 code_t*converttype(code_t*c, class_signature_t*from, class_signature_t*to)
680 /*TODO: can omit this if from is zero? */
681 return abc_coerce_a(c);
683 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
684 MULTINAME(m, TYPE_UINT);
685 return abc_coerce2(c, &m);
687 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
688 MULTINAME(m, TYPE_INT);
689 return abc_coerce2(c, &m);
694 code_t*defaultvalue(code_t*c, class_signature_t*type)
696 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
697 c = abc_pushbyte(c, 0);
698 } else if(TYPE_IS_BOOLEAN(type)) {
699 c = abc_pushfalse(c);
711 /* ------------ code blocks / statements ---------------- */
715 MAYBECODE: CODE {$$=$1;}
716 MAYBECODE: {$$=code_new();}
718 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
719 CODE: CODEPIECE {$$=$1;}
721 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
722 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
723 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
724 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
725 CODEPIECE: ';' {$$=code_new();}
726 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
727 CODEPIECE: VOIDEXPRESSION {$$=$1}
728 CODEPIECE: FOR {$$=$1}
729 CODEPIECE: WHILE {$$=$1}
730 CODEPIECE: BREAK {$$=$1}
731 CODEPIECE: RETURN {$$=$1}
732 CODEPIECE: IF {$$=$1}
733 CODEPIECE: ASSIGNMENT {$$=$1}
734 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
735 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
736 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
738 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
739 CODEBLOCK : CODEPIECE ';' {$$=$1;}
740 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
742 /* ------------ functions --------------------------- */
744 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
745 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
746 if(!state->m) syntaxerror("internal error: undefined function");
747 state->initcode = abc_nop(state->initcode);
748 state->initcode = abc_nop(state->initcode);
749 state->initcode = abc_nop(state->initcode);
750 state->m->code = code_append(state->initcode, $11);state->initcode=0;
754 /* ------------ variables --------------------------- */
756 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
757 | {$$.c=abc_pushundefined(0);
761 VAR : "const" | "var"
762 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
763 if(variable_exists($2->text))
764 syntaxerror("Variable %s already defined", $2->text);
766 if(!is_subtype_of($4.t, $3)) {
767 syntaxerror("Can't convert %s to %s", $4.t->name,
771 int index = new_variable($2->text, $3);
774 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
776 $$ = converttype($$, $4.t, $3);
777 $$ = abc_setlocal($$, index);
779 $$ = defaultvalue(0, $3);
780 $$ = abc_setlocal($$, index);
783 /* push default value for type on stack */
784 state->initcode = defaultvalue(state->initcode, $3);
785 state->initcode = abc_setlocal(state->initcode, index);
787 /* only bother to actually set this variable if its syntax is either
792 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
794 $$ = abc_coerce_a($$);
795 $$ = abc_setlocal($$, index);
801 /* that's the default for a local register, anyway
803 state->initcode = abc_pushundefined(state->initcode);
804 state->initcode = abc_setlocal(state->initcode, index);
806 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
808 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
809 class_signature_t*type=0;
810 int i = find_variable($1->text, &type);
813 // convert to "any" type, the register is untyped
814 $$ = abc_coerce_a($$);
816 // TODO: convert ints to strings etc.
818 $$ = abc_setlocal($$, i);
821 /* ------------ control flow ------------------------- */
823 MAYBEELSE: %prec prec_none {$$ = code_new();}
824 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
825 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
827 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
828 $$ = state->initcode;state->initcode=0;
830 $$ = code_append($$, $4.c);
831 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
833 $$ = code_append($$, $6);
835 myjmp = $$ = abc_jump($$, 0);
837 myif->branch = $$ = abc_label($$);
839 $$ = code_append($$, $7);
840 myjmp->branch = $$ = abc_label($$);
843 $$ = killvars($$);old_state();
846 FOR_INIT : {$$=code_new();}
847 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
849 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
850 $$ = state->initcode;state->initcode=0;
852 $$ = code_append($$, $4);
853 code_t*loopstart = $$ = abc_label($$);
854 $$ = code_append($$, $6.c);
855 code_t*myif = $$ = abc_iffalse($$, 0);
856 $$ = code_append($$, $10);
857 $$ = code_append($$, $8);
858 $$ = abc_jump($$, loopstart);
859 code_t*out = $$ = abc_label($$);
860 breakjumpsto($$, out);
863 $$ = killvars($$);old_state();
866 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
867 $$ = state->initcode;state->initcode=0;
869 code_t*myjmp = $$ = abc_jump($$, 0);
870 code_t*loopstart = $$ = abc_label($$);
871 $$ = code_append($$, $6);
872 myjmp->branch = $$ = abc_label($$);
873 $$ = code_append($$, $4.c);
874 $$ = abc_iftrue($$, loopstart);
875 code_t*out = $$ = abc_label($$);
876 breakjumpsto($$, out);
878 $$ = killvars($$);old_state();
882 $$ = abc___break__(0);
885 /* ------------ packages and imports ---------------- */
887 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
888 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
890 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
891 PACKAGE: X_IDENTIFIER {$$=$1;}
893 IMPORT : "import" PACKAGE '.' X_IDENTIFIER {
894 class_signature_t*c = registry_findclass($2->text, $4->text);
896 syntaxerror("Couldn't import %s.%s\n", $2->text, $4->text);
898 dict_put(state->imports, $4->text, c);
901 IMPORT : "import" PACKAGE '.' '*' {
903 i->package = $2->text;
905 list_append(state->wildcard_imports, i);
909 /* ------------ classes and interfaces -------------- */
911 MODIFIERS : {$$=empty_token();}
912 MODIFIERS : MODIFIER_LIST {$$=$1}
913 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
914 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
915 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
917 EXTENDS : {$$=registry_getobjectclass();}
918 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
920 EXTENDS_LIST : {$$=list_new();}
921 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
923 IMPLEMENTS_LIST : {$$=list_new();}
924 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
926 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
927 EXTENDS IMPLEMENTS_LIST
928 '{' {startclass($1,$3,$4,$5, 0);}
929 MAYBE_DECLARATION_LIST
931 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
933 '{' {startclass($1,$3,0,$4,1);}
934 MAYBE_IDECLARATION_LIST
937 /* ------------- package + class ids --------------- */
939 PACKAGEANDCLASS : T_IDENTIFIER {
941 /* try current package */
942 $$ = registry_findclass(state->package, $1->text);
944 /* try explicit imports */
945 dictentry_t* e = dict_get_slot(state->imports, $1->text);
949 if(!strcmp(e->key, $1->text)) {
950 $$ = (class_signature_t*)e->data;
955 /* try package.* imports */
956 import_list_t*l = state->wildcard_imports;
960 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
961 $$ = registry_findclass(l->import->package, $1->text);
965 /* try global package */
967 $$ = registry_findclass("", $1->text);
970 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
972 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
973 $$ = registry_findclass($1->text, $3->text);
974 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
978 /* ----------function calls, constructor calls ------ */
980 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
981 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
983 MAYBE_EXPRESSION_LIST : {$$=0;}
984 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
985 EXPRESSION_LIST : EXPRESSION {$$=list_new();
986 typedcode_t*t = malloc(sizeof(typedcode_t));
989 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
990 typedcode_t*t = malloc(sizeof(typedcode_t));
994 NEW : "new" PACKAGEANDCLASS MAYBE_PARAM_VALUES {
997 $$.c = abc_findpropstrict2($$.c, &m);
998 typedcode_list_t*l = $3;
1001 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1005 $$.c = abc_constructprop2($$.c, &m, len);
1009 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1010 /* TODO: use abc_call (for calling local variables),
1011 abc_callstatic (for calling own methods) */
1013 $$.c = abc_findpropstrict($$.c, $1->text);
1014 typedcode_list_t*l = $3;
1017 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1021 $$.c = abc_callproperty($$.c, $1->text, len);
1022 /* TODO: look up the functions's return value */
1026 RETURN: "return" %prec prec_none {
1027 $$ = abc_returnvoid(0);
1029 RETURN: "return" EXPRESSION {
1031 $$ = abc_returnvalue($$);
1034 TYPE : PACKAGEANDCLASS {$$=$1;}
1035 | '*' {$$=registry_getanytype();}
1036 | "String" {$$=registry_getstringclass();}
1037 | "int" {$$=registry_getintclass();}
1038 | "uint" {$$=registry_getuintclass();}
1039 | "Boolean" {$$=registry_getbooleanclass();}
1040 | "Number" {$$=registry_getnumberclass();}
1042 MAYBETYPE: ':' TYPE {$$=$2;}
1045 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
1046 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1049 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1050 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1051 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1053 //NAMESPACE : {$$=empty_token();}
1054 //NAMESPACE : T_IDENTIFIER {$$=$1};
1056 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1057 //MULTINAME(m, registry_getintclass());
1058 //$$.c = abc_coerce2($$.c, &m); // FIXME
1061 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1064 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1067 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1070 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1073 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1076 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1077 $$.t = TYPE_BOOLEAN;
1079 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1080 $$.t = TYPE_BOOLEAN;
1082 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1086 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1089 EXPRESSION : E %prec prec_none /*precedence below '-x'*/ {$$ = $1;}
1090 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
1093 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1095 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1099 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1100 $$.t = TYPE_BOOLEAN;
1102 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1103 $$.t = TYPE_BOOLEAN;
1105 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1106 $$.t = TYPE_BOOLEAN;
1108 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1109 $$.t = TYPE_BOOLEAN;
1111 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1112 $$.t = TYPE_BOOLEAN;
1114 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1115 $$.t = TYPE_BOOLEAN;
1117 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1118 $$.t = TYPE_BOOLEAN;
1121 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1123 $$.c = converttype($$.c, $1.t, $$.t);
1124 $$.c = abc_dup($$.c);
1125 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1126 $$.c = abc_pop($$.c);
1127 $$.c = code_append($$.c,$3.c);
1128 $$.c = converttype($$.c, $1.t, $$.t);
1129 code_t*label = $$.c = abc_label($$.c);
1130 jmp->branch = label;
1132 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1134 $$.c = converttype($$.c, $1.t, $$.t);
1135 $$.c = abc_dup($$.c);
1136 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1137 $$.c = abc_pop($$.c);
1138 $$.c = code_append($$.c,$3.c);
1139 $$.c = converttype($$.c, $1.t, $$.t);
1140 code_t*label = $$.c = abc_label($$.c);
1141 jmp->branch = label;
1144 E : '!' E {$$.c=$2.c;
1145 $$.c = abc_not($$.c);
1146 $$.t = TYPE_BOOLEAN;
1151 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1152 $$.t = join_types($1.t, $3.t, '+');
1154 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1155 $$.t = join_types($1.t, $3.t, '%');
1157 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1158 $$.t = join_types($1.t, $3.t, '*');
1163 E : '(' E ')' {$$=$2;}
1166 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1167 class_signature_t*type = join_types($1.type, $3.t, '+');
1168 $$.c=converttype($$.c, type, $1.type);
1169 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1172 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1173 class_signature_t*type = join_types($1.type, $3.t, '-');
1174 $$.c=converttype($$.c, type, $1.type);
1175 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1179 // TODO: use inclocal where appropriate
1180 E : LH "++" {$$.c = $1.read;
1181 class_signature_t*type = $1.type;
1182 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1183 $$.c=abc_increment_i($$.c);
1185 $$.c=abc_increment($$.c);
1188 $$.c=converttype($$.c, type, $1.type);
1189 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1192 E : LH "--" {$$.c = $1.read;
1193 class_signature_t*type = $1.type;
1194 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1195 $$.c=abc_decrement_i($$.c);
1197 $$.c=abc_decrement($$.c);
1200 $$.c=converttype($$.c, type, $1.type);
1201 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1206 int i = find_variable($1->text, &$$.type);
1207 $$.read = abc_getlocal(0, i);
1208 $$.write = abc_setlocal(0, i);
1212 VAR_READ : T_IDENTIFIER {
1213 int i = find_variable($1->text, &$$.t);
1214 $$.c = abc_getlocal(0, i);
1217 //VARIABLE : T_IDENTIFIER
1218 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1219 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1220 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1221 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1222 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1224 // keywords which also may be identifiers
1225 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1227 GETSET : "get" {$$=$1;}
1229 | {$$=empty_token();}
1231 MAYBE_PARAM_LIST: {$$=list_new();}
1232 MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
1233 PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1; list_append($$, $3);}
1234 PARAM_LIST: PARAM {$$ = list_new();list_append($$, $1);}
1235 PARAM: T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
1236 $$->name=$1->text;$$->type = $3;}
1237 PARAM: T_IDENTIFIER {$$ = malloc(sizeof(param_t));
1238 $$->name=$1->text;$$->type = TYPE_ANY;}
1240 DECLARATION : VARIABLE_DECLARATION
1241 DECLARATION : FUNCTION_DECLARATION
1243 IDECLARATION : VARIABLE_DECLARATION
1244 IDECLARATION : FUNCTION_DECLARATION
1246 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1247 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1249 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1250 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1252 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1253 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1255 MAYBE_DECLARATION_LIST :
1256 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1257 DECLARATION_LIST : DECLARATION
1258 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1260 MAYBE_IDECLARATION_LIST :
1261 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1262 IDECLARATION_LIST : IDECLARATION
1263 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1266 // 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
1267 // syntactic keywords: each get set namespace include dynamic final native override static