blob: d4162841d0ec1e99a069085bdfa21cc03fdf6485 [file] [log] [blame]
/* 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 "CFCPerlTypeMap.h"
#include "CFCUtil.h"
#include "CFCHierarchy.h"
#include "CFCClass.h"
#include "CFCType.h"
#ifndef true
#define true 1
#define false 0
#endif
// Convert from a Perl scalar to a primitive type.
struct char_map {
char *key;
char *value;
};
char*
CFCPerlTypeMap_from_perl(CFCType *type, const char *xs_var,
const char *label) {
char *result = NULL;
if (CFCType_is_object(type)) {
const char *struct_sym = CFCType_get_specifier(type);
const char *class_var = CFCType_get_class_var(type);
const char *nullable_str = CFCType_nullable(type) ? "_nullable" : "";
const char *allocation;
if (strcmp(struct_sym, "cfish_String") == 0
|| strcmp(struct_sym, "cfish_Obj") == 0
) {
// Share buffers rather than copy between Perl scalars and
// Clownfish string types.
allocation = "CFISH_ALLOCA_OBJ(CFISH_STRING)";
}
else {
allocation = "NULL";
}
const char pattern[]
= "(%s*)XSBind_arg_to_cfish%s(aTHX_ %s, \"%s\", %s, %s)";
result = CFCUtil_sprintf(pattern, struct_sym, nullable_str, xs_var,
label, class_var, allocation);
}
else if (CFCType_is_primitive(type)) {
const char *specifier = CFCType_get_specifier(type);
if (strcmp(specifier, "double") == 0) {
result = CFCUtil_sprintf("SvNV(%s)", xs_var);
}
else if (strcmp(specifier, "float") == 0) {
result = CFCUtil_sprintf("(float)SvNV(%s)", xs_var);
}
else if (strcmp(specifier, "int") == 0) {
result = CFCUtil_sprintf("(int)SvIV(%s)", xs_var);
}
else if (strcmp(specifier, "short") == 0) {
result = CFCUtil_sprintf("(short)SvIV(%s)", xs_var);
}
else if (strcmp(specifier, "long") == 0) {
const char pattern[] =
"((sizeof(long) <= sizeof(IV)) ? (long)SvIV(%s) "
": (long)SvNV(%s))";
result = CFCUtil_sprintf(pattern, xs_var, xs_var);
}
else if (strcmp(specifier, "size_t") == 0) {
result = CFCUtil_sprintf("(size_t)SvIV(%s)", xs_var);
}
else if (strcmp(specifier, "uint64_t") == 0) {
result = CFCUtil_sprintf("(uint64_t)SvNV(%s)", xs_var);
}
else if (strcmp(specifier, "uint32_t") == 0) {
result = CFCUtil_sprintf("(uint32_t)SvUV(%s)", xs_var);
}
else if (strcmp(specifier, "uint16_t") == 0) {
result = CFCUtil_sprintf("(uint16_t)SvUV(%s)", xs_var);
}
else if (strcmp(specifier, "uint8_t") == 0) {
result = CFCUtil_sprintf("(uint8_t)SvUV(%s)", xs_var);
}
else if (strcmp(specifier, "int64_t") == 0) {
result = CFCUtil_sprintf("(int64_t)SvNV(%s)", xs_var);
}
else if (strcmp(specifier, "int32_t") == 0) {
result = CFCUtil_sprintf("(int32_t)SvIV(%s)", xs_var);
}
else if (strcmp(specifier, "int16_t") == 0) {
result = CFCUtil_sprintf("(int16_t)SvIV(%s)", xs_var);
}
else if (strcmp(specifier, "int8_t") == 0) {
result = CFCUtil_sprintf("(int8_t)SvIV(%s)", xs_var);
}
else if (strcmp(specifier, "bool") == 0) {
result = CFCUtil_sprintf("XSBind_sv_true(aTHX_ %s)", xs_var);
}
else {
FREEMEM(result);
result = NULL;
}
}
return result;
}
char*
CFCPerlTypeMap_to_perl(CFCType *type, const char *cf_var) {
char *result = NULL;
if (CFCType_is_object(type)) {
const char pattern[] = "XSBind_cfish_to_perl(aTHX_ (cfish_Obj*)%s)";
result = CFCUtil_sprintf(pattern, cf_var);
}
else if (CFCType_is_primitive(type)) {
// Convert from a primitive type to a Perl scalar.
const char *specifier = CFCType_get_specifier(type);
if (strcmp(specifier, "double") == 0) {
result = CFCUtil_sprintf("newSVnv(%s)", cf_var);
}
else if (strcmp(specifier, "float") == 0) {
result = CFCUtil_sprintf("newSVnv(%s)", cf_var);
}
else if (strcmp(specifier, "int") == 0) {
result = CFCUtil_sprintf("newSViv(%s)", cf_var);
}
else if (strcmp(specifier, "short") == 0) {
result = CFCUtil_sprintf("newSViv(%s)", cf_var);
}
else if (strcmp(specifier, "long") == 0) {
char pattern[] =
"((sizeof(long) <= sizeof(IV)) ? "
"newSViv((IV)%s) : newSVnv((NV)%s))";
result = CFCUtil_sprintf(pattern, cf_var, cf_var);
}
else if (strcmp(specifier, "size_t") == 0) {
result = CFCUtil_sprintf("newSViv(%s)", cf_var);
}
else if (strcmp(specifier, "uint64_t") == 0) {
char pattern[] =
"sizeof(UV) == 8 ? "
"newSVuv((UV)%s) : newSVnv((NV)CFISH_U64_TO_DOUBLE(%s))";
result = CFCUtil_sprintf(pattern, cf_var, cf_var);
}
else if (strcmp(specifier, "uint32_t") == 0) {
result = CFCUtil_sprintf("newSVuv(%s)", cf_var);
}
else if (strcmp(specifier, "uint16_t") == 0) {
result = CFCUtil_sprintf("newSVuv(%s)", cf_var);
}
else if (strcmp(specifier, "uint8_t") == 0) {
result = CFCUtil_sprintf("newSVuv(%s)", cf_var);
}
else if (strcmp(specifier, "int64_t") == 0) {
char pattern[] = "sizeof(IV) == 8 ? newSViv((IV)%s) : newSVnv((NV)%s)";
result = CFCUtil_sprintf(pattern, cf_var, cf_var);
}
else if (strcmp(specifier, "int32_t") == 0) {
result = CFCUtil_sprintf("newSViv(%s)", cf_var);
}
else if (strcmp(specifier, "int16_t") == 0) {
result = CFCUtil_sprintf("newSViv(%s)", cf_var);
}
else if (strcmp(specifier, "int8_t") == 0) {
result = CFCUtil_sprintf("newSViv(%s)", cf_var);
}
else if (strcmp(specifier, "bool") == 0) {
result = CFCUtil_sprintf("newSViv(%s)", cf_var);
}
else {
FREEMEM(result);
result = NULL;
}
}
return result;
}
static const char typemap_start[] =
"# Auto-generated file.\n"
"\n"
"TYPEMAP\n"
"bool\tCFISH_BOOL\n"
"int8_t\tCFISH_SIGNED_INT\n"
"int16_t\tCFISH_SIGNED_INT\n"
"int32_t\tCFISH_SIGNED_INT\n"
"int64_t\tCFISH_BIG_SIGNED_INT\n"
"uint8_t\tCFISH_UNSIGNED_INT\n"
"uint16_t\tCFISH_UNSIGNED_INT\n"
"uint32_t\tCFISH_UNSIGNED_INT\n"
"uint64_t\tCFISH_BIG_UNSIGNED_INT\n"
"\n";
static const char typemap_input[] =
"INPUT\n"
"\n"
"CFISH_BOOL\n"
" $var = ($type)XSBind_sv_true(aTHX_ $arg);\n"
"\n"
"CFISH_SIGNED_INT \n"
" $var = ($type)SvIV($arg);\n"
"\n"
"CFISH_UNSIGNED_INT\n"
" $var = ($type)SvUV($arg);\n"
"\n"
"CFISH_BIG_SIGNED_INT \n"
" $var = (sizeof(IV) == 8) ? ($type)SvIV($arg) : ($type)SvNV($arg);\n"
"\n"
"CFISH_BIG_UNSIGNED_INT \n"
" $var = (sizeof(UV) == 8) ? ($type)SvUV($arg) : ($type)SvNV($arg);\n"
"\n";
static const char typemap_output[] =
"OUTPUT\n"
"\n"
"CFISH_BOOL\n"
" sv_setiv($arg, (IV)$var);\n"
"\n"
"CFISH_SIGNED_INT\n"
" sv_setiv($arg, (IV)$var);\n"
"\n"
"CFISH_UNSIGNED_INT\n"
" sv_setuv($arg, (UV)$var);\n"
"\n"
"CFISH_BIG_SIGNED_INT\n"
" if (sizeof(IV) == 8) { sv_setiv($arg, (IV)$var); }\n"
" else { sv_setnv($arg, (NV)$var); }\n"
"\n"
"CFISH_BIG_UNSIGNED_INT\n"
" if (sizeof(UV) == 8) { sv_setuv($arg, (UV)$var); }\n"
" else {\n"
" sv_setnv($arg, (NV)CFISH_U64_TO_DOUBLE($var));\n"
" }\n"
"\n";
void
CFCPerlTypeMap_write_xs_typemap(CFCHierarchy *hierarchy) {
CFCClass **classes = CFCHierarchy_ordered_classes(hierarchy);
char *start = CFCUtil_strdup("");
char *input = CFCUtil_strdup("");
char *output = CFCUtil_strdup("");
for (int i = 0; classes[i] != NULL; i++) {
CFCClass *klass = classes[i];
const char *full_struct_sym = CFCClass_full_struct_sym(klass);
const char *class_var = CFCClass_full_class_var(klass);
start = CFCUtil_cat(start, full_struct_sym, "*\t", class_var, "_\n",
NULL);
const char *allocation;
if (strcmp(full_struct_sym, "cfish_String") == 0) {
// Share buffers rather than copy between Perl scalars and
// Clownfish string types.
allocation = "CFISH_ALLOCA_OBJ(CFISH_STRING)";
}
else {
allocation = "NULL";
}
input = CFCUtil_cat(input, class_var, "_\n"
" $var = (", full_struct_sym,
"*)XSBind_perl_to_cfish_noinc(aTHX_ $arg, ",
class_var, ", ", allocation, ");\n\n", NULL);
output = CFCUtil_cat(output, class_var, "_\n"
" $arg = (SV*)CFISH_Obj_To_Host((cfish_Obj*)$var, NULL);\n"
" CFISH_DECREF($var);\n"
"\n", NULL);
}
char *content = CFCUtil_strdup("");
content = CFCUtil_cat(content, typemap_start, start, "\n\n",
typemap_input, input, "\n\n",
typemap_output, output, "\n\n", NULL);
CFCUtil_write_if_changed("typemap", content, strlen(content));
FREEMEM(content);
FREEMEM(output);
FREEMEM(input);
FREEMEM(start);
FREEMEM(classes);
}