ad2dbc0aeae4cc50a323c3a8a7846a062477656b
[swftools.git] / lib / as3 / initcode.c
1 #include <assert.h>
2 #include "../q.h"
3 #include "abc.h"
4 #include "code.h"
5 #include "common.h"
6 #include "registry.h"
7 #include "initcode.h"
8
9 int compare_parsedclass(const void *_v1, const void *_v2)
10 {
11     parsedclass_t*p1 = *(parsedclass_t**)_v1;
12     parsedclass_t*p2 = *(parsedclass_t**)_v2;
13     if((p1->cls->flags^p2->cls->flags)&FLAG_INTERFACE) {
14         return (int)(p2->cls->flags&FLAG_INTERFACE) - (int)(p1->cls->flags&FLAG_INTERFACE);
15     }
16     classinfo_t*c2 = dict_lookup(&p1->parents, p2);
17     classinfo_t*c1 = dict_lookup(&p2->parents, p1);
18     assert(!c1 || !c2); // otherwise we would have a loop
19     assert(!c1 || c1==p1->cls);
20     assert(!c2 || c2==p2->cls);
21     if(c1) {
22         return -1;
23     }
24     if(c2) {
25         return 1;
26     }
27     
28     c2 = dict_lookup(&p1->usedclasses_deep, p2);
29     c1 = dict_lookup(&p2->usedclasses_deep, p1);
30     assert(!c1 || !c2);
31     assert(!c1 || c1==p1->cls);
32     assert(!c2 || c2==p2->cls);
33     if(c1) {
34         return -1;
35     }
36     if(c2) {
37         return 1;
38     }
39     return 0;
40 }
41
42 void add_parent(parsedclass_t*p, classinfo_t*c, dict_t*s2p, char soft)
43 {
44     dict_t*parents = soft?(&p->usedclasses_deep):(&p->parents);
45     int t;
46     if(dict_contains(parents, p)) {
47         if(soft) {
48             as3_warning("circular reference: class %s references self (through static code)", p->cls->name);
49             return;
50         } else {
51             syntaxerror("circular reference: class %s references self", p->cls->name);
52         }
53     }
54
55     if(c) {
56         parsedclass_t*n = dict_lookup(s2p, c);
57         if(n && !dict_contains(parents, n)) {
58             assert(n->cls == c);
59             dict_put(parents, n, c);
60         }
61     } else {
62         c = p->cls;
63     }
64
65     if(soft && dict_contains(s2p, c)) {
66         parsedclass_t*pp = dict_lookup(s2p, c);
67         DICT_ITERATE_KEY(&pp->usedclasses, classinfo_t*, cc) {
68             add_parent(p, cc, s2p, soft);
69         }
70     }
71     if(c->superclass) {
72         add_parent(p, c->superclass, s2p, soft);
73     }
74     for(t=0;c->interfaces[t];t++) {
75         add_parent(p, c->interfaces[t], s2p, soft);
76     }
77 }
78
79 parsedclass_t* parsedclass_new(classinfo_t*cls, abc_class_t*abc)
80 {
81     NEW(parsedclass_t,p);
82     p->cls = cls;
83     p->abc = abc;
84     dict_init2(&p->parents, &ptr_type, 1);
85     dict_init2(&p->usedclasses, &ptr_type, 1);
86     dict_init2(&p->usedclasses_deep, &ptr_type, 1);
87     return p;
88 }
89
90 /* sort classes so that 
91    (a) interfaces appear before classes
92    (b) base classes always appear before their subclasses
93    (c) classes appear after the classes they use in static code
94 */
95 parsedclass_t** initcode_sort_classlist(parsedclass_list_t*classes)
96 {
97     dict_t* s2p = dict_new2(&ptr_type);
98
99     /* create hash tables */
100     int count = 0;
101     parsedclass_list_t*l;
102     for(l=classes;l;l=l->next) {
103         dict_put(s2p, l->parsedclass->cls, l->parsedclass);
104         count++;
105     }
106     for(l=classes;l;l=l->next) {
107         add_parent(l->parsedclass, 0, s2p, 0);
108         DICT_ITERATE_KEY(&l->parsedclass->usedclasses, classinfo_t*, c) {
109             add_parent(l->parsedclass, c, s2p, 1);
110         }
111     }
112
113     parsedclass_t**list = malloc(sizeof(parsedclass_t*)*count);
114
115     /* build an array for each class */
116     int i = 0;
117     for(l=classes;l;l=l->next) {
118         list[i++] = l->parsedclass;
119     }
120     
121     /* sort and flatten */
122     qsort(list, count, sizeof(void**), compare_parsedclass);
123
124     parsedclass_t**list2 = malloc(sizeof(parsedclass_t*)*(count+1));
125     for(i=0;i<count;i++) {
126         list2[i] = (parsedclass_t*)list[i];
127     }
128     list2[count]=0;
129     free(list);
130
131     dict_destroy(s2p);
132     return list2;
133 }
134
135 void parsedclass_add_dependency(parsedclass_t*p, classinfo_t*c)
136 {
137     if(!dict_contains(&p->usedclasses, c)) {
138         dict_put(&p->usedclasses, c, c);
139     }
140 }
141
142 void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*_classes)
143 {
144     code_t*c = 0;
145
146     c = abc_getlocal_0(c);
147     c = abc_pushscope(c);
148   
149     parsedclass_t**classes = initcode_sort_classlist(_classes);
150
151     int t;
152     for(t=0;classes[t];t++) {
153         abc_class_t*abc = classes[t]->abc;
154         classinfo_t*cls = classes[t]->cls;
155         
156         array_append(init->file->classes, "", abc);
157
158         /* write the construction code for this class to the global init
159            function */
160         MULTINAME(classname2,cls);
161         trait_t*trait = abc_initscript_addClassTrait(init, &classname2, abc);
162
163         c = abc_findpropstrict(c, "trace");
164         c = abc_pushstring(c, allocprintf("initialize class %s", cls->name));
165         c = abc_callpropvoid(c, "trace", 1);
166
167         c = abc_getglobalscope(c);
168         classinfo_t*s = cls->superclass;
169
170         int count=0;
171
172         while(s) {
173             //TODO: take a look at the current scope stack, maybe 
174             //      we can re-use something
175             s = s->superclass;
176             if(!s) 
177             break;
178            
179             multiname_t*s2 = sig2mname(s);
180             c = abc_getlex2(c, s2);
181             multiname_destroy(s2);
182
183             c = abc_pushscope(c); count++;
184             c = c->prev->prev; // invert
185         }
186         /* continue appending after last op end */
187         while(c && c->next) c = c->next; 
188
189         multiname_t*extends2 = sig2mname(cls->superclass);
190         /* TODO: if this is one of *our* classes, we can also 
191                  do a getglobalscope/getslot <nr> (which references
192                  the init function's slots) */
193         if(extends2) {
194             c = abc_getlex2(c, extends2);
195             c = abc_dup(c);
196             /* notice: we get a Verify Error #1107 if the top elemnt on the scope
197                stack is not the superclass */
198             c = abc_pushscope(c);count++;
199         } else {
200             c = abc_pushnull(c);
201             /* notice: we get a verify error #1107 if the top element on the scope 
202                stack is not the global object */
203             c = abc_getlocal_0(c);
204             c = abc_pushscope(c);count++;
205         }
206         c = abc_newclass(c,abc);
207         while(count--) {
208             c = abc_popscope(c);
209         }
210         c = abc_setslot(c, trait->slot_id);
211         multiname_destroy(extends2);
212     }
213     c = abc_returnvoid(c);
214
215     free(classes);
216
217     init->method->body->code = c;
218 }
219