>From 471b1778f2c85b66d654bd1dd225cd79879107c7 Mon Sep 17 00:00:00 2001 From: Evan Hanson Date: Thu, 3 Jul 2014 22:31:09 +1200 Subject: [PATCH 2/3] 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. --- NEWS | 3 +++ chicken-syntax.scm | 17 +---------------- expand.scm | 39 +++++++++++++++++++++++++++------------ tests/r7rs-tests.scm | 24 ++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 28 deletions(-) diff --git a/NEWS b/NEWS index bbb2b30..12fd0bf 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 ff3f494..baf6a35 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 40f0c50..1a951e7 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,13 @@ (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 +580,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 942b4f3..1933b2b 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) -- 1.7.10.4