Autogenerate CGO method bindings.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/8f15e5a1 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/8f15e5a1 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/8f15e5a1 Branch: refs/heads/master Commit: 8f15e5a1be84bba8c497c54180d8715015d45255 Parents: 0d5e92e Author: Marvin Humphrey <[email protected]> Authored: Mon Apr 6 20:11:42 2015 -0700 Committer: Marvin Humphrey <[email protected]> Committed: Wed May 6 14:28:15 2015 -0700 ---------------------------------------------------------------------- compiler/src/CFCGo.c | 19 ++++++- compiler/src/CFCGoClass.c | 22 ++++++++ compiler/src/CFCGoClass.h | 3 ++ compiler/src/CFCGoFunc.c | 100 ++++++++++++++++++++++++++++++++++++ compiler/src/CFCGoFunc.h | 43 ++++++++++++++++ compiler/src/CFCGoMethod.c | 109 ++++++++++++++++++++++++++++++++++++++++ compiler/src/CFCGoMethod.h | 3 ++ 7 files changed, 298 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGo.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c index 36d1263..be67747 100644 --- a/compiler/src/CFCGo.c +++ b/compiler/src/CFCGo.c @@ -30,6 +30,7 @@ #include "CFCHierarchy.h" #include "CFCUtil.h" #include "CFCGoClass.h" +#include "CFCGoMethod.h" #include "CFCGoTypeMap.h" static void @@ -191,9 +192,15 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) { CFCGoClass **registry = CFCGoClass_registry(); char *type_decs = CFCUtil_strdup(""); char *boilerplate = CFCUtil_strdup(""); + char *meth_defs = CFCUtil_strdup(""); for (int i = 0; registry[i] != NULL; i++) { CFCGoClass *class_binding = registry[i]; + CFCClass *client = CFCGoClass_get_client(class_binding); + + if (CFCClass_get_parcel(client) != parcel) { + continue; + } char *type_dec = CFCGoClass_go_typing(class_binding); type_decs = CFCUtil_cat(type_decs, type_dec, "\n", NULL); @@ -202,6 +209,10 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) { char *boiler_code = CFCGoClass_boilerplate_funcs(class_binding); boilerplate = CFCUtil_cat(boilerplate, boiler_code, "\n", NULL); FREEMEM(boiler_code); + + char *glue = CFCGoClass_gen_meth_glue(class_binding); + meth_defs = CFCUtil_cat(meth_defs, glue, "\n", NULL); + FREEMEM(glue); } char pattern[] = @@ -213,9 +224,15 @@ S_gen_autogen_go(CFCGo *self, CFCParcel *parcel) { "\n" "%s\n" "\n" + "// Method bindings.\n" + "\n" + "%s\n" + "\n" ; - char *content = CFCUtil_sprintf(pattern, type_decs, boilerplate); + char *content + = CFCUtil_sprintf(pattern, type_decs, boilerplate, meth_defs); + FREEMEM(meth_defs); FREEMEM(boilerplate); FREEMEM(type_decs); return content; http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoClass.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoClass.c b/compiler/src/CFCGoClass.c index d35d3f3..50e512c 100644 --- a/compiler/src/CFCGoClass.c +++ b/compiler/src/CFCGoClass.c @@ -266,6 +266,15 @@ S_lazy_init_method_bindings(CFCGoClass *self) { continue; } + // Only include novel methods. + if (!CFCMethod_novel(method)) { + continue; + } + const char *sym = CFCMethod_get_macro_sym(method); + if (!CFCClass_fresh_method(self->client, sym)) { + continue; + } + /* Create the binding, add it to the array. */ CFCGoMethod *meth_binding = CFCGoMethod_new(method); @@ -280,3 +289,16 @@ S_lazy_init_method_bindings(CFCGoClass *self) { self->num_bound = num_bound; } +char* +CFCGoClass_gen_meth_glue(CFCGoClass *self) { + S_lazy_init_method_bindings(self); + char *meth_defs = CFCUtil_strdup(""); + for (size_t i = 0; self->method_bindings[i] != NULL; i++) { + CFCGoMethod *meth_binding = self->method_bindings[i]; + char *method_def = CFCGoMethod_func_def(meth_binding); + meth_defs = CFCUtil_cat(meth_defs, method_def, "\n", NULL); + FREEMEM(method_def); + } + return meth_defs; +} + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoClass.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoClass.h b/compiler/src/CFCGoClass.h index a1f603c..98d5fce 100644 --- a/compiler/src/CFCGoClass.h +++ b/compiler/src/CFCGoClass.h @@ -70,6 +70,9 @@ CFCGoClass_go_typing(CFCGoClass *self); char* CFCGoClass_boilerplate_funcs(CFCGoClass *self); +char* +CFCGoClass_gen_meth_glue(CFCGoClass *self); + #ifdef __cplusplus } #endif http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoFunc.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c new file mode 100644 index 0000000..db540aa --- /dev/null +++ b/compiler/src/CFCGoFunc.c @@ -0,0 +1,100 @@ +/* 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 "CFCGoFunc.h" +#include "CFCGoTypeMap.h" +#include "CFCBase.h" +#include "CFCFunction.h" +#include "CFCUtil.h" +#include "CFCParcel.h" +#include "CFCParamList.h" +#include "CFCVariable.h" +#include "CFCType.h" + +#ifndef true + #define true 1 + #define false 0 +#endif + +char* +CFCGoFunc_go_meth_name(const char *orig) { + char *go_name = CFCUtil_strdup(orig); + for (int i = 0, j = 0, max = strlen(go_name) + 1; i < max; i++) { + if (go_name[i] != '_') { + go_name[j++] = go_name[i]; + } + } + return go_name; +} + +char* +CFCGoFunc_func_start(CFCParcel *parcel, const char *name, + CFCParamList *param_list, CFCType *return_type, + int is_method) { + CFCVariable **param_vars = CFCParamList_get_variables(param_list); + char *invocant; + if (is_method) { + CFCVariable *var = param_vars[0]; + CFCType *type = CFCVariable_get_type(var); + char *go_type_name = CFCGoTypeMap_go_type_name(type, parcel); + invocant = CFCUtil_sprintf("(%s *%sIMP) ", CFCVariable_micro_sym(var), + go_type_name); + FREEMEM(go_type_name); + } + else { + invocant = CFCUtil_strdup(""); + } + + char *params = CFCUtil_strdup(""); + int start = is_method ? 1 : 0; + for (int i = start; param_vars[i] != NULL; i++) { + CFCVariable *var = param_vars[i]; + CFCType *type = CFCVariable_get_type(var); + char *go_type_name = CFCGoTypeMap_go_type_name(type, parcel); + if (i > start) { + params = CFCUtil_cat(params, ", ", NULL); + } + params = CFCUtil_cat(params, CFCVariable_micro_sym(var), " ", + go_type_name, NULL); + FREEMEM(go_type_name); + } + + char *ret_type_str; + if (CFCType_is_void(return_type)) { + ret_type_str = CFCUtil_strdup(""); + } + else { + ret_type_str = CFCGoTypeMap_go_type_name(return_type, parcel); + if (ret_type_str == NULL) { + CFCUtil_die("Can't convert invalid type in method %s", name); + } + } + + char pattern[] = + "func %s%s(%s) %s {\n" + ; + char *content + = CFCUtil_sprintf(pattern, invocant, name, params, ret_type_str); + + FREEMEM(invocant); + FREEMEM(params); + FREEMEM(ret_type_str); + return content; +} + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoFunc.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoFunc.h b/compiler/src/CFCGoFunc.h new file mode 100644 index 0000000..d9ee98b --- /dev/null +++ b/compiler/src/CFCGoFunc.h @@ -0,0 +1,43 @@ +/* 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_CFCGOFUNC +#define H_CFCGOFUNC + +#ifdef __cplusplus +extern "C" { +#endif + +struct CFCFunction; +struct CFCParcel; +struct CFCType; +struct CFCParamList; + +char* +CFCGoFunc_go_meth_name(const char *orig); + +char* +CFCGoFunc_func_start(struct CFCParcel *parcel, const char *name, + struct CFCParamList *param_list, + struct CFCType *return_type, int is_method); + +#ifdef __cplusplus +} +#endif + +#endif /* H_CFCGOFUNC */ + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoMethod.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoMethod.c b/compiler/src/CFCGoMethod.c index ae1999e..7aef897 100644 --- a/compiler/src/CFCGoMethod.c +++ b/compiler/src/CFCGoMethod.c @@ -21,6 +21,7 @@ #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" +#include "CFCGoFunc.h" #include "CFCGoMethod.h" #include "CFCUtil.h" #include "CFCClass.h" @@ -66,3 +67,111 @@ S_CFCGoMethod_destroy(CFCGoMethod *self) { CFCBase_destroy((CFCBase*)self); } +static char* +S_prep_cfargs(CFCParamList *param_list) { + CFCVariable **vars = CFCParamList_get_variables(param_list); + char *cfargs = CFCUtil_strdup(""); + for (int i = 0; vars[i] != NULL; i++) { + CFCVariable *var = vars[i]; + CFCType *type = CFCVariable_get_type(var); + const char *name = CFCVariable_micro_sym(var); + if (i > 0) { + cfargs = CFCUtil_cat(cfargs, ", ", NULL); + } + if (CFCType_is_primitive(type)) { + cfargs = CFCUtil_cat(cfargs, "C.", CFCType_get_specifier(type), + "(", name, ")", NULL); + } + else if (CFCType_is_object(type)) { + char *obj_pattern; + if (CFCType_decremented(type)) { + obj_pattern = "%s(*C.%s)(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(%s.TOPTR()))))"; + } + else { + obj_pattern = "%s(*C.%s)(unsafe.Pointer(%s.TOPTR()))"; + } + char *temp = CFCUtil_sprintf(obj_pattern, cfargs, + CFCType_get_specifier(type), name); + FREEMEM(cfargs); + cfargs = temp; + } + } + return cfargs; +} + +char* +CFCGoMethod_func_def(CFCGoMethod *self) { + CFCMethod *method = self->method; + CFCParcel *parcel = CFCMethod_get_parcel(method); + CFCParamList *param_list = CFCMethod_get_param_list(method); + CFCType *ret_type = CFCMethod_get_return_type(method); + char *name = CFCGoFunc_go_meth_name(CFCMethod_get_macro_sym(method)); + char *first_line = CFCGoFunc_func_start(parcel, name, param_list, + ret_type, true); + char *full_meth_sym = CFCMethod_full_method_sym(method, NULL); + + char *cfargs = S_prep_cfargs(param_list); + + char *ret_type_str; + char *maybe_retval; + char *maybe_return; + if (CFCType_is_void(ret_type)) { + ret_type_str = CFCUtil_strdup(""); + maybe_retval = CFCUtil_strdup(""); + maybe_return = CFCUtil_strdup(""); + } + else { + ret_type_str = CFCGoTypeMap_go_type_name(ret_type, parcel); + if (ret_type_str == NULL) { + CFCUtil_die("Can't convert invalid type in method %s", name); + } + maybe_retval = CFCUtil_strdup("retvalCF := "); + + if (CFCType_is_primitive(ret_type)) { + maybe_return = CFCUtil_sprintf("\treturn %s(retvalCF)\n", ret_type_str); + } + else if (CFCType_is_object(ret_type)) { + char *go_type_name = CFCGoTypeMap_go_type_name(ret_type, parcel); + char *struct_name = go_type_name; + char *go_package = CFCUtil_strdup(go_type_name); + for (int i = strlen(go_package) - 1; i >= 0; i--) { + if (go_package[i] == '.') { + struct_name += i + 1; + break; + } + go_package[i] = '\0'; + } + char *pattern; + if (CFCType_incremented(ret_type)) { + pattern = "\treturn %sWRAP%s(unsafe.Pointer(retvalCF))\n"; + } + else { + pattern = "\treturn %sWRAP%s(unsafe.Pointer(C.cfish_inc_refcount(unsafe.Pointer(retvalCF))))\n"; + } + maybe_return = CFCUtil_sprintf(pattern, go_package, struct_name); + FREEMEM(go_type_name); + FREEMEM(go_package); + } + else { + CFCUtil_die("Unexpected type: %s", CFCType_to_c(ret_type)); + } + } + + char pattern[] = + "%s" + "\t%sC.%s(%s)\n" + "%s" + "}\n" + ; + char *content = CFCUtil_sprintf(pattern, first_line, maybe_retval, + full_meth_sym, cfargs, maybe_return); + + FREEMEM(maybe_retval); + FREEMEM(maybe_return); + FREEMEM(ret_type_str); + FREEMEM(cfargs); + FREEMEM(first_line); + FREEMEM(name); + return content; +} + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/8f15e5a1/compiler/src/CFCGoMethod.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoMethod.h b/compiler/src/CFCGoMethod.h index be8c1a6..b94529e 100644 --- a/compiler/src/CFCGoMethod.h +++ b/compiler/src/CFCGoMethod.h @@ -30,6 +30,9 @@ struct CFCMethod; CFCGoMethod* CFCGoMethod_new(struct CFCMethod *method); +char* +CFCGoMethod_func_def(CFCGoMethod *self); + #ifdef __cplusplus } #endif
