Skip to content

Commit 117e509

Browse files
committed
1 parent c4ad8a7 commit 117e509

File tree

4 files changed

+94
-0
lines changed

4 files changed

+94
-0
lines changed

index.scrbl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
@include-example{optional-assert}
2121
@include-example{cross-macro-communication}
2222
@include-example{let-star}
23+
@include-example{while-break}
2324
@include-example{def}
2425
@include-example{conditional-require}
2526
@include-example{multi-check-true}

while-break/while-break-test.rkt

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#lang racket/base
2+
(module+ test
3+
(require rackunit racket/port syntax-parse-example/while-break/while-break)
4+
5+
(test-begin
6+
(define x 5)
7+
8+
(test-case "ex1"
9+
(check-equal?
10+
(with-output-to-string
11+
(lambda ()
12+
(while (> x 0)
13+
(displayln x)
14+
(set! x (sub1 x)))))
15+
"5\n4\n3\n2\n1\n"))
16+
17+
(set! x 5)
18+
19+
(test-case "ex2"
20+
(check-equal?
21+
(with-output-to-string
22+
(lambda ()
23+
(while #t
24+
(displayln x)
25+
(set! x (sub1 x))
26+
(unless (> x 0)
27+
(break)))))
28+
"5\n4\n3\n2\n1\n")))
29+
30+
)

while-break/while-break.rkt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#lang racket/base
2+
(provide while break)
3+
(require syntax/parse/define racket/stxparam (for-syntax racket/base))
4+
5+
(define-syntax-parameter break
6+
(lambda (stx)
7+
(raise-syntax-error (syntax-e stx) "can only be used inside `while`")))
8+
9+
(define-syntax-parse-rule (while condition body ...)
10+
(call/ec
11+
(λ (return)
12+
(syntax-parameterize ([break (make-rename-transformer #'return)])
13+
(let loop ()
14+
(when condition
15+
(begin body ...
16+
(loop))))))))
17+

while-break/while-break.scrbl

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#lang syntax-parse-example
2+
@require[
3+
(for-label racket/base syntax/parse syntax-parse-example/while-break/while-break)]
4+
5+
@(define while-break-eval
6+
(make-base-eval '(require syntax-parse-example/while-break/while-break)))
7+
8+
@title{Basic while loop equipped with break}
9+
@stxbee2021["countvajhula" 20]
10+
11+
@; =============================================================================
12+
13+
@defmodule[syntax-parse-example/while-break/while-break]{}
14+
15+
@defform[(while test body ...+)]{
16+
17+
@examples[#:eval while-break-eval
18+
(define x 5)
19+
20+
(while (> x 0)
21+
(displayln x)
22+
(set! x (sub1 x)))
23+
24+
(set! x 5)
25+
26+
(while #t
27+
(displayln x)
28+
(set! x (sub1 x))
29+
(unless (> x 0)
30+
(break)))
31+
]
32+
33+
34+
@; TODO add description here
35+
}
36+
37+
@defidform[break]{
38+
May only appear within an @racket[while] form.
39+
}
40+
41+
The macro uses an escape continuation to provide the semantics of @racket[break], and
42+
leverages it using a syntax parameter so that the continuation is accessible
43+
in the lexical scope of the @racket[while] body, and also so that @racket[break] is a syntax
44+
error outside the @racket[while] loop.
45+
46+
@racketfile{while-break.rkt}

0 commit comments

Comments
 (0)