Repository: lucy-clownfish Updated Branches: refs/heads/py_exp1 [created] 43bafd4be
WIP add CFC module for Go/C type mapping. Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/26ef33c7 Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/26ef33c7 Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/26ef33c7 Branch: refs/heads/py_exp1 Commit: 26ef33c7ad206ba62b2579613212728cb1a2b039 Parents: 80154f6 Author: Marvin Humphrey <[email protected]> Authored: Wed Dec 3 20:56:52 2014 -0800 Committer: Marvin Humphrey <[email protected]> Committed: Sat Dec 6 13:54:50 2014 -0800 ---------------------------------------------------------------------- compiler/src/CFCGoTypeMap.c | 172 +++++++++++++++++++++++++++++++++++++++ compiler/src/CFCGoTypeMap.h | 43 ++++++++++ 2 files changed, 215 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/26ef33c7/compiler/src/CFCGoTypeMap.c ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c new file mode 100644 index 0000000..62f04ab --- /dev/null +++ b/compiler/src/CFCGoTypeMap.c @@ -0,0 +1,172 @@ +/* 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 <ctype.h> +#include <stdlib.h> + +#include "CFCGoTypeMap.h" +#include "CFCParcel.h" +#include "CFCType.h" +#include "CFCUtil.h" + +/* Integer types with implementation-specific widths are tricky to convert. + * If a C `int` and a Go `int` are not the same width, it is potentially + * dangerous to map between them. For example, if a function takes a 32-bit C + * `int` and we wrap that in a Go function which takes a 64-bit Go `int`, a + * user who sees the Go function signature will being misled about the range + * of valid input. + * + * Therefore, we take a mostly conservative approach and err on the side of + * artificially limiting the range. + */ +static struct { + const char *c; + const char *go; +} conversions[] = { + {"bool", "bool"}, + {"char", "int8"}, + {"short", "int16"}, + {"int", "int32"}, + {"long", "int32"}, + {"size_t", "uintptr"}, + {"int8_t", "int8"}, + {"int16_t", "int16"}, + {"int32_t", "int32"}, + {"int64_t", "int64"}, + {"uint8_t", "uint8"}, + {"uint16_t", "uint16"}, + {"uint32_t", "uint32"}, + {"uint64_t", "uint64"}, + {"float", "float32"}, + {"double", "float64"}, +}; + +static int num_conversions = sizeof(conversions) / sizeof(conversions[0]); + +/* TODO: Optimize local conversions by creating a static wrapper function + * which takes a buffer and allocates memory only if the buffer isn't big + * enough. */ + +char* +CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) { + if (CFCType_is_object(type)) { + // Divide the specifier into prefix and struct name. + const char *specifier = CFCType_get_specifier(type); + size_t prefix_len = 0; + for (size_t max = strlen(specifier); prefix_len < max; prefix_len++) { + if (isupper(specifier[prefix_len])) { + break; + } + } + if (!prefix_len) { + CFCUtil_die("Can't convert object type name '%s'", specifier); + } + const char *struct_sym = specifier + prefix_len; + + // Find the parcel that the type lives in. + CFCParcel** all_parcels = CFCParcel_all_parcels(); + CFCParcel *parcel = NULL; + for (int i = 0; all_parcels[i] != NULL; i++) { + const char *candidate = CFCParcel_get_prefix(all_parcels[i]); + if (strncmp(candidate, specifier, prefix_len) == 0 + && strlen(candidate) == prefix_len + ) { + parcel = all_parcels[i]; + break; + } + } + if (!parcel) { + CFCUtil_die("Can't find parcel for type '%s'", specifier); + } + + // If the type lives in this parcel, return only the struct sym + // without a go package prefix. + if (parcel == current_parcel) { + return CFCUtil_strdup(struct_sym); + } + + // The type lives in another parcel, so prefix its Go package name. + // TODO: Stop downcasing once Clownfish parcel names are constrained + // to lower case. + const char *package_name = CFCParcel_get_name(parcel); + if (strrchr(package_name, '.')) { + package_name = strrchr(package_name, '.') + 1; + } + char *result = CFCUtil_sprintf("%s.%s", package_name, struct_sym); + for (int i = 0; result[i] != '.'; i++) { + result[i] = tolower(result[i]); + } + return result; + } + else if (CFCType_is_primitive(type)) { + const char *specifier = CFCType_get_specifier(type); + for (int i = 0; i < num_conversions; i++) { + if (strcmp(specifier, conversions[i].c) == 0) { + return CFCUtil_strdup(conversions[i].go); + } + } + } + + return NULL; +} + +char* +CFCGoTypeMap_go_var_to_c(CFCType *type, const char *go_var) { + char *result = NULL; + + if (CFCType_is_object(type)) { + const char *specifier = CFCType_get_specifier(type); + result = CFCUtil_sprintf("((*C.%s)(clownfish.CallToPtr(%s)))", + specifier, go_var); + } + else if (CFCType_is_primitive(type)) { + const char *specifier = CFCType_get_specifier(type); + // Sanity check, then cast to known type. + for (int i = 0; i < num_conversions; i++) { + if (strcmp(specifier, conversions[i].c) == 0) { + result = CFCUtil_sprintf("C.%s(%s)", specifier, go_var); + } + } + } + + return result; +} + +char* +CFCGoTypeMap_c_var_to_go(CFCType *type, const char *c_var, + CFCParcel *current_parcel) { + if (CFCType_is_primitive(type)) { + const char *specifier = CFCType_get_specifier(type); + for (int i = 0; i < num_conversions; i++) { + if (strcmp(specifier, conversions[i].c) == 0) { + return CFCUtil_sprintf("%s(%s)", conversions[i].go, c_var); + } + } + } + else if (CFCType_is_object(type)) { + char *go_type_name = CFCGoTypeMap_go_type_name(type, current_parcel); + if (!go_type_name) { + return NULL; + } + char *result = CFCUtil_sprintf("%s(%s)", go_type_name, c_var); + free(go_type_name); + return result; + } + + return NULL; +} + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/26ef33c7/compiler/src/CFCGoTypeMap.h ---------------------------------------------------------------------- diff --git a/compiler/src/CFCGoTypeMap.h b/compiler/src/CFCGoTypeMap.h new file mode 100644 index 0000000..d99dc41 --- /dev/null +++ b/compiler/src/CFCGoTypeMap.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_CFCGOTYPEMAP +#define H_CFCGOTYPEMAP + +#ifdef __cplusplus +extern "C" { +#endif + +struct CFCType; +struct CFCParcel; + +char* +CFCGoTypeMap_go_type_name(struct CFCType *type, + struct CFCParcel *current_parcel); + +char* +CFCGoTypeMap_go_var_to_c(struct CFCType *type, const char *go_var); + +char* +CFCGoTypeMap_c_var_to_go(struct CFCType *type, const char *c_var, + struct CFCParcel *current_parcel); + +#ifdef __cplusplus +} +#endif + +#endif /* H_CFCGOTYPEMAP */ +
