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 classinfo_t*classinfo;
45 classinfo_list_t*classinfo_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"
89 %token<token> KW_NULL "null"
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 '.'
135 %type <token> X_IDENTIFIER
137 %type <code> CODEPIECE
138 %type <code> CODEBLOCK MAYBECODE
139 %type <token> PACKAGE_DECLARATION
140 %type <token> FUNCTION_DECLARATION
141 %type <code> VARIABLE_DECLARATION
142 %type <token> CLASS_DECLARATION
143 %type <token> NAMESPACE_DECLARATION
144 %type <token> INTERFACE_DECLARATION
145 %type <code> VOIDEXPRESSION
146 %type <value> EXPRESSION
147 %type <value> MAYBEEXPRESSION
150 %type <value> CONSTANT
151 %type <code> FOR IF WHILE MAYBEELSE BREAK RETURN
152 %type <token> USE_NAMESPACE
153 %type <code> ASSIGNMENT FOR_INIT
155 %type <classinfo> MAYBETYPE
158 %type <param_list> PARAM_LIST
159 %type <param_list> MAYBE_PARAM_LIST
160 %type <token> MODIFIERS
161 %type <token> MODIFIER_LIST
162 %type <classinfo_list> IMPLEMENTS_LIST
163 %type <classinfo> EXTENDS
164 %type <classinfo_list> EXTENDS_LIST
165 %type <classinfo> CLASS PACKAGEANDCLASS QNAME
166 %type <classinfo_list> QNAME_LIST
167 %type <classinfo> TYPE
169 //%type <token> VARIABLE
170 %type <value> VAR_READ
172 //%type <token> T_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
216 // needed for "return" precedence:
217 %nonassoc T_STRING T_REGEXP
218 %nonassoc T_INT T_UINT T_BYTE T_SHORT T_FLOAT
219 %nonassoc "new" "false" "true" "null"
226 static int yyerror(char*s)
228 syntaxerror("%s", s);
230 static token_t* concat2(token_t* t1, token_t* t2)
233 int l1 = strlen(t1->text);
234 int l2 = strlen(t2->text);
235 t->text = malloc(l1+l2+1);
236 memcpy(t->text , t1->text, l1);
237 memcpy(t->text+l1, t2->text, l2);
241 static token_t* concat3(token_t* t1, token_t* t2, token_t* t3)
244 int l1 = strlen(t1->text);
245 int l2 = strlen(t2->text);
246 int l3 = strlen(t3->text);
247 t->text = malloc(l1+l2+l3+1);
248 memcpy(t->text , t1->text, l1);
249 memcpy(t->text+l1, t2->text, l2);
250 memcpy(t->text+l1+l2, t3->text, l3);
251 t->text[l1+l2+l3] = 0;
254 static char* concat3str(const char* t1, const char* t2, const char* t3)
259 char*text = malloc(l1+l2+l3+1);
260 memcpy(text , t1, l1);
261 memcpy(text+l1, t2, l2);
262 memcpy(text+l1+l2, t3, l3);
267 typedef struct _import {
271 DECLARE_LIST(import);
273 typedef struct _state {
281 /* code that needs to be executed at the start of
282 a method (like initializing local registers) */
287 import_list_t*wildcard_imports;
289 char has_own_imports;
299 static state_t* state = 0;
303 #define MULTINAME(m,x) multiname_t m;namespace_t m##_ns;registry_fill_multiname(&m, &m##_ns, x);
305 static state_list_t*state_stack=0;
307 static void new_state()
310 NEW(state_list_t, sl);
312 state_t*oldstate = state;
314 memcpy(s, state, sizeof(state_t)); //shallow copy
315 sl->next = state_stack;
318 s->local_var_base = array_length(oldstate->vars) + oldstate->local_var_base;
321 s->imports = dict_new();
326 state->vars = array_new();
328 state->has_own_imports = 0;
330 static void state_has_imports()
332 state->wildcard_imports = list_clone(state->wildcard_imports);
333 state->imports = dict_clone(state->imports);
334 state->has_own_imports = 1;
337 static void old_state()
339 if(!state_stack || !state_stack->next)
340 syntaxerror("invalid nesting");
341 state_t*oldstate = state;
342 state_list_t*old = state_stack;
343 state_stack = state_stack->next;
345 state = state_stack->state;
346 /*if(state->initcode) {
347 printf("residual initcode\n");
348 code_dump(state->initcode, 0, 0, "", stdout);
350 if(oldstate->has_own_imports) {
351 list_free(oldstate->wildcard_imports);
352 dict_destroy(oldstate->imports);oldstate->imports=0;
354 state->initcode = code_append(state->initcode, oldstate->initcode);
356 void initialize_state()
360 state->file = abc_file_new();
361 state->file->flags &= ~ABCFILE_LAZY;
363 state->init = abc_initscript(state->file, 0, 0);
364 abc_method_body_t*m = state->init->method->body;
367 __ findpropstrict(m, "[package]::trace");
368 __ pushstring(m, "[entering global init function]");
369 __ callpropvoid(m, "[package]::trace", 1);
371 void* finalize_state()
373 if(state->level!=1) {
374 syntaxerror("unexpected end of file");
376 abc_method_body_t*m = state->init->method->body;
379 __ findpropstrict(m, "[package]::trace");
380 __ pushstring(m, "[leaving global init function]");
381 __ callpropvoid(m, "[package]::trace", 1);
387 static void startpackage(token_t*t)
390 syntaxerror("Packages can not be nested.");
393 char*name = t?t->text:"";
394 /*printf("entering package \"%s\"\n", name);*/
395 state->package = name;
397 static void endpackage()
399 /*printf("leaving package \"%s\"\n", state->package);*/
404 static void startclass(token_t*modifiers, token_t*name, classinfo_t*extends, classinfo_list_t*implements, char interface)
407 syntaxerror("inner classes now allowed");
410 state->classname = name->text;
413 classinfo_list_t*mlist=0;
414 /*printf("entering class %s\n", name->text);
415 printf(" modifiers: ");for(t=modifiers->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
417 printf(" extends: %s.%s\n", extends->package, extends->name);
418 printf(" implements (%d): ", list_length(implements));
419 for(mlist=implements;mlist;mlist=mlist->next) {
420 printf("%s ", mlist->classinfo?mlist->classinfo->name:0);
425 char public=0,internal=0,final=0,sealed=1;
426 for(t=modifiers->tokens;t;t=t->next) {
427 if(t->token->type == KW_INTERNAL) {
428 /* the programmer is being explicit-
429 being internal is the default anyway */
431 } else if(t->token->type == KW_PUBLIC) {
433 } else if(t->token->type == KW_FINAL) {
436 syntaxerror("modifier \"%s\" not supported in class declaration", t->token->text);
440 syntaxerror("public and internal not supported at the same time.");
442 /* create the class name, together with the proper attributes */
446 if(!public && !state->package) {
447 access = ACCESS_PRIVATE; package = current_filename;
448 } else if(!public && state->package) {
449 access = ACCESS_PACKAGEINTERNAL; package = state->package;
450 } else if(state->package) {
451 access = ACCESS_PACKAGE; package = state->package;
453 syntaxerror("public classes only allowed inside a package");
456 if(registry_findclass(package, state->classname)) {
457 syntaxerror("Package \"%s\" already contains a class called \"%s\"", package, state->classname);
460 classinfo_t* classname = classinfo_register(access, package, state->classname);
462 MULTINAME(classname2,classname);
464 multiname_t*extends2 = sig2mname(extends);
466 state->cls = abc_class_new(state->file, &classname2, extends2);
467 if(final) abc_class_final(state->cls);
468 if(sealed) abc_class_sealed(state->cls);
469 if(interface) abc_class_interface(state->cls);
471 for(mlist=implements;mlist;mlist=mlist->next) {
472 MULTINAME(m, mlist->classinfo);
473 abc_class_add_interface(state->cls, &m);
476 /* now write the construction code for this class */
477 int slotindex = abc_initscript_addClassTrait(state->init, &classname2, state->cls);
479 abc_method_body_t*m = state->init->method->body;
480 __ getglobalscope(m);
481 classinfo_t*s = extends;
486 //TODO: take a look at the current scope stack, maybe
487 // we can re-use something
492 multiname_t*s2 = sig2mname(s);
494 multiname_destroy(s2);
496 __ pushscope(m); count++;
497 m->code = m->code->prev->prev; // invert
499 /* continue appending after last op end */
500 while(m->code && m->code->next) m->code = m->code->next;
502 /* TODO: if this is one of *our* classes, we can also
503 do a getglobalscope/getslot <nr> (which references
504 the init function's slots) */
506 __ getlex2(m, extends2);
508 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
509 stack is not the superclass */
510 __ pushscope(m);count++;
513 /* notice: we get a verify error #1107 if the top element on the scope
514 stack is not the global object */
516 __ pushscope(m);count++;
518 __ newclass(m,state->cls);
522 __ setslot(m, slotindex);
524 /* flash.display.MovieClip handling */
525 if(!globalclass && public && classinfo_equals(registry_getMovieClip(),extends)) {
526 if(state->package && state->package[0]) {
527 globalclass = concat3str(state->package, ".", state->classname);
529 globalclass = strdup(state->classname);
532 multiname_destroy(extends2);
535 static void endclass()
537 /*printf("leaving class %s\n", state->classname);*/
540 static void startfunction(token_t*ns, token_t*mod, token_t*getset, token_t*name,
541 param_list_t*params, classinfo_t*type)
545 state->function = name->text;
547 /*printf("entering function %s\n", name->text);
549 printf(" namespace: %s\n", ns->text);
550 printf(" getset: %s\n", getset->text);
551 printf(" params: ");for(t=params->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
552 printf(" mod: ");for(t=mod->tokens;t;t=t->next) printf("%s ", t->token->text);printf("\n");
554 printf(" type: %s.%s\n", type->package, type->name);
558 syntaxerror("not able to start another method scope");
561 multiname_t*type2 = sig2mname(type);
562 if(!strcmp(state->classname,name->text)) {
563 state->m = abc_class_constructor(state->cls, type2, 0);
565 state->m = abc_class_method(state->cls, type2, name->text, 0);
568 for(p=params;p;p=p->next) {
569 multiname_t*m = sig2mname(p->param->type);
570 list_append(state->m->method->parameters, m);
573 /* state->vars is initialized by state_new */
574 array_append(state->vars, "this", 0);
575 for(p=params;p;p=p->next) {
576 array_append(state->vars, p->param->name, 0);
579 __ getlocal_0(state->m);
580 __ pushscope(state->m);
582 static void endfunction()
584 /*printf("leaving function %s\n", state->function);*/
585 __ returnvoid(state->m);
591 static token_t* empty_token()
599 void extend(token_t*list, token_t*add) {
600 list_append(list->tokens,add);
602 list->text = add->text;
604 void extend_s(token_t*list, char*seperator, token_t*add) {
605 list_append(list->tokens,add);
606 char*t1 = list->text;
612 list->text = malloc(l1+l2+l3+1);
613 strcpy(list->text, t1);
614 strcpy(list->text+l1, t2);
615 strcpy(list->text+l1+l2, t3);
616 list->text[l1+l2+l3]=0;
619 static int find_variable(char*name, classinfo_t**m)
621 state_list_t* s = state_stack;
623 int i = array_find(s->state->vars, name);
626 *m = array_getvalue(s->state->vars, i);
628 return i + s->state->local_var_base;
634 static int find_variable_safe(char*name, classinfo_t**m)
636 int i = find_variable(name, m);
638 syntaxerror("undefined variable: %s", name);
641 static char variable_exists(char*name)
643 return array_contains(state->vars, name);
645 static int new_variable(char*name, classinfo_t*type)
647 return array_append(state->vars, name, type) + state->local_var_base;
649 code_t* killvars(code_t*c)
652 for(t=0;t<state->vars->num;t++) {
653 classinfo_t*type = array_getvalue(state->vars, t);
654 //do this always, otherwise register types don't match
655 //in the verifier when doing nested loops
656 //if(!TYPE_IS_BUILTIN_SIMPLE(type)) {
657 c = abc_kill(c, t+state->local_var_base);
663 char is_subtype_of(classinfo_t*type, classinfo_t*supertype)
668 void breakjumpsto(code_t*c, code_t*jump)
673 if(c->opcode == OPCODE___BREAK__) {
674 c->opcode = OPCODE_JUMP;
681 classinfo_t*join_types(classinfo_t*type1, classinfo_t*type2, char op)
683 return registry_getanytype(); // FIXME
685 code_t*converttype(code_t*c, classinfo_t*from, classinfo_t*to)
690 /*TODO: can omit this if from is zero? */
691 return abc_coerce_a(c);
693 if(TYPE_IS_NUMBER(from) && TYPE_IS_UINT(to)) {
694 MULTINAME(m, TYPE_UINT);
695 return abc_coerce2(c, &m);
697 if(TYPE_IS_NUMBER(from) && TYPE_IS_INT(to)) {
698 MULTINAME(m, TYPE_INT);
699 return abc_coerce2(c, &m);
704 code_t*defaultvalue(code_t*c, classinfo_t*type)
706 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type) || TYPE_IS_FLOAT(type)) {
707 c = abc_pushbyte(c, 0);
708 } else if(TYPE_IS_BOOLEAN(type)) {
709 c = abc_pushfalse(c);
721 /* ------------ code blocks / statements ---------------- */
725 MAYBECODE: CODE {$$=$1;}
726 MAYBECODE: {$$=code_new();}
728 CODE: CODE CODEPIECE {$$=code_append($1,$2);}
729 CODE: CODEPIECE {$$=$1;}
731 CODEPIECE: PACKAGE_DECLARATION {$$=code_new();/*enters a scope*/}
732 CODEPIECE: CLASS_DECLARATION {$$=code_new();/*enters a scope*/}
733 CODEPIECE: INTERFACE_DECLARATION {/*TODO*/$$=code_new();}
734 CODEPIECE: IMPORT {$$=code_new();/*adds imports to current scope*/}
735 CODEPIECE: ';' {$$=code_new();}
736 CODEPIECE: VARIABLE_DECLARATION {$$=$1}
737 CODEPIECE: VOIDEXPRESSION {$$=$1}
738 CODEPIECE: FOR {$$=$1}
739 CODEPIECE: WHILE {$$=$1}
740 CODEPIECE: BREAK {$$=$1}
741 CODEPIECE: RETURN {$$=$1}
742 CODEPIECE: IF {$$=$1}
743 CODEPIECE: ASSIGNMENT {$$=$1}
744 CODEPIECE: NAMESPACE_DECLARATION {/*TODO*/$$=code_new();}
745 CODEPIECE: FUNCTION_DECLARATION {/*TODO*/$$=code_new();}
746 CODEPIECE: USE_NAMESPACE {/*TODO*/$$=code_new();}
748 CODEBLOCK : '{' MAYBECODE '}' {$$=$2;}
749 CODEBLOCK : CODEPIECE ';' {$$=$1;}
750 CODEBLOCK : CODEPIECE %prec below_semicolon {$$=$1;}
752 /* ------------ functions --------------------------- */
754 FUNCTION_DECLARATION: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
755 MAYBETYPE '{' {startfunction(0,$1,$3,$4,$6,$8)} MAYBECODE '}' {
756 if(!state->m) syntaxerror("internal error: undefined function");
757 state->initcode = abc_nop(state->initcode);
758 state->initcode = abc_nop(state->initcode);
759 state->initcode = abc_nop(state->initcode);
760 state->m->code = code_append(state->initcode, $11);state->initcode=0;
764 /* ------------ variables --------------------------- */
766 MAYBEEXPRESSION : '=' EXPRESSION {$$=$2;}
767 | {$$.c=abc_pushundefined(0);
771 VAR : "const" | "var"
772 VARIABLE_DECLARATION : VAR T_IDENTIFIER MAYBETYPE MAYBEEXPRESSION {
773 if(variable_exists($2->text))
774 syntaxerror("Variable %s already defined", $2->text);
776 if(!is_subtype_of($4.t, $3)) {
777 syntaxerror("Can't convert %s to %s", $4.t->name,
781 int index = new_variable($2->text, $3);
784 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
786 $$ = converttype($$, $4.t, $3);
787 $$ = abc_setlocal($$, index);
789 $$ = defaultvalue(0, $3);
790 $$ = abc_setlocal($$, index);
793 /* push default value for type on stack */
794 state->initcode = defaultvalue(state->initcode, $3);
795 state->initcode = abc_setlocal(state->initcode, index);
797 /* only bother to actually set this variable if its syntax is either
802 if($4.c->prev || $4.c->opcode != OPCODE_PUSHUNDEFINED) {
804 $$ = abc_coerce_a($$);
805 $$ = abc_setlocal($$, index);
811 /* that's the default for a local register, anyway
813 state->initcode = abc_pushundefined(state->initcode);
814 state->initcode = abc_setlocal(state->initcode, index);
816 printf("variable %s -> %d (%s)\n", $2->text, index, $4.t?$4.t->name:"");
818 ASSIGNMENT : T_IDENTIFIER '=' EXPRESSION {
820 int i = find_variable_safe($1->text, &type);
823 // convert to "any" type, the register is untyped
824 $$ = abc_coerce_a($$);
826 // TODO: convert ints to strings etc.
828 $$ = abc_setlocal($$, i);
831 /* ------------ control flow ------------------------- */
833 MAYBEELSE: %prec prec_none {$$ = code_new();}
834 MAYBEELSE: "else" CODEBLOCK {$$=$2;}
835 //MAYBEELSE: ';' "else" CODEBLOCK {$$=$3;}
837 IF : "if" '(' {new_state();} EXPRESSION ')' CODEBLOCK MAYBEELSE {
838 $$ = state->initcode;state->initcode=0;
840 $$ = code_append($$, $4.c);
841 code_t*myjmp,*myif = $$ = abc_iffalse($$, 0);
843 $$ = code_append($$, $6);
845 myjmp = $$ = abc_jump($$, 0);
847 myif->branch = $$ = abc_label($$);
849 $$ = code_append($$, $7);
850 myjmp->branch = $$ = abc_label($$);
853 $$ = killvars($$);old_state();
856 FOR_INIT : {$$=code_new();}
857 FOR_INIT : ASSIGNMENT | VARIABLE_DECLARATION | VOIDEXPRESSION
859 FOR : "for" '(' {new_state();} FOR_INIT ';' EXPRESSION ';' VOIDEXPRESSION ')' CODEBLOCK {
860 $$ = state->initcode;state->initcode=0;
862 $$ = code_append($$, $4);
863 code_t*loopstart = $$ = abc_label($$);
864 $$ = code_append($$, $6.c);
865 code_t*myif = $$ = abc_iffalse($$, 0);
866 $$ = code_append($$, $10);
867 $$ = code_append($$, $8);
868 $$ = abc_jump($$, loopstart);
869 code_t*out = $$ = abc_label($$);
870 breakjumpsto($$, out);
873 $$ = killvars($$);old_state();
876 WHILE : "while" '(' {new_state();} EXPRESSION ')' CODEBLOCK {
877 $$ = state->initcode;state->initcode=0;
879 code_t*myjmp = $$ = abc_jump($$, 0);
880 code_t*loopstart = $$ = abc_label($$);
881 $$ = code_append($$, $6);
882 myjmp->branch = $$ = abc_label($$);
883 $$ = code_append($$, $4.c);
884 $$ = abc_iftrue($$, loopstart);
885 code_t*out = $$ = abc_label($$);
886 breakjumpsto($$, out);
888 $$ = killvars($$);old_state();
892 $$ = abc___break__(0);
895 /* ------------ packages and imports ---------------- */
897 X_IDENTIFIER: T_IDENTIFIER
900 PACKAGE: PACKAGE '.' X_IDENTIFIER {$$ = concat3($1,$2,$3);}
901 PACKAGE: X_IDENTIFIER {$$=$1;}
903 PACKAGE_DECLARATION : "package" PACKAGE '{' {startpackage($2)} MAYBECODE '}' {endpackage()}
904 PACKAGE_DECLARATION : "package" '{' {startpackage(0)} MAYBECODE '}' {endpackage()}
906 IMPORT : "import" QNAME {
909 syntaxerror("Couldn't import class\n");
911 dict_put(state->imports, c->name, c);
914 IMPORT : "import" PACKAGE '.' '*' {
916 i->package = $2->text;
918 list_append(state->wildcard_imports, i);
922 /* ------------ classes and interfaces -------------- */
924 MODIFIERS : {$$=empty_token();}
925 MODIFIERS : MODIFIER_LIST {$$=$1}
926 MODIFIER_LIST : MODIFIER MODIFIER_LIST {extend($2,$1);$$=$2;}
927 MODIFIER_LIST : MODIFIER {$$=empty_token();extend($$,$1);}
928 MODIFIER : KW_PUBLIC | KW_PRIVATE | KW_PROTECTED | KW_STATIC | KW_DYNAMIC | KW_FINAL | KW_OVERRIDE | KW_NATIVE | KW_INTERNAL
930 EXTENDS : {$$=registry_getobjectclass();}
931 EXTENDS : KW_EXTENDS QNAME {$$=$2;}
933 EXTENDS_LIST : {$$=list_new();}
934 EXTENDS_LIST : KW_EXTENDS QNAME_LIST {$$=$2;}
936 IMPLEMENTS_LIST : {$$=list_new();}
937 IMPLEMENTS_LIST : KW_IMPLEMENTS QNAME_LIST {$$=$2;}
939 CLASS_DECLARATION : MODIFIERS "class" T_IDENTIFIER
940 EXTENDS IMPLEMENTS_LIST
941 '{' {startclass($1,$3,$4,$5, 0);}
942 MAYBE_DECLARATION_LIST
944 INTERFACE_DECLARATION : MODIFIERS "interface" T_IDENTIFIER
946 '{' {startclass($1,$3,0,$4,1);}
947 MAYBE_IDECLARATION_LIST
950 /* ------------- package + class ids --------------- */
952 CLASS: T_IDENTIFIER {
954 /* try current package */
955 $$ = registry_findclass(state->package, $1->text);
957 /* try explicit imports */
958 dictentry_t* e = dict_get_slot(state->imports, $1->text);
962 if(!strcmp(e->key, $1->text)) {
963 $$ = (classinfo_t*)e->data;
968 /* try package.* imports */
969 import_list_t*l = state->wildcard_imports;
973 //printf("does package %s contain a class %s?\n", l->import->package, $1->text);
974 $$ = registry_findclass(l->import->package, $1->text);
978 /* try global package */
980 $$ = registry_findclass("", $1->text);
983 if(!$$) syntaxerror("Could not find class %s\n", $1->text);
986 PACKAGEANDCLASS : PACKAGE '.' T_IDENTIFIER {
987 $$ = registry_findclass($1->text, $3->text);
988 if(!$$) syntaxerror("Couldn't find class %s.%s\n", $1->text, $3->text);
991 QNAME: PACKAGEANDCLASS
995 /* ----------function calls, constructor calls ------ */
997 MAYBE_PARAM_VALUES : %prec prec_none {$$=0;}
998 MAYBE_PARAM_VALUES : '(' MAYBE_EXPRESSION_LIST ')' {$$=$2}
1000 MAYBE_EXPRESSION_LIST : {$$=0;}
1001 MAYBE_EXPRESSION_LIST : EXPRESSION_LIST
1002 EXPRESSION_LIST : EXPRESSION {$$=list_new();
1003 typedcode_t*t = malloc(sizeof(typedcode_t));
1005 list_append($$, t);}
1006 EXPRESSION_LIST : EXPRESSION_LIST ',' EXPRESSION {$$=$1;
1007 typedcode_t*t = malloc(sizeof(typedcode_t));
1009 list_append($$, t);}
1011 NEW : "new" CLASS MAYBE_PARAM_VALUES {
1014 $$.c = abc_findpropstrict2($$.c, &m);
1015 typedcode_list_t*l = $3;
1018 $$.c = code_append($$.c, l->typedcode->c); // push parameters on stack
1022 $$.c = abc_constructprop2($$.c, &m, len);
1026 /* TODO: use abc_call (for calling local variables),
1027 abc_callstatic (for calling own methods)
1030 FUNCTIONCALL : E '(' MAYBE_EXPRESSION_LIST ')' {
1031 typedcode_list_t*l = $3;
1033 code_t*paramcode = 0;
1035 paramcode = code_append(paramcode, l->typedcode->c); // push parameters on stack
1041 if($$.c->opcode == OPCODE_GETPROPERTY) {
1042 multiname_t*name = multiname_clone($$.c->data[0]);
1043 $$.c = code_cutlast($$.c);
1044 $$.c = code_append($$.c, paramcode);
1045 $$.c = abc_callproperty2($$.c, name, len);
1047 int i = find_variable_safe("this", 0);
1048 $$.c = abc_getlocal($$.c, i);
1049 $$.c = code_append($$.c, paramcode);
1050 $$.c = abc_call($$.c, len);
1052 /* TODO: look up the functions's return value */
1056 RETURN: "return" %prec prec_none {
1057 $$ = abc_returnvoid(0);
1059 RETURN: "return" EXPRESSION {
1061 $$ = abc_returnvalue($$);
1064 TYPE : QNAME {$$=$1;}
1065 | '*' {$$=registry_getanytype();}
1066 | "String" {$$=registry_getstringclass();}
1067 | "int" {$$=registry_getintclass();}
1068 | "uint" {$$=registry_getuintclass();}
1069 | "Boolean" {$$=registry_getbooleanclass();}
1070 | "Number" {$$=registry_getnumberclass();}
1072 MAYBETYPE: ':' TYPE {$$=$2;}
1075 //FUNCTION_HEADER: NAMESPACE MODIFIERS T_FUNCTION GETSET T_IDENTIFIER '(' PARAMS ')'
1076 FUNCTION_HEADER: MODIFIERS "function" GETSET T_IDENTIFIER '(' MAYBE_PARAM_LIST ')'
1079 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER
1080 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_IDENTIFIER
1081 NAMESPACE_DECLARATION : MODIFIERS KW_NAMESPACE T_IDENTIFIER '=' T_STRING
1083 //NAMESPACE : {$$=empty_token();}
1084 //NAMESPACE : T_IDENTIFIER {$$=$1};
1086 CONSTANT : T_BYTE {$$.c = abc_pushbyte(0, $1);
1087 //MULTINAME(m, registry_getintclass());
1088 //$$.c = abc_coerce2($$.c, &m); // FIXME
1091 CONSTANT : T_SHORT {$$.c = abc_pushshort(0, $1);
1094 CONSTANT : T_INT {$$.c = abc_pushint(0, $1);
1097 CONSTANT : T_UINT {$$.c = abc_pushuint(0, $1);
1100 CONSTANT : T_FLOAT {$$.c = abc_pushdouble(0, $1);
1103 CONSTANT : T_STRING {$$.c = abc_pushstring(0, $1);
1106 CONSTANT : KW_TRUE {$$.c = abc_pushtrue(0);
1107 $$.t = TYPE_BOOLEAN;
1109 CONSTANT : KW_FALSE {$$.c = abc_pushfalse(0);
1110 $$.t = TYPE_BOOLEAN;
1112 CONSTANT : KW_NULL {$$.c = abc_pushnull(0);
1116 USE_NAMESPACE : "use" "namespace" T_IDENTIFIER
1119 EXPRESSION : E %prec prec_none /*precedence below '-x'*/ {$$ = $1;}
1120 VOIDEXPRESSION : E %prec prec_none {$$=$1.c;/*calculate and discard*/$$=abc_pop($$);}
1123 E : VAR_READ %prec T_IDENTIFIER {$$ = $1;}
1125 E : T_REGEXP {$$.c = abc_pushundefined(0); /* FIXME */
1129 E : E '<' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);$$.c=abc_not($$.c);
1130 $$.t = TYPE_BOOLEAN;
1132 E : E '>' E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);
1133 $$.t = TYPE_BOOLEAN;
1135 E : E "<=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterthan($$.c);$$.c=abc_not($$.c);
1136 $$.t = TYPE_BOOLEAN;
1138 E : E ">=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_greaterequals($$.c);
1139 $$.t = TYPE_BOOLEAN;
1141 E : E "==" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);
1142 $$.t = TYPE_BOOLEAN;
1144 E : E "===" E {$$.c = code_append($1.c,$3.c);$$.c = abc_strictequals($$.c);
1145 $$.t = TYPE_BOOLEAN;
1147 E : E "!=" E {$$.c = code_append($1.c,$3.c);$$.c = abc_equals($$.c);$$.c = abc_not($$.c);
1148 $$.t = TYPE_BOOLEAN;
1151 E : E "||" E {$$.t = join_types($1.t, $3.t, 'O');
1153 $$.c = converttype($$.c, $1.t, $$.t);
1154 $$.c = abc_dup($$.c);
1155 code_t*jmp = $$.c = abc_iftrue($$.c, 0);
1156 $$.c = abc_pop($$.c);
1157 $$.c = code_append($$.c,$3.c);
1158 $$.c = converttype($$.c, $1.t, $$.t);
1159 code_t*label = $$.c = abc_label($$.c);
1160 jmp->branch = label;
1162 E : E "&&" E {$$.t = join_types($1.t, $3.t, 'A');
1164 $$.c = converttype($$.c, $1.t, $$.t);
1165 $$.c = abc_dup($$.c);
1166 code_t*jmp = $$.c = abc_iffalse($$.c, 0);
1167 $$.c = abc_pop($$.c);
1168 $$.c = code_append($$.c,$3.c);
1169 $$.c = converttype($$.c, $1.t, $$.t);
1170 code_t*label = $$.c = abc_label($$.c);
1171 jmp->branch = label;
1174 E : E '.' T_IDENTIFIER
1177 namespace_t ns = {$$.t->access, (char*)$$.t->package};
1178 multiname_t m = {QNAME, &ns, 0, $3->text};
1179 $$.c = abc_getproperty2($$.c, &m);
1180 /* FIXME: get type of ($1.t).$3 */
1181 $$.t = registry_getanytype();
1183 namespace_t ns = {ACCESS_PACKAGE, ""};
1184 multiname_t m = {QNAME, &ns, 0, $3->text};
1185 $$.c = abc_getproperty2($$.c, &m);
1186 $$.t = registry_getanytype();
1190 E : '!' E {$$.c=$2.c;
1191 $$.c = abc_not($$.c);
1192 $$.t = TYPE_BOOLEAN;
1197 E : E '+' E {$$.c = code_append($1.c,$3.c);$$.c = abc_add($$.c);$$.c=abc_coerce_a($$.c);
1198 $$.t = join_types($1.t, $3.t, '+');
1200 E : E '%' E {$$.c = code_append($1.c,$3.c);$$.c = abc_modulo($$.c);$$.c=abc_coerce_a($$.c);
1201 $$.t = join_types($1.t, $3.t, '%');
1203 E : E '*' E {$$.c = code_append($1.c,$3.c);$$.c = abc_multiply($$.c);$$.c=abc_coerce_a($$.c);
1204 $$.t = join_types($1.t, $3.t, '*');
1209 E : '(' E ')' {$$=$2;}
1212 E : LH "+=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1213 classinfo_t*type = join_types($1.type, $3.t, '+');
1214 $$.c=converttype($$.c, type, $1.type);
1215 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1218 E : LH "-=" E {$$.c = $1.read;$$.c=code_append($$.c,$3.c);$$.c=abc_add($$.c);
1219 classinfo_t*type = join_types($1.type, $3.t, '-');
1220 $$.c=converttype($$.c, type, $1.type);
1221 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1225 // TODO: use inclocal where appropriate
1226 E : LH "++" {$$.c = $1.read;
1227 classinfo_t*type = $1.type;
1228 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1229 $$.c=abc_increment_i($$.c);
1231 $$.c=abc_increment($$.c);
1234 $$.c=converttype($$.c, type, $1.type);
1235 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1238 E : LH "--" {$$.c = $1.read;
1239 classinfo_t*type = $1.type;
1240 if(TYPE_IS_INT(type) || TYPE_IS_UINT(type)) {
1241 $$.c=abc_decrement_i($$.c);
1243 $$.c=abc_decrement($$.c);
1246 $$.c=converttype($$.c, type, $1.type);
1247 $$.c=abc_dup($$.c);$$.c=code_append($$.c,$1.write);
1252 int i = find_variable_safe($1->text, &$$.type);
1253 $$.read = abc_getlocal(0, i);
1254 $$.write = abc_setlocal(0, i);
1258 VAR_READ : T_IDENTIFIER {
1261 int i = find_variable($1->text, &$$.t);
1263 $$.c = abc_getlocal($$.c, i);
1266 $$.c = abc_findpropstrict($$.c, $1->text);
1267 $$.c = abc_getproperty($$.c, $1->text);
1271 //VARIABLE : T_IDENTIFIER
1272 //VARIABLE : VARIABLE '.' T_IDENTIFIER
1273 //VARIABLE : VARIABLE ".." T_IDENTIFIER // descendants
1274 //VARIABLE : VARIABLE "::" VARIABLE // namespace declaration
1275 //VARIABLE : VARIABLE "::" '[' EXPRESSION ']' // qualified expression
1276 //VARIABLE : VARIABLE '[' EXPRESSION ']' // unqualified expression
1278 GETSET : "get" {$$=$1;}
1280 | {$$=empty_token();}
1282 MAYBE_PARAM_LIST: {$$=list_new();}
1283 MAYBE_PARAM_LIST: PARAM_LIST {$$=$1;}
1284 PARAM_LIST: PARAM_LIST ',' PARAM {$$ =$1; list_append($$, $3);}
1285 PARAM_LIST: PARAM {$$ = list_new();list_append($$, $1);}
1286 PARAM: T_IDENTIFIER ':' TYPE {$$ = malloc(sizeof(param_t));
1287 $$->name=$1->text;$$->type = $3;}
1288 PARAM: T_IDENTIFIER {$$ = malloc(sizeof(param_t));
1289 $$->name=$1->text;$$->type = TYPE_ANY;}
1291 DECLARATION : VARIABLE_DECLARATION
1292 DECLARATION : FUNCTION_DECLARATION
1294 IDECLARATION : VARIABLE_DECLARATION
1295 IDECLARATION : FUNCTION_DECLARATION
1297 //IDENTIFIER_LIST : T_IDENTIFIER ',' IDENTIFIER_LIST {extend($3,$1);$$=$3;}
1298 //IDENTIFIER_LIST : T_IDENTIFIER {$$=empty_token();extend($$,$1);}
1300 QNAME_LIST : QNAME {$$=list_new();list_append($$, $1);}
1301 QNAME_LIST : QNAME_LIST ',' QNAME {$$=$1;list_append($$,$3);}
1303 MAYBE_DECLARATION_LIST :
1304 MAYBE_DECLARATION_LIST : DECLARATION_LIST
1305 DECLARATION_LIST : DECLARATION
1306 DECLARATION_LIST : DECLARATION_LIST DECLARATION
1308 MAYBE_IDECLARATION_LIST :
1309 MAYBE_IDECLARATION_LIST : IDECLARATION_LIST
1310 IDECLARATION_LIST : IDECLARATION
1311 IDECLARATION_LIST : IDECLARATION_LIST FUNCTION_HEADER
1314 // 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
1315 // syntactic keywords: each get set namespace include dynamic final native override static