for/set: same body handling as for/list, etc.

Change `for/set` to use `split-for-body`. Also, adjust the
documentation of `for/fold/derived` to recommend using
`split-for-body`.

Closes #3351
This commit is contained in:
Matthew Flatt 2020-08-16 16:29:44 -06:00
parent 413106413d
commit 7d8a95a943
3 changed files with 76 additions and 17 deletions

View File

@ -1,5 +1,6 @@
#lang scribble/doc #lang scribble/doc
@(require "mz.rkt") @(require "mz.rkt"
(for-label syntax/for-body))
@title[#:tag "for"]{Iterations and Comprehensions: @racket[for], @racket[for/list], ...} @title[#:tag "for"]{Iterations and Comprehensions: @racket[for], @racket[for/list], ...}
@ -560,18 +561,25 @@ Like @racket[for/list], etc., but with the implicit nesting of
Like @racket[for/fold], but the extra @racket[orig-datum] is used as the Like @racket[for/fold], but the extra @racket[orig-datum] is used as the
source for all syntax errors. source for all syntax errors.
A macro that expands to @racket[for/fold/derived] should typically use
@racket[split-for-body] to handle the possibility of macros and other
definitions mixed with keywords like @racket[#:break].
@mz-examples[#:eval for-eval @mz-examples[#:eval for-eval
(require (for-syntax syntax/for-body))
(define-syntax (for/digits stx) (define-syntax (for/digits stx)
(syntax-case stx () (syntax-case stx ()
[(_ clauses body ... tail-expr) [(_ clauses body ... tail-expr)
(with-syntax ([original stx]) (with-syntax ([original stx]
[((pre-body ...) (post-body ...))
(split-for-body stx #'(body ... tail-expr))])
#'(let-values #'(let-values
([(n k) ([(n k)
(for/fold/derived (for/fold/derived
original ([n 0] [k 1]) original ([n 0] [k 1])
clauses clauses
body ... pre-body ...
(values (+ n (* tail-expr k)) (* k 10)))]) (values (+ n (* (let () post-body ...) k)) (* k 10)))])
n))])) n))]))
@code:comment{If we misuse for/digits, we can get good error reporting} @code:comment{If we misuse for/digits, we can get good error reporting}
@ -592,12 +600,14 @@ source for all syntax errors.
(define-syntax (for/max stx) (define-syntax (for/max stx)
(syntax-case stx () (syntax-case stx ()
[(_ clauses body ... tail-expr) [(_ clauses body ... tail-expr)
(with-syntax ([original stx]) (with-syntax ([original stx]
[((pre-body ...) (post-body ...))
(split-for-body stx #'(body ... tail-expr))])
#'(for/fold/derived original #'(for/fold/derived original
([current-max -inf.0]) ([current-max -inf.0])
clauses clauses
body ... pre-body ...
(define maybe-new-max tail-expr) (define maybe-new-max (let () post-body ...))
(if (> maybe-new-max current-max) (if (> maybe-new-max current-max)
maybe-new-max maybe-new-max
current-max)))])) current-max)))]))
@ -614,16 +624,19 @@ source for all syntax errors.
Like @racket[for*/fold], but the extra @racket[orig-datum] is used as the source for all syntax errors. Like @racket[for*/fold], but the extra @racket[orig-datum] is used as the source for all syntax errors.
@mz-examples[#:eval for-eval @mz-examples[#:eval for-eval
(require (for-syntax syntax/for-body))
(define-syntax (for*/digits stx) (define-syntax (for*/digits stx)
(syntax-case stx () (syntax-case stx ()
[(_ clauses body ... tail-expr) [(_ clauses body ... tail-expr)
(with-syntax ([original stx]) (with-syntax ([original stx]
[((pre-body ...) (post-body ...))
(split-for-body stx #'(body ... tail-expr))])
#'(let-values #'(let-values
([(n k) ([(n k)
(for*/fold/derived original ([n 0] [k 1]) (for*/fold/derived original ([n 0] [k 1])
clauses clauses
body ... pre-body ...
(values (+ n (* tail-expr k)) (* k 10)))]) (values (+ n (* (let () post-body ...) k)) (* k 10)))])
n))])) n))]))
(eval:error (eval:error

View File

@ -563,6 +563,50 @@
#:final (= i 2) #:final (= i 2)
(add1 i))) (add1 i)))
;; ----------------------------------------
(test (set 0) 'non-expression-last-form
(for/set ([x '(1)])
(begin
(define-syntax (m stx) #'0)
m)))
(test (set 10) 'non-expression-last-form
(for/set ([x '(1)])
(define (f x) (g x))
(define-syntax-rule (m g)
(begin
(define (g x) 10)
(f 1)))
(m g)))
(test (mutable-set 0) 'non-expression-last-form
(for/mutable-set ([x '(1)])
(begin
(define-syntax (m stx) #'0)
m)))
(test (set 0) 'non-expression-last-form
(for*/set ([x '(1)])
(begin
(define-syntax (m stx) #'0)
m)))
(test (set 10) 'non-expression-last-form
(for*/set ([x '(1)])
(define (f x) (g x))
(define-syntax-rule (m g)
(begin
(define (g x) 10)
(f 1)))
(m g)))
(test (mutable-set 0) 'non-expression-last-form
(for*/mutable-set ([x '(1)])
(begin
(define-syntax (m stx) #'0)
m)))
;; ---------------------------------------- ;; ----------------------------------------
;; chaperone-hash-set tests ;; chaperone-hash-set tests

View File

@ -8,7 +8,7 @@
racket/unsafe/ops racket/unsafe/ops
(only-in racket/syntax format-symbol) (only-in racket/syntax format-symbol)
(only-in racket/generic exn:fail:support) (only-in racket/generic exn:fail:support)
(for-syntax racket/base racket/syntax)) (for-syntax racket/base racket/syntax syntax/for-body))
(provide set seteq seteqv (provide set seteq seteqv
weak-set weak-seteq weak-seteqv weak-set weak-seteq weak-seteqv
@ -1045,13 +1045,14 @@
(lambda (stx) (lambda (stx)
(syntax-case stx () (syntax-case stx ()
[(form clauses body ... expr) [(form clauses body ... expr)
(with-syntax ([original stx]) (with-syntax ([original stx]
[((pre-body ...) (post-body ...)) (split-for-body stx #'(body ... expr))])
(syntax-protect (syntax-protect
#'(immutable-custom-set #'(immutable-custom-set
(begin0 #f (dprintf "~a\n" 'form)) (begin0 #f (dprintf "~a\n" 'form))
(for_/fold/derived original ([table (make-table)]) clauses (for_/fold/derived original ([table (make-table)]) clauses
body ... pre-body ...
(hash-set table expr #t)))))])))) (hash-set table (let () post-body ...) #t)))))]))))
(define (immutable-fors table-id) (define (immutable-fors table-id)
(values (immutable-for #'for/fold/derived table-id) (values (immutable-for #'for/fold/derived table-id)
@ -1064,13 +1065,14 @@
(lambda (stx) (lambda (stx)
(syntax-case stx () (syntax-case stx ()
[(form clauses body ... expr) [(form clauses body ... expr)
(with-syntax ([original stx]) (with-syntax ([original stx]
[((pre-body ...) (post-body ...)) (split-for-body stx #'(body ... expr))])
(syntax-protect (syntax-protect
#'(let ([table (make-table)]) #'(let ([table (make-table)])
(dprintf "~a\n" 'form) (dprintf "~a\n" 'form)
(for_/fold/derived original () clauses (for_/fold/derived original () clauses
body ... pre-body ...
(hash-set! table expr #t) (hash-set! table (let () post-body ...) #t)
(values)) (values))
(make-set #f table))))])))) (make-set #f table))))]))))