parent
fe5adac3db
commit
3ea1f05c51
70
turnstile/mode.rkt
Normal file
70
turnstile/mode.rkt
Normal file
|
@ -0,0 +1,70 @@
|
|||
#lang racket/base
|
||||
(provide (struct-out mode)
|
||||
make-mode
|
||||
current-mode
|
||||
with-mode
|
||||
make-param-mode)
|
||||
|
||||
|
||||
;; mode object. contains setup routine and teardown routine
|
||||
;; as fields.
|
||||
(struct mode (setup-fn teardown-fn))
|
||||
|
||||
(define (make-mode #:setup [setup-fn void]
|
||||
#:teardown [teardown-fn void])
|
||||
(mode setup-fn teardown-fn))
|
||||
|
||||
|
||||
;; apply the given mode for the successive expressions.
|
||||
;; e.g.
|
||||
;; (with-mode (mode (λ () (display "before "))
|
||||
;; (λ () (display "after\n")))
|
||||
;; (display "middle "))
|
||||
;; ->
|
||||
;; before middle after
|
||||
;;
|
||||
;; (with-mode <mode> <body> ...)
|
||||
(define-syntax-rule (with-mode mode-expr body ...)
|
||||
(let* ([the-mode mode-expr])
|
||||
((mode-setup-fn the-mode))
|
||||
(begin0 (parameterize ([current-mode the-mode]) body ...)
|
||||
((mode-teardown-fn the-mode)))))
|
||||
|
||||
|
||||
;; the current set mode. useful for #:submode/mode
|
||||
(define current-mode
|
||||
(make-parameter (mode void void)))
|
||||
|
||||
|
||||
;; returns a mode that sets the given
|
||||
;; parameter to the given value, for its duration.
|
||||
;; similar to (parameterize ([P value]) ...)
|
||||
;;
|
||||
;; make-param-mode : ∀T. (parameterof T) T -> mode?
|
||||
(define (make-param-mode P value)
|
||||
(let* ([swap! (λ ()
|
||||
(let ([cur (P)])
|
||||
(P value)
|
||||
(set! value cur)))])
|
||||
(mode swap! swap!)))
|
||||
|
||||
|
||||
|
||||
(module+ test
|
||||
(require rackunit)
|
||||
|
||||
(define color (make-parameter 'red))
|
||||
|
||||
(define ->blue (make-param-mode color 'blue))
|
||||
(define ->green (make-param-mode color 'green))
|
||||
|
||||
(with-mode ->blue
|
||||
(check-equal? (color) 'blue))
|
||||
(check-equal? (color) 'red)
|
||||
|
||||
(with-mode ->green
|
||||
(check-equal? (color) 'green)
|
||||
(with-mode ->blue
|
||||
(check-equal? (color) 'blue))
|
||||
(check-equal? (color) 'green))
|
||||
)
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
@(require scribble/example racket/sandbox
|
||||
(for-label racket/base
|
||||
turnstile/mode
|
||||
(except-in turnstile/turnstile ⊢ stx mk-~ mk-?))
|
||||
"doc-utils.rkt" "common.rkt")
|
||||
|
||||
|
@ -59,15 +60,17 @@ and then press Control-@litchar{\}.
|
|||
[expr-template (code:line @#,racket[quasisyntax] @#,tech:template)]
|
||||
[type-template (code:line @#,racket[quasisyntax] @#,tech:template)]
|
||||
[key identifier?]
|
||||
[premise (code:line [⊢ tc ...] ooo ...)
|
||||
(code:line [ctx ⊢ tc ...] ooo ...)
|
||||
(code:line [ctx-elem ... ⊢ tc ...] ooo ...)
|
||||
(code:line [ctx ctx ⊢ tc ...] ooo ...)
|
||||
[premise (code:line [⊢ tc ... prem-options] ooo ...)
|
||||
(code:line [ctx-elem ... ⊢ tc ... prem-options] ooo ...)
|
||||
(code:line [ctx ⊢ tc ... prem-options] ooo ...)
|
||||
(code:line [ctx ctx ⊢ tc ... prem-options] ooo ...)
|
||||
(code:line [⊢ . tc-elem] ooo ...)
|
||||
(code:line [ctx ⊢ . tc-elem] ooo ...)
|
||||
(code:line [ctx-elem ... ⊢ . tc-elem] ooo ...)
|
||||
(code:line [ctx ⊢ . tc-elem] ooo ...)
|
||||
(code:line [ctx ctx ⊢ . tc-elem] ooo ...)
|
||||
type-relation
|
||||
(code:line #:mode mode-expr (premise ...))
|
||||
(code:line #:submode fn-expr (premise ...))
|
||||
(code:line @#,racket[syntax-parse] @#,tech:pat-directive)]
|
||||
[ctx (ctx-elem ...)]
|
||||
[ctx-elem (code:line [id ≫ id key template ... ...] ooo ...)
|
||||
|
@ -83,6 +86,9 @@ and then press Control-@litchar{\}.
|
|||
(code:line [type-template τ= type-template #:for expr-template] ooo ...)
|
||||
(code:line [type-template τ⊑ type-template] ooo ...)
|
||||
(code:line [type-template τ⊑ type-template #:for expr-template] ooo ...)]
|
||||
[prem-options (code:line)
|
||||
(code:line #:mode mode-expr)
|
||||
(code:line #:submode fn-expr)]
|
||||
[conclusion [⊢ expr-template ⇒ type-template]
|
||||
[⊢ expr-template ⇒ key template]
|
||||
[⊢ expr-template (⇒ key template) ooo ...]
|
||||
|
@ -142,6 +148,26 @@ pattern @racket[x ... y ...] will not work as expected.
|
|||
For convenience, lone identifiers written to the left of the turnstile are
|
||||
automatically treated as type variables.
|
||||
|
||||
@italic{Modes}
|
||||
|
||||
The keyword @racket[#:mode], when appearing at end of a typechecking rule,
|
||||
sets the parameter @racket[current-mode] to the @racket[mode] object supplied
|
||||
by @racket[_mode-expr], for the extent of that rule. @racket[#:mode], when
|
||||
appearing as its own premise, sets the @racket[current-mode] parameter for the
|
||||
extent of all the grouped sub-premises.
|
||||
|
||||
The keyword @racket[#:submode] is similar to @racket[#:mode], but it calls
|
||||
@racket[(_fn-expr (current-mode))] to obtain the new mode object. Thus,
|
||||
@racket[#:mode (_fn-expr (current-mode))] is identical to @racket[#:submode
|
||||
_fn-expr].
|
||||
|
||||
See @secref{Modes} for more details.
|
||||
|
||||
WARNING: @racket[#:mode] is unaware of the backtracking behavior of
|
||||
@racket[syntax-parse]. If pattern backtracking escapes a @racket[#:mode] group, it may
|
||||
leave @racket[current-mode] in an undesirable state.
|
||||
|
||||
|
||||
@; ----------------------------------------------------------------------------
|
||||
@bold{Conclusion}
|
||||
|
||||
|
@ -692,7 +718,70 @@ The possible variances are:
|
|||
|
||||
@defproc[(variance? [v any/c]) boolean/c]{
|
||||
Predicate that recognizes the variance values.}
|
||||
|
||||
|
||||
|
||||
@section{Modes}
|
||||
|
||||
@defmodule[turnstile/mode #:use-sources (turnstile/mode)]
|
||||
@(define mode-ev
|
||||
(let ([ev (make-base-eval)])
|
||||
(ev '(require turnstile/mode))
|
||||
ev))
|
||||
|
||||
Modes are typically used by the @racket[#:mode] and @racket[#:submode]
|
||||
keywords in @racket[define-typed-syntax] (and related forms). When judgements
|
||||
are parameterized by a @racket[mode] value, the parameter
|
||||
@racket[current-mode] is set to that value for the extend of the
|
||||
sub-premises. Additionally, the function @racket[mode-setup-fn] is called
|
||||
before setting @racket[current-mode], and the function
|
||||
@racket[mode-teardown-fn] is called after @racket[current-mode] is restored to
|
||||
its previous value.
|
||||
|
||||
@defstruct*[mode ([setup-fn (-> any)] [teardown-fn (-> any)])]{
|
||||
Structure type for modes. Modes can be used to parameterize type judgements
|
||||
or groups of type judgements, to give additional context and to help enable
|
||||
flow-sensitive languages.
|
||||
|
||||
User defined modes should be defined as structs that inherit from @racket[mode].
|
||||
}
|
||||
|
||||
@defproc[(make-mode [#:setup setup-fn (-> any) void]
|
||||
[#:teardown teardown-fn (-> any) void]) mode?]{
|
||||
Constructs a new @racket[mode] object with the given setup and teardown functions.
|
||||
}
|
||||
|
||||
@defparam[current-mode mode mode? #:value (make-mode)]{
|
||||
A parameter that holds the current mode. Typically parameterized using the keywords
|
||||
@racket[#:mode] and @racket[#:submode] from @racket[define-typed-syntax] forms.
|
||||
}
|
||||
|
||||
@defform[(with-mode mode-expr body ...+)
|
||||
#:contracts ([mode-expr mode?])]{
|
||||
The result of @racket[with-mode] is the result of the last @racket[_body].
|
||||
The parameter @racket[current-mode] is assigned to the result of
|
||||
@racket[_mode-expr] for the extent of the @racket[_body] expressions. The
|
||||
function @racket[mode-setup-fn] is called on the result of
|
||||
@racket[_mode-expr] before @racket[current-mode] is set, and the function
|
||||
@racket[mode-teardown-fn] is called after @racket[current-mode] is restored
|
||||
to its previous value.
|
||||
|
||||
@examples[#:eval mode-ev
|
||||
(define-struct (my-mode mode) ())
|
||||
(define M (make-my-mode (λ () (displayln "M setup"))
|
||||
(λ () (displayln "M teardown"))))
|
||||
(with-mode M
|
||||
(displayln (current-mode)))]}
|
||||
|
||||
@defproc[(make-param-mode [param parameter?] [value any/c]) mode?]{
|
||||
Creates a @racket[mode] that assigns the given parameter to the given
|
||||
value for the extent of the mode.
|
||||
|
||||
@examples[#:eval mode-ev
|
||||
(define current-scope (make-parameter 'outer))
|
||||
(with-mode (make-param-mode current-scope 'inner)
|
||||
(displayln (current-scope)))]}
|
||||
|
||||
|
||||
@section{Miscellaneous Syntax Object Functions}
|
||||
|
||||
These are all phase 1 functions.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang racket/base
|
||||
|
||||
(provide (except-out (all-from-out macrotypes/typecheck)
|
||||
(provide (except-out (all-from-out macrotypes/typecheck)
|
||||
-define-typed-syntax -define-syntax-category)
|
||||
define-typed-syntax
|
||||
define-typed-variable-syntax
|
||||
|
@ -66,8 +66,9 @@
|
|||
(module syntax-classes racket/base
|
||||
(provide (all-defined-out))
|
||||
(require (for-meta 0 (submod ".." typecheck+))
|
||||
(for-meta -1 (submod ".." typecheck+)
|
||||
(except-in macrotypes/typecheck #%module-begin mk-~ mk-?))
|
||||
(for-meta -1 (submod ".." typecheck+)
|
||||
(except-in macrotypes/typecheck #%module-begin mk-~ mk-?)
|
||||
"mode.rkt")
|
||||
(for-meta -2 (except-in macrotypes/typecheck #%module-begin)))
|
||||
(define-syntax-class ---
|
||||
[pattern dashes:id
|
||||
|
@ -91,7 +92,7 @@
|
|||
(define (add-lists stx n)
|
||||
(cond [(zero? n) stx]
|
||||
[else (add-lists (list stx) (sub1 n))]))
|
||||
|
||||
|
||||
(define-splicing-syntax-class props
|
||||
[pattern (~and (~seq stuff ...) (~seq (~seq k:id v) ...))])
|
||||
(define-splicing-syntax-class ⇒-prop
|
||||
|
@ -229,10 +230,10 @@
|
|||
(attribute opts.wrap)))])
|
||||
(define-splicing-syntax-class tc-post-options
|
||||
#:attributes (wrap)
|
||||
[pattern (~seq #:mode x:id v:expr)
|
||||
#:attr wrap (λ (stx) #`(parameterize ([x v]) #,stx))]
|
||||
[pattern (~seq #:modes ([x:id v:expr] ...))
|
||||
#:attr wrap (λ (stx) #`(parameterize ([x v] ...) #,stx))]
|
||||
[pattern (~seq #:mode mode-expr)
|
||||
#:attr wrap (λ (stx) #`(with-mode mode-expr #,stx))]
|
||||
[pattern (~seq #:submode fn-expr)
|
||||
#:attr wrap (λ (stx) #`(with-mode (fn-expr (current-mode)) #,stx))]
|
||||
)
|
||||
(define-splicing-syntax-class tc-clause
|
||||
#:attributes (pat)
|
||||
|
@ -319,20 +320,26 @@
|
|||
[pattern (~seq #:fail-unless condition:expr message:expr)
|
||||
#:with pat
|
||||
#'(~post (~fail #:unless condition message))]
|
||||
[pattern (~seq #:mode param:id value:expr (sub-clause:clause ...))
|
||||
#:with tmp (generate-temporary #'param)
|
||||
[pattern (~seq #:mode mode-expr (sub-clause:clause ...))
|
||||
#:with (the-mode tmp) (generate-temporaries #'(the-mode tmp))
|
||||
#:with pat
|
||||
#'(~and (~do (define tmp [param])
|
||||
[param value])
|
||||
#'(~and (~do (define the-mode mode-expr)
|
||||
((mode-setup-fn the-mode))
|
||||
(define tmp (current-mode))
|
||||
(current-mode the-mode))
|
||||
sub-clause.pat ...
|
||||
(~do [param tmp]))]
|
||||
[pattern (~seq #:modes ([param:id value:expr] ...) (sub-clause:clause ...))
|
||||
#:with (tmp ...) (generate-temporaries #'[param ...])
|
||||
(~do (current-mode tmp)
|
||||
((mode-teardown-fn the-mode))))]
|
||||
[pattern (~seq #:submode fn-expr (sub-clause:clause ...))
|
||||
#:with (the-mode tmp) (generate-temporaries #'(the-mode tmp))
|
||||
#:with pat
|
||||
#'(~and (~do (define tmp [param]) ...
|
||||
[param value] ...)
|
||||
#'(~and (~do (define the-mode (fn-expr (current-mode)))
|
||||
((mode-setup-fn the-mode))
|
||||
(define tmp (current-mode))
|
||||
(current-mode the-mode))
|
||||
sub-clause.pat ...
|
||||
(~do [param tmp] ...))]
|
||||
(~do (current-mode tmp)
|
||||
((mode-teardown-fn the-mode))))]
|
||||
)
|
||||
(define-syntax-class last-clause
|
||||
#:datum-literals (⊢ ≫ ≻ ⇒ ⇐)
|
||||
|
|
Loading…
Reference in New Issue
Block a user