You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by nw...@apache.org on 2013/05/26 17:35:33 UTC

[lucy-commits] [5/9] git commit: refs/heads/separate-clownfish-wip1 - Support object types from other parcels without prefix

Support object types from other parcels without prefix

Resolve types after all classes have been parsed.

This means that caching of C representations has to be postponed. For
now, the C representations are cached after the types have been
resolved. This is error-prone and requires some hacks for methods. It
might be better to move to a scheme where the C strings are not cached
until they're used for the first time.

TODO: Add Perl bindings and fix Perl tests


Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/c33d5cb3
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/c33d5cb3
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/c33d5cb3

Branch: refs/heads/separate-clownfish-wip1
Commit: c33d5cb3e9ed70a55214aa54c6760dc853206865
Parents: ee195c6
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Mon May 20 01:36:52 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Sun May 26 17:19:02 2013 +0200

----------------------------------------------------------------------
 clownfish/compiler/src/CFCClass.c         |   16 +++
 clownfish/compiler/src/CFCClass.h         |    5 +
 clownfish/compiler/src/CFCDumpable.c      |   13 ++-
 clownfish/compiler/src/CFCFunction.c      |    6 +
 clownfish/compiler/src/CFCFunction.h      |    6 +
 clownfish/compiler/src/CFCHierarchy.c     |    3 +
 clownfish/compiler/src/CFCMethod.c        |   33 ++++--
 clownfish/compiler/src/CFCMethod.h        |    3 +
 clownfish/compiler/src/CFCParamList.c     |   14 ++-
 clownfish/compiler/src/CFCParamList.h     |    4 +
 clownfish/compiler/src/CFCTest.c          |    6 +
 clownfish/compiler/src/CFCTestClass.c     |   15 +++-
 clownfish/compiler/src/CFCTestFile.c      |   22 ++++-
 clownfish/compiler/src/CFCTestMethod.c    |   12 ++-
 clownfish/compiler/src/CFCTestParamList.c |   10 ++-
 clownfish/compiler/src/CFCTestParser.c    |   15 +++-
 clownfish/compiler/src/CFCTestType.c      |   35 +++++++-
 clownfish/compiler/src/CFCTestVariable.c  |   10 ++-
 clownfish/compiler/src/CFCType.c          |  123 ++++++++++++++++--------
 clownfish/compiler/src/CFCType.h          |    6 +
 clownfish/compiler/src/CFCVariable.c      |   18 +++-
 clownfish/compiler/src/CFCVariable.h      |    4 +
 22 files changed, 305 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.c b/clownfish/compiler/src/CFCClass.c
index e5022ac..0567ca4 100644
--- a/clownfish/compiler/src/CFCClass.c
+++ b/clownfish/compiler/src/CFCClass.c
@@ -459,6 +459,22 @@ CFCClass_fresh_method(CFCClass *self, const char *sym) {
     return NULL;
 }
 
+void
+CFCClass_resolve_types(CFCClass *self, CFCClass **classes) {
+    for (size_t i = 0; self->functions[i] != NULL; i++) {
+        CFCFunction_resolve_types(self->functions[i], classes);
+    }
+    for (size_t i = 0; self->methods[i] != NULL; i++) {
+        CFCMethod_resolve_types(self->methods[i], classes);
+    }
+    for (size_t i = 0; self->member_vars[i] != NULL; i++) {
+        CFCVariable_resolve_type(self->member_vars[i], classes);
+    }
+    for (size_t i = 0; self->inert_vars[i] != NULL; i++) {
+        CFCVariable_resolve_type(self->inert_vars[i], classes);
+    }
+}
+
 // Pass down member vars to from parent to children.
 static void
 S_bequeath_member_vars(CFCClass *self) {

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCClass.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCClass.h b/clownfish/compiler/src/CFCClass.h
index fd38149..cb484d8 100644
--- a/clownfish/compiler/src/CFCClass.h
+++ b/clownfish/compiler/src/CFCClass.h
@@ -150,6 +150,11 @@ CFCClass_fresh_method(CFCClass *self, const char *sym);
 struct CFCMethod*
 CFCClass_find_novel_method(CFCClass *self, const char *sym);
 
+/** Find the actual class of all object variables without prefix.
+ */
+void
+CFCClass_resolve_types(CFCClass *self, CFCClass **classes);
+
 /** Bequeath all inherited methods and members to children.
  */
 void

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCDumpable.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCDumpable.c b/clownfish/compiler/src/CFCDumpable.c
index 7fd2616..006f62a 100644
--- a/clownfish/compiler/src/CFCDumpable.c
+++ b/clownfish/compiler/src/CFCDumpable.c
@@ -110,14 +110,15 @@ CFCDumpable_add_dumpables(CFCDumpable *self, CFCClass *klass) {
 
 static CFCMethod*
 S_make_method_obj(CFCClass *klass, const char *method_name) {
-    const char *klass_struct_sym = CFCClass_get_struct_sym(klass);
+    const char *klass_full_struct_sym = CFCClass_full_struct_sym(klass);
     const char *klass_name   = CFCClass_get_class_name(klass);
     const char *klass_cnick  = CFCClass_get_cnick(klass);
     CFCParcel  *klass_parcel = CFCClass_get_parcel(klass);
 
     CFCType *return_type
-        = CFCType_new_object(CFCTYPE_INCREMENTED, klass_parcel, "Obj", 1);
-    CFCType *self_type = CFCType_new_object(0, klass_parcel, klass_struct_sym, 1);
+        = CFCType_new_object(CFCTYPE_INCREMENTED, klass_parcel, "lucy_Obj", 1);
+    CFCType *self_type = CFCType_new_object(0, klass_parcel,
+                                            klass_full_struct_sym, 1);
     CFCVariable *self_var = CFCVariable_new(NULL, NULL, NULL, NULL, "self",
                                             self_type, false);
     CFCParamList *param_list = NULL;
@@ -127,7 +128,8 @@ S_make_method_obj(CFCClass *klass, const char *method_name) {
         CFCParamList_add_param(param_list, self_var, NULL);
     }
     else if (strcmp(method_name, "Load") == 0) {
-        CFCType *dump_type = CFCType_new_object(0, klass_parcel, "Obj", 1);
+        CFCType *dump_type = CFCType_new_object(0, klass_parcel, "lucy_Obj",
+                                                1);
         CFCVariable *dump_var = CFCVariable_new(NULL, NULL, NULL, NULL, "dump",
                                                 dump_type, false);
         param_list = CFCParamList_new(false);
@@ -143,6 +145,9 @@ S_make_method_obj(CFCClass *klass, const char *method_name) {
     CFCMethod *method = CFCMethod_new(klass_parcel, "public", klass_name,
                                       klass_cnick, method_name, return_type,
                                       param_list, NULL, false, false);
+    // Hack
+    CFCClass *dummy_class = NULL;
+    CFCMethod_resolve_types(method, &dummy_class);
 
     CFCBase_decref((CFCBase*)param_list);
     CFCBase_decref((CFCBase*)self_type);

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCFunction.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCFunction.c b/clownfish/compiler/src/CFCFunction.c
index 7205622..6f781f4 100644
--- a/clownfish/compiler/src/CFCFunction.c
+++ b/clownfish/compiler/src/CFCFunction.c
@@ -84,6 +84,12 @@ CFCFunction_init(CFCFunction *self, CFCParcel *parcel, const char *exposure,
 }
 
 void
+CFCFunction_resolve_types(CFCFunction *self, struct CFCClass **classes) {
+    CFCType_resolve(self->return_type, classes);
+    CFCParamList_resolve_types(self->param_list, classes);
+}
+
+void
 CFCFunction_destroy(CFCFunction *self) {
     CFCBase_decref((CFCBase*)self->return_type);
     CFCBase_decref((CFCBase*)self->param_list);

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCFunction.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCFunction.h b/clownfish/compiler/src/CFCFunction.h
index e69b632..baab2c7 100644
--- a/clownfish/compiler/src/CFCFunction.h
+++ b/clownfish/compiler/src/CFCFunction.h
@@ -29,6 +29,7 @@ struct CFCParcel;
 struct CFCType;
 struct CFCDocuComment;
 struct CFCParamList;
+struct CFCClass;
 
 #ifdef CFC_NEED_FUNCTION_STRUCT_DEF
 #define CFC_NEED_SYMBOL_STRUCT_DEF
@@ -110,6 +111,11 @@ CFCFunction_micro_sym(CFCFunction *self);
 int
 CFCFunction_public(CFCFunction *self);
 
+/** Find the actual class of all object variables without prefix.
+ */
+void
+CFCFunction_resolve_types(CFCFunction *self, struct CFCClass **classes);
+
 #ifdef __cplusplus
 }
 #endif

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCHierarchy.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCHierarchy.c b/clownfish/compiler/src/CFCHierarchy.c
index b8ba423..5c5b192 100644
--- a/clownfish/compiler/src/CFCHierarchy.c
+++ b/clownfish/compiler/src/CFCHierarchy.c
@@ -197,6 +197,9 @@ CFCHierarchy_build(CFCHierarchy *self) {
     for (size_t i = 0; self->includes[i] != NULL; i++) {
         S_parse_cf_files(self, self->includes[i], 1);
     }
+    for (int i = 0; self->classes[i] != NULL; i++) {
+        CFCClass_resolve_types(self->classes[i], self->classes);
+    }
     S_connect_classes(self);
     for (size_t i = 0; self->trees[i] != NULL; i++) {
         CFCClass_grow_tree(self->trees[i]);

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCMethod.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCMethod.c b/clownfish/compiler/src/CFCMethod.c
index a9f0063..395eb62 100644
--- a/clownfish/compiler/src/CFCMethod.c
+++ b/clownfish/compiler/src/CFCMethod.c
@@ -105,12 +105,30 @@ CFCMethod_init(CFCMethod *self, CFCParcel *parcel, const char *exposure,
                      docucomment, false);
     FREEMEM(micro_sym);
 
+    self->macro_sym     = CFCUtil_strdup(macro_sym);
+    self->is_final      = is_final;
+    self->is_abstract   = is_abstract;
+
+    self->full_override_sym = NULL;
+
+    // Assume that this method is novel until we discover when applying
+    // inheritance that it overrides another.
+    self->is_novel = true;
+
+    return self;
+}
+
+void
+CFCMethod_resolve_types(CFCMethod *self, struct CFCClass **classes) {
+    CFCFunction_resolve_types((CFCFunction*)self, classes);
+
     // Verify that the first element in the arg list is a self.
-    CFCVariable **args = CFCParamList_get_variables(param_list);
+    CFCVariable **args = CFCParamList_get_variables(self->function.param_list);
     if (!args[0]) { CFCUtil_die("Missing 'self' argument"); }
     CFCType *type = CFCVariable_get_type(args[0]);
     const char *specifier = CFCType_get_specifier(type);
     const char *prefix    = CFCMethod_get_prefix(self);
+    const char *class_name = CFCMethod_get_class_name(self);
     const char *last_colon = strrchr(class_name, ':');
     const char *struct_sym = last_colon ? last_colon + 1 : class_name;
     char *wanted = CFCUtil_sprintf("%s%s", prefix, struct_sym);
@@ -121,19 +139,9 @@ CFCMethod_init(CFCMethod *self, CFCParcel *parcel, const char *exposure,
                     class_name, specifier);
     }
 
-    self->macro_sym     = CFCUtil_strdup(macro_sym);
-    self->is_final      = is_final;
-    self->is_abstract   = is_abstract;
-
     // Derive more symbols.
     const char *full_func_sym = CFCMethod_implementing_func_sym(self);
     self->full_override_sym = CFCUtil_sprintf("%s_OVERRIDE", full_func_sym);
-
-    // Assume that this method is novel until we discover when applying
-    // inheritance that it overrides another.
-    self->is_novel = true;
-
-    return self;
 }
 
 void
@@ -220,6 +228,9 @@ CFCMethod_finalize(CFCMethod *self) {
                         self->function.param_list,
                         self->function.docucomment, true,
                         self->is_abstract);
+    // Hack
+    CFCClass *dummy_class = NULL;
+    CFCMethod_resolve_types(finalized, &dummy_class);
     return finalized;
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCMethod.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCMethod.h b/clownfish/compiler/src/CFCMethod.h
index b7f01dd..cdceb6a 100644
--- a/clownfish/compiler/src/CFCMethod.h
+++ b/clownfish/compiler/src/CFCMethod.h
@@ -71,6 +71,9 @@ CFCMethod_init(CFCMethod *self, struct CFCParcel *parcel,
                int is_abstract);
 
 void
+CFCMethod_resolve_types(CFCMethod *self, struct CFCClass **classes);
+
+void
 CFCMethod_destroy(CFCMethod *self);
 
 /** Returns true if the methods have signatures and attributes which allow one

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCParamList.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParamList.c b/clownfish/compiler/src/CFCParamList.c
index 3e7bacf..2845480 100644
--- a/clownfish/compiler/src/CFCParamList.c
+++ b/clownfish/compiler/src/CFCParamList.c
@@ -55,11 +55,20 @@ CFCParamList_init(CFCParamList *self, int variadic) {
     self->num_vars  = 0;
     self->variables = (CFCVariable**)CALLOCATE(1, sizeof(void*));
     self->values    = (char**)CALLOCATE(1, sizeof(char*));
-    S_generate_c_strings(self);
+    self->c_string  = CFCUtil_strdup("");
+    self->name_list = CFCUtil_strdup("");
     return self;
 }
 
 void
+CFCParamList_resolve_types(CFCParamList *self, struct CFCClass **classes) {
+    for (size_t i = 0; self->variables[i]; ++i) {
+        CFCVariable_resolve_type(self->variables[i], classes);
+    }
+    S_generate_c_strings(self);
+}
+
+void
 CFCParamList_add_param(CFCParamList *self, CFCVariable *variable,
                        const char *value) {
     CFCUTIL_NULL_CHECK(variable);
@@ -72,8 +81,6 @@ CFCParamList_add_param(CFCParamList *self, CFCVariable *variable,
     self->values[self->num_vars - 1] = value ? CFCUtil_strdup(value) : NULL;
     self->variables[self->num_vars] = NULL;
     self->values[self->num_vars] = NULL;
-
-    S_generate_c_strings(self);
 }
 
 void
@@ -153,7 +160,6 @@ CFCParamList_num_vars(CFCParamList *self) {
 void
 CFCParamList_set_variadic(CFCParamList *self, int variadic) {
     self->variadic = !!variadic;
-    S_generate_c_strings(self);
 }
 
 int

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCParamList.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCParamList.h b/clownfish/compiler/src/CFCParamList.h
index 23cc0e3..886fdfe 100644
--- a/clownfish/compiler/src/CFCParamList.h
+++ b/clownfish/compiler/src/CFCParamList.h
@@ -25,6 +25,7 @@ extern "C" {
 #endif
 
 typedef struct CFCParamList CFCParamList;
+struct CFCClass;
 struct CFCVariable;
 
 /**
@@ -37,6 +38,9 @@ CFCParamList*
 CFCParamList_init(CFCParamList *self, int variadic);
 
 void
+CFCParamList_resolve_types(CFCParamList *self, struct CFCClass **classes);
+
+void
 CFCParamList_destroy(CFCParamList *self);
 
 /** Add a parameter to the ParamList.

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTest.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTest.c b/clownfish/compiler/src/CFCTest.c
index 2fd9933..21cff48 100644
--- a/clownfish/compiler/src/CFCTest.c
+++ b/clownfish/compiler/src/CFCTest.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -297,6 +298,11 @@ S_format_cfish_vtest_result(int pass, int test_num, const char *fmt,
         vprintf(fmt, args);
         printf("\n");
     }
+    else if (getenv("CFCTEST_VERBOSE")) {
+        printf("  Passed test %d: ", test_num);
+        vprintf(fmt, args);
+        printf("\n");
+    }
 }
 
 static void

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTestClass.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestClass.c b/clownfish/compiler/src/CFCTestClass.c
index 67097d6..9f841f9 100644
--- a/clownfish/compiler/src/CFCTestClass.c
+++ b/clownfish/compiler/src/CFCTestClass.c
@@ -39,7 +39,7 @@ S_has_symbol(CFCSymbol **symbols, const char *micro_sym);
 
 const CFCTestBatch CFCTEST_BATCH_CLASS = {
     "Clownfish::CFC::Model::Class",
-    83,
+    87,
     S_run_tests
 };
 
@@ -49,6 +49,10 @@ S_run_tests(CFCTest *test) {
 
     CFCParcel *neato = CFCParcel_new("Neato", NULL, NULL);
     CFCFileSpec *file_spec = CFCFileSpec_new(".", "Foo/FooJr", 0);
+    CFCClass *thing_class
+        = CFCTest_parse_class(test, parser, "class Thing {}");
+    CFCClass *widget_class
+        = CFCTest_parse_class(test, parser, "class Widget {}");
 
     CFCVariable *thing;
     CFCVariable *widget;
@@ -119,6 +123,13 @@ S_run_tests(CFCTest *test) {
         = CFCTest_parse_method(test, parser, "void Do_Stuff(Foo *self);");
     CFCClass_add_method(foo, do_stuff);
 
+    CFCClass *class_list[6] = {
+        foo, foo_jr, final_foo, thing_class, widget_class, NULL
+    };
+    CFCClass_resolve_types(foo, class_list);
+    CFCClass_resolve_types(foo_jr, class_list);
+    CFCClass_resolve_types(final_foo, class_list);
+
     CFCClass_add_child(foo, foo_jr);
     CFCClass_add_child(foo_jr, final_foo);
     CFCClass_grow_tree(foo);
@@ -330,6 +341,8 @@ S_run_tests(CFCTest *test) {
     CFCBase_decref((CFCBase*)parser);
     CFCBase_decref((CFCBase*)neato);
     CFCBase_decref((CFCBase*)file_spec);
+    CFCBase_decref((CFCBase*)thing_class);
+    CFCBase_decref((CFCBase*)widget_class);
     CFCBase_decref((CFCBase*)thing);
     CFCBase_decref((CFCBase*)widget);
     CFCBase_decref((CFCBase*)tread_water);

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTestFile.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestFile.c b/clownfish/compiler/src/CFCTestFile.c
index 2e1edc5..f62b919 100644
--- a/clownfish/compiler/src/CFCTestFile.c
+++ b/clownfish/compiler/src/CFCTestFile.c
@@ -21,6 +21,7 @@
 #include "CFCClass.h"
 #include "CFCFile.h"
 #include "CFCFileSpec.h"
+#include "CFCParcel.h"
 #include "CFCParser.h"
 #include "CFCTest.h"
 #include "CFCType.h"
@@ -32,7 +33,7 @@ S_run_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_FILE = {
     "Clownfish::CFC::Model::File",
-    19,
+    21,
     S_run_tests
 };
 
@@ -50,6 +51,8 @@ S_run_tests(CFCTest *test) {
             "    Foo *foo;\n"
             "    Bar *bar;\n"
             "}\n"
+            "class Foo {}\n"
+            "class Bar {}\n"
             "__C__\n"
             "int foo;\n"
             "__END_C__\n";
@@ -88,13 +91,17 @@ S_run_tests(CFCTest *test) {
         FREEMEM(h_path);
 
         CFCClass **classes = CFCFile_classes(file);
-        OK(test, classes[0] != NULL && classes[1] == NULL,
+        OK(test,
+           classes[0] != NULL && classes[1] != NULL && classes[2] != NULL
+           && classes[3] == NULL,
            "classes() filters blocks");
         CFCVariable **member_vars = CFCClass_member_vars(classes[0]);
         CFCType *foo_type = CFCVariable_get_type(member_vars[0]);
+        CFCType_resolve(foo_type, classes);
         STR_EQ(test, CFCType_get_specifier(foo_type), "stuff_Foo",
                "file production picked up parcel def");
         CFCType *bar_type = CFCVariable_get_type(member_vars[1]);
+        CFCType_resolve(bar_type, classes);
         STR_EQ(test, CFCType_get_specifier(bar_type), "stuff_Bar",
                "parcel def is sticky");
 
@@ -104,8 +111,12 @@ S_run_tests(CFCTest *test) {
         STR_EQ(test, CFCBase_get_cfc_class(blocks[1]),
                "Clownfish::CFC::Model::Class", "blocks[1]");
         STR_EQ(test, CFCBase_get_cfc_class(blocks[2]),
-               "Clownfish::CFC::Model::CBlock", "blocks[2]");
-        OK(test, blocks[3] == NULL, "blocks[3]");
+               "Clownfish::CFC::Model::Class", "blocks[2]");
+        STR_EQ(test, CFCBase_get_cfc_class(blocks[3]),
+               "Clownfish::CFC::Model::Class", "blocks[3]");
+        STR_EQ(test, CFCBase_get_cfc_class(blocks[4]),
+               "Clownfish::CFC::Model::CBlock", "blocks[4]");
+        OK(test, blocks[5] == NULL, "blocks[5]");
 
         CFCBase_decref((CFCBase*)file);
     }
@@ -128,5 +139,8 @@ S_run_tests(CFCTest *test) {
 
     CFCBase_decref((CFCBase*)file_spec);
     CFCBase_decref((CFCBase*)parser);
+
+    CFCClass_clear_registry();
+    CFCParcel_reap_singletons();
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTestMethod.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestMethod.c b/clownfish/compiler/src/CFCTestMethod.c
index 7122786..a805228 100644
--- a/clownfish/compiler/src/CFCTestMethod.c
+++ b/clownfish/compiler/src/CFCTestMethod.c
@@ -16,6 +16,7 @@
 
 #define CFC_USE_TEST_MACROS
 #include "CFCBase.h"
+#include "CFCClass.h"
 #include "CFCMethod.h"
 #include "CFCParamList.h"
 #include "CFCParcel.h"
@@ -41,7 +42,7 @@ S_run_final_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_METHOD = {
     "Clownfish::CFC::Model::Method",
-    66,
+    70,
     S_run_tests
 };
 
@@ -225,6 +226,11 @@ S_run_final_tests(CFCTest *test) {
     CFCParser *parser = CFCParser_new();
     CFCParcel *neato_parcel
         = CFCTest_parse_parcel(test, parser, "parcel Neato;");
+    CFCClass *obj_class
+        = CFCTest_parse_class(test, parser, "class Obj {}");
+    CFCClass *foo_class
+        = CFCTest_parse_class(test, parser, "class Neato::Foo {}");
+    CFCClass *class_list[3] = { obj_class, foo_class, NULL };
     CFCType *return_type = CFCTest_parse_type(test, parser, "Obj*");
     CFCParamList *param_list
         = CFCTest_parse_param_list(test, parser, "(Foo *self)");
@@ -233,6 +239,7 @@ S_run_final_tests(CFCTest *test) {
         = CFCMethod_new(neato_parcel, NULL, "Neato::Foo", "Foo",
                         "Return_An_Obj", return_type, param_list,
                         NULL, 0, 0);
+    CFCMethod_resolve_types(not_final, class_list);
     CFCMethod *final = CFCMethod_finalize(not_final);
     OK(test, CFCMethod_compatible(not_final, final),
        "finalize clones properly");
@@ -241,11 +248,14 @@ S_run_final_tests(CFCTest *test) {
 
     CFCBase_decref((CFCBase*)parser);
     CFCBase_decref((CFCBase*)neato_parcel);
+    CFCBase_decref((CFCBase*)obj_class);
+    CFCBase_decref((CFCBase*)foo_class);
     CFCBase_decref((CFCBase*)return_type);
     CFCBase_decref((CFCBase*)param_list);
     CFCBase_decref((CFCBase*)not_final);
     CFCBase_decref((CFCBase*)final);
 
+    CFCClass_clear_registry();
     CFCParcel_reap_singletons();
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTestParamList.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestParamList.c b/clownfish/compiler/src/CFCTestParamList.c
index 0fd552c..29ff226 100644
--- a/clownfish/compiler/src/CFCTestParamList.c
+++ b/clownfish/compiler/src/CFCTestParamList.c
@@ -16,6 +16,7 @@
 
 #define CFC_USE_TEST_MACROS
 #include "CFCBase.h"
+#include "CFCClass.h"
 #include "CFCParamList.h"
 #include "CFCParcel.h"
 #include "CFCParser.h"
@@ -27,7 +28,7 @@ S_run_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_PARAM_LIST = {
     "Clownfish::CFC::Model::ParamList",
-    21,
+    23,
     S_run_tests
 };
 
@@ -36,10 +37,13 @@ S_run_tests(CFCTest *test) {
     CFCParser *parser = CFCParser_new();
     CFCParcel *neato_parcel
         = CFCTest_parse_parcel(test, parser, "parcel Neato;");
+    CFCClass *obj_class = CFCTest_parse_class(test, parser, "class Obj {}");
+    CFCClass *class_list[2] = { obj_class, NULL };
 
     {
         CFCParamList *param_list
             = CFCTest_parse_param_list(test, parser, "(Obj *self, int num)");
+        CFCParamList_resolve_types(param_list, class_list);
         OK(test, !CFCParamList_variadic(param_list), "not variadic");
         STR_EQ(test, CFCParamList_to_c(param_list), "neato_Obj* self, int num",
                "to_c");
@@ -53,6 +57,7 @@ S_run_tests(CFCTest *test) {
         CFCParamList *param_list
             = CFCTest_parse_param_list(test, parser,
                                        "(Obj *self=NULL, int num, ...)");
+        CFCParamList_resolve_types(param_list, class_list);
         OK(test, CFCParamList_variadic(param_list), "variadic");
         STR_EQ(test, CFCParamList_to_c(param_list),
                "neato_Obj* self, int num, ...", "to_c");
@@ -72,6 +77,7 @@ S_run_tests(CFCTest *test) {
     {
         CFCParamList *param_list
             = CFCTest_parse_param_list(test, parser, "()");
+        CFCParamList_resolve_types(param_list, class_list);
         STR_EQ(test, CFCParamList_to_c(param_list), "void", "to_c");
         INT_EQ(test, CFCParamList_num_vars(param_list), 0, "num_vars");
         CFCVariable **variables = CFCParamList_get_variables(param_list);
@@ -82,7 +88,9 @@ S_run_tests(CFCTest *test) {
 
     CFCBase_decref((CFCBase*)parser);
     CFCBase_decref((CFCBase*)neato_parcel);
+    CFCBase_decref((CFCBase*)obj_class);
 
+    CFCClass_clear_registry();
     CFCParcel_reap_singletons();
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTestParser.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestParser.c b/clownfish/compiler/src/CFCTestParser.c
index 35d38ab..46611dd 100644
--- a/clownfish/compiler/src/CFCTestParser.c
+++ b/clownfish/compiler/src/CFCTestParser.c
@@ -37,7 +37,7 @@ S_test_initial_value(CFCTest *test, CFCParser *parser,
 
 const CFCTestBatch CFCTEST_BATCH_PARSER = {
     "Clownfish::CFC::Model::Parser",
-    189,
+    203,
     S_run_tests
 };
 
@@ -108,17 +108,30 @@ S_run_tests(CFCTest *test) {
         static const char *const class_names[7] = {
             "ByteBuf", "Obj", "ANDMatcher", "Foo", "FooJr", "FooIII", "Foo4th"
         };
+        CFCClass *class_list[8];
+        for (int i = 0; i < 7; ++i) {
+            char *class_code = CFCUtil_sprintf("class %s {}", class_names[i]);
+            CFCClass *klass = CFCTest_parse_class(test, parser, class_code);
+            class_list[i] = klass;
+            FREEMEM(class_code);
+        }
+        class_list[7] = NULL;
         for (int i = 0; i < 7; ++i) {
             const char *class_name = class_names[i];
             char *src      = CFCUtil_sprintf("%s*", class_name);
             char *expected = CFCUtil_sprintf("crust_%s", class_name);
             CFCType *type = CFCTest_parse_type(test, parser, src);
+            CFCType_resolve(type, class_list);
             STR_EQ(test, CFCType_get_specifier(type), expected,
                    "object_type_specifier: %s", class_name);
             FREEMEM(src);
             FREEMEM(expected);
             CFCBase_decref((CFCBase*)type);
         }
+        for (int i = 0; i < 7; ++i) {
+            CFCBase_decref((CFCBase*)class_list[i]);
+        }
+        CFCClass_clear_registry();
     }
 
     {

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTestType.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestType.c b/clownfish/compiler/src/CFCTestType.c
index 8751eb8..baa91d2 100644
--- a/clownfish/compiler/src/CFCTestType.c
+++ b/clownfish/compiler/src/CFCTestType.c
@@ -16,12 +16,18 @@
 
 #define CFC_USE_TEST_MACROS
 #include "CFCBase.h"
+#include "CFCClass.h"
 #include "CFCParcel.h"
 #include "CFCParser.h"
 #include "CFCTest.h"
 #include "CFCType.h"
 #include "CFCUtil.h"
 
+#ifndef true
+  #define true 1
+  #define false 0
+#endif
+
 static void
 S_run_tests(CFCTest *test);
 
@@ -54,7 +60,7 @@ S_run_composite_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_TYPE = {
     "Clownfish::CFC::Model::Type",
-    353,
+    361,
     S_run_tests
 };
 
@@ -287,11 +293,17 @@ S_run_object_tests(CFCTest *test) {
         for (int i = 0; i < 4; ++i) {
             const char *specifier = specifiers[i];
 
+            char *class_code = CFCUtil_sprintf("class %s {}", specifier);
+            CFCClass *klass = CFCTest_parse_class(test, parser, class_code);
+            CFCClass *class_list[2] = { klass, NULL };
+            FREEMEM(class_code);
+
             static const char *prefixes[2] = { "", "neato_" };
             char *expect = CFCUtil_sprintf("neato_%s", specifier);
             for (int j = 0; j < 2; ++j) {
                 char *src = CFCUtil_sprintf("%s%s*", prefixes[j], specifier);
                 CFCType *type = CFCTest_parse_type(test, parser, src);
+                CFCType_resolve(type, class_list);
                 STR_EQ(test, CFCType_get_specifier(type), expect,
                        "object_type_specifier: %s", src);
                 OK(test, CFCType_is_object(type), "%s is_object", src);
@@ -312,16 +324,26 @@ S_run_object_tests(CFCTest *test) {
                 FREEMEM(src);
                 CFCBase_decref((CFCBase*)type);
             }
+
+            CFCBase_decref((CFCBase*)klass);
+            CFCClass_clear_registry();
         }
 
         CFCBase_decref((CFCBase*)neato_parcel);
         CFCBase_decref((CFCBase*)parser);
     }
 
+    CFCParcel *neato_parcel = CFCParcel_new("Neato", NULL, NULL);
+    CFCClass *foo_class
+        = CFCClass_create(neato_parcel, NULL, "Foo", NULL, NULL, NULL, NULL,
+                          NULL, false, false);
+    CFCClass *class_list[2] = { foo_class, NULL };
     CFCType *foo = CFCType_new_object(0, NULL, "Foo", 1);
+    CFCType_resolve(foo, class_list);
 
     {
         CFCType *another_foo = CFCType_new_object(0, NULL, "Foo", 1);
+        CFCType_resolve(another_foo, class_list);
         OK(test, CFCType_equals(foo, another_foo), "equals");
         CFCBase_decref((CFCBase*)another_foo);
     }
@@ -335,13 +357,18 @@ S_run_object_tests(CFCTest *test) {
 
     {
         CFCParcel *foreign_parcel = CFCParcel_new("Foreign", NULL, NULL);
-        CFCParcel_register(foreign_parcel);
+        CFCClass *foreign_foo_class
+            = CFCClass_create(foreign_parcel, NULL, "Foo", NULL, NULL, NULL,
+                              NULL, NULL, false, false);
+        CFCClass *foreign_class_list[2] = { foreign_foo_class, NULL };
         CFCType *foreign_foo = CFCType_new_object(0, foreign_parcel, "Foo", 1);
+        CFCType_resolve(foreign_foo, foreign_class_list);
         OK(test, !CFCType_equals(foo, foreign_foo),
            "different parcel spoils equals");
         STR_EQ(test, CFCType_get_specifier(foreign_foo), "foreign_Foo",
                "prepend parcel prefix to specifier");
         CFCBase_decref((CFCBase*)foreign_parcel);
+        CFCBase_decref((CFCBase*)foreign_foo_class);
         CFCBase_decref((CFCBase*)foreign_foo);
     }
 
@@ -366,8 +393,10 @@ S_run_object_tests(CFCTest *test) {
         CFCBase_decref((CFCBase*)string_type);
     }
 
+    CFCBase_decref((CFCBase*)foo_class);
     CFCBase_decref((CFCBase*)foo);
 
+    CFCClass_clear_registry();
     CFCParcel_reap_singletons();
 }
 
@@ -485,7 +514,9 @@ S_run_composite_tests(CFCTest *test) {
     }
 
     {
+        CFCClass *class_list[1] = { NULL };
         CFCType *foo_array = CFCTest_parse_type(test, parser, "foo_t[]");
+        CFCType_resolve(foo_array, class_list);
         STR_EQ(test, CFCType_get_array(foo_array), "[]", "get_array");
         STR_EQ(test, CFCType_to_c(foo_array), "foo_t",
                "array subscripts not included by to_c");

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCTestVariable.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestVariable.c b/clownfish/compiler/src/CFCTestVariable.c
index fd7f291..f0cbcac 100644
--- a/clownfish/compiler/src/CFCTestVariable.c
+++ b/clownfish/compiler/src/CFCTestVariable.c
@@ -16,6 +16,7 @@
 
 #define CFC_USE_TEST_MACROS
 #include "CFCBase.h"
+#include "CFCClass.h"
 #include "CFCParcel.h"
 #include "CFCParser.h"
 #include "CFCSymbol.h"
@@ -28,7 +29,7 @@ S_run_tests(CFCTest *test);
 
 const CFCTestBatch CFCTEST_BATCH_VARIABLE = {
     "Clownfish::CFC::Model::Variable",
-    27,
+    29,
     S_run_tests
 };
 
@@ -37,11 +38,14 @@ S_run_tests(CFCTest *test) {
     CFCParser *parser = CFCParser_new();
     CFCParcel *neato_parcel
         = CFCTest_parse_parcel(test, parser, "parcel Neato;");
+    CFCClass *foo_class = CFCTest_parse_class(test, parser, "class Foo {}");
+    CFCClass *class_list[2] = { foo_class, NULL };
 
     {
         CFCType *type = CFCTest_parse_type(test, parser, "float*");
         CFCVariable *var
             = CFCVariable_new(NULL, NULL, NULL, NULL, "foo", type, 0);
+        CFCVariable_resolve_type(var, class_list);
         STR_EQ(test, CFCVariable_local_c(var), "float* foo", "local_c");
         STR_EQ(test, CFCVariable_local_declaration(var), "float* foo;",
                "local_declaration");
@@ -55,6 +59,7 @@ S_run_tests(CFCTest *test) {
         CFCType *type = CFCTest_parse_type(test, parser, "float[1]");
         CFCVariable *var
             = CFCVariable_new(NULL, NULL, NULL, NULL, "foo", type, 0);
+        CFCVariable_resolve_type(var, class_list);
         STR_EQ(test, CFCVariable_local_c(var), "float foo[1]",
                "to_c appends array to var name rather than type specifier");
 
@@ -68,6 +73,7 @@ S_run_tests(CFCTest *test) {
             = CFCVariable_new(neato_parcel, NULL,
                               "Crustacean::Lobster::LobsterClaw", "LobClaw",
                               "foo", type, 0);
+        CFCVariable_resolve_type(var, class_list);
         STR_EQ(test, CFCVariable_global_c(var), "neato_Foo* neato_LobClaw_foo",
                "global_c");
 
@@ -94,7 +100,9 @@ S_run_tests(CFCTest *test) {
 
     CFCBase_decref((CFCBase*)parser);
     CFCBase_decref((CFCBase*)neato_parcel);
+    CFCBase_decref((CFCBase*)foo_class);
 
+    CFCClass_clear_registry();
     CFCParcel_reap_singletons();
 }
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCType.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCType.c b/clownfish/compiler/src/CFCType.c
index 549dff1..0494f93 100644
--- a/clownfish/compiler/src/CFCType.c
+++ b/clownfish/compiler/src/CFCType.c
@@ -26,6 +26,7 @@
 #define CFC_NEED_BASE_STRUCT_DEF
 #include "CFCBase.h"
 #include "CFCType.h"
+#include "CFCClass.h"
 #include "CFCParcel.h"
 #include "CFCSymbol.h"
 #include "CFCUtil.h"
@@ -92,15 +93,8 @@ CFCType_init(CFCType *self, int flags, struct CFCParcel *parcel,
     self->width       = 0;
     self->array       = NULL;
     self->child       = NULL;
-    if (flags & CFCTYPE_OBJECT) {
-        self->vtable_var = CFCUtil_strdup(specifier);
-        for (int i = 0; self->vtable_var[i] != 0; i++) {
-            self->vtable_var[i] = toupper(self->vtable_var[i]);
-        }
-    }
-    else {
-        self->vtable_var  = NULL;
-    }
+    self->vtable_var  = NULL;
+
     return self;
 }
 
@@ -216,14 +210,8 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
         flags |= CFCTYPE_STRING_TYPE;
     }
 
-    char full_specifier[MAX_SPECIFIER_LEN + 1];
     char small_specifier[MAX_SPECIFIER_LEN + 1];
     if (isupper(*specifier)) {
-        const char *prefix = CFCParcel_get_prefix(parcel);
-        if (strlen(prefix) + strlen(specifier) > MAX_SPECIFIER_LEN) {
-            CFCUtil_die("Specifier and/or parcel prefix too long");
-        }
-        sprintf(full_specifier, "%s%s", prefix, specifier);
         strcpy(small_specifier, specifier);
     }
     else if (!isalpha(*specifier)) {
@@ -243,7 +231,6 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
             }
             probe++;
         }
-        strcpy(full_specifier, specifier);
         strcpy(small_specifier, probe);
     }
 
@@ -251,15 +238,6 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
         CFCUtil_die("Invalid specifier: '%s'", specifier);
     }
 
-    // Cache C representation.
-    char c_string[MAX_SPECIFIER_LEN + 10];
-    if (flags & CFCTYPE_CONST) {
-        sprintf(c_string, "const %s*", full_specifier);
-    }
-    else {
-        sprintf(c_string, "%s*", full_specifier);
-    }
-
     int acceptable_flags = CFCTYPE_OBJECT
                            | CFCTYPE_STRING_TYPE
                            | CFCTYPE_CONST
@@ -268,7 +246,7 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier,
                            | CFCTYPE_DECREMENTED;
     S_check_flags(flags, acceptable_flags, "Object");
 
-    return CFCType_new(flags, parcel, full_specifier, 1, c_string);
+    return CFCType_new(flags, parcel, specifier, 1, NULL);
 }
 
 #define MAX_COMPOSITE_LEN 256
@@ -282,22 +260,8 @@ CFCType_new_composite(int flags, CFCType *child, int indirection,
     flags |= CFCTYPE_COMPOSITE;
     S_check_flags(flags, CFCTYPE_COMPOSITE | CFCTYPE_NULLABLE, "Composite");
 
-    // Cache C representation.
-    // NOTE: Array postfixes are NOT included.
-    const char   *child_c_string = CFCType_to_c(child);
-    size_t        child_c_len    = strlen(child_c_string);
-    size_t        amount         = child_c_len + indirection;
-    if (amount > MAX_COMPOSITE_LEN) {
-        CFCUtil_die("C representation too long");
-    }
-    char c_string[MAX_COMPOSITE_LEN + 1];
-    strcpy(c_string, child_c_string);
-    for (int i = 0; i < indirection; i++) {
-        strncat(c_string, "*", 1);
-    }
-
     CFCType *self = CFCType_new(flags, NULL, CFCType_get_specifier(child),
-                                indirection, c_string);
+                                indirection, NULL);
     self->child = (CFCType*)CFCBase_incref((CFCBase*)child);
 
     // Record array spec.
@@ -335,6 +299,83 @@ CFCType_new_arbitrary(CFCParcel *parcel, const char *specifier) {
 }
 
 void
+CFCType_resolve(CFCType *self, CFCClass **classes) {
+    if (CFCType_is_composite(self)) {
+        CFCType_resolve(self->child, classes);
+
+        // Cache C representation.
+        // NOTE: Array postfixes are NOT included.
+        const char   *child_c_string = CFCType_to_c(self->child);
+        size_t        child_c_len    = strlen(child_c_string);
+        size_t        amount         = child_c_len + self->indirection;
+        if (amount > MAX_COMPOSITE_LEN) {
+            CFCUtil_die("C representation too long");
+        }
+        char c_string[MAX_COMPOSITE_LEN + 1];
+        strcpy(c_string, child_c_string);
+        for (int i = 0; i < self->indirection; i++) {
+            strncat(c_string, "*", 1);
+        }
+        FREEMEM(self->c_string);
+        self->c_string = CFCUtil_strdup(c_string);
+
+        return;
+    }
+    if (!CFCType_is_object(self)) {
+        return;
+    }
+
+    if (isupper(self->specifier[0])) {
+        // Try to find class from class list.
+        const char *specifier = self->specifier;
+        CFCClass   *klass     = NULL;
+
+        for (size_t i = 0; classes[i]; ++i) {
+            CFCClass   *maybe_class = classes[i];
+            const char *struct_sym  = CFCClass_get_struct_sym(maybe_class);
+
+            if (strcmp(specifier, struct_sym) == 0) {
+                if (klass) {
+                    CFCUtil_die("Type '%s' is ambigious", specifier);
+                }
+                klass = maybe_class;
+            }
+        }
+
+        if (!klass) {
+            CFCUtil_die("No class found for type '%s'", specifier);
+        }
+
+        // Create actual specifier with prefix.
+        const char *prefix = CFCClass_get_prefix(klass);
+        if (strlen(prefix) + strlen(specifier) > MAX_SPECIFIER_LEN) {
+            CFCUtil_die("Specifier and/or parcel prefix too long");
+        }
+        char full_specifier[MAX_SPECIFIER_LEN + 1];
+        sprintf(full_specifier, "%s%s", prefix, specifier);
+        FREEMEM(self->specifier);
+        self->specifier = CFCUtil_strdup(full_specifier);
+    }
+
+    // Cache C representation.
+    char c_string[MAX_SPECIFIER_LEN + 10];
+    if (CFCType_const(self)) {
+        sprintf(c_string, "const %s*", self->specifier);
+    }
+    else {
+        sprintf(c_string, "%s*", self->specifier);
+    }
+    FREEMEM(self->c_string);
+    self->c_string = CFCUtil_strdup(c_string);
+
+    // Cache name of VTable variable.
+    self->vtable_var = CFCUtil_strdup(self->specifier);
+    for (int i = 0; self->vtable_var[i] != 0; i++) {
+        self->vtable_var[i] = toupper(self->vtable_var[i]);
+    }
+}
+
+void
 CFCType_destroy(CFCType *self) {
     if (self->child) {
         CFCBase_decref((CFCBase*)self->child);

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCType.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCType.h b/clownfish/compiler/src/CFCType.h
index 5c1354b..937ae94 100644
--- a/clownfish/compiler/src/CFCType.h
+++ b/clownfish/compiler/src/CFCType.h
@@ -25,6 +25,7 @@ extern "C" {
 #endif
 
 typedef struct CFCType CFCType;
+struct CFCClass;
 struct CFCParcel;
 
 #define CFCTYPE_CONST       0x00000001
@@ -173,6 +174,11 @@ CFCType_new_va_list(void);
 CFCType*
 CFCType_new_arbitrary(struct CFCParcel *parcel, const char *specifier);
 
+/** Find the actual class of an object variable without prefix.
+ */
+void
+CFCType_resolve(CFCType *self, struct CFCClass **classes);
+
 void
 CFCType_destroy(CFCType *self);
 

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCVariable.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCVariable.c b/clownfish/compiler/src/CFCVariable.c
index adf743b..54c2a17 100644
--- a/clownfish/compiler/src/CFCVariable.c
+++ b/clownfish/compiler/src/CFCVariable.c
@@ -74,18 +74,30 @@ CFCVariable_init(CFCVariable *self, struct CFCParcel *parcel,
     self->type = (CFCType*)CFCBase_incref((CFCBase*)type);
     self->inert = !!inert;
 
-    // Cache various C string representations.
+    self->local_c   = NULL;
+    self->local_dec = NULL;
+    self->global_c  = NULL;
+
+    return self;
+}
+
+// Cache various C string representations. Will be called after type has
+// been resolved.
+void
+CFCVariable_resolve_type(CFCVariable *self, struct CFCClass **classes) {
+    CFCType *type = self->type;
+    CFCType_resolve(type, classes);
+
     const char *type_str = CFCType_to_c(type);
     const char *postfix  = "";
     if (CFCType_is_composite(type) && CFCType_get_array(type) != NULL) {
         postfix = CFCType_get_array(type);
     }
+    const char *micro_sym = CFCVariable_micro_sym(self);
     self->local_c = CFCUtil_sprintf("%s %s%s", type_str, micro_sym, postfix);
     self->local_dec = CFCUtil_sprintf("%s;", self->local_c);
     const char *full_sym = CFCVariable_full_sym(self);
     self->global_c = CFCUtil_sprintf("%s %s%s", type_str, full_sym, postfix);
-
-    return self;
 }
 
 void

http://git-wip-us.apache.org/repos/asf/lucy/blob/c33d5cb3/clownfish/compiler/src/CFCVariable.h
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCVariable.h b/clownfish/compiler/src/CFCVariable.h
index 2d3fcfc..7263de7 100644
--- a/clownfish/compiler/src/CFCVariable.h
+++ b/clownfish/compiler/src/CFCVariable.h
@@ -34,6 +34,7 @@ extern "C" {
 #endif
 
 typedef struct CFCVariable CFCVariable;
+struct CFCClass;
 struct CFCParcel;
 struct CFCType;
 
@@ -56,6 +57,9 @@ CFCVariable_init(CFCVariable *self, struct CFCParcel *parcel,
                  struct CFCType *type, int inert);
 
 void
+CFCVariable_resolve_type(CFCVariable *self, struct CFCClass **classes);
+
+void
 CFCVariable_destroy(CFCVariable *self);
 
 int


[lucy-dev] Re: [lucy-commits] [5/9] git commit: refs/heads/separate-clownfish-wip1 - Support object types from other parcels without prefix

Posted by Marvin Humphrey <ma...@rectangular.com>.
On Sun, May 26, 2013 at 8:35 AM,  <nw...@apache.org> wrote:
> Support object types from other parcels without prefix
>
> Resolve types after all classes have been parsed.
>
> This means that caching of C representations has to be postponed. For
> now, the C representations are cached after the types have been
> resolved. This is error-prone and requires some hacks for methods. It
> might be better to move to a scheme where the C strings are not cached
> until they're used for the first time.

> Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
> Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/c33d5cb3
> Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/c33d5cb3
> Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/c33d5cb3

This commit is a very nice step in the right direction.  CFC tries to do too
much during the parse phase.  It's better to perform semantic analysis during
subsequent tree traversals, even though that may mean adding extra code to
lazily-resolved getters and such to ensure that the object is in a valid state
when they are called.

I suspect that if we move to a single registry for both parcels and classes --
or better yet, a single registry for all symbols, including methods, inert
functions, inert vars and member vars -- type resolution would get easier.

Marvin Humphrey