3 Routines for compiling Flash2 AVM2 ABC Actionscript
5 Extension module for the rfxswf library.
6 Part of the swftools package.
8 Copyright (c) 2008 Matthias Kramm <kramm@quiss.org>
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.
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.
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 */
29 dict_t
*registry_classes
=0;
30 asset_bundle_list_t
*assets
=0;
32 // ----------------------- class signature ------------------------------
34 char slotinfo_equals(slotinfo_t
*c1
, slotinfo_t
*c2
)
38 /* notice: access right is *not* respected */
39 if(!strcmp(c1
->name
, c2
->name
) &&
40 !strcmp(c1
->package
, c2
->package
)) {
45 static unsigned int slotinfo_hash(slotinfo_t
*c
)
47 unsigned int hash
= 0;
48 hash
= crc32_add_string(hash
, c
->package
);
49 hash
= crc32_add_string(hash
, c
->name
);
52 static unsigned int memberinfo_hash(slotinfo_t
*c
)
54 unsigned int hash
= 0;
55 hash
= crc32_add_string(hash
, c
->name
);
59 static void* dummy_clone(void*other
) {return other
;}
60 static void dummy_destroy(slotinfo_t
*c
) {}
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
,
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
,
75 // ----------------------- assets -------------------------------------
76 static void use_asset(asset_bundle_t
*a
)
79 asset_bundle_list_t
*l
= a
->dependencies
;
81 if(!l
->asset_bundle
->used
) {
82 use_asset(l
->asset_bundle
);
87 void registry_use(slotinfo_t
*s
)
90 if(!(s
->flags
&FLAG_USED
)) {
91 s
->flags
|= FLAG_USED
;
92 if(s
->kind
== INFOTYPE_CLASS
) {
93 classinfo_t
*c
=(classinfo_t
*)s
;
98 while(c
->interfaces
[t
]) {
99 registry_use((slotinfo_t
*)c
->interfaces
[t
]);
102 while(c
->superclass
) {
104 registry_use((slotinfo_t
*)c
);
106 } else if(s
->kind
== INFOTYPE_METHOD
) {
107 methodinfo_t
*m
=(methodinfo_t
*)s
;
109 registry_use((slotinfo_t
*)m
->parent
);
111 } else if(s
->kind
== INFOTYPE_VAR
) {
112 varinfo_t
*v
=(varinfo_t
*)s
;
114 registry_use((slotinfo_t
*)v
->parent
);
119 void registry_add_asset(asset_bundle_t
*bundle
)
121 list_append(assets
, bundle
);
123 asset_bundle_list_t
*registry_getassets()
127 // ----------------------- resolving ----------------------------------
128 slotinfo_t
* registry_resolve(slotinfo_t
*_s
)
130 if(!_s
|| _s
->kind
!= INFOTYPE_UNRESOLVED
)
132 unresolvedinfo_t
*s
= (unresolvedinfo_t
*)_s
;
135 return registry_find(s
->package
, s
->name
);
137 namespace_list_t
*l
= s
->nsset
;
139 slotinfo_t
* n
= registry_find(l
->namespace->name
, s
->name
);
146 static slotinfo_list_t
*unresolved
= 0;
147 static void schedule_for_resolve(slotinfo_t
*s
)
149 list_append(unresolved
, s
);
151 static void resolve_on_slot(slotinfo_t
*_member
)
153 if(_member
->kind
== INFOTYPE_VAR
) {
154 varinfo_t
*member
= (varinfo_t
*)_member
;
155 member
->type
= (classinfo_t
*)registry_resolve((slotinfo_t
*)member
->type
);
156 } else if(_member
->kind
== INFOTYPE_METHOD
) {
157 methodinfo_t
*member
= (methodinfo_t
*)_member
;
158 member
->return_type
= (classinfo_t
*)registry_resolve((slotinfo_t
*)member
->return_type
);
159 classinfo_list_t
*l
= member
->params
;
161 l
->classinfo
= (classinfo_t
*)registry_resolve((slotinfo_t
*)l
->classinfo
);
164 } else fprintf(stderr
, "Internal Error: bad slot %s", _member
->name
);
166 static void resolve_on_class(slotinfo_t
*_cls
)
168 classinfo_t
*cls
= (classinfo_t
*)_cls
;
169 cls
->superclass
= (classinfo_t
*)registry_resolve((slotinfo_t
*)cls
->superclass
);
171 DICT_ITERATE_DATA(&cls
->members
,slotinfo_t
*,m
) {
174 DICT_ITERATE_DATA(&cls
->static_members
,slotinfo_t
*,m2
) {
179 while(cls
->interfaces
[t
]) {
180 cls
->interfaces
[t
] = (classinfo_t
*)registry_resolve((slotinfo_t
*)cls
->interfaces
[t
]);
184 void registry_resolve_all()
187 slotinfo_t
*_s
= unresolved
->slotinfo
;
188 if(_s
->kind
== INFOTYPE_CLASS
) {
189 resolve_on_class(_s
);
190 } else if(_s
->kind
== INFOTYPE_METHOD
|| _s
->kind
== INFOTYPE_VAR
) {
193 fprintf(stderr
, "Internal Error: object %s.%s has bad type\n", _s
->package
, _s
->name
);
195 slotinfo_list_t
*tofree
= unresolved
;
196 unresolved
= unresolved
->next
;
200 // ------------------------- constructors --------------------------------
202 #define AVERAGE_NUMBER_OF_MEMBERS 8
203 classinfo_t
* classinfo_register(int access
, const char*package
, const char*name
, int num_interfaces
)
205 classinfo_t
*c
= rfx_calloc(sizeof(classinfo_t
)+(sizeof(classinfo_t
*)*(num_interfaces
+1)));
206 c
->interfaces
[0] = 0;
207 c
->kind
= INFOTYPE_CLASS
;
209 c
->package
= package
;
211 dict_put(registry_classes
, c
, c
);
212 dict_init2(&c
->members
, &memberinfo_type
, AVERAGE_NUMBER_OF_MEMBERS
);
213 dict_init2(&c
->static_members
, &memberinfo_type
, AVERAGE_NUMBER_OF_MEMBERS
);
215 schedule_for_resolve((slotinfo_t
*)c
);
218 methodinfo_t
* methodinfo_register_onclass(classinfo_t
*cls
, U8 access
, const char*ns
, const char*name
, char is_static
)
221 m
->kind
= INFOTYPE_METHOD
;
227 dict_put(&cls
->members
, m
, m
);
229 dict_put(&cls
->static_members
, m
, m
);
232 varinfo_t
* varinfo_register_onclass(classinfo_t
*cls
, U8 access
, const char*ns
, const char*name
, char is_static
)
235 m
->kind
= INFOTYPE_VAR
;
241 dict_put(&cls
->members
, m
, m
);
243 dict_put(&cls
->static_members
, m
, m
);
246 methodinfo_t
* methodinfo_register_global(U8 access
, const char*package
, const char*name
)
248 NEW(methodinfo_t
, m
);
249 m
->kind
= INFOTYPE_METHOD
;
250 m
->flags
= FLAG_STATIC
;
252 m
->package
= package
;
255 dict_put(registry_classes
, m
, m
);
257 schedule_for_resolve((slotinfo_t
*)m
);
260 varinfo_t
* varinfo_register_global(U8 access
, const char*package
, const char*name
)
263 m
->kind
= INFOTYPE_VAR
;
264 m
->flags
= FLAG_STATIC
;
266 m
->package
= package
;
269 dict_put(registry_classes
, m
, m
);
271 schedule_for_resolve((slotinfo_t
*)m
);
275 // --------------- builtin classes (from builtin.c) ----------------------
279 if(!registry_classes
)
280 registry_classes
= builtin_getclasses();
282 slotinfo_t
* registry_find(const char*package
, const char*name
)
284 assert(registry_classes
);
286 tmp
.package
= package
;
288 slotinfo_t
* c
= (slotinfo_t
*)dict_lookup(registry_classes
, &tmp
);
290 printf("%s.%s->%08x (%s.%s)\n", package, name, c, c->package, c->name);*/
293 slotinfo_t
* registry_safefind(const char*package
, const char*name
)
295 slotinfo_t
*c
= registry_find(package
, name
);
297 printf("%s.%s\n", package
, name
);
305 for(t
=0;t
<registry_classes
->hashsize
;t
++) {
306 dictentry_t
*e
= registry_classes
->slots
[t
];
308 slotinfo_t
*i
= (slotinfo_t
*)e
->key
;
309 printf("[%s] %s.%s\n", access2str(i
->access
), i
->package
, i
->name
);
315 memberinfo_t
* registry_findmember(classinfo_t
*cls
, const char*ns
, const char*name
, char recursive
, char is_static
)
319 tmp
.package
= ns
?ns
:"";
323 return (memberinfo_t
*)dict_lookup(&cls
->members
, &tmp
);
325 return (memberinfo_t
*)dict_lookup(&cls
->static_members
, &tmp
);
327 /* look at classes directly extended by this class */
331 if(recursive
>1) // check *only* superclasses
335 if(s
->kind
== INFOTYPE_UNRESOLVED
)
339 m
= (slotinfo_t
*)dict_lookup(&s
->members
, &tmp
);
340 if(m
) return (memberinfo_t
*)m
;
342 m
= (slotinfo_t
*)dict_lookup(&s
->static_members
, &tmp
);
343 if(m
) return (memberinfo_t
*)m
;
347 /* look at interfaces, and parent interfaces */
349 while(cls
->interfaces
[t
]) {
350 classinfo_t
*s
= cls
->interfaces
[t
];
351 if(s
->kind
!= INFOTYPE_UNRESOLVED
) {
354 m
= (slotinfo_t
*)dict_lookup(&s
->members
, &tmp
);
355 if(m
) return (memberinfo_t
*)m
;
357 m
= (slotinfo_t
*)dict_lookup(&s
->static_members
, &tmp
);
358 if(m
) return (memberinfo_t
*)m
;
368 memberinfo_t
* registry_findmember_nsset(classinfo_t
*cls
, namespace_list_t
*ns
, const char*name
, char superclasses
, char is_static
)
372 m
= registry_findmember(cls
, ns
->namespace->name
, name
, superclasses
, is_static
);
376 m
= registry_findmember(cls
, "", name
, superclasses
, is_static
);
378 /* TODO: it maybe would be faster to just store the builtin namespace as "" in
379 builtins.c (update: some members (e.g. XML.length) are present both for
380 "" and "http:...builtin") */
381 m
= registry_findmember(cls
, "http://adobe.com/AS3/2006/builtin", name
, superclasses
, is_static
);
387 void registry_fill_multiname(multiname_t
*m
, namespace_t
*n
, slotinfo_t
*c
)
391 m
->ns
->access
= c
->access
;
392 m
->ns
->name
= (char*)c
->package
;
394 m
->namespace_set
= 0;
396 multiname_t
* classinfo_to_multiname(slotinfo_t
*cls
)
401 namespace_t ns
= {cls
->access
, (char*)cls
->package
};
402 return multiname_new(&ns
,cls
->name
);
405 // ----------------------- memberinfo methods ------------------------------
407 /* hacky code to wrap a variable or function into a "type"
408 object, but keep a pointer to the "value" */
409 static dict_t
* functionobjects
= 0;
410 classinfo_t
* slotinfo_asclass(slotinfo_t
*f
) {
411 if(!functionobjects
) {
412 functionobjects
= dict_new2(&ptr_type
);
414 classinfo_t
*c
= dict_lookup(functionobjects
, f
);
419 classinfo_t
*c
= rfx_calloc(sizeof(classinfo_t
)+sizeof(classinfo_t
*));
420 c
->access
= ACCESS_PUBLIC
;
422 if(f
->kind
== INFOTYPE_METHOD
) {
423 c
->name
= "Function";
424 c
->superclass
= registry_getobjectclass();
425 } else if(f
->kind
== INFOTYPE_CLASS
) {
427 c
->superclass
= registry_getobjectclass();
428 } else if(f
->kind
== INFOTYPE_VAR
) {
431 c
->name
= "undefined";
434 dict_init2(&c
->members
, &memberinfo_type
, 1);
435 dict_init2(&c
->static_members
, &memberinfo_type
, 1);
437 dict_put(functionobjects
, f
, c
);
441 classinfo_t
* slotinfo_gettype(slotinfo_t
*f
)
444 if(f
->kind
== INFOTYPE_METHOD
) {
445 return slotinfo_asclass(f
);
446 } else if(f
->kind
== INFOTYPE_VAR
) {
447 varinfo_t
*v
= (varinfo_t
*)f
;
456 // ----------------------- package handling ---------------------------
457 char registry_ispackage(const char*package
)
459 /* crude approximation of "the real thing", but sufficient for now */
460 return !strncmp(package
, "flash", 5);
462 // ----------------------- builtin types ------------------------------
464 char registry_isfunctionclass(classinfo_t
*c
) {
465 return (c
&& c
->package
&& c
->name
&&
466 !strcmp(c
->package
, "") && !strcmp(c
->name
, "Function"));
468 char registry_isclassclass(classinfo_t
*c
) {
469 return (c
&& c
->package
&& c
->name
&&
470 !strcmp(c
->package
, "") && !strcmp(c
->name
, "Class"));
473 classinfo_t
* registry_getobjectclass() {
474 static classinfo_t
*c
= 0;
475 if(!c
) c
= (classinfo_t
*)registry_safefind("", "Object");
478 classinfo_t
* registry_getstringclass() {
479 static classinfo_t
*c
= 0;
480 if(!c
) c
= (classinfo_t
*)registry_safefind("", "String");
483 classinfo_t
* registry_getarrayclass() {
484 static classinfo_t
*c
= 0;
485 if(!c
) c
= (classinfo_t
*)registry_safefind("", "Array");
488 classinfo_t
* registry_getintclass() {
489 static classinfo_t
*c
= 0;
490 if(!c
) c
= (classinfo_t
*)registry_safefind("", "int");
493 classinfo_t
* registry_getuintclass() {
494 static classinfo_t
*c
= 0;
495 if(!c
) c
= (classinfo_t
*)registry_safefind("", "uint");
498 classinfo_t
* registry_getbooleanclass() {
499 static classinfo_t
*c
= 0;
500 if(!c
) c
= (classinfo_t
*)registry_safefind("", "Boolean");
503 classinfo_t
* registry_getnumberclass() {
504 static classinfo_t
*c
= 0;
505 if(!c
) c
= (classinfo_t
*)registry_safefind("", "Number");
508 classinfo_t
* registry_getregexpclass() {
509 static classinfo_t
*c
= 0;
510 if(!c
) c
= (classinfo_t
*)registry_safefind("", "RegExp");
513 classinfo_t
* registry_getdateclass() {
514 static classinfo_t
*c
= 0;
515 if(!c
) c
= (classinfo_t
*)registry_safefind("", "Date");
518 classinfo_t
* registry_getxmlclass() {
519 static classinfo_t
*c
= 0;
520 if(!c
) c
= (classinfo_t
*)registry_safefind("", "XML");
523 classinfo_t
* registry_getxmllistclass() {
524 static classinfo_t
*c
= 0;
525 if(!c
) c
= (classinfo_t
*)registry_safefind("", "XMLList");
528 classinfo_t
* registry_getnamespaceclass() {
529 static classinfo_t
*c
= 0;
530 if(!c
) c
= (classinfo_t
*)registry_safefind("", "Namespace");
533 classinfo_t
* registry_getMovieClip() {
534 static classinfo_t
*c
= 0;
535 if(!c
) c
= (classinfo_t
*)registry_safefind("flash.display", "MovieClip");
539 // ----------------------- builtin dummy types -------------------------
540 classinfo_t nullclass
= {
541 INFOTYPE_CLASS
,0,0,ACCESS_PACKAGE
, "", "null", 0,0,0,0,0,0,0,0,0,0,0,0,0,
543 classinfo_t
* registry_getnullclass() {
546 classinfo_t voidclass
= {
547 INFOTYPE_CLASS
,0,0,ACCESS_PACKAGE
, "", "void", 0,0,0,0,0,0,0,0,0,0,0,0,0,
549 classinfo_t
* registry_getvoidclass() {
553 namespace_t
access2namespace(U8 access
, char*package
)
561 char* infotypename(slotinfo_t
*s
)
565 if(s
->kind
== INFOTYPE_CLASS
) return "class";
566 else if(s
->kind
== INFOTYPE_VAR
) return "var";
567 else if(s
->kind
== INFOTYPE_METHOD
) return "function";
568 else return "object";
571 void slotinfo_dump(slotinfo_t
*s
)
574 printf("%s %s.%s", infotypename(s
), s
->package
, s
->name
);
576 printf("%s %s", infotypename(s
), s
->name
);
578 if(s
->kind
== INFOTYPE_CLASS
) {
579 classinfo_t
*c
= (classinfo_t
*)s
;
581 else if(s
->kind
== INFOTYPE_VAR
) {
582 varinfo_t
*v
= (varinfo_t
*)s
;
583 printf(":%s", v
->type
?v
->type
->name
:"*");
585 printf("=%s", constant_tostring(v
->value
));
587 printf(" (slot:%d)", v
->slot
);
589 else if(s
->kind
== INFOTYPE_METHOD
) {
590 methodinfo_t
*m
= (methodinfo_t
*)s
;