>From 722b97a77421a2723a9edfa14b148d6d6b847430 Mon Sep 17 00:00:00 2001 From: David Kastrup Date: Wed, 7 May 2014 18:43:23 +0200 Subject: [PATCH 2/3] Make (values) equivalent to *unspecified* module/ice-9/boot-9.scm states in a comment: ;;; {The Unspecified Value} ;;; ;;; Currently Guile represents unspecified values via one particular value, ;;; which may be obtained by evaluating (if #f #f). It would be nice in the ;;; future if we could replace this with a return of 0 values, though. ;;; (define-syntax *unspecified* (identifier-syntax (if #f #f))) (define (unspecified? v) (eq? v *unspecified*)) This code remains actually valid while addressing the "it would be nice" angle since (values) is now represented as SCM_UNSPECIFIED in the API while being generally treated as a valid entity in implicit single-value contexts. Since the Scheme standard considers using zero-value expressions in such contexts unspecified behavior, reverting to an identifiable *unspecified* value does not appear to violate the standard. Factually, SCM_UNSPECIFIED has already been used in the API to signify no usefully returned value, and the REPL already treated *unspecified* identical to (values) as a return value in that it did not print anything. This interpretation is now pervasive into the Scheme/vm level. *unspecified* remains less ephemeral than multiple-valued expressions since it can generally be used as a first-class value and stored in data structures. Consequently, data structure access may deliver zero values to a multiple-value accepting context: (call-with-values (lambda () (car (list *unspecified*))) list) => () Scheme or C calls of values will no longer create a values object when called without argument just like they did not do so for single arguments previously. Consequently SCM_VALUESP(SCM_UNSPECIFIED) remains false since SCM_UNSPECIFIED, like single values, is not a values object. --- libguile/eval.c | 13 +++---------- libguile/values.c | 6 ++++++ libguile/vm-engine.c | 18 ++++++++++++------ libguile/vm.c | 8 -------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/libguile/eval.c b/libguile/eval.c index 2488ee2..46a74f1 100644 --- a/libguile/eval.c +++ b/libguile/eval.c @@ -231,16 +231,7 @@ truncate_values (SCM x) if (SCM_LIKELY (scm_is_pair (l))) return scm_car (l); else - { - scm_ithrow (scm_from_latin1_symbol ("vm-run"), - scm_list_3 (scm_from_latin1_symbol ("vm-run"), - scm_from_locale_string - ("Too few values returned to continuation"), - SCM_EOL), - 1); - /* Not reached. */ - return SCM_BOOL_F; - } + return SCM_UNSPECIFIED; } } #define EVAL1(x, env) (truncate_values (eval ((x), (env)))) @@ -351,6 +342,8 @@ eval (SCM x, SCM env) v = scm_call_0 (producer); if (SCM_VALUESP (v)) args = scm_struct_ref (v, SCM_INUM0); + else if (scm_is_eq (v, SCM_UNSPECIFIED)) + args = SCM_EOL; else args = scm_list_1 (v); goto apply_proc; diff --git a/libguile/values.c b/libguile/values.c index 670e222..12c79d5 100644 --- a/libguile/values.c +++ b/libguile/values.c @@ -72,6 +72,8 @@ scm_c_nvalues (SCM obj) { if (SCM_LIKELY (SCM_VALUESP (obj))) return scm_ilength (scm_struct_ref (obj, SCM_INUM0)); + else if (scm_is_eq (obj, SCM_UNSPECIFIED)) + return 0; else return 1; } @@ -116,6 +118,8 @@ SCM_DEFINE (scm_values, "values", 0, 0, 1, SCM_VALIDATE_LIST_COPYLEN (1, args, n); if (n == 1) result = SCM_CAR (args); + else if (n == 0) + result = SCM_UNSPECIFIED; else result = scm_c_make_struct (scm_values_vtable, 0, 1, SCM_UNPACK (args)); @@ -130,6 +134,8 @@ scm_c_values (SCM *base, size_t nvalues) if (nvalues == 1) return *base; + else if (nvalues == 0) + return SCM_UNSPECIFIED; for (ret = SCM_EOL, walk = base + nvalues - 1; walk >= base; walk--) ret = scm_cons (*walk, ret); diff --git a/libguile/vm-engine.c b/libguile/vm-engine.c index c405b2b..5916cbb 100644 --- a/libguile/vm-engine.c +++ b/libguile/vm-engine.c @@ -266,8 +266,12 @@ old_fp[-1] = SCM_BOOL_F; \ old_fp[-2] = SCM_BOOL_F; \ /* Leave proc. */ \ - SCM_FRAME_LOCAL (old_fp, 1) = val; \ - vp->sp = &SCM_FRAME_LOCAL (old_fp, 1); \ + if (SCM_UNLIKELY (scm_is_eq (val, SCM_UNSPECIFIED)))\ + vp->sp = &SCM_FRAME_LOCAL (old_fp, 0); \ + else { \ + SCM_FRAME_LOCAL (old_fp, 1) = val; \ + vp->sp = &SCM_FRAME_LOCAL (old_fp, 1); \ + } \ POP_CONTINUATION_HOOK (old_fp); \ NEXT (0); \ } while (0) @@ -695,8 +699,8 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp, /* receive dst:12 proc:12 _:8 nlocals:24 * * Receive a single return value from a call whose procedure was in - * PROC, asserting that the call actually returned at least one - * value. Afterwards, resets the frame to NLOCALS locals. + * PROC, using *unspecified* if the call did not actually return at + * least one value. Afterwards, resets the frame to NLOCALS locals. */ VM_DEFINE_OP (6, receive, "receive", OP2 (U8_U12_U12, X8_U24) | OP_DST) { @@ -704,8 +708,10 @@ VM_NAME (scm_i_thread *thread, struct scm_vm *vp, scm_t_uint32 nlocals; UNPACK_12_12 (op, dst, proc); UNPACK_24 (ip[1], nlocals); - VM_ASSERT (FRAME_LOCALS_COUNT () > proc + 1, vm_error_no_values ()); - LOCAL_SET (dst, LOCAL_REF (proc + 1)); + if (SCM_UNLIKELY (FRAME_LOCALS_COUNT () <= proc + 1)) + LOCAL_SET (dst, SCM_UNSPECIFIED); + else + LOCAL_SET (dst, LOCAL_REF (proc + 1)); RESET_FRAME (nlocals); NEXT (2); } diff --git a/libguile/vm.c b/libguile/vm.c index 4516a68..ca6592b 100644 --- a/libguile/vm.c +++ b/libguile/vm.c @@ -479,7 +479,6 @@ static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN SCM static void vm_error_not_a_struct (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE; static void vm_error_not_a_vector (const char *subr, SCM v) SCM_NORETURN SCM_NOINLINE; static void vm_error_out_of_range (const char *subr, SCM k) SCM_NORETURN SCM_NOINLINE; -static void vm_error_no_values (void) SCM_NORETURN SCM_NOINLINE; static void vm_error_not_enough_values (void) SCM_NORETURN SCM_NOINLINE; static void vm_error_wrong_number_of_values (scm_t_uint32 expected) SCM_NORETURN SCM_NOINLINE; static void vm_error_continuation_not_rewindable (SCM cont) SCM_NORETURN SCM_NOINLINE; @@ -617,13 +616,6 @@ vm_error_out_of_range (const char *subr, SCM k) } static void -vm_error_no_values (void) -{ - vm_error ("Zero values returned to single-valued continuation", - SCM_UNDEFINED); -} - -static void vm_error_not_enough_values (void) { vm_error ("Too few values returned to continuation", SCM_UNDEFINED); -- 1.9.1