You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucy.apache.org by lo...@apache.org on 2013/02/10 08:54:06 UTC

[lucy-commits] [5/8] git commit: refs/heads/master - Implemented Clownfish::CFC::Binding::Ruby::write_boot

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 <lo...@gmail.com>
Authored: Sat Feb 9 15:36:04 2013 -0800
Committer: Logan Bell <lo...@gmail.com>
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