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