~ 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