Implemented Clownfish::CFC::Binding::Ruby::write_boot * Created a CFCRuby class * Modified rake build file to call Clownfish::CFC::Binding::Ruby * Modified ext/Clownfish/CFC.c ruby bindings to create * Clownfish::CFC::Binding::Ruby object.
Project: http://git-wip-us.apache.org/repos/asf/lucy/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/e516d239 Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/e516d239 Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/e516d239 Branch: refs/heads/master Commit: e516d2396a7682e792619d29c6e78b4dd1d8927e Parents: 2e8a691 Author: Logan Bell <[email protected]> Authored: Sat Feb 9 15:36:04 2013 -0800 Committer: Logan Bell <[email protected]> Committed: Sat Feb 9 15:48:46 2013 -0800 ---------------------------------------------------------------------- clownfish/compiler/include/CFC.h | 2 + clownfish/compiler/ruby/ext/Clownfish/CFC.c | 54 +++++- clownfish/compiler/src/CFCRuby.c | 241 ++++++++++++++++++++++ clownfish/compiler/src/CFCRuby.h | 94 +++++++++ clownfish/runtime/ruby/Rakefile | 12 +- clownfish/runtime/ruby/ext/Clownfish.c | 6 +- 6 files changed, 404 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy/blob/e516d239/clownfish/compiler/include/CFC.h ---------------------------------------------------------------------- diff --git a/clownfish/compiler/include/CFC.h b/clownfish/compiler/include/CFC.h index 643263e..080ad61 100644 --- a/clownfish/compiler/include/CFC.h +++ b/clownfish/compiler/include/CFC.h @@ -50,3 +50,5 @@ #include "CFCPerlPod.h" #include "CFCPerlTypeMap.h" +#include "CFCRuby.h" + http://git-wip-us.apache.org/repos/asf/lucy/blob/e516d239/clownfish/compiler/ruby/ext/Clownfish/CFC.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/ruby/ext/Clownfish/CFC.c b/clownfish/compiler/ruby/ext/Clownfish/CFC.c index 155bbc5..682e2e5 100644 --- a/clownfish/compiler/ruby/ext/Clownfish/CFC.c +++ b/clownfish/compiler/ruby/ext/Clownfish/CFC.c @@ -23,6 +23,7 @@ static VALUE mModel; static VALUE cHierarchy; static VALUE mBinding; static VALUE cBindCore; +static VALUE cBindRuby; static VALUE S_CFC_Binding_Core_Alloc(VALUE klass) { @@ -71,6 +72,56 @@ S_init_Binding_Core(void) { } static VALUE +S_CFC_Binding_Ruby_Alloc(VALUE klass) { + void *ptr = NULL; + return Data_Wrap_Struct(klass, NULL, NULL, ptr); +} + +static VALUE +S_CFC_Binding_Ruby_Init(VALUE self_rb, VALUE params) { + + CFCHierarchy* hierarchy_obj; + CFCParcel* parcel_obj; + CFCRuby* self; + + VALUE hierarchy = rb_hash_aref(params, ID2SYM(rb_intern("hierarchy"))); + VALUE parcel = rb_hash_aref(params, ID2SYM(rb_intern("parcel"))); + VALUE lib_dir = rb_hash_aref(params, ID2SYM(rb_intern("lib_dir"))); + VALUE boot_class = rb_hash_aref(params, ID2SYM(rb_intern("boot_class"))); + VALUE header = rb_hash_aref(params, ID2SYM(rb_intern("header"))); + VALUE footer = rb_hash_aref(params, ID2SYM(rb_intern("footer"))); + + parcel_obj = CFCParcel_new(StringValuePtr(parcel), NULL, NULL); + Data_Get_Struct(hierarchy, CFCHierarchy, hierarchy_obj); + Data_Get_Struct(self_rb, CFCRuby, self); + + self = CFCRuby_new(parcel_obj, hierarchy_obj, StringValuePtr(lib_dir), StringValuePtr(boot_class), + StringValuePtr(header), StringValuePtr(footer)); + DATA_PTR(self_rb) = self; + + return self_rb; +} + +static VALUE +S_CFC_Binding_Ruby_Write_Boot(VALUE self_rb) { + + CFCRuby *self; + Data_Get_Struct(self_rb, CFCRuby, self); + CFCRuby_write_boot(self); + + return Qnil; +} + +static void +S_init_Binding_Ruby(void) { + cBindRuby = rb_define_class_under(mBinding, "Ruby", rb_cObject); + rb_define_alloc_func(cBindRuby, S_CFC_Binding_Ruby_Alloc); + rb_define_method(cBindRuby, "initialize", S_CFC_Binding_Ruby_Init, 1); + rb_define_method(cBindRuby, "write_boot", + S_CFC_Binding_Ruby_Write_Boot, 0); +} + +static VALUE S_CFC_Hierarchy_Alloc(VALUE klass) { void *ptr = NULL; return Data_Wrap_Struct(klass, NULL, NULL, ptr); @@ -82,7 +133,7 @@ S_CFC_Hierarchy_Init(VALUE self_rb, VALUE params) { VALUE dest = rb_hash_aref(params, ID2SYM(rb_intern("dest"))); - Data_Get_Struct(self_rb,CFCHierarchy, self); + Data_Get_Struct(self_rb, CFCHierarchy, self); self = CFCHierarchy_new(StringValuePtr(dest)); @@ -137,6 +188,7 @@ Init_CFC() { mBinding = rb_define_module_under(mCFC, "Binding"); mModel = rb_define_module_under(mCFC, "Model"); S_init_Binding_Core(); + S_init_Binding_Ruby(); S_init_Hierarchy(); } http://git-wip-us.apache.org/repos/asf/lucy/blob/e516d239/clownfish/compiler/src/CFCRuby.c ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCRuby.c b/clownfish/compiler/src/CFCRuby.c new file mode 100644 index 0000000..89d111c --- /dev/null +++ b/clownfish/compiler/src/CFCRuby.c @@ -0,0 +1,241 @@ +/* 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 <string.h> +#include <stdio.h> +#include <ctype.h> +#define CFC_NEED_BASE_STRUCT_DEF +#include "CFCBase.h" +#include "CFCClass.h" +#include "CFCHierarchy.h" +#include "CFCParcel.h" +#include "CFCRuby.h" +#include "CFCUtil.h" + +struct CFCRuby { + CFCBase base; + CFCParcel *parcel; + CFCHierarchy *hierarchy; + char *lib_dir; + char *boot_class; + char *header; + char *footer; + char *boot_h_file; + char *boot_c_file; + char *boot_h_path; + char *boot_c_path; + char *boot_func; +}; + +// Modify a string in place, swapping out "::" for the supplied character. +static void +S_replace_double_colons(char *text, char replacement); + +const static CFCMeta CFCRUBY_META = { + "Clownfish::CFC::Binding::Ruby", + sizeof(CFCRuby), + (CFCBase_destroy_t)CFCRuby_destroy +}; + +CFCRuby* +CFCRuby_new(CFCParcel *parcel, CFCHierarchy *hierarchy, const char *lib_dir, + const char *boot_class, const char *header, const char *footer) { + CFCRuby *self = (CFCRuby*)CFCBase_allocate(&CFCRUBY_META); + return CFCRuby_init(self, parcel, hierarchy, lib_dir, boot_class, header, + footer); +} + +CFCRuby* +CFCRuby_init(CFCRuby *self, CFCParcel *parcel, CFCHierarchy *hierarchy, + const char *lib_dir, const char *boot_class, const char *header, + const char *footer) { + CFCUTIL_NULL_CHECK(parcel); + CFCUTIL_NULL_CHECK(hierarchy); + CFCUTIL_NULL_CHECK(lib_dir); + CFCUTIL_NULL_CHECK(boot_class); + CFCUTIL_NULL_CHECK(header); + CFCUTIL_NULL_CHECK(footer); + self->parcel = (CFCParcel*)CFCBase_incref((CFCBase*)parcel); + self->hierarchy = (CFCHierarchy*)CFCBase_incref((CFCBase*)hierarchy); + self->lib_dir = CFCUtil_strdup(lib_dir); + self->boot_class = CFCUtil_strdup(boot_class); + self->header = CFCUtil_strdup(header); + self->footer = CFCUtil_strdup(footer); + + const char *prefix = CFCParcel_get_prefix(parcel); + const char *inc_dest = CFCHierarchy_get_include_dest(hierarchy); + const char *src_dest = CFCHierarchy_get_source_dest(hierarchy); + self->boot_h_file = CFCUtil_cat(CFCUtil_strdup(""), prefix, "boot.h", + NULL); + self->boot_c_file = CFCUtil_cat(CFCUtil_strdup(""), prefix, "boot.c", + NULL); + self->boot_h_path = CFCUtil_cat(CFCUtil_strdup(""), inc_dest, + CFCUTIL_PATH_SEP, self->boot_h_file, + NULL); + self->boot_c_path = CFCUtil_cat(CFCUtil_strdup(""), src_dest, + CFCUTIL_PATH_SEP, self->boot_c_file, + NULL); + + self->boot_func + = CFCUtil_cat(CFCUtil_strdup(""), CFCParcel_get_prefix(parcel), + boot_class, "_bootstrap", NULL); + for (int i = 0; self->boot_func[i] != 0; i++) { + if (!isalnum(self->boot_func[i])) { + self->boot_func[i] = '_'; + } + } + + return self; +} + +void +CFCRuby_destroy(CFCRuby *self) { + CFCBase_decref((CFCBase*)self->parcel); + CFCBase_decref((CFCBase*)self->hierarchy); + FREEMEM(self->lib_dir); + FREEMEM(self->boot_class); + FREEMEM(self->header); + FREEMEM(self->footer); + FREEMEM(self->boot_h_file); + FREEMEM(self->boot_c_file); + FREEMEM(self->boot_h_path); + FREEMEM(self->boot_c_path); + FREEMEM(self->boot_func); + CFCBase_destroy((CFCBase*)self); +} + +static void +S_replace_double_colons(char *text, char replacement) { + size_t pos = 0; + for (char *ptr = text; *ptr != '\0'; ptr++) { + if (strncmp(ptr, "::", 2) == 0) { + text[pos++] = replacement; + ptr++; + } + else { + text[pos++] = *ptr; + } + } + text[pos] = '\0'; +} + +static void +S_write_boot_h(CFCRuby *self) { + char *guard = CFCUtil_cat(CFCUtil_strdup(""), self->boot_class, + "_BOOT", NULL); + S_replace_double_colons(guard, '_'); + for (char *ptr = guard; *ptr != '\0'; ptr++) { + if (isalpha(*ptr)) { + *ptr = toupper(*ptr); + } + } + + const char pattern[] = + "%s\n" + "\n" + "#ifndef %s\n" + "#define %s 1\n" + "\n" + "void\n" + "%s();\n" + "\n" + "#endif /* %s */\n" + "\n" + "%s\n"; + + size_t size = sizeof(pattern) + + strlen(self->header) + + strlen(guard) + + strlen(guard) + + strlen(self->boot_func) + + strlen(guard) + + strlen(self->footer) + + 20; + char *content = (char*)MALLOCATE(size); + sprintf(content, pattern, self->header, guard, guard, self->boot_func, + guard, self->footer); + CFCUtil_write_file(self->boot_h_path, content, strlen(content)); + + FREEMEM(content); + FREEMEM(guard); +} + +static void +S_write_boot_c(CFCRuby *self) { + CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); + char *pound_includes = CFCUtil_strdup(""); + const char *prefix = CFCParcel_get_prefix(self->parcel); + + for (size_t i = 0; ordered[i] != NULL; i++) { + CFCClass *klass = ordered[i]; + if (CFCClass_included(klass)) { continue; } + + const char *include_h = CFCClass_include_h(klass); + pound_includes = CFCUtil_cat(pound_includes, "#include \"", + include_h, "\"\n", NULL); + + if (CFCClass_inert(klass)) { continue; } + + CFCClass *parent = CFCClass_get_parent(klass); + if (parent) { + /* Need to implement */ + } + } + + const char pattern[] = + "%s\n" + "\n" + "#include \"charmony.h\"\n" + "#include \"%s\"\n" + "#include \"parcel.h\"\n" + "#include \"Clownfish/CharBuf.h\"\n" + "#include \"Clownfish/VTable.h\"\n" + "%s\n" + "\n" + "void\n" + "%s() {\n" + " %sbootstrap_parcel();\n" + "\n" + " cfish_ZombieCharBuf *alias = CFISH_ZCB_WRAP_STR(\"\", 0);\n" + "}\n" + "\n" + "%s\n" + "\n"; + + size_t size = sizeof(pattern) + + strlen(self->header) + + strlen(self->boot_h_file) + + strlen(pound_includes) + + strlen(self->boot_func) + + strlen(prefix) + + strlen(self->footer) + + 100; + char *content = (char*)MALLOCATE(size); + sprintf(content, pattern, self->header, self->boot_h_file, pound_includes, + self->boot_func, prefix, self->footer); + CFCUtil_write_file(self->boot_c_path, content, strlen(content)); + + FREEMEM(content); + FREEMEM(pound_includes); + FREEMEM(ordered); +} + +void +CFCRuby_write_boot(CFCRuby *self) { + S_write_boot_h(self); + S_write_boot_c(self); +} + http://git-wip-us.apache.org/repos/asf/lucy/blob/e516d239/clownfish/compiler/src/CFCRuby.h ---------------------------------------------------------------------- diff --git a/clownfish/compiler/src/CFCRuby.h b/clownfish/compiler/src/CFCRuby.h new file mode 100644 index 0000000..657cb9f --- /dev/null +++ b/clownfish/compiler/src/CFCRuby.h @@ -0,0 +1,94 @@ +/* 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. + */ + +#ifndef H_CFCRUBY +#define H_CFCRUBY + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CFCRuby CFCRuby; +struct CFCParcel; +struct CFCHierarchy; + +/** Clownfish::CFC::Binding::Ruby - Perl bindings for a + * Clownfish::CFC::Model::Hierarchy. + * + * Clownfish::CFC::Binding::Ruby presents an interface for auto-generating XS + * and Perl code to bind C code for a Clownfish class hierarchy to Perl. + * + * In theory this module could be much more flexible and its API could be more + * elegant. There are many ways which you could walk the parsed parcels, + * classes, methods, etc. in a Clownfish::CFC::Model::Hierarchy and generate + * binding code. However, our needs are very limited, so we are content with + * a "one size fits one" solution. + * + * In particular, this module assumes that the XS bindings for all classes in + * the hierarchy should be assembled into a single shared object which belongs + * to the primary, "boot" class. There's no reason why it could not write one + * .xs file per class, or one per parcel, instead. + * + * The files written by this class are derived from the name of the boot class. + * If it is "Crustacean", the following files will be generated. + * + * # Generated by write_bindings() + * $lib_dir/Crustacean.xs + * + * # Generated by write_boot() + * $hierarchy_dest_dir/crust_boot.h + * $hierarchy_dest_dir/crust_boot.c + */ + +/** + * @param parcel The L<Clownfish::CFC::Model::Parcel> to which the + * C<boot_class> belongs. + * @param hierarchy A Clownfish::CFC::Model::Hierarchy. + * @param lib_dir location of the Perl lib directory to which files will be + * written. + * @param boot_class The name of the main class, which will own the shared + * object. + * @param header Text which will be prepended to generated C/XS files -- + * typically, an "autogenerated file" warning. + * @param footer Text to be appended to the end of generated C/XS files -- + * typically copyright information. + */ +CFCRuby* +CFCRuby_new(struct CFCParcel *parcel, struct CFCHierarchy *hierarchy, + const char *lib_dir, const char *boot_class, const char *header, + const char *footer); + +CFCRuby* +CFCRuby_init(CFCRuby *self, struct CFCParcel *parcel, + struct CFCHierarchy *hierarchy, const char *lib_dir, + const char *boot_class, const char *header, const char *footer); + +void +CFCRuby_destroy(CFCRuby *self); + +/** Write out "boot" files to the Hierarchy's "dest_dir" which contain code + * for bootstrapping Clownfish classes. + */ +void +CFCRuby_write_boot(CFCRuby *self); + + +#ifdef __cplusplus +} +#endif + +#endif /* H_CFCPERL */ + http://git-wip-us.apache.org/repos/asf/lucy/blob/e516d239/clownfish/runtime/ruby/Rakefile ---------------------------------------------------------------------- diff --git a/clownfish/runtime/ruby/Rakefile b/clownfish/runtime/ruby/Rakefile index b2fc539..2236733 100644 --- a/clownfish/runtime/ruby/Rakefile +++ b/clownfish/runtime/ruby/Rakefile @@ -70,13 +70,23 @@ task :build_clownfish => [:build_charmonizer_tests] do core_binding = Clownfish::CFC::Binding::Core.new(:hierarchy => hierarchy, :header => autogen_header, :footer => '') core_binding.write_all_modified + ruby_binding = Clownfish::CFC::Binding::Ruby.new( + :parcel => "Clownfish", + :hierarchy => hierarchy, + :lib_dir => LIB_DIR, + :boot_class => "Clownfish", + :header => autogen_header, + :footer => '' + ) + puts "Building Binding Code" + ruby_binding.write_boot Rake::Task['compile'].invoke end desc "Building Charmonizer Tests" -task :build_charmonizer_tests => [:charmonize] do +task :build_charmonizer_tests => [:charmony] do puts "Building Charmonizer Tests" flags = [ '-fno-common', http://git-wip-us.apache.org/repos/asf/lucy/blob/e516d239/clownfish/runtime/ruby/ext/Clownfish.c ---------------------------------------------------------------------- diff --git a/clownfish/runtime/ruby/ext/Clownfish.c b/clownfish/runtime/ruby/ext/Clownfish.c index 354326f..64b011c 100644 --- a/clownfish/runtime/ruby/ext/Clownfish.c +++ b/clownfish/runtime/ruby/ext/Clownfish.c @@ -29,9 +29,9 @@ static VALUE cTest; static VALUE S_CFC_Test_Run_Tests(VALUE self_rb, VALUE package) { - if (strEQ(StringValuePtr(package), "TestCharBuf")) { + /*if (strEQ(StringValuePtr(package), "TestCharBuf")) { lucy_TestCB_run_tests(); - } + }*/ return Qnil; } @@ -39,7 +39,7 @@ S_CFC_Test_Run_Tests(VALUE self_rb, VALUE package) { static void S_init_Test(void) { cTest = rb_define_class_under(mClownfish, "Test", rb_cObject); - rb_define_singleton_method(cTest, "run_tests", S_CFC_Hierarchy_Build, 0); +// rb_define_singleton_method(cTest, "run_tests", S_CFC_Hierarchy_Build, 0); } void
