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;
53 writeable_t writeable;
58 %token<token> T_IDENTIFIER
59 %token<string> T_STRING
60 %token<token> T_REGEXP
62 %token<number_int> T_INT
63 %token<number_uint> T_UINT
64 %token<number_uint> T_BYTE
65 %token<number_uint> T_SHORT
66 %token<number_float> T_FLOAT
68 %token<token> KW_IMPLEMENTS
69 %token<token> KW_NAMESPACE "namespace"
70 %token<token> KW_PACKAGE "package"
71 %token<token> KW_PROTECTED
72 %token<token> KW_PUBLIC
73 %token<token> KW_PRIVATE
74 %token<token> KW_USE "use"
75 %token<token> KW_INTERNAL
76 %token<token> KW_NEW "new"
77 %token<token> KW_NATIVE
78 %token<token> KW_FUNCTION "function"
79 %token<token> KW_FOR "for"
80 %token<token> KW_CLASS "class"
81 %token<token> KW_CONST "const"
82 %token<token> KW_SET "set"
83 %token<token> KW_STATIC
84 %token<token> KW_IMPORT "import"
85 %token<token> KW_INTERFACE "interface"
87 %token<token> KW_VAR "var"
88 %token<token> KW_DYNAMIC
89 %token<token> KW_OVERRIDE
90 %token<token> KW_FINAL
91 %token<token> KW_GET "get"
92 %token<token> KW_EXTENDS
93 %token<token> KW_FALSE "false"
94 %token<token> KW_TRUE "true"
95 %token<token> KW_BOOLEAN "Boolean"
96 %token<token> KW_UINT "uint"
97 %token<token> KW_INT "int"
98 %token<token> KW_WHILE "while"
99 %token<token> KW_NUMBER "Number"
100 %token<token> KW_STRING "String"
101 %token<token> KW_IF "if"
102 %token<token> KW_ELSE "else"
103 %token<token> KW_BREAK "break"
104 %token<token> KW_IS "is"
105 %token<token> KW_AS "as"
107 %token<token> T_EQEQ "=="
108 %token<token> T_EQEQEQ "==="
109 %token<token> T_NE "!="
110 %token<token> T_LE "<="
111 %token<token> T_GE ">="
112 %token<token> T_DIVBY "/="
113 %token<token> T_MODBY "%="
114 %token<token> T_PLUSBY "+="
115 %token<token> T_MINUSBY "-="
116 %token<token> T_SHRBY ">>="
117 %token<token> T_SHLBY "<<="
118 %token<token> T_USHRBY ">>>="
119 %token<token> T_OROR "||"
120 %token<token> T_ANDAND "&&"
121 %token<token> T_COLONCOLON "::"
122 %token<token> T_MINUSMINUS "--"
123 %token<token> T_PLUSPLUS "++"
124 %token<token> T_DOTDOT ".."
125 %token<token> T_SHL "<<"
126 %token<token> T_USHR ">>>"
127 %token<token> T_SHR ">>"
128 %token<token> T_SEMICOLON ';'
129 %token<token> T_STAR '*'
130 %token<token> T_DOT '.'
133 %type <code> CODEPIECE
134 %type <code> CODEBLOCK MAYBECODE
135 %type <token> PACKAGE_DECLARATION
136 %type <token> FUNCTION_DECLARATION
137 %type <code> VARIABLE_DECLARATION
138 %type <token> CLASS_DECLARATION
139 %type <token> NAMESPACE_DECLARATION
140 %type <token> INTERFACE_DECLARATION
141 %type <code> VOIDEXPRESSION
142 %type <value> EXPRESSION
143 %type <value> MAYBEEXPRESSION
146 %type <value> CONSTANT
147 %type <code> FOR IF WHILE MAYBEELSE BREAK
148 %type <token> USE_NAMESPACE
149 %type <code> ASSIGNMENT FOR_INIT
151 %type <class_signature> MAYBETYPE
155 %type <token> PARAM_LIST
156 %type <token> MODIFIERS
157 %type <token> MODIFIER_LIST
158 %type <class_signature_list> IMPLEMENTS_LIST
159 %type <class_signature> EXTENDS
160 %type <class_signature_list> EXTENDS_LIST
161 %type <class_signature> PACKAGEANDCLASS
162 %type <class_signature_list> PACKAGEANDCLASS_LIST
163 %type <token> MULTILEVELIDENTIFIER
164 %type <class_signature> TYPE
166 //%type <token> VARIABLE
167 %type <value> VAR_READ
169 %type <token> X_IDENTIFIER
170 %type <token> MODIFIER
171 %type <token> PACKAGE
172 %type <value> FUNCTIONCALL
173 %type <value_list> MAYBE_EXPRESSION_LIST EXPRESSION_LIST
175 // precendence: from low to high
176 // http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000012.html
191 %nonassoc "!=" "==" "===" "<=" '<' ">=" '>' // TODO: support "a < b < c" syntax?
207 %nonassoc T_IDENTIFIER
208 %left below_semicolon
217 static int yyerror(char*s)
219 syntaxerror("%s", s);
221 static token_t* concat2(token_t* t1, token_t* t2)
224 int l1 = strlen(t1->text);
225 int l2 = strlen(t2->text);
226 t->text = malloc(l1+l2+1);
227 memcpy(t->text , t1->text, l1);
228 memcpy(t->text+l1, t2->text, l2);
232 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
235 int l1 = strlen(t1->text);
236 int l2 = strlen(t2->text);
237 int l3 = strlen(t3->text);
238 t->text = malloc(l1+l2+l3+1);
239 memcpy(t->text , t1->text, l1);
240 memcpy(t->text+l1, t2->text, l2);
241 memcpy(t->text+l1+l2, t3->text, l3);
242 t->text[l1+l2+l3] = 0;
245 static char* concat3str(const char* t1, const char* t2, const char* t3)
250 char*text = malloc(l1+l2+l3+1);
251 memcpy(text , t1, l1);
252 memcpy(text+l1, t2, l2);
253 memcpy(text+l1+l2, t3, l3);
258 typedef struct _import {
262 DECLARE_LIST(import);
264 typedef struct _state {
272 /* code that needs to be executed at the start of
273 a method (like initializing local registers) */
278 import_list_t*wildcard_imports;
280 char has_own_imports;
290 static state_t* state = 0;
294 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
296 static state_list_t*state_stack=0;
298 static void new_state()
301 NEW(state_list_t, sl);
303 state_t*oldstate = state;
305 memcpy(s, state, sizeof(state_t)); //shallow copy
306 sl->next = state_stack;
309 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
312 s->imports = dict_new();
317 state->vars = array_new();
319 state->has_own_imports = 0;
321 static void state_has_imports()
323 state->wildcard_imports = list_clone(state->wildcard_imports);
324 state->imports = dict_clone(state->imports);
325 state->has_own_imports = 1;
328 static void old_state()
330 if(!state_stack || !state_stack->next)
331 syntaxerror("invalid nesting");
332 state_t*oldstate = state;
333 state_list_t*old = state_stack;
334 state_stack = state_stack->next;
336 state = state_stack->state;
337 /*if(state->initcode) {
338 printf("residual initcode\n");
339 code_dump(state->initcode, 0, 0, "", stdout);
341 if(oldstate->has_own_imports) {
342 list_free(oldstate->wildcard_imports);
343 dict_destroy(oldstate->imports);oldstate->imports=0;
345 state->initcode = code_append(state->initcode, oldstate->initcode);
347 void initialize_state()
351 state->file = abc_file_new();
352 state->file->flags &= ~ABCFILE_LAZY;
354 state->init = abc_initscript(state->file, 0, 0);
355 abc_method_body_t*m = state->init->method->body;
358 __ findpropstrict(m, "[package]::trace");
359 __ pushstring(m, "[entering global init function]");
360 __ callpropvoid(m, "[package]::trace", 1);
362 void* finalize_state()
364 if(state->level!=1) {
365 syntaxerror("unexpected end of file");
367 abc_method_body_t*m = state->init->method->body;
370 __ findpropstrict(m, "[package]::trace");
371 __ pushstring(m, "[leaving global init function]");
372 __ callpropvoid(m, "[package]::trace", 1);
378 static void startpackage(token_t*t)
381 syntaxerror("Packages can not be nested.");
384 char*name = t?t->text:"";
385 /*printf("entering package \"%s\"\n", name);*/
386 state->package = name;
388 static void endpackage()
390 /*printf("leaving package \"%s\"\n", state->package);*/
395 static void startclass(token_t*modifiers, token_t*name, class_signature_t*extends, class_signature_list_t*implements, char interface)
398 syntaxerror("inner classes now allowed");
401 state->classname = name->text;
404 class_signature_list_t*mlist=0;
405 /*printf("entering class %s\n", name->text);
406 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
408 printf(" extends: %s.%s\n", extends->package, extends->name);
409 printf(" implements (%d): ", list_length(implements));
410 for(mlist=implements;mlist;mlist=mlist->next) {
411 printf("%s ", mlist->class_signature?mlist->class_signature->name:0);
416 char public=0,internal=0,final=0,sealed=1;
417 for(t=modifiers->tokens;t;t=t->next) {
418 if(t->token->type == KW_INTERNAL) {
419 /* the programmer is being explicit-
420 being internal is the default anyway */
422 } else if(t->token->type == KW_PUBLIC) {
424 } else if(t->token->type == KW_FINAL) {
427 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
431 syntaxerror("public and internal not supported at the same time.");
433 /* create the class name, together with the proper attributes */
437 if(!public && !state->package) {
438 access = ACCESS_PRIVATE; package = current_filename;
439 } else if(!public && state->package) {
440 access = ACCESS_PACKAGEINTERNAL; package = state->package;
441 } else if(state->package) {
442 access = ACCESS_PACKAGE; package = state->package;
444 syntaxerror("public classes only allowed inside a package");
447 if(registry_findclass(package, state->classname)) {
448 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
451 class_signature_t* classname = class_signature_register(access, package, state->classname);
453 MULTINAME(classname2,classname);
455 multiname_t*extends2 = sig2mname(extends);
457 state->cls = abc_class_new(state->file, &classname2, extends2);
458 if(final) abc_class_final(state->cls);
459 if(sealed) abc_class_sealed(state->cls);
460 if(interface) abc_class_interface(state->cls);
462 for(mlist=implements;mlist;mlist=mlist->next) {
463 MULTINAME(m, mlist->class_signature);
464 abc_class_add_interface(state->cls, &m);
467 /* now write the construction code for this class */
468 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
470 abc_method_body_t*m = state->init->method->body;
471 __ getglobalscope(m);
472 class_signature_t*s = extends;
477 //TODO: take a look at the current scope stack, maybe
478 // we can re-use something
483 multiname_t*s2 = sig2mname(s);
485 multiname_destroy(s2);
488 m->code = m->code->prev->prev; // invert
491 /* continue appending after last op end */
492 while(m->code && m->code->next) m->code = m->code->next;
494 /* TODO: if this is one of *our* classes, we can also
495 do a getglobalscope/getslot <nr> (which references
496 the init function's slots) */
498 __ getlex2(m, extends2);
500 __ pushscope(m); // we get a Verify Error #1107 if this is not the top scope
504 __ newclass(m,state->cls);
508 __ setslot(m, slotindex);
510 /* flash.display.MovieClip handling */
511 if(!globalclass && public && class_signature_equals(registry_getMovieClip(),extends)) {
512 if(state->package && state->package[0]) {
513 globalclass = concat3str(state->package, ".", state->classname);
515 globalclass = strdup(state->classname);
518 multiname_destroy(extends2);
521 static void endclass()
523 /*printf("leaving class %s\n", state->classname);*/
526 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
527 token_t*params, class_signature_t*type)
531 state->function = name->text;
533 /*printf("entering function %s\n", name->text);
535 printf(" namespace: %s\n", ns->text);
536 printf(" getset: %s\n", getset->text);
537 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
538 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
540 printf(" type: %s.%s\n", type->package, type->name);
544 syntaxerror("not able to start another method scope");
547 multiname_t*type2 = sig2mname(type);
549 if(!strcmp(state->classname,name->text)) {
550 state->m = abc_class_constructor(state->cls, type2, 0);
552 state->m = abc_class_method(state->cls, type2, name->text, 0);
554 /* state->vars is initialized by state_new */
555 array_append(state->vars, "this", 0);
557 __ getlocal_0(state->m);
558 __ pushscope(state->m);
560 multiname_destroy(type2);
562 static void endfunction()
564 /*printf("leaving function %s\n", state->function);*/
565 __ returnvoid(state->m);
571 static token_t* empty_token()
579 void extend(token_t*list, token_t*add) {
580 list_append(list->tokens,add);
582 list->text = add->text;
584 void extend_s(token_t*list, char*seperator, token_t*add) {
585 list_append(list->tokens,add);
586 char*t1 = list->text;
592 list->text = malloc(l1+l2+l3+1);
593 strcpy(list->text, t1);
594 strcpy(list->text+l1, t2);
595 strcpy(list->text+l1+l2, t3);
596 list->text[l1+l2+l3]=0;
599 static int find_variable(char*name, class_signature_t**m)
601 state_list_t* s = state_stack;
603 int i = array_find(s->state->vars, name);
606 *m = array_getvalue(s->state->vars, i);
608 return i + s->state->local_var_base;
612 syntaxerror("undefined variable: %s", name);
614 static char variable_exists(char*name)
616 return array_contains(state->vars, name);
618 static int new_variable(char*name, class_signature_t*type)
620 return array_append(state->vars, name, type) + state->local_var_base;
622 code_t* killvars(code_t*c)
625 for(t=0;t<state->vars->num;t++) {
626 class_signature_t*type = array_getvalue(state->vars, t);
627 //do this always, otherwise register types don't match
628 //in the verifier when doing nested loops
629 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
630 c = abc_kill(c, t+state->local_var_base);
636 class_signature_t*join_types(class_signature_t*type1, class_signature_t*type2, char op)
638 return registry_getanytype(); // FIXME
640 char is_subtype_of(class_signature_t*type, class_signature_t*supertype)
645 void breakjumpsto(code_t*c, code_t*jump)
650 if(c->opcode == OPCODE___BREAK__) {
651 c->opcode = OPCODE_JUMP;
657 code_t*converttype(code_t*c, class_signature_t*from, class_signature_t*to)
660 /*TODO: can omit this if from is zero? */
661 return abc_coerce_a(c);
663 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
664 MULTINAME(m, TYPE_UINT);
665 return abc_coerce2(c, &m);
667 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
668 MULTINAME(m, TYPE_INT);
669 return abc_coerce2(c, &m);
674 code_t*defaultvalue(code_t*c, class_signature_t*type)
676 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
677 c = abc_pushbyte(c, 0);
678 } else if(TYPE_IS_BOOLEAN(type)) {
679 c = abc_pushfalse(c);
691 /* ------------ code blocks / statements ---------------- */
695 MAYBECODE: CODE {$$=$1;}
696 MAYBECODE: {$$=code_new();}
698 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
699 CODE: CODEPIECE {$$=$1;}
701 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
702 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
703 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
704 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
705 CODEPIECE: ';' {$$=code_new();}
706 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
707 CODEPIECE: VOIDEXPRESSION {$$=$1}
708 CODEPIECE: FOR {$$=$1}
709 CODEPIECE: WHILE {$$=$1}
710 CODEPIECE: BREAK {$$=$1}
711 CODEPIECE: IF {$$=$1}
712 CODEPIECE: ASSIGNMENT {$$=$1}
713 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
714 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
715 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
717 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
718 CODEBLOCK : CODEPIECE ';' {$$=$1;}
719 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
721 /* ------------ functions --------------------------- */
723 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
724 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
725 if(!state->m) syntaxerror("internal error: undefined function");
726 state->initcode = abc_nop(state->initcode);
727 state->initcode = abc_nop(state->initcode);
728 state->initcode = abc_nop(state->initcode);
729 state->m->code = code_append(state->initcode, $11);state->initcode=0;
733 /* ------------ variables --------------------------- */
735 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
736 | {$$.c=abc_pushundefined(0);
740 VAR : "const" | "var"
741 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
742 if(variable_exists($2->text))
743 syntaxerror("Variable %s already defined", $2->text);
745 if(!is_subtype_of($4.t, $3)) {
746 syntaxerror("Can't convert %s to %s", $4.t->name,
750 int index = new_variable($2->text, $3);
753 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
755 $$ = converttype($$, $4.t, $3);
756 $$ = abc_setlocal($$, index);
758 $$ = defaultvalue(0, $3);
759 $$ = abc_setlocal($$, index);
762 /* push default value for type on stack */
763 state->initcode = defaultvalue(state->initcode, $3);
764 state->initcode = abc_setlocal(state->initcode, index);
766 /* only bother to actually set this variable if its syntax is either
771 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
773 $$ = abc_coerce_a($$);
774 $$ = abc_setlocal($$, index);
780 /* that's the default for a local register, anyway
782 state->initcode = abc_pushundefined(state->initcode);
783 state->initcode = abc_setlocal(state->initcode, index);
785 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
787 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
788 class_signature_t*type=0;
789 int i = find_variable($1->text, &type);
792 // convert to "any" type, the register is untyped
793 $$ = abc_coerce_a($$);
795 // TODO: convert ints to strings etc.
797 $$ = abc_setlocal($$, i);
800 /* ------------ control flow ------------------------- */
802 MAYBEELSE: %prec prec_none {$$ = code_new();}
803 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
804 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
806 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
807 $$ = state->initcode;state->initcode=0;
809 $$ = code_append($$, $4.c);
810 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
812 $$ = code_append($$, $6);
814 myjmp = $$ = abc_jump($$, 0);
816 myif->branch = $$ = abc_label($$);
818 $$ = code_append($$, $7);
819 myjmp->branch = $$ = abc_label($$);
822 $$ = killvars($$);old_state();
825 FOR_INIT : {$$=code_new();}
826 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
828 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
829 $$ = state->initcode;state->initcode=0;
831 $$ = code_append($$, $4);
832 code_t*loopstart = $$ = abc_label($$);
833 $$ = code_append($$, $6.c);
834 code_t*myif = $$ = abc_iffalse($$, 0);
835 $$ = code_append($$, $10);
836 $$ = code_append($$, $8);
837 $$ = abc_jump($$, loopstart);
838 code_t*out = $$ = abc_label($$);
839 breakjumpsto($$, out);
842 $$ = killvars($$);old_state();
845 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
846 $$ = state->initcode;state->initcode=0;
848 code_t*myjmp = $$ = abc_jump($$, 0);
849 code_t*loopstart = $$ = abc_label($$);
850 $$ = code_append($$, $6);
851 myjmp->branch = $$ = abc_label($$);
852 $$ = code_append($$, $4.c);
853 $$ = abc_iftrue($$, loopstart);
854 code_t*out = $$ = abc_label($$);
855 breakjumpsto($$, out);
857 $$ = killvars($$);old_state();
861 $$ = abc___break__(0);
864 /* ------------ packages and imports ---------------- */
866 PACKAGE_DECLARATION : "package" MULTILEVELIDENTIFIER '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
867 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
869 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
870 PACKAGE: X_IDENTIFIER {$$=$1;}
872 IMPORT : "import" PACKAGE '.' X_IDENTIFIER {
873 class_signature_t*c = registry_findclass($2->text, $4->text);
875 syntaxerror("Couldn't import %s.%s\n", $2->text, $4->text);
877 dict_put(state->imports, $4->text, c);
880 IMPORT : "import" PACKAGE '.' '*' {
882 i->package = $2->text;
884 list_append(state->wildcard_imports, i);
888 /* ------------ classes and interfaces -------------- */
890 MODIFIERS : {$$=empty_token();}
891 MODIFIERS : MODIFIER_LIST {$$=$1}
892 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
893 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
894 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
896 EXTENDS : {$$=registry_getobjectclass();}
897 EXTENDS : KW_EXTENDS PACKAGEANDCLASS {$$=$2;}
899 EXTENDS_LIST : {$$=list_new();}
900 EXTENDS_LIST : KW_EXTENDS PACKAGEANDCLASS_LIST {$$=$2;}
902 IMPLEMENTS_LIST : {$$=list_new();}
903 IMPLEMENTS_LIST : KW_IMPLEMENTS PACKAGEANDCLASS_LIST {$$=$2;}
905 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
906 EXTENDS IMPLEMENTS_LIST
907 '{' {startclass($1,$3,$4,$5, 0);}
908 MAYBE_DECLARATION_LIST
910 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
912 '{' {startclass($1,$3,0,$4,1);}
913 MAYBE_IDECLARATION_LIST
916 TYPE : PACKAGEANDCLASS {$$=$1;}
917 | '*' {$$=registry_getanytype();}
918 | "String" {$$=registry_getstringclass();}
919 | "int" {$$=registry_getintclass();}
920 | "uint" {$$=registry_getuintclass();}
921 | "Boolean" {$$=registry_getbooleanclass();}
922 | "Number" {$$=registry_getnumberclass();}
924 MAYBETYPE: ':' TYPE {$$=$2;}
927 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
928 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' PARAMS ')'
931 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
932 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
933 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
935 //NAMESPACE : {$$=empty_token();}
936 //NAMESPACE : T_IDENTIFIER {$$=$1};
938 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
939 //MULTINAME(m, registry_getintclass());
940 //$$.c = abc_coerce2($$.c, &m); // FIXME
943 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
946 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
949 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
952 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
955 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
958 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
961 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
964 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
968 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
971 EXPRESSION : E %prec prec_none /*precendence below '-x'*/ {$$ = $1;}
972 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
975 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
976 E : NEW {$$.c = abc_pushundefined(0); /* FIXME */
979 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
983 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
986 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
989 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
992 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
995 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
998 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1001 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1002 $$.t = TYPE_BOOLEAN;
1007 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1008 $$.t = join_types($1.t, $3.t, '+');
1010 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1011 $$.t = join_types($1.t, $3.t, '%');
1013 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1014 $$.t = join_types($1.t, $3.t, '*');
1019 E : '(' E ')' {$$=$2;}
1022 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1023 class_signature_t*type = join_types($1.type, $3.t, '+');
1024 $$.c=converttype($$.c, type, $1.type);
1025 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1028 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1029 class_signature_t*type = join_types($1.type, $3.t, '-');
1030 $$.c=converttype($$.c, type, $1.type);
1031 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1035 // TODO: use inclocal where appropriate
1036 E : LH "++" {$$.c = $1.read;$$.c=abc_increment($$.c);
1037 class_signature_t*type = $1.type;
1038 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1039 $$.c=converttype($$.c, type, $1.type);
1040 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1043 E : LH "--" {$$.c = $1.read;$$.c=abc_decrement($$.c);
1044 class_signature_t*type = $1.type;
1045 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) type = TYPE_NUMBER;
1046 $$.c=converttype($$.c, 0, $1.type);
1047 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1052 int i = find_variable($1->text, &$$.type);
1053 $$.read = abc_getlocal(0, i);
1054 $$.write = abc_setlocal(0, i);
1057 NEW : "new" T_IDENTIFIER {$$.c=0;$$.t=0;/*FIXME*/}
1058 | "new" T_IDENTIFIER '(' ')' {$$.c=0;$$.t=0;/*FIXME*/}
1059 | "new" T_IDENTIFIER '(' EXPRESSION_LIST ')' {$$.c=0;$$.t=0;/*FIXME*/}
1061 FUNCTIONCALL : T_IDENTIFIER '(' MAYBE_EXPRESSION_LIST ')' {
1062 /* TODO: use abc_call (for calling local variables),
1063 abc_callstatic (for calling own methods) */
1065 $$.c = abc_findpropstrict($$.c, $1->text);
1066 typedcode_list_t*l = $3;
1067 // push parameters on stack
1070 $$.c = code_append($$.c, l->typedcode.c);
1074 $$.c = abc_callproperty($$.c, $1->text, len);
1077 MAYBE_EXPRESSION_LIST : {$$=0;}
1078 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1079 EXPRESSION_LIST : EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1081 $$->typedcode = $1;}
1082 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=malloc(sizeof(typedcode_list_t));
1087 VAR_READ : T_IDENTIFIER {
1088 int i = find_variable($1->text, &$$.t);
1089 $$.c = abc_getlocal(0, i);
1092 //VARIABLE : T_IDENTIFIER
1093 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1094 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1095 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1096 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1097 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1099 // keywords which also may be identifiers
1100 X_IDENTIFIER : T_IDENTIFIER | KW_PACKAGE
1102 GETSET : "get" {$$=$1;}
1104 | {$$=empty_token();}
1106 PARAMS: {$$=empty_token();}
1107 PARAMS: PARAM_LIST {$$=$1;}
1108 PARAM_LIST: PARAM_LIST ',' PARAM {extend($1,$3);$$=$1;}
1109 PARAM_LIST: PARAM {$$=empty_token();extend($$,$1);}
1110 PARAM: T_IDENTIFIER ':' TYPE {$$=$1;}
1112 DECLARATION : VARIABLE_DECLARATION
1113 DECLARATION : FUNCTION_DECLARATION
1115 IDECLARATION : VARIABLE_DECLARATION
1116 IDECLARATION : FUNCTION_DECLARATION
1118 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1119 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1121 PACKAGEANDCLASS : T_IDENTIFIER {
1122 $$ = registry_findclass(state->package, $1->text);
1123 import_list_t*l = state->wildcard_imports;
1127 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
1128 $$ = registry_findclass(l->import->package, $1->text);
1131 dictentry_t* e = dict_get_slot(state->imports, $1->text);
1135 if(!strcmp(e->key, $1->text)) {
1136 $$ = (class_signature_t*)e->data;
1140 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
1142 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
1143 $$ = registry_findclass($1->text, $3->text);
1144 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
1148 MULTILEVELIDENTIFIER : MULTILEVELIDENTIFIER '.' X_IDENTIFIER {$$=$1;extend_s($$, ".", $3)}
1149 MULTILEVELIDENTIFIER : T_IDENTIFIER {$$=$1;extend($$,$1)};
1151 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS {$$=list_new();list_append($$, $1);}
1152 PACKAGEANDCLASS_LIST : PACKAGEANDCLASS_LIST ',' PACKAGEANDCLASS {$$=$1;list_append($$,$3);}
1154 MAYBE_DECLARATION_LIST :
1155 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1156 DECLARATION_LIST : DECLARATION
1157 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1159 MAYBE_IDECLARATION_LIST :
1160 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1161 IDECLARATION_LIST : IDECLARATION
1162 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1165 // 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
1166 // syntactic keywords: each get set namespace include dynamic final native override static