4b6b66c139480d4549b5f0ed46751a74d49bb15a
[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 asset_bundle_list_t*assets=0;
31
32 // ----------------------- class signature ------------------------------
33
34 char slotinfo_equals(slotinfo_t*c1, slotinfo_t*c2)
35 {
36     if(!!c1 != !!c2)
37         return 0;
38     /* notice: access right is *not* respected */
39     if(!strcmp(c1->name, c2->name) &&
40        !strcmp(c1->package, c2->package)) {
41         return 1;
42     }
43     return 0;
44 }
45 static unsigned int slotinfo_hash(slotinfo_t*c)
46 {
47     unsigned int hash = 0;
48     hash = crc32_add_string(hash, c->package);
49     hash = crc32_add_string(hash, c->name);
50     return hash;
51 }
52 static unsigned int memberinfo_hash(slotinfo_t*c)
53 {
54     unsigned int hash = 0;
55     hash = crc32_add_string(hash, c->name);
56     return hash;
57 }
58
59 static void* dummy_clone(void*other) {return other;}
60 static void dummy_destroy(slotinfo_t*c) {}
61
62 type_t slotinfo_type = {
63     hash: (hash_func)slotinfo_hash,
64     equals: (equals_func)slotinfo_equals,
65     dup: (dup_func)dummy_clone, // all signatures are static
66     free: (free_func)dummy_destroy,
67 };
68 type_t memberinfo_type = {
69     hash: (hash_func)memberinfo_hash,
70     equals: (equals_func)slotinfo_equals,
71     dup: (dup_func)dummy_clone, // all signatures are static
72     free: (free_func)dummy_destroy,
73 };
74
75 // ----------------------- assets -------------------------------------
76 void registry_use(slotinfo_t*s)
77 {
78     if(s->kind == INFOTYPE_CLASS) {
79         classinfo_t*c=(classinfo_t*)s;
80         if(c->assets) c->assets->used = 1;
81     } else if(s->kind == INFOTYPE_METHOD) {
82         methodinfo_t*m=(methodinfo_t*)s;
83         if(m->parent) {
84             registry_use((slotinfo_t*)m->parent);
85         }
86     } else if(s->kind == INFOTYPE_VAR) {
87         varinfo_t*v=(varinfo_t*)s;
88         if(v->parent) {
89             registry_use((slotinfo_t*)v->parent);
90         }
91     }
92 }
93 void registry_add_asset(asset_bundle_t*bundle)
94 {
95     list_append(assets, bundle);
96 }
97 asset_bundle_list_t*registry_getassets()
98 {
99     return assets;
100 }
101 // ----------------------- resolving ----------------------------------
102 slotinfo_t* registry_resolve(slotinfo_t*_s)
103 {
104     if(!_s || _s->kind != INFOTYPE_UNRESOLVED)
105         return _s;
106     unresolvedinfo_t*s = (unresolvedinfo_t*)_s;
107
108     if(s->package)
109         return registry_find(s->package, s->name);
110
111     namespace_list_t*l = s->nsset;
112     while(l) {
113         slotinfo_t* n = registry_find(l->namespace->name, s->name);
114         if(n) return n;
115         l = l->next;
116     }
117     return 0;
118 }
119
120 static slotinfo_list_t*unresolved = 0;
121 static void schedule_for_resolve(slotinfo_t*s)
122 {
123     list_append(unresolved, s);
124 }
125 static void resolve_on_slot(slotinfo_t*_member)
126 {
127     if(_member->kind == INFOTYPE_VAR) {
128         varinfo_t*member = (varinfo_t*)_member;
129         member->type = (classinfo_t*)registry_resolve((slotinfo_t*)member->type);
130     } else if(_member->kind == INFOTYPE_METHOD) {
131         methodinfo_t*member = (methodinfo_t*)_member;
132         member->return_type = (classinfo_t*)registry_resolve((slotinfo_t*)member->return_type);
133         classinfo_list_t*l = member->params;
134         while(l) {
135             l->classinfo = (classinfo_t*)registry_resolve((slotinfo_t*)l->classinfo);
136             l = l->next;
137         }
138     } else fprintf(stderr, "Internal Error: bad slot %s", _member->name);
139 }
140 static void resolve_on_class(slotinfo_t*_cls)
141 {
142     classinfo_t*cls = (classinfo_t*)_cls;
143     cls->superclass = (classinfo_t*)registry_resolve((slotinfo_t*)cls->superclass);
144         
145     DICT_ITERATE_DATA(&cls->members,slotinfo_t*,m) {
146         resolve_on_slot(m);
147     }
148     DICT_ITERATE_DATA(&cls->static_members,slotinfo_t*,m2) {
149         resolve_on_slot(m2);
150     }
151
152     int t=0;
153     while(cls->interfaces[t]) {
154         cls->interfaces[t] = (classinfo_t*)registry_resolve((slotinfo_t*)cls->interfaces[t]);
155         t++;
156     }
157 }
158 void registry_resolve_all()
159 {
160     while(unresolved) {
161         slotinfo_t*_s = unresolved->slotinfo;
162         if(_s->kind == INFOTYPE_CLASS) {
163             resolve_on_class(_s);
164         } else if(_s->kind == INFOTYPE_METHOD || _s->kind == INFOTYPE_VAR) {
165             resolve_on_slot(_s);
166         } else {
167             fprintf(stderr, "Internal Error: object %s.%s has bad type\n", _s->package, _s->name);
168         }
169         slotinfo_list_t*tofree = unresolved;
170         unresolved = unresolved->next;
171         free(tofree);
172     }
173 }
174 // ------------------------- constructors --------------------------------
175
176 #define AVERAGE_NUMBER_OF_MEMBERS 8
177 classinfo_t* classinfo_register(int access, const char*package, const char*name, int num_interfaces)
178 {
179     classinfo_t*c = rfx_calloc(sizeof(classinfo_t)+(sizeof(classinfo_t*)*(num_interfaces+1)));
180     c->interfaces[0] = 0;
181     c->kind = INFOTYPE_CLASS;
182     c->access = access;
183     c->package = package;
184     c->name = name;
185     dict_put(registry_classes, c, c);
186     dict_init2(&c->members, &memberinfo_type, AVERAGE_NUMBER_OF_MEMBERS);
187     dict_init2(&c->static_members, &memberinfo_type, AVERAGE_NUMBER_OF_MEMBERS);
188
189     schedule_for_resolve((slotinfo_t*)c);
190     return c;
191 }
192 methodinfo_t* methodinfo_register_onclass(classinfo_t*cls, U8 access, const char*ns, const char*name, char is_static)
193 {
194     NEW(methodinfo_t,m);
195     m->kind = INFOTYPE_METHOD;
196     m->access = access;
197     m->name = name;
198     m->package = ns;
199     m->parent = cls;
200     if(!is_static) 
201         dict_put(&cls->members, m, m);
202     else
203         dict_put(&cls->static_members, m, m);
204     return m;
205 }
206 varinfo_t* varinfo_register_onclass(classinfo_t*cls, U8 access, const char*ns, const char*name, char is_static)
207 {
208     NEW(varinfo_t,m);
209     m->kind = INFOTYPE_VAR;
210     m->access = access;
211     m->name = name;
212     m->package = ns;
213     m->parent = cls;
214     if(!is_static) 
215         dict_put(&cls->members, m, m);
216     else
217         dict_put(&cls->static_members, m, m);
218     return m;
219 }
220 methodinfo_t* methodinfo_register_global(U8 access, const char*package, const char*name)
221 {
222     NEW(methodinfo_t, m);
223     m->kind = INFOTYPE_METHOD;
224     m->flags = FLAG_STATIC;
225     m->access = access;
226     m->package = package;
227     m->name = name;
228     m->parent = 0;
229     dict_put(registry_classes, m, m);
230     
231     schedule_for_resolve((slotinfo_t*)m);
232     return m;
233 }
234 varinfo_t* varinfo_register_global(U8 access, const char*package, const char*name)
235 {
236     NEW(varinfo_t, m);
237     m->kind = INFOTYPE_VAR;
238     m->flags = FLAG_STATIC;
239     m->access = access;
240     m->package = package;
241     m->name = name;
242     m->parent = 0;
243     dict_put(registry_classes, m, m);
244     
245     schedule_for_resolve((slotinfo_t*)m);
246     return m;
247 }
248
249 // --------------- builtin classes (from builtin.c) ----------------------
250
251 void registry_init()
252 {
253     if(!registry_classes)
254         registry_classes = builtin_getclasses();
255 }
256 slotinfo_t* registry_find(const char*package, const char*name)
257 {
258     assert(registry_classes);
259     slotinfo_t tmp;
260     tmp.package = package;
261     tmp.name = name;
262     slotinfo_t* c = (slotinfo_t*)dict_lookup(registry_classes, &tmp);
263     /*if(c)
264         printf("%s.%s->%08x (%s.%s)\n", package, name, c, c->package, c->name);*/
265     return c;
266 }
267 slotinfo_t* registry_safefind(const char*package, const char*name)
268 {
269     slotinfo_t*c = registry_find(package, name);
270     if(!c) {
271         printf("%s.%s\n", package, name);
272     }
273     assert(c);
274     return c;
275 }
276 void registry_dump()
277 {
278     int t;
279     for(t=0;t<registry_classes->hashsize;t++) {
280         dictentry_t*e = registry_classes->slots[t];
281         while(e) {
282             slotinfo_t*i = (slotinfo_t*)e->key;
283             printf("[%s] %s.%s\n", access2str(i->access), i->package, i->name);
284             e = e->next;
285         }
286     }
287 }
288
289 memberinfo_t* registry_findmember(classinfo_t*cls, const char*ns, const char*name, char recursive, char is_static)
290 {
291     memberinfo_t tmp;
292     tmp.name = name;
293     tmp.package = ns?ns:"";
294
295     if(!recursive) {
296         if(!is_static) 
297             return (memberinfo_t*)dict_lookup(&cls->members, &tmp);
298         else
299             return (memberinfo_t*)dict_lookup(&cls->static_members, &tmp);
300     }
301     /* look at classes directly extended by this class */
302     slotinfo_t*m = 0;
303     classinfo_t*s = cls;
304
305     if(recursive>1) // check *only* superclasses
306         s = s->superclass;
307
308     while(s) {
309         if(s->kind == INFOTYPE_UNRESOLVED)
310             break;
311
312         if(!is_static) {
313             m = (slotinfo_t*)dict_lookup(&s->members, &tmp);
314             if(m) return (memberinfo_t*)m;
315         }
316         m = (slotinfo_t*)dict_lookup(&s->static_members, &tmp);
317         if(m) return (memberinfo_t*)m;
318
319         s = s->superclass;
320     }
321     /* look at interfaces, and parent interfaces */
322     int t=0;
323     while(cls->interfaces[t]) {
324         classinfo_t*s = cls->interfaces[t];
325         if(s->kind != INFOTYPE_UNRESOLVED) {
326             while(s) {
327                 if(!is_static) {
328                     m = (slotinfo_t*)dict_lookup(&s->members, &tmp);
329                     if(m) return (memberinfo_t*)m;
330                 }
331                 m = (slotinfo_t*)dict_lookup(&s->static_members, &tmp);
332                 if(m) return (memberinfo_t*)m;
333
334                 s = s->superclass;
335             }
336         }
337         t++;
338     }
339     return 0;
340 }
341
342 memberinfo_t* registry_findmember_nsset(classinfo_t*cls, namespace_list_t*ns, const char*name, char superclasses, char is_static)
343 {
344     memberinfo_t*m = 0;
345     while(ns) {
346         m = registry_findmember(cls, ns->namespace->name, name, superclasses, is_static);
347         if(m) return m;
348         ns = ns->next;
349     }
350     m = registry_findmember(cls, "", name, superclasses, is_static);
351     if(m) return m;
352     /* TODO: it maybe would be faster to just store the builtin namespace as "" in
353              builtins.c (update: some members (e.g. XML.length) are present both for
354             "" and "http:...builtin") */
355     m = registry_findmember(cls, "http://adobe.com/AS3/2006/builtin", name, superclasses, is_static);
356     if(m) return m;
357     return 0;
358 }
359
360
361 void registry_fill_multiname(multiname_t*m, namespace_t*n, slotinfo_t*c)
362 {
363     m->type = QNAME;
364     m->ns = n;
365     m->ns->access = c->access;
366     m->ns->name = (char*)c->package;
367     m->name = c->name;
368     m->namespace_set = 0;
369 }
370 multiname_t* classinfo_to_multiname(slotinfo_t*cls)
371 {
372     if(!cls)
373         return 0;
374     multiname_t*m=0;
375     namespace_t ns = {cls->access, (char*)cls->package};
376     return multiname_new(&ns,cls->name);
377 }
378
379 // ----------------------- memberinfo methods ------------------------------
380
381 /* hacky code to wrap a variable or function into a "type"
382    object, but keep a pointer to the "value" */
383 static dict_t* functionobjects = 0;
384 classinfo_t* slotinfo_asclass(slotinfo_t*f) {
385     if(!functionobjects) {
386         functionobjects = dict_new2(&ptr_type);
387     } else {
388         classinfo_t*c = dict_lookup(functionobjects, f);
389         if(c)
390             return c;
391     }
392
393     classinfo_t*c = rfx_calloc(sizeof(classinfo_t)+sizeof(classinfo_t*));
394     c->access = ACCESS_PUBLIC;
395     c->package = "";
396     if(f->kind == INFOTYPE_METHOD) {
397         c->name = "Function";
398         c->superclass = registry_getobjectclass();
399     } else if(f->kind == INFOTYPE_CLASS) {
400         c->name = "Class";
401         c->superclass = registry_getobjectclass();
402     } else if(f->kind == INFOTYPE_VAR) {
403         c->name = "Object";
404     } else {
405         c->name = "undefined";
406     }
407     
408     dict_init2(&c->members, &memberinfo_type, 1);
409     dict_init2(&c->static_members, &memberinfo_type, 1);
410     c->data = f;
411     dict_put(functionobjects, f, c);
412     return c;
413 }
414
415 classinfo_t* slotinfo_gettype(slotinfo_t*f)
416 {
417     if(f) {
418        if(f->kind == INFOTYPE_METHOD) {
419            return slotinfo_asclass(f);
420        } else if(f->kind == INFOTYPE_VAR) {
421            varinfo_t*v = (varinfo_t*)f;
422            return v->type;
423        } else 
424            return 0;
425     } else {
426        return TYPE_ANY;
427     }
428 }
429
430 // ----------------------- package handling ---------------------------
431 char registry_ispackage(const char*package)
432 {
433     /* crude approximation of "the real thing", but sufficient for now */
434     return !strncmp(package, "flash", 5);
435 }
436 // ----------------------- builtin types ------------------------------
437
438 char registry_isfunctionclass(classinfo_t*c) {
439     return (c && c->package && c->name && 
440             !strcmp(c->package, "") && !strcmp(c->name, "Function"));
441 }
442 char registry_isclassclass(classinfo_t*c) {
443     return (c && c->package && c->name && 
444             !strcmp(c->package, "") && !strcmp(c->name, "Class"));
445 }
446
447 classinfo_t* registry_getobjectclass() {
448     static classinfo_t*c = 0;
449     if(!c) c = (classinfo_t*)registry_safefind("", "Object");
450     return c;
451 }
452 classinfo_t* registry_getstringclass() {
453     static classinfo_t*c = 0;
454     if(!c) c = (classinfo_t*)registry_safefind("", "String");
455     return c;
456 }
457 classinfo_t* registry_getarrayclass() {
458     static classinfo_t*c = 0;
459     if(!c) c = (classinfo_t*)registry_safefind("", "Array");
460     return c;
461 }
462 classinfo_t* registry_getintclass() {
463     static classinfo_t*c = 0;
464     if(!c) c = (classinfo_t*)registry_safefind("", "int");
465     return c;
466 }
467 classinfo_t* registry_getuintclass() {
468     static classinfo_t*c = 0;
469     if(!c) c = (classinfo_t*)registry_safefind("", "uint");
470     return c;
471 }
472 classinfo_t* registry_getbooleanclass() {
473     static classinfo_t*c = 0;
474     if(!c) c = (classinfo_t*)registry_safefind("", "Boolean");
475     return c;
476 }
477 classinfo_t* registry_getnumberclass() {
478     static classinfo_t*c = 0;
479     if(!c) c = (classinfo_t*)registry_safefind("", "Number");
480     return c;
481 }
482 classinfo_t* registry_getregexpclass() {
483     static classinfo_t*c = 0;
484     if(!c) c = (classinfo_t*)registry_safefind("", "RegExp");
485     return c;
486 }
487 classinfo_t* registry_getdateclass() {
488     static classinfo_t*c = 0;
489     if(!c) c = (classinfo_t*)registry_safefind("", "Date");
490     return c;
491 }
492 classinfo_t* registry_getxmlclass() {
493     static classinfo_t*c = 0;
494     if(!c) c = (classinfo_t*)registry_safefind("", "XML");
495     return c;
496 }
497 classinfo_t* registry_getxmllistclass() {
498     static classinfo_t*c = 0;
499     if(!c) c = (classinfo_t*)registry_safefind("", "XMLList");
500     return c;
501 }
502 classinfo_t* registry_getnamespaceclass() {
503     static classinfo_t*c = 0;
504     if(!c) c = (classinfo_t*)registry_safefind("", "Namespace");
505     return c;
506 }
507 classinfo_t* registry_getMovieClip() {
508     static classinfo_t*c = 0;
509     if(!c) c = (classinfo_t*)registry_safefind("flash.display", "MovieClip");
510     return c;
511 }
512
513 // ----------------------- builtin dummy types -------------------------
514 classinfo_t nullclass = {
515     INFOTYPE_CLASS,0,0,ACCESS_PACKAGE, "", "null", 0, 0, 0
516 };
517 classinfo_t* registry_getnullclass() {
518     return &nullclass;
519 }
520 classinfo_t voidclass = {
521     INFOTYPE_CLASS,0,0,ACCESS_PACKAGE, "", "void", 0, 0, 0
522 };
523 classinfo_t* registry_getvoidclass() {
524     return &voidclass;
525 }
526
527 namespace_t access2namespace(U8 access, char*package)
528 {
529     namespace_t ns;
530     ns.access = access;
531     ns.name = package;
532     return ns;
533 }
534
535 char* infotypename(slotinfo_t*s)
536 {
537     if(s->kind == INFOTYPE_CLASS) return "class";
538     else if(s->kind == INFOTYPE_VAR) return "var";
539     else if(s->kind == INFOTYPE_METHOD) return "function";
540     else return "object";
541 }
542
543 void slotinfo_dump(slotinfo_t*s)
544 {
545     if(s->package[0]) {
546         printf("%s %s.%s", infotypename(s), s->package, s->name);
547     } else {
548         printf("%s %s", infotypename(s), s->name);
549     }
550     if(s->kind == INFOTYPE_CLASS) {
551         classinfo_t*c = (classinfo_t*)s;
552     }
553     else if(s->kind == INFOTYPE_VAR) {
554         varinfo_t*v = (varinfo_t*)s;
555         printf(":%s", v->type?v->type->name:"*");
556         if(v->value)
557             printf("=%s", constant_tostring(v->value));
558         if(v->slot)
559             printf(" (slot:%d)", v->slot);
560     }
561     else if(s->kind == INFOTYPE_METHOD) {
562         methodinfo_t*m = (methodinfo_t*)s;
563     }
564     else {
565     }
566     printf("\n");
567 }
568