as3: improved inner function handling, factor static class code into class initializa...
[swftools.git] / lib / as3 / initcode.c
index 9bb4ffc..ad2dbc0 100644 (file)
+#include <assert.h>
+#include "../q.h"
 #include "abc.h"
 #include "code.h"
+#include "common.h"
 #include "registry.h"
 #include "initcode.h"
 
-int compare_lists(const void *_v1, const void *_v2)
+int compare_parsedclass(const void *_v1, const void *_v2)
 {
-    classinfo_t**v1 = *(classinfo_t***)_v1;
-    classinfo_t**v2 = *(classinfo_t***)_v2;
-    parsedclass_t*p1 = **(parsedclass_t***)_v1;
-    parsedclass_t*p2 = **(parsedclass_t***)_v2;
+    parsedclass_t*p1 = *(parsedclass_t**)_v1;
+    parsedclass_t*p2 = *(parsedclass_t**)_v2;
     if((p1->cls->flags^p2->cls->flags)&FLAG_INTERFACE) {
         return (int)(p2->cls->flags&FLAG_INTERFACE) - (int)(p1->cls->flags&FLAG_INTERFACE);
     }
-    do {
-        v1++;v2++;
-        if(*v1<*v2) return -1;
-        else if(*v1>*v2) return 1;
-    } while(*v1 && *v2);
+    classinfo_t*c2 = dict_lookup(&p1->parents, p2);
+    classinfo_t*c1 = dict_lookup(&p2->parents, p1);
+    assert(!c1 || !c2); // otherwise we would have a loop
+    assert(!c1 || c1==p1->cls);
+    assert(!c2 || c2==p2->cls);
+    if(c1) {
+        return -1;
+    }
+    if(c2) {
+        return 1;
+    }
+    
+    c2 = dict_lookup(&p1->usedclasses_deep, p2);
+    c1 = dict_lookup(&p2->usedclasses_deep, p1);
+    assert(!c1 || !c2);
+    assert(!c1 || c1==p1->cls);
+    assert(!c2 || c2==p2->cls);
+    if(c1) {
+        return -1;
+    }
+    if(c2) {
+        return 1;
+    }
     return 0;
 }
 
+void add_parent(parsedclass_t*p, classinfo_t*c, dict_t*s2p, char soft)
+{
+    dict_t*parents = soft?(&p->usedclasses_deep):(&p->parents);
+    int t;
+    if(dict_contains(parents, p)) {
+        if(soft) {
+            as3_warning("circular reference: class %s references self (through static code)", p->cls->name);
+            return;
+        } else {
+            syntaxerror("circular reference: class %s references self", p->cls->name);
+        }
+    }
+
+    if(c) {
+        parsedclass_t*n = dict_lookup(s2p, c);
+        if(n && !dict_contains(parents, n)) {
+            assert(n->cls == c);
+            dict_put(parents, n, c);
+        }
+    } else {
+        c = p->cls;
+    }
+
+    if(soft && dict_contains(s2p, c)) {
+        parsedclass_t*pp = dict_lookup(s2p, c);
+        DICT_ITERATE_KEY(&pp->usedclasses, classinfo_t*, cc) {
+            add_parent(p, cc, s2p, soft);
+        }
+    }
+    if(c->superclass) {
+        add_parent(p, c->superclass, s2p, soft);
+    }
+    for(t=0;c->interfaces[t];t++) {
+        add_parent(p, c->interfaces[t], s2p, soft);
+    }
+}
+
+parsedclass_t* parsedclass_new(classinfo_t*cls, abc_class_t*abc)
+{
+    NEW(parsedclass_t,p);
+    p->cls = cls;
+    p->abc = abc;
+    dict_init2(&p->parents, &ptr_type, 1);
+    dict_init2(&p->usedclasses, &ptr_type, 1);
+    dict_init2(&p->usedclasses_deep, &ptr_type, 1);
+    return p;
+}
+
 /* sort classes so that 
    (a) interfaces appear before classes
    (b) base classes always appear before their subclasses
-   (c) neighboring elements have similar scope stacks 
-
-   Notice: we don't yet handle multiple inheritance (in interfaces) correctly.
+   (c) classes appear after the classes they use in static code
 */
 parsedclass_t** initcode_sort_classlist(parsedclass_list_t*classes)
 {
-    /* count classes */
+    dict_t* s2p = dict_new2(&ptr_type);
+
+    /* create hash tables */
     int count = 0;
     parsedclass_list_t*l;
     for(l=classes;l;l=l->next) {
+        dict_put(s2p, l->parsedclass->cls, l->parsedclass);
         count++;
     }
-    void***list = malloc(sizeof(void**)*count);
+    for(l=classes;l;l=l->next) {
+        add_parent(l->parsedclass, 0, s2p, 0);
+        DICT_ITERATE_KEY(&l->parsedclass->usedclasses, classinfo_t*, c) {
+            add_parent(l->parsedclass, c, s2p, 1);
+        }
+    }
+
+    parsedclass_t**list = malloc(sizeof(parsedclass_t*)*count);
 
     /* build an array for each class */
     int i = 0;
     for(l=classes;l;l=l->next) {
-        classinfo_t*cls = l->parsedclass->cls;
-        int len=0;
-        classinfo_t*c=cls;
-        while(c) {
-            len ++;
-            c = c->flags&FLAG_INTERFACE?c->interfaces[0]:c->superclass;
-        }
-        void**a = (void**)malloc(sizeof(void*)*(len+2));
-        a[0] = l->parsedclass;
-        a[len+1] = 0;
-        int t=len;
-        c = cls;
-        while(c) {
-            len ++;
-            a[t--] = c;
-            c = c->flags&FLAG_INTERFACE?c->interfaces[0]:c->superclass;
-        }
-        list[i++] = a;
+        list[i++] = l->parsedclass;
     }
     
     /* sort and flatten */
-    qsort(list, count, sizeof(void**), compare_lists);
+    qsort(list, count, sizeof(void**), compare_parsedclass);
 
     parsedclass_t**list2 = malloc(sizeof(parsedclass_t*)*(count+1));
     for(i=0;i<count;i++) {
-        list2[i] = (parsedclass_t*)list[i][0];
-        free(list[i]);
+        list2[i] = (parsedclass_t*)list[i];
     }
     list2[count]=0;
     free(list);
+
+    dict_destroy(s2p);
     return list2;
 }
 
+void parsedclass_add_dependency(parsedclass_t*p, classinfo_t*c)
+{
+    if(!dict_contains(&p->usedclasses, c)) {
+        dict_put(&p->usedclasses, c, c);
+    }
+}
+
 void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*_classes)
 {
     code_t*c = 0;
@@ -94,6 +160,10 @@ void initcode_add_classlist(abc_script_t*init, parsedclass_list_t*_classes)
         MULTINAME(classname2,cls);
         trait_t*trait = abc_initscript_addClassTrait(init, &classname2, abc);
 
+        c = abc_findpropstrict(c, "trace");
+        c = abc_pushstring(c, allocprintf("initialize class %s", cls->name));
+        c = abc_callpropvoid(c, "trace", 1);
+
         c = abc_getglobalscope(c);
         classinfo_t*s = cls->superclass;