new registry format
[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 dict_t*registry_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(registry_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(registry_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(registry_classes, m, m);
119     return m;
120 }
121
122 // --------------- builtin classes (from builtin.c) ----------------------
123
124 void registry_init()
125 {
126     if(!registry_classes)
127         registry_classes = builtin_getclasses();
128 }
129 slotinfo_t* registry_find(const char*package, const char*name)
130 {
131     assert(registry_classes);
132     slotinfo_t tmp;
133     tmp.package = package;
134     tmp.name = name;
135     slotinfo_t* c = (slotinfo_t*)dict_lookup(registry_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<registry_classes->hashsize;t++) {
153         dictentry_t*e = registry_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     else {
239         c->name = "undefined";
240     }
241     
242     dict_init(&c->members,1);
243     c->data = f;
244     dict_put(functionobjects, f, c);
245     return c;
246 }
247
248 classinfo_t* slotinfo_gettype(slotinfo_t*f)
249 {
250     if(f) {
251        if(f->kind == INFOTYPE_METHOD) {
252            return slotinfo_asclass(f);
253        } else if(f->kind == INFOTYPE_SLOT) {
254            varinfo_t*v = (varinfo_t*)f;
255            return v->type;
256        } else 
257            return 0;
258     } else {
259        return registry_getanytype();
260     }
261 }
262 // ----------------------- builtin types ------------------------------
263 classinfo_t* registry_getanytype() {return 0;}
264
265 char registry_isfunctionclass(classinfo_t*c) {
266     return (c && c->package && c->name && 
267             !strcmp(c->package, "") && !strcmp(c->name, "Function"));
268 }
269 char registry_isclassclass(classinfo_t*c) {
270     return (c && c->package && c->name && 
271             !strcmp(c->package, "") && !strcmp(c->name, "Class"));
272 }
273
274 classinfo_t* registry_getobjectclass() {
275     static classinfo_t*c = 0;
276     if(!c) c = (classinfo_t*)registry_safefind("", "Object");
277     return c;
278 }
279 classinfo_t* registry_getstringclass() {
280     static classinfo_t*c = 0;
281     if(!c) c = (classinfo_t*)registry_safefind("", "String");
282     return c;
283 }
284 classinfo_t* registry_getarrayclass() {
285     static classinfo_t*c = 0;
286     if(!c) c = (classinfo_t*)registry_safefind("", "Array");
287     return c;
288 }
289 classinfo_t* registry_getintclass() {
290     static classinfo_t*c = 0;
291     if(!c) c = (classinfo_t*)registry_safefind("", "int");
292     return c;
293 }
294 classinfo_t* registry_getuintclass() {
295     static classinfo_t*c = 0;
296     if(!c) c = (classinfo_t*)registry_safefind("", "uint");
297     return c;
298 }
299 classinfo_t* registry_getbooleanclass() {
300     static classinfo_t*c = 0;
301     if(!c) c = (classinfo_t*)registry_safefind("", "Boolean");
302     return c;
303 }
304 classinfo_t* registry_getnumberclass() {
305     static classinfo_t*c = 0;
306     if(!c) c = (classinfo_t*)registry_safefind("", "Number");
307     return c;
308 }
309 classinfo_t* registry_getregexpclass() {
310     static classinfo_t*c = 0;
311     if(!c) c = (classinfo_t*)registry_safefind("", "RegExp");
312     return c;
313 }
314 classinfo_t* registry_getMovieClip() {
315     static classinfo_t*c = 0;
316     if(!c) c = (classinfo_t*)registry_safefind("flash.display", "MovieClip");
317     return c;
318 }
319
320 // ----------------------- builtin dummy types -------------------------
321 classinfo_t nullclass = {
322     INFOTYPE_CLASS,0,0,ACCESS_PACKAGE, "", "null", 0, 0, 0
323 };
324 classinfo_t* registry_getnullclass() {
325     return &nullclass;
326 }
327
328 namespace_t access2namespace(U8 access, char*package)
329 {
330     namespace_t ns;
331     ns.access = access;
332     ns.name = package;
333     return ns;
334 }
335
336 char* infotypename(slotinfo_t*s)
337 {
338     if(s->kind == INFOTYPE_CLASS) return "class";
339     else if(s->kind == INFOTYPE_SLOT) return "member";
340     else if(s->kind == INFOTYPE_METHOD) return "method";
341     else return "object";
342 }
343