~ chicken-core (chicken-5) 3a00e602d3babbc89df699446ca6ee38bd4dbe19
commit 3a00e602d3babbc89df699446ca6ee38bd4dbe19
Author: Evan Hanson <evhan@foldling.org>
AuthorDate: Thu Jul 3 22:31:09 2014 +1200
Commit: Peter Bex <peter.bex@xs4all.nl>
CommitDate: Sat Jul 12 17:19:54 2014 +0200
Add full lambda list support for define-values forms in internal definitions
Since ##sys#canonicalize-body does its own rewriting of internal
definitions (including define-values), this factors the logic for
expanding multi-valued assignments out of the set!-values transformer
and into a dedicated procedure that both can use for binding variables.
Signed-off-by: Peter Bex <peter.bex@xs4all.nl>
diff --git a/NEWS b/NEWS
index e64569a2..dfaec6d6 100644
--- a/NEWS
+++ b/NEWS
@@ -29,6 +29,9 @@
##sys#zap-strings, ##sys#round, ##sys#foreign-number-vector-argument,
##sys#check-port-mode, ##sys#check-port*
+- Syntax expander
+ - define-values and set!-values now support full lambda lists
+
- C API
- Removed deprecated C_get_argument[_2] and
C_get_environment_variable[_2] functions.
diff --git a/chicken-syntax.scm b/chicken-syntax.scm
index ff3f4947..baf6a351 100644
--- a/chicken-syntax.scm
+++ b/chicken-syntax.scm
@@ -326,22 +326,7 @@
(##sys#er-transformer
(lambda (form r c)
(##sys#check-syntax 'set!-values form '(_ lambda-list _))
- (let ((formals (cadr form))
- (exp (caddr form)))
- (##sys#decompose-lambda-list
- formals
- (lambda (vars argc rest)
- (let ((aliases (if (symbol? formals) '() (map gensym formals)))
- (rest-alias (if (not rest) '() (gensym rest))))
- `(##sys#call-with-values
- (##core#lambda () ,exp)
- (##core#lambda
- ,(append aliases rest-alias)
- ,@(map (lambda (v a) `(##core#set! ,v ,a)) vars aliases)
- ,@(cond
- ((null? formals) '((##core#undefined)))
- ((null? rest-alias) '())
- (else `((##core#set! ,rest ,rest-alias)))))))))))))
+ (##sys#expand-multiple-values-assignment (cadr form) (caddr form)))))
(set! ##sys#define-values-definition
(##sys#extend-macro-environment
diff --git a/expand.scm b/expand.scm
index 40f0c501..72e246a4 100644
--- a/expand.scm
+++ b/expand.scm
@@ -438,6 +438,26 @@
"redefinition of currently used defining form" ; help me find something better
form))
+;;; Expansion of multiple values assignments.
+;
+; Given a lambda list and a multi-valued expression, returns a form that
+; will `set!` each variable to its corresponding value in order.
+
+(define (##sys#expand-multiple-values-assignment formals expr)
+ (##sys#decompose-lambda-list
+ formals
+ (lambda (vars argc rest)
+ (let ((aliases (if (symbol? formals) '() (map gensym formals)))
+ (rest-alias (if (not rest) '() (gensym rest))))
+ `(##sys#call-with-values
+ (##core#lambda () ,expr)
+ (##core#lambda
+ ,(append aliases rest-alias)
+ ,@(map (lambda (v a) `(##core#set! ,v ,a)) vars aliases)
+ ,@(cond
+ ((null? formals) '((##core#undefined)))
+ ((null? rest-alias) '())
+ (else `((##core#set! ,rest ,rest-alias))))))))))
;;; Expansion of bodies (and internal definitions)
;
@@ -478,18 +498,14 @@
(result
`(##core#let
,(##sys#map
- (lambda (v) (##sys#list v (##sys#list '##core#undefined)))
- (apply ##sys#append vars mvars) )
+ (lambda (v) (##sys#list v '(##core#undefined)))
+ (foldl (lambda (l v) ; flatten multi-value formals
+ (##sys#append l (##sys#decompose-lambda-list
+ v (lambda (a _ _) a))))
+ vars
+ mvars))
,@(map (lambda (v x) `(##core#set! ,v ,x)) vars (reverse vals))
- ,@(map (lambda (vs x)
- (let ([tmps (##sys#map gensym vs)])
- `(##sys#call-with-values
- (##core#lambda () ,x)
- (##core#lambda
- ,tmps
- ,@(map (lambda (v t)
- `(##core#set! ,v ,t))
- vs tmps) ) ) ) )
+ ,@(map ##sys#expand-multiple-values-assignment
(reverse mvars)
(reverse mvals) )
,@body) ) )
@@ -565,7 +581,7 @@
(fini/syntax vars vals mvars mvals body) )
((comp 'define-values head)
;;XXX check for any of the variables being `define-values'
- (##sys#check-syntax 'define-values x '(_ #(_ 0) _) #f se)
+ (##sys#check-syntax 'define-values x '(_ lambda-list _) #f se)
(loop rest vars vals (cons (cadr x) mvars) (cons (caddr x) mvals)))
((comp '##core#begin head)
(loop (##sys#append (cdr x) rest) vars vals mvars mvals) )
diff --git a/tests/r7rs-tests.scm b/tests/r7rs-tests.scm
index 942b4f33..1933b2b3 100644
--- a/tests/r7rs-tests.scm
+++ b/tests/r7rs-tests.scm
@@ -136,6 +136,30 @@
(lambda () (force (delay (values))))
(lambda mv (test '() #f mv)))
+
+(SECTION 5 3)
+
+(test '(1 2)
+ (lambda ()
+ (define-values (a b) (values 1 2))
+ (list a b)))
+
+(test '(1 (2))
+ (lambda ()
+ (define-values (a . b) (values 1 2))
+ (list a b)))
+
+(test '((1 2))
+ (lambda ()
+ (define-values a (values 1 2))
+ (list a)))
+
+(test 'ok ; Just tests that no error is thrown.
+ (lambda ()
+ (define-values () (values))
+ 'ok))
+
+
(SECTION 6 6)
Trap