summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-09-24 21:24:29 -0700
committerKaz Kylheku <kaz@kylheku.com>2012-09-24 21:24:29 -0700
commitbe8c893f57c2816cd00234286f2f17fa15924e6e (patch)
treeef63835fb572dc868335c9a6ba526464f6915da0
parent7458d8311b5c81177559145b1fc8576d9a99c3d3 (diff)
downloadtxr-be8c893f57c2816cd00234286f2f17fa15924e6e.tar.gz
txr-be8c893f57c2816cd00234286f2f17fa15924e6e.tar.bz2
txr-be8c893f57c2816cd00234286f2f17fa15924e6e.zip
Bugfix: internal funcall functions not handling functions
with optional arguments. * lib.c (generic_funcall): New static function, based on apply from eval.c. (funcall, funcall1, funcall2, funcall3, funcall4): If the function being called has optional arguments, then go through generic_funcall.
-rw-r--r--ChangeLog10
-rw-r--r--lib.c114
2 files changed, 123 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index f7bf481b..3d05b8ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
2012-09-24 Kaz Kylheku <kaz@kylheku.com>
+ Bugfix: internal funcall functions not handling functions
+ with optional arguments.
+
+ * lib.c (generic_funcall): New static function, based on apply
+ from eval.c.
+ (funcall, funcall1, funcall2, funcall3, funcall4): If the function
+ being called has optional arguments, then go through generic_funcall.
+
+2012-09-24 Kaz Kylheku <kaz@kylheku.com>
+
* arith.c (logand): Fix incorrect return value.
2012-09-18 Kaz Kylheku <kaz@kylheku.com>
diff --git a/lib.c b/lib.c
index 8492c3dc..89a38496 100644
--- a/lib.c
+++ b/lib.c
@@ -2759,10 +2759,103 @@ val interp_fun_p(val obj)
return (functionp(obj) && obj->f.functype == FINTERP) ? t : nil;
}
+static val generic_funcall(val fun, val arg[], int nargs)
+{
+ int variadic, fixparam, reqargs;
+
+ type_check (fun, FUN);
+
+ variadic = fun->f.variadic;
+ fixparam = fun->f.fixparam;
+ reqargs = fixparam - fun->f.optargs;
+
+ if (!variadic) {
+ if (nargs < reqargs)
+ uw_throw(error_s, lit("funcall: missing required arguments"));
+
+ if (nargs > fixparam)
+ uw_throw(error_s, lit("funcall: too many arguments"));
+
+ for (; nargs < fixparam; )
+ arg[nargs++] = 0;
+
+ switch (fun->f.functype) {
+ case F0:
+ return fun->f.f.f0(fun->f.env);
+ case F1:
+ return fun->f.f.f1(fun->f.env, arg[0]);
+ case F2:
+ return fun->f.f.f2(fun->f.env, arg[0], arg[1]);
+ case F3:
+ return fun->f.f.f3(fun->f.env, arg[0], arg[1], arg[2]);
+ case F4:
+ return fun->f.f.f4(fun->f.env, arg[0], arg[1], arg[2], arg[3]);
+ case N0:
+ return fun->f.f.n0();
+ case N1:
+ return fun->f.f.n1(arg[0]);
+ case N2:
+ return fun->f.f.n2(arg[0], arg[1]);
+ case N3:
+ return fun->f.f.n3(arg[0], arg[1], arg[2]);
+ case N4:
+ return fun->f.f.n4(arg[0], arg[1], arg[2], arg[3]);
+ case FINTERP:
+ internal_error("unsupported function type");
+ }
+ } else {
+ val arglist = nil;
+
+ if (nargs > fixparam)
+ nargs = fixparam;
+
+ if (nargs < reqargs)
+ uw_throw(error_s, lit("funcall: missing required arguments"));
+
+ for (; nargs < fixparam; )
+ arg[nargs++] = nil;
+
+ for (; nargs > fixparam; )
+ arglist = cons(arg[--nargs], arglist);
+
+ switch (fun->f.functype) {
+ case FINTERP:
+ return interp_fun(fun->f.env, fun->f.f.interp_fun, arglist);
+ case F0:
+ return fun->f.f.f0v(fun->f.env, arglist);
+ case F1:
+ return fun->f.f.f1v(fun->f.env, arg[0], arglist);
+ case F2:
+ return fun->f.f.f2v(fun->f.env, arg[0], arg[1], arglist);
+ case F3:
+ return fun->f.f.f3v(fun->f.env, arg[0], arg[1], arg[2], arglist);
+ case F4:
+ return fun->f.f.f4v(fun->f.env, arg[0], arg[1], arg[2], arg[3], arglist);
+ case N0:
+ return fun->f.f.n0v(arglist);
+ case N1:
+ return fun->f.f.n1v(arg[0], arglist);
+ case N2:
+ return fun->f.f.n2v(arg[0], arg[1], arglist);
+ case N3:
+ return fun->f.f.n3v(arg[0], arg[1], arg[2], arglist);
+ case N4:
+ return fun->f.f.n4v(arg[0], arg[1], arg[2], arg[3], arglist);
+ }
+ }
+
+ internal_error("corrupt function type field");
+}
+
val funcall(val fun)
{
type_check(fun, FUN);
+ if (fun->f.optargs) {
+ val arg[32] = { nil };
+ return generic_funcall(fun, arg, 0);
+ }
+
if (fun->f.variadic) {
switch (fun->f.functype) {
case FINTERP:
@@ -2791,6 +2884,11 @@ val funcall1(val fun, val arg)
{
type_check(fun, FUN);
+ if (fun->f.optargs) {
+ val args[32] = { arg };
+ return generic_funcall(fun, args, 1);
+ }
+
if (fun->f.variadic) {
switch (fun->f.functype) {
case FINTERP:
@@ -2823,6 +2921,11 @@ val funcall2(val fun, val arg1, val arg2)
{
type_check(fun, FUN);
+ if (fun->f.optargs) {
+ val arg[32] = { arg1, arg2 };
+ return generic_funcall(fun, arg, 2);
+ }
+
if (fun->f.variadic) {
switch (fun->f.functype) {
case FINTERP:
@@ -2860,6 +2963,11 @@ val funcall3(val fun, val arg1, val arg2, val arg3)
{
type_check(fun, FUN);
+ if (fun->f.optargs) {
+ val arg[32] = { arg1, arg2, arg3 };
+ return generic_funcall(fun, arg, 3);
+ }
+
if (fun->f.variadic) {
switch (fun->f.functype) {
case FINTERP:
@@ -2901,6 +3009,11 @@ val funcall4(val fun, val arg1, val arg2, val arg3, val arg4)
{
type_check(fun, FUN);
+ if (fun->f.optargs) {
+ val arg[32] = { arg1, arg2, arg3, arg4 };
+ return generic_funcall(fun, arg, 4);
+ }
+
if (fun->f.variadic) {
switch (fun->f.functype) {
case FINTERP:
@@ -2942,7 +3055,6 @@ val funcall4(val fun, val arg1, val arg2, val arg3, val arg4)
uw_throw(error_s, lit("funcall4: wrong number of arguments"));
}
-
val reduce_left(val fun, val list, val init, val key)
{
if (!key)