20e483aa373b87e90b176e51b6287142ba67fc70
[swftools.git] / lib / as3 / initcode.c
1 #include "abc.h"
2 #include "code.h"
3 #include "registry.h"
4 #include "initcode.h"
5
6 int compare_lists(const void *_v1, const void *_v2)
7 {
8     classinfo_t**v1 = *(classinfo_t***)_v1;
9     classinfo_t**v2 = *(classinfo_t***)_v2;
10     parsedclass_t*p1 = **(parsedclass_t***)_v1;
11     parsedclass_t*p2 = **(parsedclass_t***)_v2;
12     if((p1->cls->flags^p2->cls->flags)&FLAG_INTERFACE) {
13         return (int)(p2->cls->flags&FLAG_INTERFACE) - (int)(p1->cls->flags&FLAG_INTERFACE);
14     }
15     do {
16         v1++;v2++;
17         if(*v1<*v2) return -1;
18         else if(*v1>*v2) return 1;
19     } while(*v1 && *v2);
20     return 0;
21 }
22
23 /* sort classes so that 
24    (a) interfaces appear before classes
25    (b) base classes always appear before their subclasses
26    (c) neighboring elements have similar scope stacks 
27
28    Notice: we don't yet handle multiple inheritance (in interfaces) correctly.
29 */
30 parsedclass_t** initcode_sort_classlist(parsedclass_list_t*classes)
31 {
32     /* count classes */
33     int count = 0;
34     parsedclass_list_t*l;
35     for(l=classes;l;l=l->next) {
36         count++;
37     }
38     void***list = malloc(sizeof(void**)*count);
39
40     /* build an array for each class */
41     int i = 0;
42     for(l=classes;l;l=l->next) {
43         classinfo_t*cls = l->parsedclass->cls;
44         int len=0;
45         classinfo_t*c=cls;
46         while(c) {
47             len ++;
48             c = c->flags&FLAG_INTERFACE?c->interfaces[0]:c->superclass;
49         }
50         void**a = (void**)malloc(sizeof(void*)*(len+2));
51         a[0] = l->parsedclass;
52         a[len+1] = 0;
53         int t=len;
54         c = cls;
55         while(c) {
56             len ++;
57             a[t--] = c;
58             c = c->flags&FLAG_INTERFACE?c->interfaces[0]:c->superclass;
59         }
60         list[i++] = a;
61     }
62     
63     /* sort and flatten */
64     qsort(list, count, sizeof(void**), compare_lists);
65
66     parsedclass_t**list2 = malloc(sizeof(parsedclass_t*)*(count+1));
67     for(i=0;i<count;i++) {
68         list2[i] = (parsedclass_t*)list[i][0];
69         free(list[i]);
70     }
71     list2[count]=0;
72     free(list);
73     return list2;
74 }
75
76 void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*_classes)
77 {
78     code_t*c = 0;
79
80     c = abc_getlocal_0(c);
81     c = abc_pushscope(c);
82   
83     parsedclass_t**classes = initcode_sort_classlist(_classes);
84
85     int t;
86     for(t=0;classes[t];t++) {
87         abc_class_t*abc = classes[t]->abc;
88         classinfo_t*cls = classes[t]->cls;
89         
90         array_append(init->file->classes, "", abc);
91
92         /* write the construction code for this class to the global init
93            function */
94         MULTINAME(classname2,cls);
95         int slotindex = abc_initscript_addClassTrait(init, &classname2, abc);
96
97         c = abc_getglobalscope(c);
98         classinfo_t*s = cls->superclass;
99
100         int count=0;
101
102         while(s) {
103             //TODO: take a look at the current scope stack, maybe 
104             //      we can re-use something
105             s = s->superclass;
106             if(!s) 
107             break;
108            
109             multiname_t*s2 = sig2mname(s);
110             c = abc_getlex2(c, s2);
111             multiname_destroy(s2);
112
113             c = abc_pushscope(c); count++;
114             c = c->prev->prev; // invert
115         }
116         /* continue appending after last op end */
117         while(c && c->next) c = c->next; 
118
119         multiname_t*extends2 = sig2mname(cls->superclass);
120         /* TODO: if this is one of *our* classes, we can also 
121                  do a getglobalscope/getslot <nr> (which references
122                  the init function's slots) */
123         if(extends2) {
124             c = abc_getlex2(c, extends2);
125             c = abc_dup(c);
126             /* notice: we get a Verify Error #1107 if the top elemnt on the scope
127                stack is not the superclass */
128             c = abc_pushscope(c);count++;
129         } else {
130             c = abc_pushnull(c);
131             /* notice: we get a verify error #1107 if the top element on the scope 
132                stack is not the global object */
133             c = abc_getlocal_0(c);
134             c = abc_pushscope(c);count++;
135         }
136         c = abc_newclass(c,abc);
137         while(count--) {
138             c = abc_popscope(c);
139         }
140         c = abc_setslot(c, slotindex);
141         multiname_destroy(extends2);
142     }
143     c = abc_returnvoid(c);
144
145     free(classes);
146
147     init->method->body->code = c;
148 }
149