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_INTERFACE "interface"
89 %token<token> KW_VAR "var"
90 %token<token> KW_DYNAMIC
91 %token<token> KW_OVERRIDE
92 %token<token> KW_FINAL
93 %token<token> KW_GET "get"
94 %token<token> KW_EXTENDS
95 %token<token> KW_FALSE "false"
96 %token<token> KW_TRUE "true"
97 %token<token> KW_BOOLEAN "Boolean"
98 %token<token> KW_UINT "uint"
99 %token<token> KW_INT "int"
100 %token<token> KW_WHILE "while"
101 %token<token> KW_NUMBER "Number"
102 %token<token> KW_STRING "String"
103 %token<token> KW_IF "if"
104 %token<token> KW_ELSE "else"
105 %token<token> KW_BREAK "break"
106 %token<token> KW_IS "is"
107 %token<token> KW_AS "as"
109 %token<token> T_EQEQ "=="
110 %token<token> T_EQEQEQ "==="
111 %token<token> T_NE "!="
112 %token<token> T_LE "<="
113 %token<token> T_GE ">="
114 %token<token> T_DIVBY "/="
115 %token<token> T_MODBY "%="
116 %token<token> T_PLUSBY "+="
117 %token<token> T_MINUSBY "-="
118 %token<token> T_SHRBY ">>="
119 %token<token> T_SHLBY "<<="
120 %token<token> T_USHRBY ">>>="
121 %token<token> T_OROR "||"
122 %token<token> T_ANDAND "&&"
123 %token<token> T_COLONCOLON "::"
124 %token<token> T_MINUSMINUS "--"
125 %token<token> T_PLUSPLUS "++"
126 %token<token> T_DOTDOT ".."
127 %token<token> T_SHL "<<"
128 %token<token> T_USHR ">>>"
129 %token<token> T_SHR ">>"
130 %token<token> T_SEMICOLON ';'
131 %token<token> T_STAR '*'
132 %token<token> T_DOT '.'
135 %type <code> CODEPIECE
136 %type <code> CODEBLOCK MAYBECODE
137 %type <token> PACKAGE_DECLARATION
138 %type <token> FUNCTION_DECLARATION
139 %type <code> VARIABLE_DECLARATION
140 %type <token> CLASS_DECLARATION
141 %type <token> NAMESPACE_DECLARATION
142 %type <token> INTERFACE_DECLARATION
143 %type <code> VOIDEXPRESSION
144 %type <value> EXPRESSION
145 %type <value> MAYBEEXPRESSION
148 %type <value> CONSTANT
149 %type <code> FOR IF WHILE MAYBEELSE BREAK
150 %type <token> USE_NAMESPACE
151 %type <code> ASSIGNMENT FOR_INIT
153 %type <class_signature> MAYBETYPE
156 %type <param_list> PARAM_LIST
157 %type <param_list> MAYBE_PARAM_LIST
158 %type <token> MODIFIERS
159 %type <token> MODIFIER_LIST
160 %type <class_signature_list> IMPLEMENTS_LIST
161 %type <class_signature> EXTENDS
162 %type <class_signature_list> EXTENDS_LIST
163 %type <class_signature> PACKAGEANDCLASS
164 %type <class_signature_list> PACKAGEANDCLASS_LIST
165 %type <token> MULTILEVELIDENTIFIER
166 %type <class_signature> TYPE
168 //%type <token> VARIABLE
169 %type <value> VAR_READ
171 %type <token> X_IDENTIFIER
172 %type <token> MODIFIER
173 %type <token> PACKAGE
174 %type <value> FUNCTIONCALL
175 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST MAYBE_PARAM_VALUES
177 // precendence: from low to high
178 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
193 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
209 %nonassoc T_IDENTIFIER
210 %left below_semicolon
218 static int yyerror(char*s)
220 syntaxerror("%s", s);
222 static token_t* concat2(token_t* t1, token_t* t2)
225 int l1 = strlen(t1->text);
226 int l2 = strlen(t2->text);
227 t->text = malloc(l1+l2+1);
228 memcpy(t->text , t1->text, l1);
229 memcpy(t->text+l1, t2->text, l2);
233 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
236 int l1 = strlen(t1->text);
237 int l2 = strlen(t2->text);
238 int l3 = strlen(t3->text);
239 t->text = malloc(l1+l2+l3+1);
240 memcpy(t->text , t1->text, l1);
241 memcpy(t->text+l1, t2->text, l2);
242 memcpy(t->text+l1+l2, t3->text, l3);
243 t->text[l1+l2+l3] = 0;
246 static char* concat3str(const char* t1, const char* t2, const char* t3)
251 char*text = malloc(l1+l2+l3+1);
252 memcpy(text , t1, l1);
253 memcpy(text+l1, t2, l2);
254 memcpy(text+l1+l2, t3, l3);
259 typedef struct _import {
263 DECLARE_LIST(import);
265 typedef struct _state {
273 /* code that needs to be executed at the start of
274 a method (like initializing local registers) */
279 import_list_t*wildcard_imports;
281 char has_own_imports;
291 static state_t* state = 0;
295 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
297 static state_list_t*state_stack=0;
299 static void new_state()
302 NEW(state_list_t, sl);
304 state_t*oldstate = state;
306 memcpy(s, state, sizeof(state_t)); //shallow copy
307 sl->next = state_stack;
310 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
313 s->imports = dict_new();
318 state->vars = array_new();
320 state->has_own_imports = 0;
322 static void state_has_imports()
324 state->wildcard_imports = list_clone(state->wildcard_imports);
325 state->imports = dict_clone(state->imports);
326 state->has_own_imports = 1;
329 static void old_state()
331 if(!state_stack || !state_stack->next)
332 syntaxerror("invalid nesting");
333 state_t*oldstate = state;
334 state_list_t*old = state_stack;
335 state_stack = state_stack->next;
337 state = state_stack->state;
338 /*if(state->initcode) {
339 printf("residual initcode\n");
340 code_dump(state->initcode, 0, 0, "", stdout);
342 if(oldstate->has_own_imports) {
343 list_free(oldstate->wildcard_imports);
344 dict_destroy(oldstate->imports);oldstate->imports=0;
346 state->initcode = code_append(state->initcode, oldstate->initcode);
348 void initialize_state()
352 state->file = abc_file_new();
353 state->file->flags &= ~ABCFILE_LAZY;
355 state->init = abc_initscript(state->file, 0, 0);
356 abc_method_body_t*m = state->init->method->body;
359 __ findpropstrict(m, "[package]::trace");
360 __ pushstring(m, "[entering global init function]");
361 __ callpropvoid(m, "[package]::trace", 1);
363 void* finalize_state()
365 if(state->level!=1) {
366 syntaxerror("unexpected end of file");
368 abc_method_body_t*m = state->init->method->body;
371 __ findpropstrict(m, "[package]::trace");
372 __ pushstring(m, "[leaving global init function]");
373 __ callpropvoid(m, "[package]::trace", 1);
379 static void startpackage(token_t*t)
382 syntaxerror("Packages can not be nested.");
385 char*name = t?t->text:"";
386 /*printf("entering package \"%s\"\n", name);*/
387 state->package = name;
389 static void endpackage()
391 /*printf("leaving package \"%s\"\n", state->package);*/
396 static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements, char interface)
399 syntaxerror("inner classes now allowed");
402 state->classname = name->text;
405 class_signature_list_t*mlist=0;
406 /*printf("entering class %s\n", name->text);
407 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
409 printf(" extends: %s.%s\n", extends->package, extends->name);
410 printf(" implements (%d): ", list_length(implements));
411 for(mlist=implements;mlist;mlist=mlist->next) {
412 printf("%s ", mlist->class_signature?mlist->class_signature->name:0);
417 char public=0,internal=0,final=0,sealed=1;
418 for(t=modifiers->tokens;t;t=t->next) {
419 if(t->token->type == KW_INTERNAL) {
420 /* the programmer is being explicit-
421 being internal is the default anyway */
423 } else if(t->token->type == KW_PUBLIC) {
425 } else if(t->token->type == KW_FINAL) {
428 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
432 syntaxerror("public and internal not supported at the same time.");
434 /* create the class name, together with the proper attributes */
438 if(!public && !state->package) {
439 access = ACCESS_PRIVATE; package = current_filename;
440 } else if(!public && state->package) {
441 access = ACCESS_PACKAGEINTERNAL; package = state->package;
442 } else if(state->package) {
443 access = ACCESS_PACKAGE; package = state->package;
445 syntaxerror("public classes only allowed inside a package");
448 if(registry_findclass(package, state->classname)) {
449 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
452 class_signature_t* classname = class_signature_register(access, package, state->classname);
454 MULTINAME(classname2,classname);
456 multiname_t*extends2 = sig2mname(extends);
458 state->cls = abc_class_new(state->file, &classname2, extends2);
459 if(final) abc_class_final(state->cls);
460 if(sealed) abc_class_sealed(state->cls);
461 if(interface) abc_class_interface(state->cls);
463 for(mlist=implements;mlist;mlist=mlist->next) {
464 MULTINAME(m, mlist->class_signature);
465 abc_class_add_interface(state->cls, &m);
468 /* now write the construction code for this class */
469 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
471 abc_method_body_t*m = state->init->method->body;
472 __ getglobalscope(m);
473 class_signature_t*s = extends;
478 //TODO: take a look at the current scope stack, maybe
479 // we can re-use something
484 multiname_t*s2 = sig2mname(s);
486 multiname_destroy(s2);
489 m->code = m->code->prev->prev; // invert
492 /* continue appending after last op end */
493 while(m->code && m->code->next) m->code = m->code->next;
495 /* TODO: if this is one of *our* classes, we can also
496 do a getglobalscope/getslot <nr> (which references
497 the init function's slots) */
499 __ getlex2(m, extends2);
501 __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
505 __ newclass(m,state->cls);
509 __ setslot(m, slotindex);
511 /* flash.display.MovieClip handling */
512 if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
513 if(state->package && state->package[0]) {
514 globalclass = concat3str(state->package, ".", state->classname);
516 globalclass = strdup(state->classname);
519 multiname_destroy(extends2);
522 static void endclass()
524 /*printf("leaving class %s\n", state->classname);*/
527 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
528 param_list_t*params, class_signature_t*type)
532 state->function = name->text;
534 /*printf("entering function %s\n", name->text);
536 printf(" namespace: %s\n", ns->text);
537 printf(" getset: %s\n", getset->text);
538 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
539 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
541 printf(" type: %s.%s\n", type->package, type->name);
545 syntaxerror("not able to start another method scope");
548 multiname_t*type2 = sig2mname(type);
550 if(!strcmp(state->classname,name->text)) {
551 state->m = abc_class_constructor(state->cls, type2, 0);
553 state->m = abc_class_method(state->cls, type2, name->text, 0);
556 for(p=params;p;p=p->next) {
557 multiname_t*m = sig2mname(p->param->type);
558 list_append(state->m->method->parameters, m);
561 /* state->vars is initialized by state_new */
562 array_append(state->vars, "this", 0);
563 for(p=params;p;p=p->next) {
564 array_append(state->vars, p->param->name, 0);
567 __ getlocal_0(state->m);
568 __ pushscope(state->m);
570 multiname_destroy(type2);
572 static void endfunction()
574 /*printf("leaving function %s\n", state->function);*/
575 __ returnvoid(state->m);
581 static token_t* empty_token()
589 void extend(token_t*list, token_t*add) {
590 list_append(list->tokens,add);
592 list->text = add->text;
594 void extend_s(token_t*list, char*seperator, token_t*add) {
595 list_append(list->tokens,add);
596 char*t1 = list->text;
602 list->text = malloc(l1+l2+l3+1);
603 strcpy(list->text, t1);
604 strcpy(list->text+l1, t2);
605 strcpy(list->text+l1+l2, t3);
606 list->text[l1+l2+l3]=0;
609 static int find_variable(char*name, class_signature_t**m)
611 state_list_t* s = state_stack;
613 int i = array_find(s->state->vars, name);
616 *m = array_getvalue(s->state->vars, i);
618 return i + s->state->local_var_base;
622 syntaxerror("undefined variable: %s", name);
624 static char variable_exists(char*name)
626 return array_contains(state->vars, name);
628 static int new_variable(char*name, class_signature_t*type)
630 return array_append(state->vars, name, type) + state->local_var_base;
632 code_t* killvars(code_t*c)
635 for(t=0;t<state->vars->num;t++) {
636 class_signature_t*type = array_getvalue(state->vars, t);
637 //do this always, otherwise register types don't match
638 //in the verifier when doing nested loops
639 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
640 c = abc_kill(c, t+state->local_var_base);
646 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
648 return registry_getanytype(); // FIXME
650 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
655 void breakjumpsto(code_t*c, code_t*jump)
660 if(c->opcode == OPCODE___BREAK__) {
661 c->opcode = OPCODE_JUMP;
667 code_t*converttype(code_t*c, class_signature_t*from, class_signature_t*to)
670 /*TODO: can omit this if from is zero? */
671 return abc_coerce_a(c);
673 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
674 MULTINAME(m, TYPE_UINT);
675 return abc_coerce2(c, &m);
677 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
678 MULTINAME(m, TYPE_INT);
679 return abc_coerce2(c, &m);
684 code_t*defaultvalue(code_t*c, class_signature_t*type)
686 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
687 c = abc_pushbyte(c, 0);
688 } else if(TYPE_IS_BOOLEAN(type)) {
689 c = abc_pushfalse(c);
701 /* ------------ code blocks / statements ---------------- */
705 MAYBECODE: CODE {$$=$1;}
706 MAYBECODE: {$$=code_new();}
708 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
709 CODE: CODEPIECE {$$=$1;}
711 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
712 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
713 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
714 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
715 CODEPIECE: ';' {$$=code_new();}
716 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
717 CODEPIECE: VOIDEXPRESSION {$$=$1}
718 CODEPIECE: FOR {$$=$1}
719 CODEPIECE: WHILE {$$=$1}
720 CODEPIECE: BREAK {$$=$1}
721 CODEPIECE: IF {$$=$1}
722 CODEPIECE: ASSIGNMENT {$$=$1}
723 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
724 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
725 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
727 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
728 CODEBLOCK : CODEPIECE ';' {$$=$1;}
729 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
731 /* ------------ functions --------------------------- */
733 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
734 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
735 if(!state->m) syntaxerror("internal error: undefined function");
736 state->initcode = abc_nop(state->initcode);
737 state->initcode = abc_nop(state->initcode);
738 state->initcode = abc_nop(state->initcode);
739 state->m->code = code_append(state->initcode, $11);state->initcode=0;
743 /* ------------ variables --------------------------- */
745 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
746 | {$$.c=abc_pushundefined(0);
750 VAR : "const" | "var"
751 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
752 if(variable_exists($2->text))
753 syntaxerror("Variable %s already defined", $2->text);
755 if(!is_subtype_of($4.t, $3)) {
756 syntaxerror("Can't convert %s to %s", $4.t->name,
760 int index = new_variable($2->text, $3);
763 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
765 $$ = converttype($$, $4.t, $3);
766 $$ = abc_setlocal($$, index);
768 $$ = defaultvalue(0, $3);
769 $$ = abc_setlocal($$, index);
772 /* push default value for type on stack */
773 state->initcode = defaultvalue(state->initcode, $3);
774 state->initcode = abc_setlocal(state->initcode, index);
776 /* only bother to actually set this variable if its syntax is either
781 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
783 $$ = abc_coerce_a($$);
784 $$ = abc_setlocal($$, index);
790 /* that's the default for a local register, anyway
792 state->initcode = abc_pushundefined(state->initcode);
793 state->initcode = abc_setlocal(state->initcode, index);
795 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
797 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
798 class_signature_t*type=0;
799 int i = find_variable($1->text, &type);
802 // convert to "any" type, the register is untyped
803 $$ = abc_coerce_a($$);
805 // TODO: convert ints to strings etc.
807 $$ = abc_setlocal($$, i);
810 /* ------------ control flow ------------------------- */
812 MAYBEELSE: %prec prec_none {$$ = code_new();}
813 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
814 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
816 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
817 $$ = state->initcode;state->initcode=0;
819 $$ = code_append($$, $4.c);
820 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
822 $$ = code_append($$, $6);
824 myjmp = $$ = abc_jump($$, 0);
826 myif->branch = $$ = abc_label($$);
828 $$ = code_append($$, $7);
829 myjmp->branch = $$ = abc_label($$);
832 $$ = killvars($$);old_state();
835 FOR_INIT : {$$=code_new();}
836 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
838 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
839 $$ = state->initcode;state->initcode=0;
841 $$ = code_append($$, $4);
842 code_t*loopstart = $$ = abc_label($$);
843 $$ = code_append($$, $6.c);
844 code_t*myif = $$ = abc_iffalse($$, 0);
845 $$ = code_append($$, $10);
846 $$ = code_append($$, $8);
847 $$ = abc_jump($$, loopstart);
848 code_t*out = $$ = abc_label($$);
849 breakjumpsto($$, out);
852 $$ = killvars($$);old_state();
855 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
856 $$ = state->initcode;state->initcode=0;
858 code_t*myjmp = $$ = abc_jump($$, 0);
859 code_t*loopstart = $$ = abc_label($$);
860 $$ = code_append($$, $6);
861 myjmp->branch = $$ = abc_label($$);
862 $$ = code_append($$, $4.c);
863 $$ = abc_iftrue($$, loopstart);
864 code_t*out = $$ = abc_label($$);
865 breakjumpsto($$, out);
867 $$ = killvars($$);old_state();
871 $$ = abc___break__(0);
874 /* ------------ packages and imports ---------------- */
876 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
877 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
879 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
880 PACKAGE: X_IDENTIFIER {$$=$1;}
882 IMPORT : "import" PACKAGE '.' X_IDENTIFIER {
883 class_signature_t*c = registry_findclass($2->text, $4->text);
885 syntaxerror("Couldn't import %s.%s\n", $2->text, $4->text);
887 dict_put(state->imports, $4->text, c);
890 IMPORT : "import" PACKAGE '.' '*' {
892 i->package = $2->text;
894 list_append(state->wildcard_imports, i);
898 /* ------------ classes and interfaces -------------- */
900 MODIFIERS : {$$=empty_token();}
901 MODIFIERS : MODIFIER_LIST {$$=$1}
902 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
903 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
904 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
906 EXTENDS : {$$=registry_getobjectclass();}
907 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
909 EXTENDS_LIST : {$$=list_new();}
910 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
912 IMPLEMENTS_LIST : {$$=list_new();}
913 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
915 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
916 EXTENDS IMPLEMENTS_LIST
917 '{' {startclass($1,$3,$4,$5, 0);}
918 MAYBE_DECLARATION_LIST
920 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
922 '{' {startclass($1,$3,0,$4,1);}
923 MAYBE_IDECLARATION_LIST
926 TYPE : PACKAGEANDCLASS {$$=$1;}
927 | '*' {$$=registry_getanytype();}
928 | "String" {$$=registry_getstringclass();}
929 | "int" {$$=registry_getintclass();}
930 | "uint" {$$=registry_getuintclass();}
931 | "Boolean" {$$=registry_getbooleanclass();}
932 | "Number" {$$=registry_getnumberclass();}
934 MAYBETYPE: ':' TYPE {$$=$2;}
937 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
938 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
941 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
942 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
943 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
945 //NAMESPACE : {$$=empty_token();}
946 //NAMESPACE : T_IDENTIFIER {$$=$1};
948 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
949 //MULTINAME(m, registry_getintclass());
950 //$$.c = abc_coerce2($$.c, &m); // FIXME
953 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
956 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
959 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
962 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
965 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
968 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
971 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
974 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
978 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
981 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
982 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
985 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
987 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
991 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
994 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
997 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1000 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1001 $$.t = TYPE_BOOLEAN;
1003 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1004 $$.t = TYPE_BOOLEAN;
1006 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1007 $$.t = TYPE_BOOLEAN;
1009 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1010 $$.t = TYPE_BOOLEAN;
1013 E : E "||" E {$$.c = $1.c;
1015 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1017 $$.c = code_append($$.c,$3.c);
1018 code_t*label = $$.c = abc_label($$.c);
1019 jmp->branch = label;
1020 $$.t = join_types($1.t, $3.t, 'O');
1022 E : E "&&" E {$$.c = $1.c;
1024 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1026 $$.c = code_append($$.c,$3.c);
1027 code_t*label = $$.c = abc_label($$.c);
1028 jmp->branch = label;
1029 $$.t = join_types($1.t, $3.t, 'A');
1032 E : '!' E {$$.c=$2.c;
1033 $$.c = abc_not($$.c);
1034 $$.t = TYPE_BOOLEAN;
1039 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1040 $$.t = join_types($1.t, $3.t, '+');
1042 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1043 $$.t = join_types($1.t, $3.t, '%');
1045 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1046 $$.t = join_types($1.t, $3.t, '*');
1051 E : '(' E ')' {$$=$2;}
1054 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1055 class_signature_t*type = join_types($1.type, $3.t, '+');
1056 $$.c=converttype($$.c, type, $1.type);
1057 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1060 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1061 class_signature_t*type = join_types($1.type, $3.t, '-');
1062 $$.c=converttype($$.c, type, $1.type);
1063 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1067 // TODO: use inclocal where appropriate
1068 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
1069 class_signature_t*type = $1.type;
1070 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1071 $$.c=converttype($$.c, type, $1.type);
1072 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1075 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
1076 class_signature_t*type = $1.type;
1077 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1078 $$.c=converttype($$.c, 0, $1.type);
1079 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1084 int i = find_variable($1->text, &$$.type);
1085 $$.read = abc_getlocal(0, i);
1086 $$.write = abc_setlocal(0, i);
1089 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1090 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1092 NEW : "new" PACKAGEANDCLASS MAYBE_PARAM_VALUES {
1095 $$.c = abc_findpropstrict2($$.c, &m);
1096 typedcode_list_t*l = $3;
1099 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1103 $$.c = abc_constructprop2($$.c, &m, len);
1107 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1108 /* TODO: use abc_call (for calling local variables),
1109 abc_callstatic (for calling own methods) */
1111 $$.c = abc_findpropstrict($$.c, $1->text);
1112 typedcode_list_t*l = $3;
1115 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1119 $$.c = abc_callproperty($$.c, $1->text, len);
1120 /* TODO: look up the functions's return value */
1124 MAYBE_EXPRESSION_LIST : {$$=0;}
1125 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1126 EXPRESSION_LIST : EXPRESSION {$$=list_new();
1127 typedcode_t*t = malloc(sizeof(typedcode_t));
1129 list_append($$, t);}
1130 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
1131 typedcode_t*t = malloc(sizeof(typedcode_t));
1133 list_append($$, t);}
1135 VAR_READ : T_IDENTIFIER {
1136 int i = find_variable($1->text, &$$.t);
1137 $$.c = abc_getlocal(0, i);
1140 //VARIABLE : T_IDENTIFIER
1141 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1142 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1143 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1144 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1145 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1147 // keywords which also may be identifiers
1148 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1150 GETSET : "get" {$$=$1;}
1152 | {$$=empty_token();}
1154 MAYBE_PARAM_LIST: {$$=list_new();}
1155 MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
1156 PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1; list_append($$, $3);}
1157 PARAM_LIST: PARAM {$$ = list_new();list_append($$, $1);}
1158 PARAM: T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
1159 $$->name=$1->text;$$->type = $3;}
1160 PARAM: T_IDENTIFIER {$$ = malloc(sizeof(param_t));
1161 $$->name=$1->text;$$->type = TYPE_ANY;}
1163 DECLARATION : VARIABLE_DECLARATION
1164 DECLARATION : FUNCTION_DECLARATION
1166 IDECLARATION : VARIABLE_DECLARATION
1167 IDECLARATION : FUNCTION_DECLARATION
1169 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1170 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1172 PACKAGEANDCLASS : T_IDENTIFIER {
1174 /* try current package */
1175 $$ = registry_findclass(state->package, $1->text);
1177 /* try explicit imports */
1178 dictentry_t* e = dict_get_slot(state->imports, $1->text);
1182 if(!strcmp(e->key, $1->text)) {
1183 $$ = (class_signature_t*)e->data;
1188 /* try package.* imports */
1189 import_list_t*l = state->wildcard_imports;
1193 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1194 $$ = registry_findclass(l->import->package, $1->text);
1198 /* try global package */
1200 $$ = registry_findclass("", $1->text);
1203 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1205 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1206 $$ = registry_findclass($1->text, $3->text);
1207 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1211 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1212 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1214 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1215 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1217 MAYBE_DECLARATION_LIST :
1218 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1219 DECLARATION_LIST : DECLARATION
1220 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1222 MAYBE_IDECLARATION_LIST :
1223 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1224 IDECLARATION_LIST : IDECLARATION
1225 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1228 // keywords: as break case catch class const continue default delete do else extends false finally for function if implements import in instanceof interface internal is native new null package private protected public return super switch this throw to true try typeof use var void while with
1229 // syntactic keywords: each get set namespace include dynamic final native override static