refactored
[swftools.git] / lib / as3 / registry.c
1 /* registry.c
2
3    Routines for compiling Flash2 AVM2 ABC Actionscript
4
5    Extension module for the rfxswf library.
6    Part of the swftools package.
7
8    Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
9  
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.
14
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.
19
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 */
23
24 #include <assert.h>
25 #include "pool.h"
26 #include "registry.h"
27 #include "builtin.h"
28
29 static dict_t*classes=0;
30
31 // ----------------------- class signature ------------------------------
32
33 char slotinfo_equals(slotinfo_t*c1, slotinfo_t*c2)
34 {
35     if(!!c1 != !!c2)
36         return 0;
37     /* notice: access right is *not* respected */
38     if(!strcmp(c1->name, c2->name) &&
39        !strcmp(c1->package, c2->package)) {
40         return 1;
41     }
42     return 0;
43 }
44 static unsigned int slotinfo_hash(slotinfo_t*c)
45 {
46     unsigned int hash = 0;
47     hash = crc32_add_string(hash, c->package);
48     hash = crc32_add_string(hash, c->name);
49     return hash;
50 }
51
52 static void* dummy_clone(void*other) {return other;}
53 static void dummy_destroy(slotinfo_t*c) {}
54
55 type_t slotinfo_type = {
56     hash: (hash_func)slotinfo_hash,
57     equals: (equals_func)slotinfo_equals,
58     dup: (dup_func)dummy_clone, // all signatures are static
59     free: (free_func)dummy_destroy,
60 };
61
62 // ------------------------- constructors --------------------------------
63
64 #define AVERAGE_NUMBER_OF_MEMBERS 8
65 classinfo_t* classinfo_register(int access, const char*package, const char*name, int num_interfaces)
66 {
67     classinfo_t*c = rfx_calloc(sizeof(classinfo_t)+(sizeof(classinfo_t*)*(num_interfaces+1)));
68     c->interfaces[0] = 0;
69     c->kind = INFOTYPE_CLASS;
70     c->access = access;
71     c->package = package;
72     c->name = name;
73     dict_put(classes, c, c);
74     dict_init(&c->members,AVERAGE_NUMBER_OF_MEMBERS);
75     return c;
76 }
77 methodinfo_t* methodinfo_register_onclass(classinfo_t*cls, U8 access, const char*name)
78 {
79     NEW(methodinfo_t,m);
80     m->kind = INFOTYPE_METHOD;
81     m->access = access;
82     m->name = name;
83     m->parent = cls;
84     dict_put(&cls->members, name, m);
85     return m;
86 }
87 varinfo_t* varinfo_register_onclass(classinfo_t*cls, U8 access, const char*name)
88 {
89     NEW(varinfo_t,m);
90     m->kind = INFOTYPE_SLOT;
91     m->access = access;
92     m->name = name;
93     m->parent = cls;
94     dict_put(&cls->members, name, m);
95     return m;
96 }
97 methodinfo_t* methodinfo_register_global(U8 access, const char*package, const char*name)
98 {
99     NEW(methodinfo_t, m);
100     m->kind = INFOTYPE_METHOD;
101     m->flags = FLAG_STATIC;
102     m->access = access;
103     m->package = package;
104     m->name = name;
105     m->parent = 0;
106     dict_put(classes, m, m);
107     return m;
108 }
109 varinfo_t* varinfo_register_global(U8 access, const char*package, const char*name)
110 {
111     NEW(varinfo_t, m);
112     m->kind = INFOTYPE_SLOT;
113     m->flags = FLAG_STATIC;
114     m->access = access;
115     m->package = package;
116     m->name = name;
117     m->parent = 0;
118     dict_put(classes, m, m);
119     return m;
120 }
121
122 // --------------- builtin classes (from builtin.c) ----------------------
123
124 void registry_init()
125 {
126     if(!classes)
127         classes = builtin_getclasses();
128 }
129 slotinfo_t* registry_find(const char*package, const char*name)
130 {
131     assert(classes);
132     slotinfo_t tmp;
133     tmp.package = package;
134     tmp.name = name;
135     slotinfo_t* c = (slotinfo_t*)dict_lookup(classes, &tmp);
136     /*if(c)
137         printf("%s.%s->%08x (%s.%s)\n", package, name, c, c->package, c->name);*/
138     return c;
139 }
140 slotinfo_t* registry_safefind(const char*package, const char*name)
141 {
142     slotinfo_t*c = registry_find(package, name);
143     if(!c) {
144         printf("%s.%s\n", package, name);
145     }
146     assert(c);
147     return c;
148 }
149 void registry_dump()
150 {
151     int t;
152     for(t=0;t<classes->hashsize;t++) {
153         dictentry_t*e = classes->slots[t];
154         while(e) {
155             slotinfo_t*i = (slotinfo_t*)e->key;
156             printf("[%s] %s.%s\n", access2str(i->access), i->package, i->name);
157             e = e->next;
158         }
159     }
160 }
161
162 memberinfo_t* registry_findmember(classinfo_t*cls, const char*name, char recursive)
163 {
164     if(!recursive) {
165         return (memberinfo_t*)dict_lookup(&cls->members, name);
166     }
167     /* look at classes directly extended by this class */
168     slotinfo_t*m = 0;
169     classinfo_t*s = cls;
170
171     if(recursive>1) // check *only* superclasses
172         s = s->superclass;
173
174     while(s) {
175         m = (slotinfo_t*)dict_lookup(&s->members, name);
176         if(m) {
177             return (memberinfo_t*)m;
178         }
179         s = s->superclass;
180     }
181     /* look at interfaces, and parent interfaces */
182     int t=0;
183     while(cls->interfaces[t]) {
184         classinfo_t*s = cls->interfaces[t];
185         while(s) {
186             m = (slotinfo_t*)dict_lookup(&s->members, name);
187             if(m) {
188                 return (memberinfo_t*)m;
189             }
190             s = s->superclass;
191         }
192         t++;
193     }
194     return 0;
195
196 }
197 void registry_fill_multiname(multiname_t*m, namespace_t*n, slotinfo_t*c)
198 {
199     m->type = QNAME;
200     m->ns = n;
201     m->ns->access = c->access;
202     m->ns->name = (char*)c->package;
203     m->name = c->name;
204     m->namespace_set = 0;
205 }
206 multiname_t* classinfo_to_multiname(slotinfo_t*cls)
207 {
208     if(!cls)
209         return 0;
210     multiname_t*m=0;
211     namespace_t ns = {cls->access, (char*)cls->package};
212     return multiname_new(&ns,cls->name);
213 }
214
215 // ----------------------- memberinfo methods ------------------------------
216
217 /* hacky code to wrap a variable or function into a "type"
218    object, but keep a pointer to the "value" */
219 static dict_t* functionobjects = 0;
220 classinfo_t* slotinfo_asclass(slotinfo_t*f) {
221     if(!functionobjects) {
222         functionobjects = dict_new2(&ptr_type);
223     } else {
224         classinfo_t*c = dict_lookup(functionobjects, f);
225         if(c)
226             return c;
227     }
228
229     classinfo_t*c = rfx_calloc(sizeof(classinfo_t)+sizeof(classinfo_t*));
230     c->access = ACCESS_PUBLIC;
231     c->package = "";
232     if(f->kind == INFOTYPE_METHOD)
233         c->name = "Function";
234     else if(f->kind == INFOTYPE_CLASS)
235         c->name = "Class";
236     else if(f->kind == INFOTYPE_SLOT)
237         c->name = "Object";
238     
239     dict_init(&c->members,1);
240     c->data = f;
241     dict_put(functionobjects, f, c);
242     return c;
243 }
244
245 classinfo_t* slotinfo_gettype(slotinfo_t*f)
246 {
247     if(f) {
248        if(f->kind == INFOTYPE_METHOD) {
249            return slotinfo_asclass(f);
250        } else if(f->kind == INFOTYPE_SLOT) {
251            varinfo_t*v = (varinfo_t*)f;
252            return v->type;
253        } else 
254            return 0;
255     } else {
256        return registry_getanytype();
257     }
258 }
259 // ----------------------- builtin types ------------------------------
260 classinfo_t* registry_getanytype() {return 0;}
261
262 char registry_isfunctionclass(classinfo_t*c) {
263     return (c && c->package && c->name && 
264             !strcmp(c->package, "") && !strcmp(c->name, "Function"));
265 }
266 char registry_isclassclass(classinfo_t*c) {
267     return (c && c->package && c->name && 
268             !strcmp(c->package, "") && !strcmp(c->name, "Class"));
269 }
270
271 classinfo_t* registry_getobjectclass() {
272     static classinfo_t*c = 0;
273     if(!c) c = (classinfo_t*)registry_safefind("", "Object");
274     return c;
275 }
276 classinfo_t* registry_getstringclass() {
277     static classinfo_t*c = 0;
278     if(!c) c = (classinfo_t*)registry_safefind("", "String");
279     return c;
280 }
281 classinfo_t* registry_getarrayclass() {
282     static classinfo_t*c = 0;
283     if(!c) c = (classinfo_t*)registry_safefind("", "Array");
284     return c;
285 }
286 classinfo_t* registry_getintclass() {
287     static classinfo_t*c = 0;
288     if(!c) c = (classinfo_t*)registry_safefind("", "int");
289     return c;
290 }
291 classinfo_t* registry_getuintclass() {
292     static classinfo_t*c = 0;
293     if(!c) c = (classinfo_t*)registry_safefind("", "uint");
294     return c;
295 }
296 classinfo_t* registry_getbooleanclass() {
297     static classinfo_t*c = 0;
298     if(!c) c = (classinfo_t*)registry_safefind("", "Boolean");
299     return c;
300 }
301 classinfo_t* registry_getnumberclass() {
302     static classinfo_t*c = 0;
303     if(!c) c = (classinfo_t*)registry_safefind("", "Number");
304     return c;
305 }
306 classinfo_t* registry_getregexpclass() {
307     static classinfo_t*c = 0;
308     if(!c) c = (classinfo_t*)registry_safefind("", "RegExp");
309     return c;
310 }
311 classinfo_t* registry_getMovieClip() {
312     static classinfo_t*c = 0;
313     if(!c) c = (classinfo_t*)registry_safefind("flash.display", "MovieClip");
314     return c;
315 }
316
317 // ----------------------- builtin dummy types -------------------------
318 classinfo_t nullclass = {
319     INFOTYPE_CLASS,0,0,ACCESS_PACKAGE, "", "null", 0, 0, 0
320 };
321 classinfo_t* registry_getnullclass() {
322     return &nullclass;
323 }
324
325 namespace_t access2namespace(U8 access, char*package)
326 {
327     namespace_t ns;
328     ns.access = access;
329     ns.name = package;
330     return ns;
331 }
332
333 char* infotypename(slotinfo_t*s)
334 {
335     if(s->kind == INFOTYPE_CLASS) return "class";
336     else if(s->kind == INFOTYPE_SLOT) return "member";
337     else if(s->kind == INFOTYPE_METHOD) return "method";
338     else return "object";
339 }
340