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/30 22:36:30 UTC

[lucy-commits] [12/26] git commit: refs/heads/separate-clownfish-wip2 - 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/fa4918d2
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/fa4918d2
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/fa4918d2

Branch: refs/heads/separate-clownfish-wip2
Commit: fa4918d2c11e1cf600579a977f8e752227dc5d2f
Parents: cecd524
Author: Nick Wellnhofer <we...@aevum.de>
Authored: Mon May 20 01:36:52 2013 +0200
Committer: Nick Wellnhofer <we...@aevum.de>
Committed: Thu May 30 22:30:17 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        |   30 ++++--
 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      |   36 +++++++-
 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, 303 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/clownfish/compiler/src/CFCMethod.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCMethod.c b/clownfish/compiler/src/CFCMethod.c
index a9f0063..f659323 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

http://git-wip-us.apache.org/repos/asf/lucy/blob/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/clownfish/compiler/src/CFCTestType.c
----------------------------------------------------------------------
diff --git a/clownfish/compiler/src/CFCTestType.c b/clownfish/compiler/src/CFCTestType.c
index 8751eb8..759aa42 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,11 @@ S_run_object_tests(CFCTest *test) {
         CFCBase_decref((CFCBase*)string_type);
     }
 
+    CFCBase_decref((CFCBase*)neato_parcel);
+    CFCBase_decref((CFCBase*)foo_class);
     CFCBase_decref((CFCBase*)foo);
 
+    CFCClass_clear_registry();
     CFCParcel_reap_singletons();
 }
 
@@ -485,7 +515,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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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/fa4918d2/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