>From a647d9ed65f44df527e513464093447f56e24ead Mon Sep 17 00:00:00 2001 From: felix Date: Thu, 1 Aug 2013 11:52:57 +0200 Subject: [PATCH] Adds "letrec*" and minimal tests. "letrec*" ist not used explicitly and only in internal expansions to avoid bootstrapping issues. Internal defines expand into uses of "letrec*". Signed-off-by: Peter Bex --- NEWS | 2 ++ chicken-syntax.scm | 11 ++++++----- compiler.scm | 21 ++++++++++++++++++++- eval.scm | 19 ++++++++++++++++++- expand.scm | 11 ++++++++++- extras.scm | 2 +- manual/Non-standard macros and special forms | 7 +++++++ tests/syntax-tests.scm | 16 ++++++++++++++++ 8 files changed, 80 insertions(+), 9 deletions(-) diff --git a/NEWS b/NEWS index 2d9ab2b..4d96844 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,8 @@ - For R7RS compatibility, named character literals #\escape and #\null are supported as aliases for #\esc and #\nul. WRITE will output R7RS names. - The CASE form accepts => proc syntax, like COND (as specified by R7RS). + - letrec* was added for R7RS compatibility. Plain letrec no longer behaves + like letrec*. - Compiler - the "inline" declaration does not force inlining anymore as recursive diff --git a/chicken-syntax.scm b/chicken-syntax.scm index ce1bdf6..29ed89d 100644 --- a/chicken-syntax.scm +++ b/chicken-syntax.scm @@ -422,6 +422,7 @@ `(,%let-values (,(car vbindings)) ,(fold (cdr vbindings))) ) ) )))) +;;XXX do we need letrec*-values ? (##sys#extend-macro-environment 'letrec-values '() (##sys#er-transformer @@ -1056,11 +1057,11 @@ (##sys#check-syntax 'rec form '(_ _ . _)) (let ((head (cadr form))) (if (pair? head) - `(##core#letrec ((,(car head) - (##core#lambda ,(cdr head) - ,@(cddr form)))) - ,(car head)) - `(##core#letrec ((,head ,@(cddr form))) ,head)))))) + `(##core#letrec* ((,(car head) + (##core#lambda ,(cdr head) + ,@(cddr form)))) + ,(car head)) + `(##core#letrec* ((,head ,@(cddr form))) ,head)))))) ;;; Definitions available at macroexpansion-time: diff --git a/compiler.scm b/compiler.scm index 3cadc6b..0398eef 100644 --- a/compiler.scm +++ b/compiler.scm @@ -105,6 +105,7 @@ ; (##core#let ({( )}) ) ; (##core#let ({( )}) ) ; (##core#letrec ({( )}) ) +; (##core#letrec* ({( )}) ) ; (##core#let-location [] ) ; (##core#lambda ) ; (##core#lambda ({}+ [. ]) ) @@ -616,7 +617,7 @@ (append aliases e) se2 dest ldest h ln) ) ) ) - ((##core#letrec) + ((##core#letrec*) (let ((bindings (cadr x)) (body (cddr x)) ) (walk @@ -630,6 +631,24 @@ (##core#let () ,@body) ) e se dest ldest h ln))) + ((##core#letrec) + (let* ((bindings (cadr x)) + (vars (unzip1 bindings)) + (tmps (map gensym vars)) + (body (cddr x)) ) + (walk + `(##core#let + ,(map (lambda (b) + (list (car b) '(##core#undefined))) + bindings) + (##core#let + ,(map (lambda (t b) (list t (cadr b))) tmps bindings) + ,@(map (lambda (v t) + `(##core#set! ,v ,t)) + vars tmps) + (##core#let () ,@body) ) ) + e se dest ldest h ln))) + ((##core#lambda) (let ((llist (cadr x)) (obody (cddr x)) ) diff --git a/eval.scm b/eval.scm index 4adc696..607246b 100644 --- a/eval.scm +++ b/eval.scm @@ -436,7 +436,7 @@ (##sys#setslot v2 i (##core#app (##sys#slot vlist 0) v)) ) (##core#app body (cons v2 v)) ) ) ) ] ) ) ] - ((##core#letrec) + ((##core#letrec*) (let ((bindings (cadr x)) (body (cddr x)) ) (compile @@ -450,6 +450,23 @@ (##core#let () ,@body) ) e h tf cntr se))) + ((##core#letrec) + (let* ((bindings (cadr x)) + (vars (map car bindings)) + (tmps (map gensym vars)) + (body (cddr x)) ) + (compile + `(##core#let + ,(map (lambda (b) + (list (car b) '(##core#undefined))) + bindings) + (##core#let ,(map (lambda (t b) (list t (cadr b))) tmps bindings) + ,@(map (lambda (v t) + `(##core#set! ,v ,t)) + vars tmps) + (##core#let () ,@body) ) ) + e h tf cntr se))) + [(##core#lambda) (##sys#check-syntax 'lambda x '(_ lambda-list . #(_ 1)) #f se) (let* ([llist (cadr x)] diff --git a/expand.scm b/expand.scm index d5f3652..2f34df3 100644 --- a/expand.scm +++ b/expand.scm @@ -277,7 +277,7 @@ (let ([bs (cadr body)]) (values `(##core#app - (##core#letrec + (##core#letrec* ([,bindings (##core#loop-lambda ,(map (lambda (b) (car b)) bs) ,@(cddr body))]) @@ -1050,6 +1050,15 @@ `(##core#let ,@(cdr x))))) (##sys#extend-macro-environment + 'letrec* + '() + (##sys#er-transformer + (lambda (x r c) + (##sys#check-syntax 'letrec* x '(_ #((symbol _) 0) . #(_ 1))) + (check-for-multiple-bindings (cadr x) x "letrec*") + `(##core#letrec* ,@(cdr x))))) + +(##sys#extend-macro-environment 'letrec '() (##sys#er-transformer diff --git a/extras.scm b/extras.scm index f6daf1c..49ab5cf 100644 --- a/extras.scm +++ b/extras.scm @@ -557,7 +557,7 @@ (define (style head) (case head - ((lambda let* letrec define) pp-lambda) + ((lambda let* letrec letrec* define) pp-lambda) ((if set!) pp-if) ((cond) pp-cond) ((case) pp-case) diff --git a/manual/Non-standard macros and special forms b/manual/Non-standard macros and special forms index ee22283..728ce3b 100644 --- a/manual/Non-standard macros and special forms +++ b/manual/Non-standard macros and special forms @@ -172,6 +172,13 @@ executed normally and the result of the last expression is the result of the {{and-let*}} form. See also the documentation for [[http://srfi.schemers.org/srfi-2/srfi-2.html|SRFI-2]]. +==== letrec* + +(letrec* ((VARIABLE EXPRESSION) ...) BODY ...) + +Implements R6RS/R7RS {{letrec*}}. {{letrec*}} is similar to {{letrec}} but +binds the variables sequentially and is to {{letrec}} what {{let*}} is to {{let}}. + ==== rec (rec NAME EXPRESSION)
diff --git a/tests/syntax-tests.scm b/tests/syntax-tests.scm index c496270..a5f4323 100644 --- a/tests/syntax-tests.scm +++ b/tests/syntax-tests.scm @@ -1100,3 +1100,19 @@ take ((_) (begin (define req 2) (display req) (newline))))) (bar) (assert (eq? req 1))) + + +;; letrec vs. letrec* + +;;XXX this fails - the optimizer substitutes "foo" for it's known constant value +#;(t (void) (letrec ((foo 1) + (bar foo)) + bar)) + +(t (void) (letrec ((foo (gc)) + (bar foo)) + bar)) + +(t 1 (letrec* ((foo 1) + (bar foo)) + bar)) -- 1.8.2.3