syntax/parse: add docs for ~undo, #:undo

This commit is contained in:
Ryan Culpepper 2017-12-09 12:34:56 +01:00
parent 414fd515ab
commit e0a8058db5
2 changed files with 47 additions and 5 deletions

View File

@ -34,7 +34,7 @@ means specifically @tech{@Spattern}.
@racketgrammar*[#:literals (_ ~var ~literal ~or ~alt ~or* ~and ~not ~rest ~datum
~describe ~seq ~optional ~rep ~once ~between
~! ~bind ~fail ~parse ~peek ~peek-not ~do ~post)
~! ~bind ~fail ~parse ~peek ~peek-not ~do ~undo ~post)
[S-pattern
pvar-id
pvar-id:syntax-class-id
@ -98,7 +98,8 @@ means specifically @tech{@Spattern}.
(~parse S-pattern stx-expr)
(@#,ref[~and a] A-pattern ...+)
(@#,ref[~post a] A-pattern)
(~do defn-or-expr ...)]
(~do defn-or-expr ...)
(~undo defn-or-expr ...)]
[proper-S-pattern
#, @elem{a @svar{S-pattern} that is not a @svar{A-pattern}}]
[proper-H-pattern
@ -1095,6 +1096,36 @@ definition in a @racket[~do] block.
]
}
@specsubform[(@#,defhere[~undo] defn-or-expr ...)]{
Has no effect when initially matched, but if backtracking returns to a
point @emph{before} the @racket[~undo] pattern, the
@racket[defn-or-expr]s are executed. They are evaluated in the scope
of all previous attribute bindings.
Use @racket[~do] paired with @racket[~undo] to perform side effects
and then unwind them if the enclosing pattern is later discarded.
@examples[#:eval the-eval
(define total 0)
(define-syntax-class nat/add
(pattern (~and n:nat
(~do (printf "adding ~s\n" (syntax-e #'n))
(set! total (+ total (syntax-e #'n))))
(~undo (printf "subtracting ~s\n" (syntax-e #'n))
(set! total (- total (syntax-e #'n)))))))
(syntax-parse #'(1 2 3)
[(x:nat/add ...) 'ok])
total
(set! total 0)
(syntax-parse #'(1 2 3 bad)
[(x:nat/add ...) 'ok]
[_ 'something-else])
total
]
}
@specsubform[(@#,def[~post a] A-pattern)]{
Like the @Spattern version, @ref[~post s], but contains only

View File

@ -200,7 +200,8 @@ follows:
(code:line #:fail-when condition-expr message-expr)
(code:line #:fail-unless condition-expr message-expr)
(code:line #:when condition-expr)
(code:line #:do [def-or-expr ...])]
(code:line #:do [def-or-expr ...])
(code:line #:undo [def-or-expr ...])]
@specsubform[(code:line #:declare pvar-id stxclass maybe-role)
#:grammar
@ -325,7 +326,7 @@ backtracks. In other words, @racket[#:when] is like
Equivalent to @racket[#:post (~fail #:unless condition-expr #f)].
}
@specsubform[(code:line #:do [def-or-expr ...])]{
@specsubform[(code:line #:do [defn-or-expr ...])]{
Takes a sequence of definitions and expressions, which may be
intermixed, and evaluates them in the scope of all previous attribute
@ -336,7 +337,17 @@ There is currently no way to bind attributes using a @racket[#:do]
block. It is an error to shadow an attribute binding with a definition
in a @racket[#:do] block.
Equivalent to @racket[#:and (~do def-or-expr ...)].
Equivalent to @racket[#:and (~do defn-or-expr ...)].
}
@specsubform[(code:line #:undo [defn-or-expr ...])]{
Has no effect when initially matched, but if backtracking returns to a
point @emph{before} the @racket[#:undo] directive, the
@racket[defn-or-expr]s are executed. See @racket[~undo] for an
example.
Equivalent to @racket[#:and (~undo defn-or-expr ...)].
}