Skip to content

Commit

Permalink
add while / break
Browse files Browse the repository at this point in the history
  • Loading branch information
bennn committed Oct 11, 2021
1 parent c4ad8a7 commit 117e509
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 0 deletions.
1 change: 1 addition & 0 deletions index.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
@include-example{optional-assert}
@include-example{cross-macro-communication}
@include-example{let-star}
@include-example{while-break}
@include-example{def}
@include-example{conditional-require}
@include-example{multi-check-true}
Expand Down
30 changes: 30 additions & 0 deletions while-break/while-break-test.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#lang racket/base
(module+ test
(require rackunit racket/port syntax-parse-example/while-break/while-break)

(test-begin
(define x 5)

(test-case "ex1"
(check-equal?
(with-output-to-string
(lambda ()
(while (> x 0)
(displayln x)
(set! x (sub1 x)))))
"5\n4\n3\n2\n1\n"))

(set! x 5)

(test-case "ex2"
(check-equal?
(with-output-to-string
(lambda ()
(while #t
(displayln x)
(set! x (sub1 x))
(unless (> x 0)
(break)))))
"5\n4\n3\n2\n1\n")))

)
17 changes: 17 additions & 0 deletions while-break/while-break.rkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#lang racket/base
(provide while break)
(require syntax/parse/define racket/stxparam (for-syntax racket/base))

(define-syntax-parameter break
(lambda (stx)
(raise-syntax-error (syntax-e stx) "can only be used inside `while`")))

(define-syntax-parse-rule (while condition body ...)
(call/ec
(λ (return)
(syntax-parameterize ([break (make-rename-transformer #'return)])
(let loop ()
(when condition
(begin body ...
(loop))))))))

46 changes: 46 additions & 0 deletions while-break/while-break.scrbl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#lang syntax-parse-example
@require[
(for-label racket/base syntax/parse syntax-parse-example/while-break/while-break)]

@(define while-break-eval
(make-base-eval '(require syntax-parse-example/while-break/while-break)))

@title{Basic while loop equipped with break}
@stxbee2021["countvajhula" 20]

@; =============================================================================

@defmodule[syntax-parse-example/while-break/while-break]{}

@defform[(while test body ...+)]{

@examples[#:eval while-break-eval
(define x 5)

(while (> x 0)
(displayln x)
(set! x (sub1 x)))

(set! x 5)

(while #t
(displayln x)
(set! x (sub1 x))
(unless (> x 0)
(break)))
]


@; TODO add description here
}

@defidform[break]{
May only appear within an @racket[while] form.
}

The macro uses an escape continuation to provide the semantics of @racket[break], and
leverages it using a syntax parameter so that the continuation is accessible
in the lexical scope of the @racket[while] body, and also so that @racket[break] is a syntax
error outside the @racket[while] loop.

@racketfile{while-break.rkt}

0 comments on commit 117e509

Please sign in to comment.