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)
672 /*TODO: can omit this if from is zero? */
673 return abc_coerce_a(c);
675 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
676 MULTINAME(m, TYPE_UINT);
677 return abc_coerce2(c, &m);
679 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
680 MULTINAME(m, TYPE_INT);
681 return abc_coerce2(c, &m);
686 code_t*defaultvalue(code_t*c, class_signature_t*type)
688 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
689 c = abc_pushbyte(c, 0);
690 } else if(TYPE_IS_BOOLEAN(type)) {
691 c = abc_pushfalse(c);
703 /* ------------ code blocks / statements ---------------- */
707 MAYBECODE: CODE {$$=$1;}
708 MAYBECODE: {$$=code_new();}
710 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
711 CODE: CODEPIECE {$$=$1;}
713 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
714 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
715 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
716 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
717 CODEPIECE: ';' {$$=code_new();}
718 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
719 CODEPIECE: VOIDEXPRESSION {$$=$1}
720 CODEPIECE: FOR {$$=$1}
721 CODEPIECE: WHILE {$$=$1}
722 CODEPIECE: BREAK {$$=$1}
723 CODEPIECE: IF {$$=$1}
724 CODEPIECE: ASSIGNMENT {$$=$1}
725 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
726 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
727 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
729 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
730 CODEBLOCK : CODEPIECE ';' {$$=$1;}
731 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
733 /* ------------ functions --------------------------- */
735 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
736 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
737 if(!state->m) syntaxerror("internal error: undefined function");
738 state->initcode = abc_nop(state->initcode);
739 state->initcode = abc_nop(state->initcode);
740 state->initcode = abc_nop(state->initcode);
741 state->m->code = code_append(state->initcode, $11);state->initcode=0;
745 /* ------------ variables --------------------------- */
747 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
748 | {$$.c=abc_pushundefined(0);
752 VAR : "const" | "var"
753 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
754 if(variable_exists($2->text))
755 syntaxerror("Variable %s already defined", $2->text);
757 if(!is_subtype_of($4.t, $3)) {
758 syntaxerror("Can't convert %s to %s", $4.t->name,
762 int index = new_variable($2->text, $3);
765 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
767 $$ = converttype($$, $4.t, $3);
768 $$ = abc_setlocal($$, index);
770 $$ = defaultvalue(0, $3);
771 $$ = abc_setlocal($$, index);
774 /* push default value for type on stack */
775 state->initcode = defaultvalue(state->initcode, $3);
776 state->initcode = abc_setlocal(state->initcode, index);
778 /* only bother to actually set this variable if its syntax is either
783 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
785 $$ = abc_coerce_a($$);
786 $$ = abc_setlocal($$, index);
792 /* that's the default for a local register, anyway
794 state->initcode = abc_pushundefined(state->initcode);
795 state->initcode = abc_setlocal(state->initcode, index);
797 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
799 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
800 class_signature_t*type=0;
801 int i = find_variable($1->text, &type);
804 // convert to "any" type, the register is untyped
805 $$ = abc_coerce_a($$);
807 // TODO: convert ints to strings etc.
809 $$ = abc_setlocal($$, i);
812 /* ------------ control flow ------------------------- */
814 MAYBEELSE: %prec prec_none {$$ = code_new();}
815 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
816 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
818 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
819 $$ = state->initcode;state->initcode=0;
821 $$ = code_append($$, $4.c);
822 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
824 $$ = code_append($$, $6);
826 myjmp = $$ = abc_jump($$, 0);
828 myif->branch = $$ = abc_label($$);
830 $$ = code_append($$, $7);
831 myjmp->branch = $$ = abc_label($$);
834 $$ = killvars($$);old_state();
837 FOR_INIT : {$$=code_new();}
838 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
840 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
841 $$ = state->initcode;state->initcode=0;
843 $$ = code_append($$, $4);
844 code_t*loopstart = $$ = abc_label($$);
845 $$ = code_append($$, $6.c);
846 code_t*myif = $$ = abc_iffalse($$, 0);
847 $$ = code_append($$, $10);
848 $$ = code_append($$, $8);
849 $$ = abc_jump($$, loopstart);
850 code_t*out = $$ = abc_label($$);
851 breakjumpsto($$, out);
854 $$ = killvars($$);old_state();
857 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
858 $$ = state->initcode;state->initcode=0;
860 code_t*myjmp = $$ = abc_jump($$, 0);
861 code_t*loopstart = $$ = abc_label($$);
862 $$ = code_append($$, $6);
863 myjmp->branch = $$ = abc_label($$);
864 $$ = code_append($$, $4.c);
865 $$ = abc_iftrue($$, loopstart);
866 code_t*out = $$ = abc_label($$);
867 breakjumpsto($$, out);
869 $$ = killvars($$);old_state();
873 $$ = abc___break__(0);
876 /* ------------ packages and imports ---------------- */
878 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
879 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
881 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
882 PACKAGE: X_IDENTIFIER {$$=$1;}
884 IMPORT : "import" PACKAGE '.' X_IDENTIFIER {
885 class_signature_t*c = registry_findclass($2->text, $4->text);
887 syntaxerror("Couldn't import %s.%s\n", $2->text, $4->text);
889 dict_put(state->imports, $4->text, c);
892 IMPORT : "import" PACKAGE '.' '*' {
894 i->package = $2->text;
896 list_append(state->wildcard_imports, i);
900 /* ------------ classes and interfaces -------------- */
902 MODIFIERS : {$$=empty_token();}
903 MODIFIERS : MODIFIER_LIST {$$=$1}
904 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
905 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
906 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
908 EXTENDS : {$$=registry_getobjectclass();}
909 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
911 EXTENDS_LIST : {$$=list_new();}
912 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
914 IMPLEMENTS_LIST : {$$=list_new();}
915 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
917 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
918 EXTENDS IMPLEMENTS_LIST
919 '{' {startclass($1,$3,$4,$5, 0);}
920 MAYBE_DECLARATION_LIST
922 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
924 '{' {startclass($1,$3,0,$4,1);}
925 MAYBE_IDECLARATION_LIST
928 TYPE : PACKAGEANDCLASS {$$=$1;}
929 | '*' {$$=registry_getanytype();}
930 | "String" {$$=registry_getstringclass();}
931 | "int" {$$=registry_getintclass();}
932 | "uint" {$$=registry_getuintclass();}
933 | "Boolean" {$$=registry_getbooleanclass();}
934 | "Number" {$$=registry_getnumberclass();}
936 MAYBETYPE: ':' TYPE {$$=$2;}
939 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
940 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
943 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
944 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
945 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
947 //NAMESPACE : {$$=empty_token();}
948 //NAMESPACE : T_IDENTIFIER {$$=$1};
950 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
951 //MULTINAME(m, registry_getintclass());
952 //$$.c = abc_coerce2($$.c, &m); // FIXME
955 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
958 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
961 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
964 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
967 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
970 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
973 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
976 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
980 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
983 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
984 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
987 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
989 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
993 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
996 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
999 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1000 $$.t = TYPE_BOOLEAN;
1002 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1003 $$.t = TYPE_BOOLEAN;
1005 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1006 $$.t = TYPE_BOOLEAN;
1008 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1009 $$.t = TYPE_BOOLEAN;
1011 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1012 $$.t = TYPE_BOOLEAN;
1015 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1017 $$.c = converttype($$.c, $1.t, $$.t);
1018 $$.c = abc_dup($$.c);
1019 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1020 $$.c = abc_pop($$.c);
1021 $$.c = code_append($$.c,$3.c);
1022 $$.c = converttype($$.c, $1.t, $$.t);
1023 code_t*label = $$.c = abc_label($$.c);
1024 jmp->branch = label;
1026 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1028 $$.c = converttype($$.c, $1.t, $$.t);
1029 $$.c = abc_dup($$.c);
1030 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1031 $$.c = abc_pop($$.c);
1032 $$.c = code_append($$.c,$3.c);
1033 $$.c = converttype($$.c, $1.t, $$.t);
1034 code_t*label = $$.c = abc_label($$.c);
1035 jmp->branch = label;
1038 E : '!' E {$$.c=$2.c;
1039 $$.c = abc_not($$.c);
1040 $$.t = TYPE_BOOLEAN;
1045 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1046 $$.t = join_types($1.t, $3.t, '+');
1048 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1049 $$.t = join_types($1.t, $3.t, '%');
1051 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1052 $$.t = join_types($1.t, $3.t, '*');
1057 E : '(' E ')' {$$=$2;}
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);
1066 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1067 class_signature_t*type = join_types($1.type, $3.t, '-');
1068 $$.c=converttype($$.c, type, $1.type);
1069 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1073 // TODO: use inclocal where appropriate
1074 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
1075 class_signature_t*type = $1.type;
1076 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1077 $$.c=converttype($$.c, type, $1.type);
1078 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1081 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
1082 class_signature_t*type = $1.type;
1083 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1084 $$.c=converttype($$.c, 0, $1.type);
1085 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1090 int i = find_variable($1->text, &$$.type);
1091 $$.read = abc_getlocal(0, i);
1092 $$.write = abc_setlocal(0, i);
1095 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
1096 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1098 NEW : "new" PACKAGEANDCLASS MAYBE_PARAM_VALUES {
1101 $$.c = abc_findpropstrict2($$.c, &m);
1102 typedcode_list_t*l = $3;
1105 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1109 $$.c = abc_constructprop2($$.c, &m, len);
1113 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1114 /* TODO: use abc_call (for calling local variables),
1115 abc_callstatic (for calling own methods) */
1117 $$.c = abc_findpropstrict($$.c, $1->text);
1118 typedcode_list_t*l = $3;
1121 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1125 $$.c = abc_callproperty($$.c, $1->text, len);
1126 /* TODO: look up the functions's return value */
1130 MAYBE_EXPRESSION_LIST : {$$=0;}
1131 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1132 EXPRESSION_LIST : EXPRESSION {$$=list_new();
1133 typedcode_t*t = malloc(sizeof(typedcode_t));
1135 list_append($$, t);}
1136 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
1137 typedcode_t*t = malloc(sizeof(typedcode_t));
1139 list_append($$, t);}
1141 VAR_READ : T_IDENTIFIER {
1142 int i = find_variable($1->text, &$$.t);
1143 $$.c = abc_getlocal(0, i);
1146 //VARIABLE : T_IDENTIFIER
1147 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1148 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1149 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1150 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1151 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1153 // keywords which also may be identifiers
1154 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1156 GETSET : "get" {$$=$1;}
1158 | {$$=empty_token();}
1160 MAYBE_PARAM_LIST: {$$=list_new();}
1161 MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
1162 PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1; list_append($$, $3);}
1163 PARAM_LIST: PARAM {$$ = list_new();list_append($$, $1);}
1164 PARAM: T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
1165 $$->name=$1->text;$$->type = $3;}
1166 PARAM: T_IDENTIFIER {$$ = malloc(sizeof(param_t));
1167 $$->name=$1->text;$$->type = TYPE_ANY;}
1169 DECLARATION : VARIABLE_DECLARATION
1170 DECLARATION : FUNCTION_DECLARATION
1172 IDECLARATION : VARIABLE_DECLARATION
1173 IDECLARATION : FUNCTION_DECLARATION
1175 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1176 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1178 PACKAGEANDCLASS : T_IDENTIFIER {
1180 /* try current package */
1181 $$ = registry_findclass(state->package, $1->text);
1183 /* try explicit imports */
1184 dictentry_t* e = dict_get_slot(state->imports, $1->text);
1188 if(!strcmp(e->key, $1->text)) {
1189 $$ = (class_signature_t*)e->data;
1194 /* try package.* imports */
1195 import_list_t*l = state->wildcard_imports;
1199 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1200 $$ = registry_findclass(l->import->package, $1->text);
1204 /* try global package */
1206 $$ = registry_findclass("", $1->text);
1209 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1211 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1212 $$ = registry_findclass($1->text, $3->text);
1213 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1217 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1218 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1220 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1221 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1223 MAYBE_DECLARATION_LIST :
1224 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1225 DECLARATION_LIST : DECLARATION
1226 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1228 MAYBE_IDECLARATION_LIST :
1229 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1230 IDECLARATION_LIST : IDECLARATION
1231 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1234 // 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
1235 // syntactic keywords: each get set namespace include dynamic final native override static