Rework labeled argument assignment
Change the code to assign labeled arguments from
bool args_ok = XSBind_allot_params(aTHX_ &ST(0), 1, items,
ALLOT_SIZE_T(&arg_first, "first", ...),
ALLOT_OBJ(&arg_second, "second", ...),
NULL);
if (!args_ok) {
CFISH_RETHROW(...);
}
to
static const XSBind_Param param_specs[2] = {
XSBIND_PARAM("first", ...),
XSBIND_PARAM("second", ...),
};
int32_t locations[2];
XSBind_locate_args(aTHX_ &ST(0), 1, items, param_specs, locations, 2);
arg_first = (size_t)SvIV(ST(locations[0]));
arg_second = (Type*)XSBind_arg_to_cfish(..., ST(locations[1]), ...);
This simplifies the code, replaces the vararg lists with static arrays and
replaces the switch statement in S_extract_from_sv with direct calls to
conversion functions.
Accept undef for nullable parameters.
Optimize constructors with no parameters.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/ffeefa58
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/ffeefa58
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/ffeefa58
Branch: refs/heads/master
Commit: ffeefa582cf9fb07d07edcf3f7badc4e160bc32c
Parents: fab17a8
Author: Nick Wellnhofer <[email protected]>
Authored: Fri Nov 20 20:42:27 2015 +0100
Committer: Nick Wellnhofer <[email protected]>
Committed: Thu Nov 26 19:18:22 2015 +0100
----------------------------------------------------------------------
compiler/perl/lib/Clownfish/CFC.xs | 11 +-
compiler/src/CFCParamList.c | 6 +
compiler/src/CFCPerlConstructor.c | 72 ++++--
compiler/src/CFCPerlMethod.c | 85 +++----
compiler/src/CFCPerlSub.c | 197 ++++++++--------
compiler/src/CFCPerlSub.h | 13 +-
compiler/src/CFCPerlTypeMap.c | 14 +-
compiler/src/CFCPerlTypeMap.h | 3 +-
.../perl/buildlib/Clownfish/Build/Binding.pm | 21 +-
runtime/perl/t/binding/019-obj.t | 2 +-
runtime/perl/xs/XSBind.c | 226 ++++---------------
runtime/perl/xs/XSBind.h | 203 ++++-------------
12 files changed, 306 insertions(+), 547 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/perl/lib/Clownfish/CFC.xs
----------------------------------------------------------------------
diff --git a/compiler/perl/lib/Clownfish/CFC.xs
b/compiler/perl/lib/Clownfish/CFC.xs
index 27fa942..d7a5385 100644
--- a/compiler/perl/lib/Clownfish/CFC.xs
+++ b/compiler/perl/lib/Clownfish/CFC.xs
@@ -2068,11 +2068,11 @@ CODE:
OUTPUT: RETVAL
SV*
-build_allot_params(self, first)
+build_param_specs(self, first)
CFCPerlSub *self;
size_t first;
CODE:
- RETVAL = S_sv_eat_c_string(CFCPerlSub_build_allot_params(self, first));
+ RETVAL = S_sv_eat_c_string(CFCPerlSub_build_param_specs(self, first));
OUTPUT: RETVAL
@@ -2418,11 +2418,12 @@ OUTPUT: RETVAL
MODULE = Clownfish PACKAGE = Clownfish::CFC::Binding::Perl::TypeMap
SV*
-from_perl(type, xs_var)
- CFCType *type;
+from_perl(type, xs_var, label)
+ CFCType *type;
const char *xs_var;
+ const char *label;
CODE:
- RETVAL = S_sv_eat_c_string(CFCPerlTypeMap_from_perl(type, xs_var));
+ RETVAL = S_sv_eat_c_string(CFCPerlTypeMap_from_perl(type, xs_var, label));
OUTPUT: RETVAL
SV*
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/src/CFCParamList.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCParamList.c b/compiler/src/CFCParamList.c
index 190dd97..6c23f7f 100644
--- a/compiler/src/CFCParamList.c
+++ b/compiler/src/CFCParamList.c
@@ -72,6 +72,12 @@ void
CFCParamList_add_param(CFCParamList *self, CFCVariable *variable,
const char *value) {
CFCUTIL_NULL_CHECK(variable);
+ // It might be better to enforce that object parameters with a NULL
+ // default are also nullable.
+ if (value && strcmp(value, "NULL") == 0) {
+ CFCType *type = CFCVariable_get_type(variable);
+ CFCType_set_nullable(type, 1);
+ }
self->num_vars++;
size_t amount = (self->num_vars + 1) * sizeof(void*);
self->variables = (CFCVariable**)REALLOCATE(self->variables, amount);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/src/CFCPerlConstructor.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerlConstructor.c
b/compiler/src/CFCPerlConstructor.c
index 9dfce1f..1d235ca 100644
--- a/compiler/src/CFCPerlConstructor.c
+++ b/compiler/src/CFCPerlConstructor.c
@@ -89,17 +89,43 @@ CFCPerlConstructor_destroy(CFCPerlConstructor *self) {
char*
CFCPerlConstructor_xsub_def(CFCPerlConstructor *self, CFCClass *klass) {
- const char *c_name = self->sub.c_name;
- CFCParamList *param_list = self->sub.param_list;
- char *name_list = CFCPerlSub_arg_name_list((CFCPerlSub*)self);
- CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
- char *func_sym = CFCFunction_full_func_sym(self->init_func, klass);
- char *arg_decls = CFCPerlSub_arg_declarations((CFCPerlSub*)self, 0);
- char *allot_params = CFCPerlSub_build_allot_params((CFCPerlSub*)self, 1);
- CFCVariable *self_var = arg_vars[0];
- CFCType *self_type = CFCVariable_get_type(self_var);
- const char *self_type_str = CFCType_to_c(self_type);
- const char *self_name = CFCVariable_get_name(self_var);
+ const char *c_name = self->sub.c_name;
+ CFCParamList *param_list = self->sub.param_list;
+ size_t num_vars = CFCParamList_num_vars(param_list);
+ CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
+ CFCVariable *self_var = arg_vars[0];
+ CFCType *self_type = CFCVariable_get_type(self_var);
+ const char *self_type_str = CFCType_to_c(self_type);
+ const char *self_name = CFCVariable_get_name(self_var);
+ const char *items_check = NULL;
+
+ char *param_specs = NULL;
+ char *arg_decls = CFCPerlSub_arg_declarations((CFCPerlSub*)self, 0);
+ char *locs_decl = NULL;
+ char *locate_args = NULL;
+ char *arg_assigns = CFCPerlSub_arg_assignments((CFCPerlSub*)self);
+ char *func_sym = CFCFunction_full_func_sym(self->init_func, klass);
+ char *name_list = CFCPerlSub_arg_name_list((CFCPerlSub*)self);
+
+ if (num_vars <= 1) {
+ // No params.
+ items_check = "items != 1";
+ param_specs = CFCUtil_strdup("");
+ locs_decl = CFCUtil_strdup("");
+ locate_args = CFCUtil_strdup("");
+ }
+ else {
+ unsigned num_params = num_vars - 1;
+ items_check = "items < 1";
+ param_specs = CFCPerlSub_build_param_specs((CFCPerlSub*)self, 1);
+ locs_decl = CFCUtil_sprintf(" int32_t locations[%u];\n",
+ num_params);
+
+ const char *pattern =
+ " XSBind_locate_args(aTHX_ &ST(0), 1, items, param_specs,\n"
+ " locations, %u);\n";
+ locate_args = CFCUtil_sprintf(pattern, num_params);
+ }
// Compensate for swallowed refcounts.
char *refcount_mods = CFCUtil_strdup("");
@@ -118,15 +144,17 @@ CFCPerlConstructor_xsub_def(CFCPerlConstructor *self,
CFCClass *klass) {
"XS(%s);\n"
"XS(%s) {\n"
" dXSARGS;\n"
- "%s"
- " bool args_ok;\n"
+ "%s" // param_specs
+ "%s" // locs_decl
+ "%s" // arg_decls
" %s retval;\n"
"\n"
" CFISH_UNUSED_VAR(cv);\n"
- " if (items < 1) { CFISH_THROW(CFISH_ERR, \"Usage: %%s(class_name,
...)\", GvNAME(CvGV(cv))); }\n"
+ " if (%s) { CFISH_THROW(CFISH_ERR, \"Usage: %%s(class_name, ...)\",
GvNAME(CvGV(cv))); }\n"
" SP -= items;\n"
"\n"
- " %s\n"
+ "%s" // locate_args
+ "%s" // arg_assigns
// Create "self" last, so that earlier exceptions while fetching
// params don't trigger a bad invocation of DESTROY.
" arg_%s = (%s)XSBind_new_blank_obj(aTHX_ ST(0));%s\n"
@@ -143,15 +171,19 @@ CFCPerlConstructor_xsub_def(CFCPerlConstructor *self,
CFCClass *klass) {
" XSRETURN(1);\n"
"}\n\n";
char *xsub_def
- = CFCUtil_sprintf(pattern, c_name, c_name, arg_decls, self_type_str,
- allot_params, self_name, self_type_str,
- refcount_mods, func_sym, name_list);
+ = CFCUtil_sprintf(pattern, c_name, c_name, param_specs, locs_decl,
+ arg_decls, self_type_str, items_check, locate_args,
+ arg_assigns, self_name, self_type_str, refcount_mods,
+ func_sym, name_list);
FREEMEM(refcount_mods);
+ FREEMEM(name_list);
FREEMEM(func_sym);
+ FREEMEM(arg_assigns);
+ FREEMEM(locate_args);
+ FREEMEM(locs_decl);
FREEMEM(arg_decls);
- FREEMEM(allot_params);
- FREEMEM(name_list);
+ FREEMEM(param_specs);
return xsub_def;
}
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/src/CFCPerlMethod.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerlMethod.c b/compiler/src/CFCPerlMethod.c
index 7939748..06f92e4 100644
--- a/compiler/src/CFCPerlMethod.c
+++ b/compiler/src/CFCPerlMethod.c
@@ -240,12 +240,14 @@ S_xsub_def_labeled_params(CFCPerlMethod *self, CFCClass
*klass) {
CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
CFCVariable *self_var = arg_vars[0];
CFCType *return_type = CFCMethod_get_return_type(method);
+ size_t num_vars = CFCParamList_num_vars(param_list);
const char *self_name = CFCVariable_get_name(self_var);
- char *arg_decls = CFCPerlSub_arg_declarations((CFCPerlSub*)self, 0);
- char *meth_type_c = CFCMethod_full_typedef(method, klass);
- char *self_assign = S_self_assign_statement(self);
- char *allot_params = CFCPerlSub_build_allot_params((CFCPerlSub*)self, 1);
- char *body = S_xsub_body(self, klass);
+ char *param_specs = CFCPerlSub_build_param_specs((CFCPerlSub*)self, 1);
+ char *arg_decls = CFCPerlSub_arg_declarations((CFCPerlSub*)self, 0);
+ char *meth_type_c = CFCMethod_full_typedef(method, klass);
+ char *self_assign = S_self_assign_statement(self);
+ char *arg_assigns = CFCPerlSub_arg_assignments((CFCPerlSub*)self);
+ char *body = S_xsub_body(self, klass);
char *retval_decl;
if (CFCType_is_void(return_type)) {
@@ -260,31 +262,34 @@ S_xsub_def_labeled_params(CFCPerlMethod *self, CFCClass
*klass) {
"XS(%s);\n"
"XS(%s) {\n"
" dXSARGS;\n"
- "%s"
+ "%s" // param_specs
+ " int32_t locations[%d];\n"
+ "%s" // arg_decls
" %s method;\n"
- " bool args_ok;\n"
"%s"
"\n"
" CFISH_UNUSED_VAR(cv);\n"
" if (items < 1) { CFISH_THROW(CFISH_ERR, \"Usage: %%s(%s, ...)\",
GvNAME(CvGV(cv))); }\n"
" SP -= items;\n"
"\n"
- " /* Extract vars from Perl stack. */\n"
- " %s\n"
- " %s\n"
+ " /* Locate args on Perl stack. */\n"
+ " XSBind_locate_args(aTHX_ &ST(0), 1, items, param_specs,\n"
+ " locations, %d);\n"
+ " %s\n" // self_assign
+ "%s" // arg_assigns
"\n"
" /* Execute */\n"
- " %s\n"
+ " %s\n" // body
"}\n";
char *xsub_def
- = CFCUtil_sprintf(pattern, c_name, c_name, arg_decls,
- meth_type_c, retval_decl, self_name,
- allot_params, self_assign, body);
+ = CFCUtil_sprintf(pattern, c_name, c_name, param_specs, num_vars - 1,
+ arg_decls, meth_type_c, retval_decl, self_name,
+ num_vars - 1, self_assign, arg_assigns, body);
+ FREEMEM(param_specs);
FREEMEM(arg_decls);
FREEMEM(meth_type_c);
FREEMEM(self_assign);
- FREEMEM(allot_params);
FREEMEM(body);
FREEMEM(retval_decl);
return xsub_def;
@@ -297,15 +302,16 @@ S_xsub_def_positional_args(CFCPerlMethod *self, CFCClass
*klass) {
CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
CFCType *return_type = CFCMethod_get_return_type(method);
const char **arg_inits = CFCParamList_get_initial_values(param_list);
- unsigned num_vars = (unsigned)CFCParamList_num_vars(param_list);
+ size_t num_vars = CFCParamList_num_vars(param_list);
char *arg_decls = CFCPerlSub_arg_declarations((CFCPerlSub*)self, 0);
char *meth_type_c = CFCMethod_full_typedef(method, klass);
char *self_assign = S_self_assign_statement(self);
+ char *arg_assigns = CFCPerlSub_arg_assignments((CFCPerlSub*)self);
char *body = S_xsub_body(self, klass);
// Determine how many args are truly required and build an error check.
- unsigned min_required = 0;
- for (unsigned i = 0; i < num_vars; i++) {
+ size_t min_required = 0;
+ for (size_t i = 0; i < num_vars; i++) {
if (arg_inits[i] == NULL) {
min_required = i + 1;
}
@@ -313,7 +319,7 @@ S_xsub_def_positional_args(CFCPerlMethod *self, CFCClass
*klass) {
char *xs_name_list = num_vars > 0
? CFCUtil_strdup(CFCVariable_get_name(arg_vars[0]))
: CFCUtil_strdup("");
- for (unsigned i = 1; i < num_vars; i++) {
+ for (size_t i = 1; i < num_vars; i++) {
const char *var_name = CFCVariable_get_name(arg_vars[i]);
if (i < min_required) {
xs_name_list = CFCUtil_cat(xs_name_list, ", ", var_name, NULL);
@@ -335,41 +341,6 @@ S_xsub_def_positional_args(CFCPerlMethod *self, CFCClass
*klass) {
xs_name_list);
}
- // Var assignments.
- char *var_assignments = CFCUtil_strdup("");
- for (unsigned i = 1; i < num_vars; i++) {
- CFCVariable *var = arg_vars[i];
- const char *val = arg_inits[i];
- const char *var_name = CFCVariable_get_name(var);
- CFCType *var_type = CFCVariable_get_type(var);
- const char *type_c = CFCType_to_c(var_type);
-
- char perl_stack_var[30];
- sprintf(perl_stack_var, "ST(%u)", i);
- char *conversion
- = CFCPerlTypeMap_from_perl(var_type, perl_stack_var);
- if (!conversion) {
- CFCUtil_die("Can't map type '%s'", type_c);
- }
- if (val) {
- char pattern[] =
- "\n arg_%s ="
- " ( items >= %u"" && XSBind_sv_defined(aTHX_ ST(%u)) )"
- " ? %s : %s;";
- char *statement = CFCUtil_sprintf(pattern, var_name, i, i,
- conversion, val);
- var_assignments
- = CFCUtil_cat(var_assignments, statement, NULL);
- FREEMEM(statement);
- }
- else {
- var_assignments
- = CFCUtil_cat(var_assignments, "\n arg_", var_name, " = ",
- conversion, ";", NULL);
- }
- FREEMEM(conversion);
- }
-
char *retval_decl;
if (CFCType_is_void(return_type)) {
retval_decl = CFCUtil_strdup("");
@@ -393,7 +364,7 @@ S_xsub_def_positional_args(CFCPerlMethod *self, CFCClass
*klass) {
"\n"
" /* Extract vars from Perl stack. */\n"
" %s\n"
- " %s\n"
+ "%s" // arg_assigns
"\n"
" /* Execute */\n"
" %s\n"
@@ -401,10 +372,10 @@ S_xsub_def_positional_args(CFCPerlMethod *self, CFCClass
*klass) {
char *xsub
= CFCUtil_sprintf(pattern, self->sub.c_name, self->sub.c_name,
arg_decls, meth_type_c, retval_decl,
- num_args_check, self_assign, var_assignments, body);
+ num_args_check, self_assign, arg_assigns, body);
FREEMEM(num_args_check);
- FREEMEM(var_assignments);
+ FREEMEM(arg_assigns);
FREEMEM(arg_decls);
FREEMEM(meth_type_c);
FREEMEM(self_assign);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/src/CFCPerlSub.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerlSub.c b/compiler/src/CFCPerlSub.c
index 1695b43..f1dee85 100644
--- a/compiler/src/CFCPerlSub.c
+++ b/compiler/src/CFCPerlSub.c
@@ -23,6 +23,7 @@
#include "CFCFunction.h"
#include "CFCUtil.h"
#include "CFCParamList.h"
+#include "CFCPerlTypeMap.h"
#include "CFCVariable.h"
#include "CFCType.h"
@@ -31,6 +32,10 @@
#define false 0
#endif
+static char*
+S_arg_assignment(CFCVariable *var, const char *val,
+ const char *stack_location);
+
CFCPerlSub*
CFCPerlSub_init(CFCPerlSub *self, CFCParamList *param_list,
const char *class_name, const char *alias,
@@ -111,73 +116,6 @@ CFCPerlSub_params_hash_def(CFCPerlSub *self) {
return def;
}
-struct allot_macro_map {
- const char *prim_type;
- const char *allot_macro;
-};
-
-struct allot_macro_map prim_type_to_allot_macro[] = {
- { "double", "ALLOT_F64" },
- { "float", "ALLOT_F32" },
- { "int", "ALLOT_INT" },
- { "short", "ALLOT_SHORT" },
- { "long", "ALLOT_LONG" },
- { "size_t", "ALLOT_SIZE_T" },
- { "uint64_t", "ALLOT_U64" },
- { "uint32_t", "ALLOT_U32" },
- { "uint16_t", "ALLOT_U16" },
- { "uint8_t", "ALLOT_U8" },
- { "int64_t", "ALLOT_I64" },
- { "int32_t", "ALLOT_I32" },
- { "int16_t", "ALLOT_I16" },
- { "int8_t", "ALLOT_I8" },
- { "bool", "ALLOT_BOOL" },
- { NULL, NULL }
-};
-
-static char*
-S_allot_params_arg(CFCType *type, const char *label, int required) {
- const char *type_c_string = CFCType_to_c(type);
- unsigned label_len = (unsigned)strlen(label);
- const char *req_string = required ? "true" : "false";
-
- if (CFCType_is_object(type)) {
- const char *struct_sym = CFCType_get_specifier(type);
- const char *class_var = CFCType_get_class_var(type);
-
- // Share buffers rather than copy between Perl scalars and Clownfish
- // string types.
- int use_sv_buffer = false;
- if (strcmp(struct_sym, "cfish_String") == 0
- || strcmp(struct_sym, "cfish_Obj") == 0
- ) {
- use_sv_buffer = true;
- }
- const char *allocation = use_sv_buffer
- ? "CFISH_ALLOCA_OBJ(CFISH_STRING)"
- : "NULL";
- const char pattern[] = "ALLOT_OBJ(&arg_%s, \"%s\", %u, %s, %s, %s)";
- char *arg = CFCUtil_sprintf(pattern, label, label, label_len,
- req_string, class_var, allocation);
- return arg;
- }
- else if (CFCType_is_primitive(type)) {
- for (int i = 0; prim_type_to_allot_macro[i].prim_type != NULL; i++) {
- const char *prim_type = prim_type_to_allot_macro[i].prim_type;
- if (strcmp(prim_type, type_c_string) == 0) {
- const char *allot = prim_type_to_allot_macro[i].allot_macro;
- char pattern[] = "%s(&arg_%s, \"%s\", %u, %s)";
- char *arg = CFCUtil_sprintf(pattern, allot, label, label,
- label_len, req_string);
- return arg;
- }
- }
- }
-
- CFCUtil_die("Missing typemap for %s", type_c_string);
- return NULL; // unreachable
-}
-
char*
CFCPerlSub_arg_declarations(CFCPerlSub *self, size_t first) {
CFCParamList *param_list = self->param_list;
@@ -217,51 +155,100 @@ CFCPerlSub_arg_name_list(CFCPerlSub *self) {
}
char*
-CFCPerlSub_build_allot_params(CFCPerlSub *self, size_t first) {
- CFCParamList *param_list = self->param_list;
- CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
- const char **arg_inits = CFCParamList_get_initial_values(param_list);
- size_t num_vars = CFCParamList_num_vars(param_list);
- char *allot_params = CFCUtil_strdup("");
+CFCPerlSub_build_param_specs(CFCPerlSub *self, size_t first) {
+ CFCParamList *param_list = self->param_list;
+ CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
+ const char **arg_inits = CFCParamList_get_initial_values(param_list);
+ size_t num_vars = CFCParamList_num_vars(param_list);
- // Declare variables and assign default values.
- for (size_t i = first; i < num_vars; i++) {
- CFCVariable *arg_var = arg_vars[i];
- const char *val = arg_inits[i];
- const char *var_name = CFCVariable_get_name(arg_var);
- if (val == NULL) {
- CFCType *arg_type = CFCVariable_get_type(arg_var);
- val = CFCType_is_object(arg_type)
- ? "NULL"
- : "0";
- }
- allot_params = CFCUtil_cat(allot_params, "arg_", var_name, " = ", val,
- ";\n ", NULL);
- }
+ const char *pattern
+ = " static const XSBind_ParamSpec param_specs[%d] = {";
+ char *param_specs = CFCUtil_sprintf(pattern, num_vars - first);
// Iterate over args in param list.
- allot_params
- = CFCUtil_cat(allot_params,
- "args_ok = XSBind_allot_params(aTHX_\n"
- " &(ST(0)), 1, items,\n", NULL);
for (size_t i = first; i < num_vars; i++) {
- CFCVariable *var = arg_vars[i];
- const char *val = arg_inits[i];
+ if (i != first) {
+ param_specs = CFCUtil_cat(param_specs, ",", NULL);
+ }
+
+ CFCVariable *var = arg_vars[i];
+ const char *val = arg_inits[i];
+ const char *name = CFCVariable_get_name(var);
int required = val ? 0 : 1;
- const char *name = CFCVariable_get_name(var);
- CFCType *type = CFCVariable_get_type(var);
- char *arg = S_allot_params_arg(type, name, required);
- allot_params
- = CFCUtil_cat(allot_params, " ", arg, ",\n", NULL);
- FREEMEM(arg);
+
+ char *spec = CFCUtil_sprintf("XSBIND_PARAM(\"%s\", %d)", name,
+ required);
+ param_specs = CFCUtil_cat(param_specs, "\n ", spec, NULL);
+ FREEMEM(spec);
+ }
+
+ param_specs = CFCUtil_cat(param_specs, "\n };\n", NULL);
+
+ return param_specs;
+}
+
+char*
+CFCPerlSub_arg_assignments(CFCPerlSub *self) {
+ CFCParamList *param_list = self->param_list;
+ CFCVariable **arg_vars = CFCParamList_get_variables(param_list);
+ const char **arg_inits = CFCParamList_get_initial_values(param_list);
+ size_t num_vars = CFCParamList_num_vars(param_list);
+
+ char *arg_assigns = CFCUtil_strdup("");
+
+ for (size_t i = 1; i < num_vars; i++) {
+ char stack_location[30];
+ if (self->use_labeled_params) {
+ sprintf(stack_location, "locations[%u]", (unsigned)(i - 1));
+ }
+ else {
+ sprintf(stack_location, "%u", (unsigned)i);
+ }
+ char *statement = S_arg_assignment(arg_vars[i], arg_inits[i],
+ stack_location);
+ arg_assigns = CFCUtil_cat(arg_assigns, statement, NULL);
+ FREEMEM(statement);
+ }
+
+ return arg_assigns;
+}
+
+static char*
+S_arg_assignment(CFCVariable *var, const char *val,
+ const char *stack_location) {
+ const char *var_name = CFCVariable_get_name(var);
+ CFCType *var_type = CFCVariable_get_type(var);
+ char *statement = NULL;
+
+ char perl_stack_var[40];
+ sprintf(perl_stack_var, "ST(%s)", stack_location);
+ char *conversion = CFCPerlTypeMap_from_perl(var_type, perl_stack_var,
+ var_name);
+ if (!conversion) {
+ const char *type_c = CFCType_to_c(var_type);
+ CFCUtil_die("Can't map type '%s'", type_c);
+ }
+ if (val) {
+ if (CFCType_is_object(var_type)) {
+ char pattern[] = " arg_%s = %s < items ? %s : %s;\n";
+ statement = CFCUtil_sprintf(pattern, var_name, stack_location,
+ conversion, val);
+ }
+ else {
+ char pattern[] =
+ " arg_%s = %s < items && XSBind_sv_defined(aTHX_ %s)\n"
+ " ? %s : %s;\n";
+ statement = CFCUtil_sprintf(pattern, var_name, stack_location,
+ perl_stack_var, conversion, val);
+ }
+ }
+ else {
+ const char pattern[] = " arg_%s = %s;\n";
+ statement = CFCUtil_sprintf(pattern, var_name, conversion);
}
- allot_params
- = CFCUtil_cat(allot_params, " NULL);\n",
- " if (!args_ok) {\n"
- "
CFISH_RETHROW(CFISH_INCREF(cfish_Err_get_error()));\n"
- " }", NULL);
+ FREEMEM(conversion);
- return allot_params;
+ return statement;
}
CFCParamList*
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/src/CFCPerlSub.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerlSub.h b/compiler/src/CFCPerlSub.h
index ffb4a2f..d45852a 100644
--- a/compiler/src/CFCPerlSub.h
+++ b/compiler/src/CFCPerlSub.h
@@ -25,6 +25,7 @@ typedef struct CFCPerlSub CFCPerlSub;
struct CFCFunction;
struct CFCParamList;
struct CFCType;
+struct CFCVariable;
#ifdef CFC_NEED_PERLSUB_STRUCT_DEF
#define CFC_NEED_BASE_STRUCT_DEF
@@ -83,12 +84,16 @@ CFCPerlSub_arg_declarations(CFCPerlSub *self, size_t first);
char*
CFCPerlSub_arg_name_list(CFCPerlSub *self);
-/** Generate code which will invoke XSBind_allot_params() to parse labeled
- * parameters supplied to an XSUB. Parameters from `first` onwards are
- * included.
+/** Generate code that initializes a static array of XSBind_ParamSpecs.
+ * Parameters from `first` onwards are included.
*/
char*
-CFCPerlSub_build_allot_params(CFCPerlSub *self, size_t first);
+CFCPerlSub_build_param_specs(CFCPerlSub *self, size_t first);
+
+/** Generate code that that converts and assigns the arguments.
+ */
+char*
+CFCPerlSub_arg_assignments(CFCPerlSub *self);
/** Accessor for param list.
*/
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/src/CFCPerlTypeMap.c
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerlTypeMap.c b/compiler/src/CFCPerlTypeMap.c
index ef76755..f320a82 100644
--- a/compiler/src/CFCPerlTypeMap.c
+++ b/compiler/src/CFCPerlTypeMap.c
@@ -35,12 +35,14 @@ struct char_map {
char*
-CFCPerlTypeMap_from_perl(CFCType *type, const char *xs_var) {
+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 *struct_sym = CFCType_get_specifier(type);
+ const char *class_var = CFCType_get_class_var(type);
+ const char *nullable_str = CFCType_nullable(type) ? "true" : "false";
const char *allocation;
if (strcmp(struct_sym, "cfish_String") == 0
|| strcmp(struct_sym, "cfish_Obj") == 0
@@ -53,9 +55,9 @@ CFCPerlTypeMap_from_perl(CFCType *type, const char *xs_var) {
allocation = "NULL";
}
const char pattern[]
- = "(%s*)XSBind_perl_to_cfish_noinc(aTHX_ %s, %s, %s)";
- result = CFCUtil_sprintf(pattern, struct_sym, xs_var, class_var,
- allocation);
+ = "(%s*)XSBind_arg_to_cfish(aTHX_ %s, \"%s\", %s, %s, %s)";
+ result = CFCUtil_sprintf(pattern, struct_sym, xs_var, label,
+ nullable_str, class_var, allocation);
}
else if (CFCType_is_primitive(type)) {
const char *specifier = CFCType_get_specifier(type);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/compiler/src/CFCPerlTypeMap.h
----------------------------------------------------------------------
diff --git a/compiler/src/CFCPerlTypeMap.h b/compiler/src/CFCPerlTypeMap.h
index eceb86d..0f8d271 100644
--- a/compiler/src/CFCPerlTypeMap.h
+++ b/compiler/src/CFCPerlTypeMap.h
@@ -42,7 +42,8 @@ struct CFCType;
* a value.
*/
char*
-CFCPerlTypeMap_from_perl(struct CFCType *type, const char *xs_var);
+CFCPerlTypeMap_from_perl(struct CFCType *type, const char *xs_var,
+ const char *label);
/** Return an expression converts from a variable of type $type to a Perl
* scalar.
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/runtime/perl/buildlib/Clownfish/Build/Binding.pm
----------------------------------------------------------------------
diff --git a/runtime/perl/buildlib/Clownfish/Build/Binding.pm
b/runtime/perl/buildlib/Clownfish/Build/Binding.pm
index 9ddc150..068a29e 100644
--- a/runtime/perl/buildlib/Clownfish/Build/Binding.pm
+++ b/runtime/perl/buildlib/Clownfish/Build/Binding.pm
@@ -959,19 +959,22 @@ singleton(unused_sv, ...)
SV *unused_sv;
CODE:
{
+ static const XSBind_ParamSpec param_specs[2] = {
+ XSBIND_PARAM("class_name", true),
+ XSBIND_PARAM("parent", false),
+ };
+ int32_t locations[2];
cfish_String *class_name = NULL;
cfish_Class *parent = NULL;
cfish_Class *singleton = NULL;
- bool args_ok
- = XSBind_allot_params(aTHX_ &(ST(0)), 1, items,
- ALLOT_OBJ(&class_name, "class_name", 10, true,
- CFISH_STRING,
CFISH_ALLOCA_OBJ(CFISH_STRING)),
- ALLOT_OBJ(&parent, "parent", 6, false,
- CFISH_CLASS, NULL),
- NULL);
CFISH_UNUSED_VAR(unused_sv);
- if (!args_ok) {
- CFISH_RETHROW(CFISH_INCREF(cfish_Err_get_error()));
+ XSBind_locate_args(aTHX_ &(ST(0)), 1, items, param_specs, locations, 2);
+ class_name = (cfish_String*)XSBind_arg_to_cfish(
+ aTHX_ ST(locations[0]), "class_name", false, CFISH_STRING,
+ CFISH_ALLOCA_OBJ(CFISH_STRING));
+ if (locations[1] < items) {
+ parent = (cfish_Class*)XSBind_arg_to_cfish(
+ aTHX_ ST(locations[1]), "parent", true, CFISH_CLASS, NULL);
}
singleton = cfish_Class_singleton(class_name, parent);
RETVAL = (SV*)CFISH_Class_To_Host(singleton);
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/runtime/perl/t/binding/019-obj.t
----------------------------------------------------------------------
diff --git a/runtime/perl/t/binding/019-obj.t b/runtime/perl/t/binding/019-obj.t
index 545b235..7d71149 100644
--- a/runtime/perl/t/binding/019-obj.t
+++ b/runtime/perl/t/binding/019-obj.t
@@ -103,7 +103,7 @@ ok( !$object->is_a(""), "custom is_a
blank" );
ok( !$object->is_a("thing"), "custom is_a wrong" );
eval { my $another_obj = TestObj->new( kill_me_now => 1 ) };
-like( $@, qr/kill_me_now/, "reject bad param" );
+like( $@, qr/Usage: new/, "reject bad param" );
eval { $object->clone };
like( $@, qr/Abstract method 'Clone' not defined by TestObj/,
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/runtime/perl/xs/XSBind.c
----------------------------------------------------------------------
diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c
index e72d1e0..7b9e1e5 100644
--- a/runtime/perl/xs/XSBind.c
+++ b/runtime/perl/xs/XSBind.c
@@ -307,218 +307,92 @@ XSBind_trap(SV *routine, SV *context) {
return cfish_Err_trap(S_attempt_perl_call, &args);
}
-static bool
-S_extract_from_sv(pTHX_ SV *value, void *target, const char *label,
- bool required, int type, cfish_Class *klass,
- void *allocation) {
- bool valid_assignment = false;
-
- if (XSBind_sv_defined(aTHX_ value)) {
- switch (type) {
- case XSBIND_WANT_I8:
- *((int8_t*)target) = (int8_t)SvIV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_I16:
- *((int16_t*)target) = (int16_t)SvIV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_I32:
- *((int32_t*)target) = (int32_t)SvIV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_I64:
- if (sizeof(IV) == 8) {
- *((int64_t*)target) = (int64_t)SvIV(value);
- }
- else { // sizeof(IV) == 4
- // lossy.
- *((int64_t*)target) = (int64_t)SvNV(value);
- }
- valid_assignment = true;
- break;
- case XSBIND_WANT_U8:
- *((uint8_t*)target) = (uint8_t)SvUV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_U16:
- *((uint16_t*)target) = (uint16_t)SvUV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_U32:
- *((uint32_t*)target) = (uint32_t)SvUV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_U64:
- if (sizeof(UV) == 8) {
- *((uint64_t*)target) = (uint64_t)SvUV(value);
- }
- else { // sizeof(UV) == 4
- // lossy.
- *((uint64_t*)target) = (uint64_t)SvNV(value);
- }
- valid_assignment = true;
- break;
- case XSBIND_WANT_BOOL:
- *((bool*)target) = !!SvTRUE(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_F32:
- *((float*)target) = (float)SvNV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_F64:
- *((double*)target) = SvNV(value);
- valid_assignment = true;
- break;
- case XSBIND_WANT_OBJ: {
- cfish_Obj *object = NULL;
- bool success
- = S_maybe_perl_to_cfish(aTHX_ value, klass, false,
- allocation, &object);
- if (success && object) {
- *((cfish_Obj**)target) = object;
- valid_assignment = true;
- }
- else {
- cfish_String *mess
- = CFISH_MAKE_MESS(
- "Invalid value for '%s' - not a %o",
- label, CFISH_Class_Get_Name(klass));
- cfish_Err_set_error(cfish_Err_new(mess));
- return false;
- }
- }
- break;
- case XSBIND_WANT_SV:
- *((SV**)target) = value;
- valid_assignment = true;
- break;
- default: {
- cfish_String *mess
- = CFISH_MAKE_MESS("Unrecognized type: %i32 for param
'%s'",
- (int32_t)type, label);
- cfish_Err_set_error(cfish_Err_new(mess));
- return false;
- }
- }
- }
-
- // Enforce that required params cannot be undef and must present valid
- // values.
- if (required && !valid_assignment) {
- cfish_String *mess = CFISH_MAKE_MESS("Missing required param %s",
- label);
- cfish_Err_set_error(cfish_Err_new(mess));
- return false;
- }
-
- return true;
-}
-
-bool
-XSBind_allot_params(pTHX_ SV** stack, int32_t start, int32_t num_stack_elems,
- ...) {
- va_list args;
-
- // Verify that our args come in pairs. Return success if there are no
- // args.
- if ((num_stack_elems - start) % 2 != 0) {
- cfish_String *mess
- = CFISH_MAKE_MESS(
- "Expecting hash-style params, got odd number of args");
- cfish_Err_set_error(cfish_Err_new(mess));
- return false;
+void
+cfish_XSBind_locate_args(pTHX_ SV** stack, int32_t start, int32_t items,
+ const XSBind_ParamSpec *specs, int32_t *locations,
+ int32_t num_params) {
+ // Verify that our args come in pairs.
+ if ((items - start) % 2 != 0) {
+ THROW(CFISH_ERR,
+ "Expecting hash-style params, got odd number of args");
+ return;
}
int32_t num_consumed = 0;
- void *target;
- va_start(args, num_stack_elems);
- while (NULL != (target = va_arg(args, void*))) {
- char *label = va_arg(args, char*);
- int label_len = va_arg(args, int);
- int required = va_arg(args, int);
- int type = va_arg(args, int);
- cfish_Class *klass = va_arg(args, cfish_Class*);
- void *allocation = va_arg(args, void*);
+ for (int32_t i = 0; i < num_params; i++) {
+ const XSBind_ParamSpec *spec = &specs[i];
// Iterate through the stack looking for labels which match this param
// name. If the label appears more than once, keep track of where it
// appears *last*, as the last time a param appears overrides all
// previous appearances.
- int32_t found_arg = -1;
- for (int32_t tick = start; tick < num_stack_elems; tick += 2) {
+ int32_t location = items;
+ for (int32_t tick = start; tick < items; tick += 2) {
SV *const key_sv = stack[tick];
- if (SvCUR(key_sv) == (STRLEN)label_len) {
- if (memcmp(SvPVX(key_sv), label, label_len) == 0) {
- found_arg = tick;
+ if (SvCUR(key_sv) == (STRLEN)spec->label_len) {
+ if (memcmp(SvPVX(key_sv), spec->label, spec->label_len) == 0) {
+ location = tick + 1;
++num_consumed;
}
}
}
- if (found_arg == -1) {
- // Didn't find this parameter. Throw an error if it was required.
- if (required) {
- cfish_String *mess
- = CFISH_MAKE_MESS("Missing required parameter: '%s'",
- label);
- cfish_Err_set_error(cfish_Err_new(mess));
- return false;
- }
- }
- else {
- // Found the arg. Extract the value.
- SV *value = stack[found_arg + 1];
- bool got_arg = S_extract_from_sv(aTHX_ value, target, label,
- required, type, klass,
- allocation);
- if (!got_arg) {
- CFISH_ERR_ADD_FRAME(cfish_Err_get_error());
- return false;
- }
+ // Didn't find this parameter. Throw an error if it was required.
+ if (location == items && spec->required) {
+ THROW(CFISH_ERR, "Missing required parameter: '%s'", spec->label);
+ return;
}
+
+ // Store the location.
+ locations[i] = location;
}
- va_end(args);
// Ensure that all parameter labels were valid.
- if (num_consumed != (num_stack_elems - start) / 2) {
+ if (num_consumed != (items - start) / 2) {
// Find invalid parameter.
- for (int32_t tick = start; tick < num_stack_elems; tick += 2) {
+ for (int32_t tick = start; tick < items; tick += 2) {
SV *const key_sv = stack[tick];
const char *key = SvPVX(key_sv);
STRLEN key_len = SvCUR(key_sv);
bool found = false;
- va_start(args, num_stack_elems);
- while (NULL != (target = va_arg(args, void*))) {
- char *label = va_arg(args, char*);
- int label_len = va_arg(args, int);
- va_arg(args, int);
- va_arg(args, int);
- va_arg(args, cfish_Class*);
- va_arg(args, void*);
-
- if (key_len == (STRLEN)label_len
- && memcmp(key, label, label_len) == 0
+ for (int32_t i = 0; i < num_params; ++i) {
+ const XSBind_ParamSpec *spec = &specs[i];
+
+ if (key_len == (STRLEN)spec->label_len
+ && memcmp(key, spec->label, key_len) == 0
) {
found = true;
break;
}
}
- va_end(args);
if (!found) {
const char *key_c = SvPV_nolen(key_sv);
- cfish_String *mess
- = CFISH_MAKE_MESS("Invalid parameter: '%s'", key_c);
- cfish_Err_set_error(cfish_Err_new(mess));
- return false;
+ THROW(CFISH_ERR, "Invalid parameter: '%s'", key_c);
+ return;
}
}
}
+}
- return true;
+cfish_Obj*
+XSBind_arg_to_cfish(pTHX_ SV *value, const char *label, bool nullable,
+ cfish_Class *klass, void *allocation) {
+ cfish_Obj *obj = NULL;
+
+ if (!S_maybe_perl_to_cfish(aTHX_ value, klass, false, allocation, &obj)) {
+ THROW(CFISH_ERR, "Invalid value for '%s' - not a %o", label,
+ CFISH_Class_Get_Name(klass));
+ CFISH_UNREACHABLE_RETURN(cfish_Obj*);
+ }
+
+ if (!obj && !nullable) {
+ THROW(CFISH_ERR, "'%s' must not be undef", label);
+ CFISH_UNREACHABLE_RETURN(cfish_Obj*);
+ }
+
+ return obj;
}
/***************************************************************************
http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/ffeefa58/runtime/perl/xs/XSBind.h
----------------------------------------------------------------------
diff --git a/runtime/perl/xs/XSBind.h b/runtime/perl/xs/XSBind.h
index 096fbc0..a104797 100644
--- a/runtime/perl/xs/XSBind.h
+++ b/runtime/perl/xs/XSBind.h
@@ -44,6 +44,12 @@
extern "C" {
#endif
+typedef struct cfish_XSBind_ParamSpec {
+ const char *label;
+ uint16_t label_len;
+ char required;
+} cfish_XSBind_ParamSpec;
+
/** Given either a class name or a perl object, manufacture a new Clownfish
* object suitable for supplying to a cfish_Foo_init() function.
*/
@@ -153,157 +159,44 @@ cfish_XSBind_hash_key_to_utf8(pTHX_ HE *entry, STRLEN
*size_ptr);
cfish_Err*
cfish_XSBind_trap(SV *routine, SV *context);
-/** Process hash-style params passed to an XS subroutine. The varargs must be
- * a NULL-terminated series of ALLOT_ macros.
- *
- * cfish_XSBind_allot_params(stack, start, num_stack_elems,
- * ALLOT_OBJ(&field, "field", 5, CFISH_STRING, true,
CFISH_ALLOCA_OBJ(CFISH_STRING),
- * ALLOT_OBJ(&term, "term", 4, CFISH_STRING, true,
CFISH_ALLOCA_OBJ(CFISH_STRING),
- * NULL);
- *
- * The following ALLOT_ macros are available for primitive types:
- *
- * ALLOT_I8(ptr, key, keylen, required)
- * ALLOT_I16(ptr, key, keylen, required)
- * ALLOT_I32(ptr, key, keylen, required)
- * ALLOT_I64(ptr, key, keylen, required)
- * ALLOT_U8(ptr, key, keylen, required)
- * ALLOT_U16(ptr, key, keylen, required)
- * ALLOT_U32(ptr, key, keylen, required)
- * ALLOT_U64(ptr, key, keylen, required)
- * ALLOT_BOOL(ptr, key, keylen, required)
- * ALLOT_CHAR(ptr, key, keylen, required)
- * ALLOT_SHORT(ptr, key, keylen, required)
- * ALLOT_INT(ptr, key, keylen, required)
- * ALLOT_LONG(ptr, key, keylen, required)
- * ALLOT_SIZE_T(ptr, key, keylen, required)
- * ALLOT_F32(ptr, key, keylen, required)
- * ALLOT_F64(ptr, key, keylen, required)
- *
- * The four arguments to these ALLOT_ macros have the following meanings:
- *
- * ptr -- A pointer to the variable to be extracted.
- * key -- The name of the parameter as a C string.
- * keylen -- The length of the parameter name in bytes.
- * required -- A boolean indicating whether the parameter is required.
- *
- * If a required parameter is not present, allot_params() will set the global
- * error object and return false.
- *
- * Use the following macro if a Clownfish object is desired:
- *
- * ALLOT_OBJ(ptr, key, keylen, required, klass, allocation)
- *
- * The "klass" argument must be the Class corresponding to the class of the
- * desired object. The "allocation" argument must be a blob of memory
- * allocated on the stack sufficient to hold a String. (Use
- * CFISH_ALLOCA_OBJ to allocate the object.)
- *
- * To extract a Perl scalar, use the following ALLOT_ macro:
- *
- * ALLOT_SV(ptr, key, keylen, required)
+/** Locate hash-style params passed to an XS subroutine. If a required
+ * parameter is not present, locate_args() will throw an error.
*
- * All possible valid param names must be passed via the ALLOT_ macros; if a
- * user-supplied param cannot be matched up with an ALLOT_ macro,
- * allot_params() will set the global error object and return false.
+ * All possible valid param names must be passed in `specs`; if a
+ * user-supplied param cannot be matched up, locate_args() will throw an
+ * error.
*
* @param stack The Perl stack.
* @param start Where on the Perl stack to start looking for params. For
* methods, this would typically be 1; for functions, most likely 0.
- * @param num_stack_elems The number of arguments passed to the Perl function
- * (generally, the XS variable "items").
- * @return true on success, false on failure (sets the global error object).
+ * @param items The number of arguments passed to the Perl function
+ * (generally, the XS variable `items`).
+ * @params specs An array of XSBind_ParamSpec structs describing the
+ * parameters.
+ * @param locations On success, this output argument will be set to the
+ * location on the stack of each param. Optional arguments that could not
+ * be found have their location set to `items`.
+ * @param The number of parameters in `specs` and elements in `locations`.
+ */
+CFISH_VISIBLE void
+cfish_XSBind_locate_args(pTHX_ SV** stack, int32_t start, int32_t items,
+ const cfish_XSBind_ParamSpec *specs,
+ int32_t *locations, int32_t num_params);
+
+/** Convert an argument from the Perl stack to a Clownfish object.
+ *
+ * @param value The SV from the Perl stack.
+ * @param label The name of the param.
+ * @param nullable Whether undef is allowed for objects.
+ * @param klass The class to convert to.
+ * @param allocation Stack allocation for Obj and String.
*/
-CFISH_VISIBLE bool
-cfish_XSBind_allot_params(pTHX_ SV** stack, int32_t start,
- int32_t num_stack_elems, ...);
-
-#define XSBIND_WANT_I8 0x1
-#define XSBIND_WANT_I16 0x2
-#define XSBIND_WANT_I32 0x3
-#define XSBIND_WANT_I64 0x4
-#define XSBIND_WANT_U8 0x5
-#define XSBIND_WANT_U16 0x6
-#define XSBIND_WANT_U32 0x7
-#define XSBIND_WANT_U64 0x8
-#define XSBIND_WANT_BOOL 0x9
-#define XSBIND_WANT_F32 0xA
-#define XSBIND_WANT_F64 0xB
-#define XSBIND_WANT_OBJ 0xC
-#define XSBIND_WANT_SV 0xD
-
-#if (CFISH_SIZEOF_CHAR == 1)
- #define XSBIND_WANT_CHAR XSBIND_WANT_I8
-#else
- #error "Can't build unless sizeof(char) == 1"
-#endif
-
-#if (CFISH_SIZEOF_SHORT == 2)
- #define XSBIND_WANT_SHORT XSBIND_WANT_I16
-#else
- #error "Can't build unless sizeof(short) == 2"
-#endif
-
-#if (CFISH_SIZEOF_INT == 4)
- #define XSBIND_WANT_INT XSBIND_WANT_I32
-#elif (CFISH_SIZEOF_INT == 8)
- #define XSBIND_WANT_INT XSBIND_WANT_I64
-#else
- #error "Can't build unless sizeof(int) == 4 or sizeof(int) == 8"
-#endif
-
-#if (CFISH_SIZEOF_LONG == 4)
- #define XSBIND_WANT_LONG XSBIND_WANT_I32
-#elif (CFISH_SIZEOF_LONG == 8)
- #define XSBIND_WANT_LONG XSBIND_WANT_I64
-#else
- #error "Can't build unless sizeof(long) == 4 or sizeof(long) == 8"
-#endif
-
-#if (CFISH_SIZEOF_SIZE_T == 4)
- #define XSBIND_WANT_SIZE_T XSBIND_WANT_U32
-#elif (CFISH_SIZEOF_SIZE_T == 8)
- #define XSBIND_WANT_SIZE_T XSBIND_WANT_U64
-#else
- #error "Can't build unless sizeof(size_t) == 4 or sizeof(size_t) == 8"
-#endif
+CFISH_VISIBLE cfish_Obj*
+cfish_XSBind_arg_to_cfish(pTHX_ SV *value, const char *label, bool nullable,
+ cfish_Class *klass, void *allocation);
-#define XSBIND_ALLOT_I8(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_I8, NULL, NULL
-#define XSBIND_ALLOT_I16(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_I16, NULL, NULL
-#define XSBIND_ALLOT_I32(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_I32, NULL, NULL
-#define XSBIND_ALLOT_I64(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_I64, NULL, NULL
-#define XSBIND_ALLOT_U8(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_U8, NULL, NULL
-#define XSBIND_ALLOT_U16(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_U16, NULL, NULL
-#define XSBIND_ALLOT_U32(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_U32, NULL, NULL
-#define XSBIND_ALLOT_U64(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_U64, NULL, NULL
-#define XSBIND_ALLOT_BOOL(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_BOOL, NULL, NULL
-#define XSBIND_ALLOT_CHAR(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_CHAR, NULL, NULL
-#define XSBIND_ALLOT_SHORT(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_SHORT, NULL, NULL
-#define XSBIND_ALLOT_INT(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_INT, NULL, NULL
-#define XSBIND_ALLOT_LONG(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_LONG, NULL, NULL
-#define XSBIND_ALLOT_SIZE_T(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_SIZE_T, NULL, NULL
-#define XSBIND_ALLOT_F32(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_F32, NULL, NULL
-#define XSBIND_ALLOT_F64(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_F64, NULL, NULL
-#define XSBIND_ALLOT_OBJ(ptr, key, keylen, required, klass, allocation) \
- ptr, key, keylen, required, XSBIND_WANT_OBJ, klass, allocation
-#define XSBIND_ALLOT_SV(ptr, key, keylen, required) \
- ptr, key, keylen, required, XSBIND_WANT_SV, NULL, NULL
+#define XSBIND_PARAM(key, required) \
+ { key, (int16_t)sizeof("" key) - 1, (char)required }
/* Define short names for most of the symbols in this file. Note that these
* short names are ALWAYS in effect, since they are only used for Perl and we
@@ -311,6 +204,7 @@ cfish_XSBind_allot_params(pTHX_ SV** stack, int32_t start,
* full symbols nevertheless in case someone else defines e.g. a function
* named "XSBind_sv_defined".)
*/
+#define XSBind_ParamSpec cfish_XSBind_ParamSpec
#define XSBind_new_blank_obj cfish_XSBind_new_blank_obj
#define XSBind_foster_obj cfish_XSBind_foster_obj
#define XSBind_sv_defined cfish_XSBind_sv_defined
@@ -322,25 +216,8 @@ cfish_XSBind_allot_params(pTHX_ SV** stack, int32_t start,
#define XSBind_perl_to_cfish_noinc cfish_XSBind_perl_to_cfish_noinc
#define XSBind_hash_key_to_utf8 cfish_XSBind_hash_key_to_utf8
#define XSBind_trap cfish_XSBind_trap
-#define XSBind_allot_params cfish_XSBind_allot_params
-#define ALLOT_I8 XSBIND_ALLOT_I8
-#define ALLOT_I16 XSBIND_ALLOT_I16
-#define ALLOT_I32 XSBIND_ALLOT_I32
-#define ALLOT_I64 XSBIND_ALLOT_I64
-#define ALLOT_U8 XSBIND_ALLOT_U8
-#define ALLOT_U16 XSBIND_ALLOT_U16
-#define ALLOT_U32 XSBIND_ALLOT_U32
-#define ALLOT_U64 XSBIND_ALLOT_U64
-#define ALLOT_BOOL XSBIND_ALLOT_BOOL
-#define ALLOT_CHAR XSBIND_ALLOT_CHAR
-#define ALLOT_SHORT XSBIND_ALLOT_SHORT
-#define ALLOT_INT XSBIND_ALLOT_INT
-#define ALLOT_LONG XSBIND_ALLOT_LONG
-#define ALLOT_SIZE_T XSBIND_ALLOT_SIZE_T
-#define ALLOT_F32 XSBIND_ALLOT_F32
-#define ALLOT_F64 XSBIND_ALLOT_F64
-#define ALLOT_OBJ XSBIND_ALLOT_OBJ
-#define ALLOT_SV XSBIND_ALLOT_SV
+#define XSBind_locate_args cfish_XSBind_locate_args
+#define XSBind_arg_to_cfish cfish_XSBind_arg_to_cfish
/* Strip the prefix from some common ClownFish symbols where we know there's
* no conflict with Perl. It's a little inconsistent to do this rather than