CFCBindSpecs class Handle ClassSpecs and MethSpecs in a single place.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/2b3ed29a Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/2b3ed29a Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/2b3ed29a Branch: refs/heads/master Commit: 2b3ed29a7cf05fd1c0ae6b23482cadcf445dbf03 Parents: 8bfda83 Author: Nick Wellnhofer <[email protected]> Authored: Thu Jul 23 19:51:01 2015 +0200 Committer: Nick Wellnhofer <[email protected]> Committed: Mon Jul 27 18:26:18 2015 +0200 ---------------------------------------------------------------------- compiler/include/CFC.h | 1 + compiler/perl/lib/Clownfish/CFC.xs | 24 -- compiler/src/CFCBindClass.c | 205 +--------------- compiler/src/CFCBindClass.h | 5 - compiler/src/CFCBindCore.c | 89 +++---- compiler/src/CFCBindMethod.c | 75 ------ compiler/src/CFCBindMethod.h | 20 -- compiler/src/CFCBindSpecs.c | 419 ++++++++++++++++++++++++++++++++ compiler/src/CFCBindSpecs.h | 58 +++++ compiler/src/CFCClass.c | 18 ++ compiler/src/CFCClass.h | 6 + 11 files changed, 534 insertions(+), 386 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/include/CFC.h ---------------------------------------------------------------------- diff --git a/compiler/include/CFC.h b/compiler/include/CFC.h index e57c873..9d1c222 100644 --- a/compiler/include/CFC.h +++ b/compiler/include/CFC.h @@ -44,6 +44,7 @@ #include "CFCBindFile.h" #include "CFCBindFunction.h" #include "CFCBindMethod.h" +#include "CFCBindSpecs.h" #include "CFCGo.h" #include "CFCGoClass.h" http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/perl/lib/Clownfish/CFC.xs ---------------------------------------------------------------------- diff --git a/compiler/perl/lib/Clownfish/CFC.xs b/compiler/perl/lib/Clownfish/CFC.xs index d9e28bf..c779c5b 100644 --- a/compiler/perl/lib/Clownfish/CFC.xs +++ b/compiler/perl/lib/Clownfish/CFC.xs @@ -1908,30 +1908,6 @@ CODE: RETVAL = S_sv_eat_c_string(CFCBindMeth_method_def(meth, klass)); OUTPUT: RETVAL -SV* -_novel_spec_def(meth, klass) - CFCMethod *meth; - CFCClass *klass; -CODE: - RETVAL = S_sv_eat_c_string(CFCBindMeth_novel_spec_def(meth, klass)); -OUTPUT: RETVAL - -SV* -_overridden_spec_def(meth, klass) - CFCMethod *meth; - CFCClass *klass; -CODE: - RETVAL = S_sv_eat_c_string(CFCBindMeth_overridden_spec_def(meth, klass)); -OUTPUT: RETVAL - -SV* -_inherited_spec_def(meth, klass) - CFCMethod *meth; - CFCClass *klass; -CODE: - RETVAL = S_sv_eat_c_string(CFCBindMeth_inherited_spec_def(meth, klass)); -OUTPUT: RETVAL - MODULE = Clownfish::CFC PACKAGE = Clownfish::CFC::Binding::Core::Aliases SV* http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindClass.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindClass.c b/compiler/src/CFCBindClass.c index d1cebf6..f19a174 100644 --- a/compiler/src/CFCBindClass.c +++ b/compiler/src/CFCBindClass.c @@ -45,11 +45,6 @@ S_to_c_header_inert(CFCBindClass *self); static char* S_to_c_header_dynamic(CFCBindClass *self); -// Count the number of member variables declared in ancestor classes -// outside this package. -static int -S_count_non_package_members(CFCBindClass *self); - // Create the definition for the instantiable object struct. static char* S_struct_definition(CFCBindClass *self); @@ -286,16 +281,12 @@ CFCBindClass_to_c_data(CFCBindClass *self) { } const char *ivars_offset = CFCClass_full_ivars_offset(client); - const char *class_var = CFCClass_full_class_var(client); CFCMethod **methods = CFCClass_methods(client); char *offsets = CFCUtil_strdup(""); char *method_defs = CFCUtil_strdup(""); - char *novel_ms_var = CFCUtil_strdup(""); - char *overridden_ms_var = CFCUtil_strdup(""); - char *inherited_ms_var = CFCUtil_strdup(""); for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) { CFCMethod *method = methods[meth_num]; @@ -314,69 +305,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) { method_defs = CFCUtil_cat(method_defs, method_def, "\n", NULL); FREEMEM(method_def); } - - if (is_fresh && CFCMethod_novel(method)) { - if (novel_ms_var[0] == '\0') { - // Start an array of cfish_NovelMethSpec structs. Since C89 - // doesn't allow us to initialize a pointer to an anonymous - // array inside a global struct, we have to give it a real - // symbol and then store a pointer to that symbol inside the - // ClassSpec struct. - novel_ms_var - = CFCUtil_cat(novel_ms_var, - "static const cfish_NovelMethSpec ", - class_var, "_NOVEL_METHS[] = {\n", NULL); - } - else { - novel_ms_var = CFCUtil_cat(novel_ms_var, ",\n", NULL); - } - char *ms_def = CFCBindMeth_novel_spec_def(method, client); - novel_ms_var = CFCUtil_cat(novel_ms_var, ms_def, NULL); - FREEMEM(ms_def); - } - else if (is_fresh) { - if (overridden_ms_var[0] == '\0') { - // Start an array of cfish_OverriddenMethSpec structs. - overridden_ms_var - = CFCUtil_cat(overridden_ms_var, - "static const cfish_OverriddenMethSpec ", - class_var, "_OVERRIDDEN_METHS[] = {\n", - NULL); - } - else { - overridden_ms_var - = CFCUtil_cat(overridden_ms_var, ",\n", NULL); - } - char *ms_def = CFCBindMeth_overridden_spec_def(method, client); - overridden_ms_var = CFCUtil_cat(overridden_ms_var, ms_def, NULL); - FREEMEM(ms_def); - } - else { - if (inherited_ms_var[0] == '\0') { - // Start an array of cfish_InheritedMethSpec structs. - inherited_ms_var - = CFCUtil_cat(inherited_ms_var, - "static const cfish_InheritedMethSpec ", - class_var, "_INHERITED_METHS[] = {\n", NULL); - } - else { - inherited_ms_var = CFCUtil_cat(inherited_ms_var, ",\n", NULL); - } - char *ms_def = CFCBindMeth_inherited_spec_def(method, client); - inherited_ms_var = CFCUtil_cat(inherited_ms_var, ms_def, NULL); - FREEMEM(ms_def); - } - } - - // Close MethSpec array definitions. - if (novel_ms_var[0] != '\0') { - novel_ms_var = CFCUtil_cat(novel_ms_var, "\n};\n\n", NULL); - } - if (overridden_ms_var[0] != '\0') { - overridden_ms_var = CFCUtil_cat(overridden_ms_var, "\n};\n\n", NULL); - } - if (inherited_ms_var[0] != '\0') { - inherited_ms_var = CFCUtil_cat(inherited_ms_var, "\n};\n\n", NULL); } const char pattern[] = @@ -397,12 +325,6 @@ CFCBindClass_to_c_data(CFCBindClass *self) { "\n" "%s\n" "\n" - "/* Define the MethSpec structs used during Class initialization.\n" - " */\n" - "\n" - "%s" - "%s" - "%s" "/* Define the pointer to the Class singleton object.\n" " */\n" "\n" @@ -410,36 +332,13 @@ CFCBindClass_to_c_data(CFCBindClass *self) { "\n"; char *code = CFCUtil_sprintf(pattern, ivars_offset, offsets, method_defs, - novel_ms_var, overridden_ms_var, inherited_ms_var, class_var); FREEMEM(offsets); FREEMEM(method_defs); - FREEMEM(novel_ms_var); - FREEMEM(overridden_ms_var); - FREEMEM(inherited_ms_var); return code; } -// Count the number of member variables declared in ancestor classes -// outside this package. -static int -S_count_non_package_members(CFCBindClass *self) { - CFCClass *const client = self->client; - CFCParcel *parcel = CFCClass_get_parcel(client); - CFCClass *ancestor = CFCClass_get_parent(client); - int num_non_package_members = 0; - - while (ancestor && CFCClass_get_parcel(ancestor) == parcel) { - ancestor = CFCClass_get_parent(ancestor); - } - if (ancestor) { - num_non_package_members = CFCClass_num_member_vars(ancestor); - } - - return num_non_package_members; -} - // Create the definition for the instantiable object struct. static char* S_struct_definition(CFCBindClass *self) { @@ -458,7 +357,7 @@ S_struct_definition(CFCBindClass *self) { // Add all member variables declared by classes in this package. CFCVariable **member_vars = CFCClass_member_vars(client); - int num_non_package_members = S_count_non_package_members(self); + int num_non_package_members = CFCClass_num_non_package_ivars(client); for (int i = num_non_package_members; member_vars[i] != NULL; i++) { const char *member_dec = CFCVariable_local_declaration(member_vars[i]); member_decs = CFCUtil_cat(member_decs, "\n ", member_dec, NULL); @@ -479,108 +378,6 @@ S_struct_definition(CFCBindClass *self) { return struct_def; } -// Return C definition of the class's ClassSpec. -char* -CFCBindClass_spec_def(CFCBindClass *self) { - CFCClass *client = self->client; - - CFCParcel *parcel = CFCClass_get_parcel(client); - CFCClass *parent = CFCClass_get_parent(client); - const char *class_name = CFCClass_get_name(client); - const char *class_var = CFCClass_full_class_var(client); - const char *struct_sym = CFCClass_full_struct_sym(client); - const char *ivars_struct = CFCClass_full_ivars_struct(client); - - // Create a pointer to the parent Class object. - char *parent_ref; - if (parent) { - parent_ref = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent)); - } - else { - // No parent, e.g. Obj or inert classes. - parent_ref = CFCUtil_strdup("NULL"); - } - - int num_novel = 0; - int num_overridden = 0; - int num_inherited = 0; - CFCMethod **methods = CFCClass_methods(client); - - for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) { - CFCMethod *method = methods[meth_num]; - - if (CFCMethod_is_fresh(method, client)) { - if (CFCMethod_novel(method)) { - ++num_novel; - } - else { - ++num_overridden; - } - } - else { - ++num_inherited; - } - } - - char *novel_ms_var = num_novel - ? CFCUtil_sprintf("%s_NOVEL_METHS", class_var) - : CFCUtil_strdup("NULL"); - char *overridden_ms_var = num_overridden - ? CFCUtil_sprintf("%s_OVERRIDDEN_METHS", - class_var) - : CFCUtil_strdup("NULL"); - char *inherited_ms_var = num_inherited - ? CFCUtil_sprintf("%s_INHERITED_METHS", - class_var) - : CFCUtil_strdup("NULL"); - - char *ivars_size = NULL; - - if (CFCParcel_is_cfish(parcel)) { - ivars_size = CFCUtil_sprintf("sizeof(%s)", struct_sym); - } - else { - int num_non_package_members = S_count_non_package_members(self); - int num_members = CFCClass_num_member_vars(client); - - if (num_non_package_members == num_members) { - // No members in this package. - ivars_size = CFCUtil_strdup("0"); - } - else { - ivars_size = CFCUtil_sprintf("sizeof(%s)", ivars_struct); - } - } - const char *ivars_offset_name = CFCClass_full_ivars_offset(client); - - char pattern[] = - " {\n" - " &%s, /* class */\n" - " %s, /* parent */\n" - " \"%s\", /* name */\n" - " %s, /* ivars_size */\n" - " &%s, /* ivars_offset_ptr */\n" - " %d, /* num_novel */\n" - " %d, /* num_overridden */\n" - " %d, /* num_inherited */\n" - " %s, /* novel_meth_specs */\n" - " %s, /* overridden_meth_specs */\n" - " %s /* inherited_meth_specs */\n" - " }"; - char *code - = CFCUtil_sprintf(pattern, class_var, parent_ref, class_name, - ivars_size, ivars_offset_name, num_novel, - num_overridden, num_inherited, novel_ms_var, - overridden_ms_var, inherited_ms_var); - - FREEMEM(parent_ref); - FREEMEM(novel_ms_var); - FREEMEM(overridden_ms_var); - FREEMEM(inherited_ms_var); - FREEMEM(ivars_size); - return code; -} - // Declare typedefs for every method, to ease casting. static char* S_method_typedefs(CFCBindClass *self) { http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindClass.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindClass.h b/compiler/src/CFCBindClass.h index c915c65..4780bdc 100644 --- a/compiler/src/CFCBindClass.h +++ b/compiler/src/CFCBindClass.h @@ -54,11 +54,6 @@ CFCBindClass_to_c_header(CFCBindClass *self); char* CFCBindClass_to_c_data(CFCBindClass *self); -/** Return the autogenerated C definition of class's ClassSpec. - */ -char* -CFCBindClass_spec_def(CFCBindClass *self); - #ifdef __cplusplus } #endif http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindCore.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindCore.c b/compiler/src/CFCBindCore.c index 985f00c..d5f59d7 100644 --- a/compiler/src/CFCBindCore.c +++ b/compiler/src/CFCBindCore.c @@ -24,6 +24,7 @@ #include "CFCBindCore.h" #include "CFCBindClass.h" #include "CFCBindFile.h" +#include "CFCBindSpecs.h" #include "CFCClass.h" #include "CFCFile.h" #include "CFCHierarchy.h" @@ -300,41 +301,6 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) { "#define CFISH_fREFCOUNTSPECIAL 0x00000001\n" ; const char *cfish_defs_2 = - "/* Structs for Class initialization.\n" - " */\n" - "\n" - "typedef struct cfish_NovelMethSpec {\n" - " size_t *offset;\n" - " const char *name;\n" - " cfish_method_t func;\n" - " cfish_method_t callback_func;\n" - "} cfish_NovelMethSpec;\n" - "\n" - "typedef struct cfish_OverriddenMethSpec {\n" - " size_t *offset;\n" - " size_t *parent_offset;\n" - " cfish_method_t func;\n" - "} cfish_OverriddenMethSpec;\n" - "\n" - "typedef struct cfish_InheritedMethSpec {\n" - " size_t *offset;\n" - " size_t *parent_offset;\n" - "} cfish_InheritedMethSpec;\n" - "\n" - "typedef struct cfish_ClassSpec {\n" - " cfish_Class **klass;\n" - " cfish_Class **parent;\n" - " const char *name;\n" - " size_t ivars_size;\n" - " size_t *ivars_offset_ptr;\n" - " uint32_t num_novel_meths;\n" - " uint32_t num_overridden_meths;\n" - " uint32_t num_inherited_meths;\n" - " const cfish_NovelMethSpec *novel_meth_specs;\n" - " const cfish_OverriddenMethSpec *overridden_meth_specs;\n" - " const cfish_InheritedMethSpec *inherited_meth_specs;\n" - "} cfish_ClassSpec;\n" - "\n" "#ifdef CFISH_USE_SHORT_NAMES\n" " #define UNUSED_VAR CFISH_UNUSED_VAR\n" " #define UNREACHABLE_RETURN CFISH_UNREACHABLE_RETURN\n" @@ -352,7 +318,9 @@ S_write_parcel_h(CFCBindCore *self, CFCParcel *parcel) { char *extra_defs; char *extra_includes; if (CFCParcel_is_cfish(parcel)) { - extra_defs = CFCUtil_sprintf("%s%s", cfish_defs_1, cfish_defs_2); + const char *spec_typedefs = CFCBindSpecs_get_typedefs(); + extra_defs = CFCUtil_sprintf("%s%s%s", cfish_defs_1, spec_typedefs, + cfish_defs_2); extra_includes = CFCUtil_strdup(cfish_includes); } else { @@ -439,10 +407,9 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) { char *privacy_syms = CFCUtil_strdup(""); char *includes = CFCUtil_strdup(""); char *c_data = CFCUtil_strdup(""); - char *class_specs = CFCUtil_strdup( - "static const cfish_ClassSpec class_specs[] = {\n"); - int num_specs = 0; - CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy); + CFCBindSpecs *specs = CFCBindSpecs_new(); + CFCClass **ordered = CFCHierarchy_ordered_classes(hierarchy); + for (int i = 0; ordered[i] != NULL; i++) { CFCClass *klass = ordered[i]; const char *class_prefix = CFCClass_get_prefix(klass); @@ -453,24 +420,22 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) { "\"\n", NULL); CFCBindClass *class_binding = CFCBindClass_new(klass); + char *class_c_data = CFCBindClass_to_c_data(class_binding); c_data = CFCUtil_cat(c_data, class_c_data, "\n", NULL); FREEMEM(class_c_data); - if (!CFCClass_inert(klass)) { - if (num_specs != 0) { - class_specs = CFCUtil_cat(class_specs, ",\n", NULL); - } - char *class_spec = CFCBindClass_spec_def(class_binding); - class_specs = CFCUtil_cat(class_specs, class_spec, NULL); - FREEMEM(class_spec); - ++num_specs; - } - CFCBase_decref((CFCBase*)class_binding); + + CFCBindSpecs_add_class(specs, klass); + const char *privacy_sym = CFCClass_privacy_symbol(klass); privacy_syms = CFCUtil_cat(privacy_syms, "#define ", privacy_sym, "\n", NULL); + + CFCBase_decref((CFCBase*)class_binding); } - class_specs = CFCUtil_cat(class_specs, "\n};\n", NULL); + + char *spec_defs = CFCBindSpecs_defs(specs); + char *spec_init_func = CFCBindSpecs_init_func_def(specs); FREEMEM(ordered); // Bootstrapping code for prerequisite parcels. @@ -514,9 +479,15 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) { "\n" "%s\n" "\n" - "/* ClassSpec structs for initialization.\n" + "/* ClassSpec and MethSpec structs for initialization.\n" " */\n" - "%s\n" + "\n" + "%s" // spec_defs + "\n" + "/* Code to initialize ClassSpec and MethSpec structs.\n" + " */\n" + "\n" + "%s" // spec_init_func "\n" "static int bootstrap_state = 0;\n" "\n" @@ -530,7 +501,7 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) { " if (bootstrap_state >= 2) { return; }\n" " bootstrap_state = 1;\n" "%s" // Bootstrap inherited parcels. - " cfish_Class_bootstrap(class_specs, %d);\n" + " S_bootstrap_specs();\n" " bootstrap_state = 2;\n" "}\n" "\n" @@ -546,9 +517,9 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) { "%s\n"; char *file_content = CFCUtil_sprintf(pattern, self->c_header, privacy_syms, includes, - c_data, class_specs, prefix, inh_bootstrap, - num_specs, prefix, prefix, prereq_bootstrap, prefix, - self->c_footer); + c_data, spec_defs, spec_init_func, prefix, + inh_bootstrap, prefix, prefix, prereq_bootstrap, + prefix, self->c_footer); // Unlink then open file. const char *src_dest = CFCHierarchy_get_source_dest(hierarchy); @@ -558,10 +529,12 @@ S_write_parcel_c(CFCBindCore *self, CFCParcel *parcel) { CFCUtil_write_file(filepath, file_content, strlen(file_content)); FREEMEM(filepath); + CFCBase_decref((CFCBase*)specs); FREEMEM(privacy_syms); FREEMEM(includes); FREEMEM(c_data); - FREEMEM(class_specs); + FREEMEM(spec_defs); + FREEMEM(spec_init_func); FREEMEM(inh_bootstrap); FREEMEM(prereq_bootstrap); FREEMEM(file_content); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindMethod.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindMethod.c b/compiler/src/CFCBindMethod.c index 925f481..e4d7301 100644 --- a/compiler/src/CFCBindMethod.c +++ b/compiler/src/CFCBindMethod.c @@ -162,81 +162,6 @@ CFCBindMeth_typedef_dec(struct CFCMethod *method, CFCClass *klass) { } char* -CFCBindMeth_novel_spec_def(CFCMethod *method, CFCClass *klass) { - const char *meth_name = CFCMethod_get_name(method); - - char *full_override_sym; - if (!CFCMethod_final(method)) { - full_override_sym = CFCMethod_full_override_sym(method, klass); - } - else { - full_override_sym = CFCUtil_strdup("NULL"); - } - - char *imp_func = CFCMethod_imp_func(method, klass); - char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); - - char pattern[] = - " {\n" - " &%s, /* offset */\n" - " \"%s\", /* name */\n" - " (cfish_method_t)%s, /* func */\n" - " (cfish_method_t)%s /* callback_func */\n" - " }"; - char *def - = CFCUtil_sprintf(pattern, full_offset_sym, meth_name, imp_func, - full_override_sym); - - FREEMEM(full_offset_sym); - FREEMEM(imp_func); - FREEMEM(full_override_sym); - return def; -} - -char* -CFCBindMeth_overridden_spec_def(CFCMethod *method, CFCClass *klass) { - char *imp_func = CFCMethod_imp_func(method, klass); - char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); - - CFCClass *parent = CFCClass_get_parent(klass); - char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent); - - char pattern[] = - " {\n" - " &%s, /* offset */\n" - " &%s, /* parent_offset */\n" - " (cfish_method_t)%s /* func */\n" - " }"; - char *def - = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset_sym, - imp_func); - - FREEMEM(parent_offset_sym); - FREEMEM(full_offset_sym); - FREEMEM(imp_func); - return def; -} - -char* -CFCBindMeth_inherited_spec_def(CFCMethod *method, CFCClass *klass) { - char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); - - CFCClass *parent = CFCClass_get_parent(klass); - char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent); - - char pattern[] = - " {\n" - " &%s, /* offset */\n" - " &%s /* parent_offset */\n" - " }"; - char *def = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset_sym); - - FREEMEM(full_offset_sym); - FREEMEM(parent_offset_sym); - return def; -} - -char* CFCBindMeth_abstract_method_def(CFCMethod *method, CFCClass *klass) { CFCType *ret_type = CFCMethod_get_return_type(method); const char *ret_type_str = CFCType_to_c(ret_type); http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindMethod.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindMethod.h b/compiler/src/CFCBindMethod.h index 3bc16ab..4928c70 100644 --- a/compiler/src/CFCBindMethod.h +++ b/compiler/src/CFCBindMethod.h @@ -44,26 +44,6 @@ CFCBindMeth_method_def(struct CFCMethod *method, struct CFCClass *klass); char* CFCBindMeth_typedef_dec(struct CFCMethod *method, struct CFCClass *klass); -/** Return C code defining the MethSpec object for a novel method, which - * is used during Class initialization. - */ -char* -CFCBindMeth_novel_spec_def(struct CFCMethod *method, struct CFCClass *klass); - -/** Return C code defining the MethSpec object for an overridden method, - * which is used during Class initialization. - */ -char* -CFCBindMeth_overridden_spec_def(struct CFCMethod *method, - struct CFCClass *klass); - -/** Return C code defining the MethSpec object for an inherited method, - * which is used during Class initialization. - */ -char* -CFCBindMeth_inherited_spec_def(struct CFCMethod *method, - struct CFCClass *klass); - /** Return C code implementing a version of the method which throws an * "abstract method" error at runtime, for methods which are declared as * "abstract" in a Clownfish header file. http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindSpecs.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindSpecs.c b/compiler/src/CFCBindSpecs.c new file mode 100644 index 0000000..513806b --- /dev/null +++ b/compiler/src/CFCBindSpecs.c @@ -0,0 +1,419 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "charmony.h" + +#include "CFCBindSpecs.h" + +#define CFC_NEED_BASE_STRUCT_DEF +#include "CFCBase.h" +#include "CFCClass.h" +#include "CFCMethod.h" +#include "CFCParcel.h" +#include "CFCUtil.h" + +struct CFCBindSpecs { + CFCBase base; + + char *novel_specs; + char *overridden_specs; + char *inherited_specs; + char *class_specs; + + int num_novel; + int num_overridden; + int num_inherited; + int num_specs; +}; + +static char* +S_ivars_size(CFCClass *klass); + +static char* +S_novel_meth(CFCMethod *method, CFCClass *klass); + +static char* +S_parent_offset(CFCMethod *method, CFCClass *klass); + +static char* +S_overridden_meth(CFCMethod *method, CFCClass *klass); + +static char* +S_inherited_meth(CFCMethod *method, CFCClass *klass); + +static const CFCMeta CFCBINDSPECS_META = { + "Clownfish::CFC::Binding::Core::Specs", + sizeof(CFCBindSpecs), + (CFCBase_destroy_t)CFCBindSpecs_destroy +}; + +CFCBindSpecs* +CFCBindSpecs_new() { + CFCBindSpecs *self = (CFCBindSpecs*)CFCBase_allocate(&CFCBINDSPECS_META); + return CFCBindSpecs_init(self); +} + +CFCBindSpecs* +CFCBindSpecs_init(CFCBindSpecs *self) { + self->novel_specs = CFCUtil_strdup(""); + self->overridden_specs = CFCUtil_strdup(""); + self->inherited_specs = CFCUtil_strdup(""); + self->class_specs = CFCUtil_strdup(""); + + return self; +} + +void +CFCBindSpecs_destroy(CFCBindSpecs *self) { + FREEMEM(self->novel_specs); + FREEMEM(self->overridden_specs); + FREEMEM(self->inherited_specs); + FREEMEM(self->class_specs); + CFCBase_destroy((CFCBase*)self); +} + +const char* +CFCBindSpecs_get_typedefs() { + return + "/* Structs for Class initialization.\n" + " */\n" + "\n" + "typedef struct cfish_NovelMethSpec {\n" + " size_t *offset;\n" + " const char *name;\n" + " cfish_method_t func;\n" + " cfish_method_t callback_func;\n" + "} cfish_NovelMethSpec;\n" + "\n" + "typedef struct cfish_OverriddenMethSpec {\n" + " size_t *offset;\n" + " size_t *parent_offset;\n" + " cfish_method_t func;\n" + "} cfish_OverriddenMethSpec;\n" + "\n" + "typedef struct cfish_InheritedMethSpec {\n" + " size_t *offset;\n" + " size_t *parent_offset;\n" + "} cfish_InheritedMethSpec;\n" + "\n" + "typedef struct cfish_ClassSpec {\n" + " cfish_Class **klass;\n" + " cfish_Class **parent;\n" + " const char *name;\n" + " size_t ivars_size;\n" + " size_t *ivars_offset_ptr;\n" + " uint32_t num_novel_meths;\n" + " uint32_t num_overridden_meths;\n" + " uint32_t num_inherited_meths;\n" + " const cfish_NovelMethSpec *novel_meth_specs;\n" + " const cfish_OverriddenMethSpec *overridden_meth_specs;\n" + " const cfish_InheritedMethSpec *inherited_meth_specs;\n" + "} cfish_ClassSpec;\n" + "\n"; +} + +void +CFCBindSpecs_add_class(CFCBindSpecs *self, CFCClass *klass) { + if (CFCClass_inert(klass)) { return; } + + const char *class_name = CFCClass_get_name(klass); + const char *class_var = CFCClass_full_class_var(klass); + const char *ivars_offset_name = CFCClass_full_ivars_offset(klass); + + char *ivars_size = S_ivars_size(klass); + + char *parent_ptr = NULL; + CFCClass *parent = CFCClass_get_parent(klass); + if (!parent) { + parent_ptr = CFCUtil_strdup("NULL"); + } + else { + parent_ptr = CFCUtil_sprintf("&%s", CFCClass_full_class_var(parent)); + } + + char *novel_specs = CFCUtil_strdup(""); + char *overridden_specs = CFCUtil_strdup(""); + char *inherited_specs = CFCUtil_strdup(""); + int num_new_novel = 0; + int num_new_overridden = 0; + int num_new_inherited = 0; + CFCMethod **methods = CFCClass_methods(klass); + + for (int meth_num = 0; methods[meth_num] != NULL; meth_num++) { + CFCMethod *method = methods[meth_num]; + + if (CFCMethod_is_fresh(method, klass)) { + if (CFCMethod_novel(method)) { + const char *sep = num_new_novel == 0 ? "" : ",\n"; + char *def = S_novel_meth(method, klass); + novel_specs = CFCUtil_cat(novel_specs, sep, def, NULL); + FREEMEM(def); + ++num_new_novel; + } + else { + const char *sep = num_new_overridden == 0 ? "" : ",\n"; + char *def = S_overridden_meth(method, klass); + overridden_specs = CFCUtil_cat(overridden_specs, sep, def, + NULL); + FREEMEM(def); + ++num_new_overridden; + } + } + else { + const char *sep = num_new_inherited == 0 ? "" : ",\n"; + char *def = S_inherited_meth(method, klass); + inherited_specs = CFCUtil_cat(inherited_specs, sep, def, NULL); + FREEMEM(def); + ++num_new_inherited; + } + } + + char *novel_spec_var; + + if (num_new_novel) { + novel_spec_var = CFCUtil_sprintf("%s_NOVEL_METHS", class_var); + + const char *pattern = + "static cfish_NovelMethSpec %s[] = {\n" + "%s\n" + "};\n" + "\n"; + char *spec_def = CFCUtil_sprintf(pattern, novel_spec_var, novel_specs); + self->novel_specs = CFCUtil_cat(self->novel_specs, spec_def, NULL); + FREEMEM(spec_def); + } + else { + novel_spec_var = CFCUtil_strdup("NULL"); + } + + char *overridden_spec_var; + + if (num_new_overridden) { + overridden_spec_var = CFCUtil_sprintf("%s_OVERRIDDEN_METHS", + class_var); + + const char *pattern = + "static cfish_OverriddenMethSpec %s[] = {\n" + "%s\n" + "};\n" + "\n"; + char *spec_def = CFCUtil_sprintf(pattern, overridden_spec_var, + overridden_specs); + self->overridden_specs = CFCUtil_cat(self->overridden_specs, spec_def, + NULL); + FREEMEM(spec_def); + } + else { + overridden_spec_var = CFCUtil_strdup("NULL"); + } + + char *inherited_spec_var; + + if (num_new_inherited) { + inherited_spec_var = CFCUtil_sprintf("%s_INHERITED_METHS", class_var); + + const char *pattern = + "static cfish_InheritedMethSpec %s[] = {\n" + "%s\n" + "};\n" + "\n"; + char *spec_def = CFCUtil_sprintf(pattern, inherited_spec_var, + inherited_specs); + self->inherited_specs = CFCUtil_cat(self->inherited_specs, spec_def, + NULL); + FREEMEM(spec_def); + } + else { + inherited_spec_var = CFCUtil_strdup("NULL"); + } + + char pattern[] = + " {\n" + " &%s, /* class */\n" + " %s, /* parent */\n" + " \"%s\", /* name */\n" + " %s, /* ivars_size */\n" + " &%s, /* ivars_offset_ptr */\n" + " %d, /* num_novel */\n" + " %d, /* num_overridden */\n" + " %d, /* num_inherited */\n" + " %s,\n" + " %s,\n" + " %s\n" + " }"; + char *class_spec + = CFCUtil_sprintf(pattern, class_var, parent_ptr, class_name, + ivars_size, ivars_offset_name, + num_new_novel, + num_new_overridden, + num_new_inherited, + novel_spec_var, + overridden_spec_var, + inherited_spec_var); + + const char *sep = self->num_specs == 0 ? "" : ",\n"; + self->class_specs = CFCUtil_cat(self->class_specs, sep, class_spec, NULL); + + self->num_novel += num_new_novel; + self->num_overridden += num_new_overridden; + self->num_inherited += num_new_inherited; + self->num_specs += 1; + + FREEMEM(class_spec); + FREEMEM(inherited_spec_var); + FREEMEM(overridden_spec_var); + FREEMEM(novel_spec_var); + FREEMEM(parent_ptr); + FREEMEM(ivars_size); +} + +char* +CFCBindSpecs_defs(CFCBindSpecs *self) { + if (!self->class_specs[0]) { return CFCUtil_strdup(""); } + + const char *pattern = + "%s" + "%s" + "%s" + "static cfish_ClassSpec class_specs[] = {\n" + "%s\n" + "};\n"; + return CFCUtil_sprintf(pattern, self->novel_specs, + self->overridden_specs, self->inherited_specs, + self->class_specs); +} + +char* +CFCBindSpecs_init_func_def(CFCBindSpecs *self) { + const char *pattern = + "static void\n" + "S_bootstrap_specs() {\n" + " cfish_Class_bootstrap(class_specs, %d);\n" + "}\n"; + return CFCUtil_sprintf(pattern, self->num_specs); +} + +static char* +S_ivars_size(CFCClass *klass) { + CFCParcel *parcel = CFCClass_get_parcel(klass); + char *ivars_size = NULL; + + if (CFCParcel_is_cfish(parcel)) { + const char *struct_sym = CFCClass_full_struct_sym(klass); + ivars_size = CFCUtil_sprintf("sizeof(%s)", struct_sym); + } + else { + int num_non_package_ivars = CFCClass_num_non_package_ivars(klass); + int num_ivars = CFCClass_num_member_vars(klass); + + if (num_non_package_ivars == num_ivars) { + // No members in this package. + ivars_size = CFCUtil_strdup("0"); + } + else { + const char *ivars_struct = CFCClass_full_ivars_struct(klass); + ivars_size = CFCUtil_sprintf("sizeof(%s)", ivars_struct); + } + } + + return ivars_size; +} + +static char* +S_novel_meth(CFCMethod *method, CFCClass *klass) { + const char *meth_name = CFCMethod_get_name(method); + + char *full_override_sym; + if (!CFCMethod_final(method)) { + full_override_sym = CFCMethod_full_override_sym(method, klass); + } + else { + full_override_sym = CFCUtil_strdup("NULL"); + } + + char *imp_func = CFCMethod_imp_func(method, klass); + char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); + + char pattern[] = + " {\n" + " &%s, /* offset */\n" + " \"%s\", /* name */\n" + " (cfish_method_t)%s, /* func */\n" + " (cfish_method_t)%s /* callback_func */\n" + " }"; + char *def + = CFCUtil_sprintf(pattern, full_offset_sym, meth_name, imp_func, + full_override_sym); + + FREEMEM(full_offset_sym); + FREEMEM(imp_func); + FREEMEM(full_override_sym); + return def; +} + +static char* +S_parent_offset(CFCMethod *method, CFCClass *klass) { + CFCClass *parent = CFCClass_get_parent(klass); + + if (!parent) { + return CFCUtil_strdup("NULL"); + } + + char *parent_offset_sym = CFCMethod_full_offset_sym(method, parent); + char *parent_offset = CFCUtil_sprintf("&%s", parent_offset_sym); + FREEMEM(parent_offset_sym); + + return parent_offset; +} + +static char* +S_overridden_meth(CFCMethod *method, CFCClass *klass) { + char *imp_func = CFCMethod_imp_func(method, klass); + char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); + char *parent_offset = S_parent_offset(method, klass); + + char pattern[] = + " {\n" + " &%s, /* offset */\n" + " %s, /* parent_offset */\n" + " (cfish_method_t)%s /* func */\n" + " }"; + char *def + = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset, imp_func); + + FREEMEM(parent_offset); + FREEMEM(full_offset_sym); + FREEMEM(imp_func); + return def; +} + +static char* +S_inherited_meth(CFCMethod *method, CFCClass *klass) { + char *full_offset_sym = CFCMethod_full_offset_sym(method, klass); + char *parent_offset = S_parent_offset(method, klass); + + char pattern[] = + " {\n" + " &%s, /* offset */\n" + " %s /* parent_offset */\n" + " }"; + char *def = CFCUtil_sprintf(pattern, full_offset_sym, parent_offset); + + FREEMEM(full_offset_sym); + FREEMEM(parent_offset); + return def; +} + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCBindSpecs.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCBindSpecs.h b/compiler/src/CFCBindSpecs.h new file mode 100644 index 0000000..d3f2b8c --- /dev/null +++ b/compiler/src/CFCBindSpecs.h @@ -0,0 +1,58 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Clownfish::CFC::Binding::Core::Specs - Generate C code for class + * initialization. + */ + +#ifndef H_CFCBINDSPECS +#define H_CFCBINDSPECS + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CFCBindSpecs CFCBindSpecs; + +struct CFCClass; + +CFCBindSpecs* +CFCBindSpecs_new(void); + +CFCBindSpecs* +CFCBindSpecs_init(CFCBindSpecs *specs); + +void +CFCBindSpecs_destroy(CFCBindSpecs *specs); + +const char* +CFCBindSpecs_get_typedefs(void); + +void +CFCBindSpecs_add_class(CFCBindSpecs *specs, struct CFCClass *klass); + +char* +CFCBindSpecs_defs(CFCBindSpecs *self); + +char* +CFCBindSpecs_init_func_def(CFCBindSpecs *self); + +#ifdef __cplusplus +} +#endif + +#endif /* H_CFCBINDSPECS */ + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCClass.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCClass.c b/compiler/src/CFCClass.c index acbc22c..1d89de4 100644 --- a/compiler/src/CFCClass.c +++ b/compiler/src/CFCClass.c @@ -810,6 +810,24 @@ CFCClass_num_member_vars(CFCClass *self) { return self->num_member_vars; } +// Count the number of member variables declared in ancestor classes +// outside this package. +size_t +CFCClass_num_non_package_ivars(CFCClass *self) { + CFCParcel *parcel = CFCClass_get_parcel(self); + CFCClass *ancestor = CFCClass_get_parent(self); + int num_non_package_members = 0; + + while (ancestor && CFCClass_get_parcel(ancestor) == parcel) { + ancestor = CFCClass_get_parent(ancestor); + } + if (ancestor) { + num_non_package_members = CFCClass_num_member_vars(ancestor); + } + + return num_non_package_members; +} + CFCVariable** CFCClass_inert_vars(CFCClass *self) { return self->inert_vars; http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2b3ed29a/compiler/src/CFCClass.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCClass.h b/compiler/src/CFCClass.h index 68870bf..e148500 100644 --- a/compiler/src/CFCClass.h +++ b/compiler/src/CFCClass.h @@ -208,6 +208,12 @@ CFCClass_member_vars(CFCClass *self); size_t CFCClass_num_member_vars(CFCClass *self); +/** Count the number of member variables declared in ancestor classes + * outside this package. + */ +size_t +CFCClass_num_non_package_ivars(CFCClass *self); + /** Return an array of all inert (shared, class) variables. */ struct CFCVariable**
