3 Routines for handling/compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008,2009 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 */
32 int compare_parsedclass(const void *_v1, const void *_v2)
34 parsedclass_t*p1 = *(parsedclass_t**)_v1;
35 parsedclass_t*p2 = *(parsedclass_t**)_v2;
36 if((p1->cls->flags^p2->cls->flags)&FLAG_INTERFACE) {
37 return (int)(p2->cls->flags&FLAG_INTERFACE) - (int)(p1->cls->flags&FLAG_INTERFACE);
39 classinfo_t*c2 = dict_lookup(&p1->parents, p2);
40 classinfo_t*c1 = dict_lookup(&p2->parents, p1);
41 assert(!c1 || !c2); // otherwise we would have a loop
42 assert(!c1 || c1==p1->cls);
43 assert(!c2 || c2==p2->cls);
52 c2 = dict_lookup(&p1->usedclasses_deep, p2);
53 c1 = dict_lookup(&p2->usedclasses_deep, p1);
55 assert(!c1 || c1==p1->cls);
56 assert(!c2 || c2==p2->cls);
67 static void add_parent(parsedclass_t*p, classinfo_t*c, dict_t*s2p, char soft)
69 dict_t*parents = soft?(&p->usedclasses_deep):(&p->parents);
71 if(dict_contains(parents, p)) {
73 as3_warning("circular reference: class %s references self (through static code)", p->cls->name);
76 syntaxerror("circular reference: class %s references self", p->cls->name);
81 parsedclass_t*n = dict_lookup(s2p, c);
82 if(n && !dict_contains(parents, n)) {
84 dict_put(parents, n, c);
90 if(soft && dict_contains(s2p, c)) {
91 parsedclass_t*pp = dict_lookup(s2p, c);
92 DICT_ITERATE_KEY(&pp->usedclasses, classinfo_t*, cc) {
93 add_parent(p, cc, s2p, soft);
97 add_parent(p, c->superclass, s2p, soft);
99 for(t=0;c->interfaces[t];t++) {
100 add_parent(p, c->interfaces[t], s2p, soft);
104 parsedclass_t* parsedclass_new(classinfo_t*cls, abc_class_t*abc)
106 NEW(parsedclass_t,p);
109 dict_init2(&p->parents, &ptr_type, 1);
110 dict_init2(&p->usedclasses, &ptr_type, 1);
111 dict_init2(&p->usedclasses_deep, &ptr_type, 1);
115 /* sort classes so that
116 (a) interfaces appear before classes
117 (b) base classes always appear before their subclasses
118 (c) classes appear after the classes they use in static code
120 parsedclass_t** initcode_sort_classlist(parsedclass_list_t*classes)
122 dict_t* s2p = dict_new2(&ptr_type);
124 /* create hash tables */
126 parsedclass_list_t*l;
127 for(l=classes;l;l=l->next) {
128 dict_put(s2p, l->parsedclass->cls, l->parsedclass);
131 for(l=classes;l;l=l->next) {
132 add_parent(l->parsedclass, 0, s2p, 0);
133 DICT_ITERATE_KEY(&l->parsedclass->usedclasses, classinfo_t*, c) {
134 add_parent(l->parsedclass, c, s2p, 1);
138 parsedclass_t**list = malloc(sizeof(parsedclass_t*)*count);
140 /* build an array for each class */
142 for(l=classes;l;l=l->next) {
143 list[i++] = l->parsedclass;
147 We unfortunately need to do insertion sort O(n^2) as
148 our dependencies are only partially ordered */
150 for(i=0;i<count;i++) {
151 for(j=i+1;j<count;j++) {
152 int r = compare_parsedclass(list+i,list+j);
154 parsedclass_t*p1 = list[i];
155 parsedclass_t*p2 = list[j];
162 parsedclass_t**list2 = malloc(sizeof(parsedclass_t*)*(count+1));
163 for(i=0;i<count;i++) {
164 list2[i] = (parsedclass_t*)list[i];
166 parsedclass_t*p = list[i];
167 printf("%s\n", p->cls->name);
168 if(p->cls->superclass)
169 printf(" extends %s\n", p->cls->superclass->name);
171 for(t=0;p->cls->interfaces[t];t++)
172 printf(" interface %s\n", p->cls->interfaces[t]->name);
173 DICT_ITERATE_KEY(&p->usedclasses, classinfo_t*, c) {
174 printf(" uses %s\n", c->name);
176 DICT_ITERATE_KEY(&p->parents, parsedclass_t*, pp) {
177 printf(" depends on (deep) %s\n", pp->cls->name);
179 DICT_ITERATE_KEY(&p->usedclasses_deep, parsedclass_t*, px) {
180 printf(" uses (deep) %s\n", px->cls->name);
192 void parsedclass_add_dependency(parsedclass_t*p, classinfo_t*c)
194 if(!dict_contains(&p->usedclasses, c)) {
195 dict_put(&p->usedclasses, c, c);
199 void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*_classes)
203 c = abc_getlocal_0(c);
204 c = abc_pushscope(c);
206 parsedclass_t**classes = initcode_sort_classlist(_classes);
209 for(t=0;classes[t];t++) {
210 abc_class_t*abc = classes[t]->abc;
211 classinfo_t*cls = classes[t]->cls;
213 array_append(init->file->classes, "", abc);
215 /* write the construction code for this class to the global init
217 MULTINAME(classname2,cls);
218 trait_t*trait = abc_initscript_addClassTrait(init, &classname2, abc);
220 c = abc_getglobalscope(c);
221 classinfo_t*s = cls->superclass;
226 //TODO: take a look at the current scope stack, maybe
227 // we can re-use something
232 multiname_t*s2 = sig2mname(s);
233 c = abc_getlex2(c, s2);
234 multiname_destroy(s2);
236 c = abc_pushscope(c); count++;
237 c = c->prev->prev; // invert
239 /* continue appending after last op end */
240 while(c && c->next) c = c->next;
242 multiname_t*extends2 = sig2mname(cls->superclass);
243 /* TODO: if this is one of *our* classes, we can also
244 do a getglobalscope/getslot <nr> (which references
245 the init function's slots) */
247 c = abc_getlex2(c, extends2);
249 /* notice: we get a Verify Error #1107 if the top elemnt on the scope
250 stack is not the superclass */
251 c = abc_pushscope(c);count++;
254 /* notice: we get a verify error #1107 if the top element on the scope
255 stack is not the global object */
256 c = abc_getlocal_0(c);
257 c = abc_pushscope(c);count++;
259 c = abc_newclass(c,abc);
263 c = abc_setslot(c, trait->slot_id);
264 multiname_destroy(extends2);
266 c = abc_returnvoid(c);
270 init->method->body->code = c;