syntax/parse: added head ~optional pattern, improved docs
svn: r15906
This commit is contained in:
parent
8f24d026d6
commit
ee41d24bb9
|
@ -308,6 +308,17 @@
|
|||
(let ([sub-id alt-sub-id] ...)
|
||||
(success pre ... id ...))))))]))
|
||||
|
||||
;; (disjunct (clause:attr ...) id (expr ...) (id ...)) : expr
|
||||
(define-syntax (disjunct/sides stx)
|
||||
(syntax-case stx ()
|
||||
[(disjunct/sides clauses success (pre ...) (id ...))
|
||||
(with-syntax ([(#s(clause:attr #s(attr sub-id _ _) _) ...) #'clauses])
|
||||
(with-syntax ([(alt-sub-id ...) (generate-temporaries #'(sub-id ...))])
|
||||
#`(let ([alt-sub-id (attribute sub-id)] ...)
|
||||
(let ([id #f] ...)
|
||||
(let ([sub-id alt-sub-id] ...)
|
||||
(success pre ... id ...))))))]))
|
||||
|
||||
(begin-for-syntax
|
||||
;; convert-list-pattern : ListPattern id -> SinglePattern
|
||||
;; Converts '() datum pattern at end of list to bind (cons stx index)
|
||||
|
@ -382,6 +393,22 @@
|
|||
#'pattern
|
||||
#'#s(internal-rest-pattern rest index index0))])
|
||||
#'(parse:S x fc pattern k)))]
|
||||
[#s(hpat:optional (a ...) pattern defaults)
|
||||
(with-syntax ([(#s(attr id _ _) ...) #'(a ...)]
|
||||
[index0 (frontier->index-expr (wash #'fc))])
|
||||
#`(let ([success
|
||||
(lambda (rest index fail id ...)
|
||||
(with-enclosing-fail fail
|
||||
(let-attributes ([a id] ...) k)))])
|
||||
(try (parse:H x fc pattern rest index
|
||||
(success rest index enclosing-fail (attribute id) ...))
|
||||
(let ([rest x]
|
||||
[index index0])
|
||||
(convert-sides x defaults
|
||||
(clause-success ()
|
||||
(disjunct/sides defaults success
|
||||
(rest index enclosing-fail)
|
||||
(id ...))))))))]
|
||||
[_
|
||||
(with-syntax ([attrs (pattern-attrs (wash #'head))]
|
||||
[index0 (frontier->index-expr (wash #'fc))])
|
||||
|
|
|
@ -30,8 +30,8 @@ A SinglePattern is one of
|
|||
(make-pat:compound SPBase Kind (listof SinglePattern))
|
||||
(make-pat:cut SPBase SinglePattern)
|
||||
(make-pat:describe SPBase stx boolean SinglePattern)
|
||||
(make-pat:bind SPBase (listof clause:attr))
|
||||
(make-pat:fail SPBase stx stx)
|
||||
(make-pat:bind SPBase (listof clause:attr))
|
||||
|
||||
A ListPattern is a subtype of SinglePattern; one of
|
||||
(make-pat:datum SPBase '())
|
||||
|
@ -53,9 +53,8 @@ A ListPattern is a subtype of SinglePattern; one of
|
|||
(define-struct pat:compound (attrs kind patterns) #:prefab)
|
||||
(define-struct pat:cut (attrs pattern) #:prefab)
|
||||
(define-struct pat:describe (attrs description transparent? pattern) #:prefab)
|
||||
(define-struct pat:bind (attrs clauses) #:prefab)
|
||||
(define-struct pat:fail (attrs when message) #:prefab)
|
||||
|
||||
(define-struct pat:bind (attrs clauses) #:prefab)
|
||||
|
||||
#|
|
||||
A HeadPattern is one of
|
||||
|
@ -63,12 +62,14 @@ A HeadPattern is one of
|
|||
(make-hpat:seq HPBase ListPattern)
|
||||
(make-hpat:or HPBase (listof HeadPattern))
|
||||
(make-hpat:describe HPBase stx/#f boolean HeadPattern)
|
||||
(make-hpat:optional HPBase HeadPattern (listof clause:attr))
|
||||
|#
|
||||
|
||||
(define-struct hpat:ssc (attrs parser description bind-term? bind-attrs?) #:prefab)
|
||||
(define-struct hpat:seq (attrs inner) #:prefab)
|
||||
(define-struct hpat:or (attrs patterns) #:prefab)
|
||||
(define-struct hpat:describe (attrs description transparent? pattern) #:prefab)
|
||||
(define-struct hpat:optional (attrs inner defaults) #:prefab)
|
||||
|
||||
#|
|
||||
An EllipsisHeadPattern is
|
||||
|
@ -114,7 +115,8 @@ A Kind is one of
|
|||
(or (hpat:ssc? x)
|
||||
(hpat:seq? x)
|
||||
(hpat:or? x)
|
||||
(hpat:describe? x)))
|
||||
(hpat:describe? x)
|
||||
(hpat:optional? x)))
|
||||
|
||||
(define (ellipsis-head-pattern? x)
|
||||
(ehpat? x))
|
||||
|
@ -143,5 +145,5 @@ A Kind is one of
|
|||
(mk-get-attrs pat:name pat:any pat:sc pat:datum pat:literal pat:head
|
||||
pat:dots pat:and pat:or pat:compound pat:cut pat:describe
|
||||
pat:bind pat:fail
|
||||
hpat:ssc hpat:seq hpat:or hpat:describe
|
||||
hpat:ssc hpat:seq hpat:or hpat:describe hpat:optional
|
||||
ehpat)))
|
||||
|
|
|
@ -306,7 +306,7 @@
|
|||
|
||||
;; parse-head-pattern : stx DeclEnv -> HeadPattern
|
||||
(define (parse-head-pattern stx decls)
|
||||
(syntax-case stx (~or ~seq ~describe)
|
||||
(syntax-case stx (~or ~seq ~describe ~optional)
|
||||
[id
|
||||
(and (identifier? #'id) (not (reserved? #'id)))
|
||||
(parse-pat:id stx decls #t)]
|
||||
|
@ -316,6 +316,8 @@
|
|||
(parse-hpat:seq stx #'rest decls)]
|
||||
[(~describe . rest)
|
||||
(parse-pat:describe stx decls #t)]
|
||||
[(~optional . rest)
|
||||
(parse-hpat:optional stx decls)]
|
||||
[_
|
||||
(parse-single-pattern stx decls)]))
|
||||
|
||||
|
@ -567,7 +569,18 @@
|
|||
[else
|
||||
(wrong-syntax stx "expected proper list pattern")]))
|
||||
|
||||
(define (parse-hpat:optional stx decls)
|
||||
(define-values (head all-iattrs _name _tmm defaults)
|
||||
(parse-optional-pattern stx decls h-optional-directive-table))
|
||||
(make hpat:optional all-iattrs head defaults))
|
||||
|
||||
(define (parse-ehpat/optional stx decls)
|
||||
(define-values (head all-iattrs name too-many-msg defaults)
|
||||
(parse-optional-pattern stx decls eh-optional-directive-table))
|
||||
(make ehpat all-iattrs head
|
||||
(make rep:optional name too-many-msg defaults)))
|
||||
|
||||
(define (parse-optional-pattern stx decls optional-directive-table)
|
||||
(syntax-case stx (~optional)
|
||||
[(~optional p . options)
|
||||
(let ([head (parse-head-pattern #'p decls)])
|
||||
|
@ -587,8 +600,7 @@
|
|||
(define all-iattrs
|
||||
(union-iattrs (list pattern-iattrs defaults-iattrs)))
|
||||
(check-iattrs-subset defaults-iattrs pattern-iattrs stx)
|
||||
(make ehpat all-iattrs head
|
||||
(make rep:optional name too-many-msg defaults))))]))
|
||||
(values head all-iattrs name too-many-msg defaults)))]))
|
||||
|
||||
(define (parse-ehpat/once stx decls)
|
||||
(syntax-case stx (~once)
|
||||
|
@ -876,8 +888,12 @@
|
|||
(define describe-option-table
|
||||
(list (list '#:transparent)))
|
||||
|
||||
;; optional-directive-table
|
||||
(define optional-directive-table
|
||||
;; eh-optional-directive-table
|
||||
(define eh-optional-directive-table
|
||||
(list (list '#:too-many check-expression)
|
||||
(list '#:name check-expression)
|
||||
(list '#:defaults check-bind-clause-list)))
|
||||
|
||||
;; h-optional-directive-table
|
||||
(define h-optional-directive-table
|
||||
(list (list '#:defaults check-bind-clause-list)))
|
||||
|
|
|
@ -12,16 +12,31 @@
|
|||
@(define ellipses @scheme[...])
|
||||
|
||||
@(begin
|
||||
(define (fixup exn)
|
||||
(let ([src (ormap values (exn:fail:syntax-exprs exn))])
|
||||
(if src
|
||||
(make-exn:fail:syntax
|
||||
(format "~a at: ~a" (exn-message exn) (syntax->datum src))
|
||||
(exn-continuation-marks exn)
|
||||
(exn:fail:syntax-exprs exn))
|
||||
exn)))
|
||||
(define the-eval
|
||||
(parameterize ((sandbox-output 'string)
|
||||
(sandbox-error-output 'string))
|
||||
(sandbox-error-output 'string)
|
||||
(sandbox-make-code-inspector current-code-inspector)
|
||||
(sandbox-eval-handlers
|
||||
(list #f
|
||||
(lambda (thunk)
|
||||
(with-handlers ([exn:fail:syntax?
|
||||
(lambda (e) (raise (fixup e)))])
|
||||
(thunk))))))
|
||||
(make-evaluator 'scheme/base
|
||||
#:requires '(syntax/parse (for-syntax scheme/base)))))
|
||||
(the-eval '(error-print-source-location #f))
|
||||
(define-syntax-rule (myexamples e ...)
|
||||
(parameterize ((error-print-source-location #f))
|
||||
(examples #:eval the-eval e ...))))
|
||||
(examples #:eval the-eval e ...)))
|
||||
|
||||
@title[#:tag "stxparse"]{Parsing and classifying syntax}
|
||||
@title[#:tag "stxparse" #:style '(toc)]{Parsing and classifying syntax}
|
||||
|
||||
The @schememodname[syntax/parse] library provides a framework for
|
||||
describing and parsing syntax. Using @schememodname[syntax/parse],
|
||||
|
@ -32,6 +47,8 @@ which offers many improvements over @scheme[syntax-case].
|
|||
|
||||
@defmodule[syntax/parse]
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
@;{----------}
|
||||
|
||||
@section{Parsing syntax}
|
||||
|
@ -59,25 +76,33 @@ subterms of the syntax object and that clause's side conditions and
|
|||
If the syntax object fails to match any of the patterns (or all
|
||||
matches fail the corresponding clauses' side conditions), a syntax
|
||||
error is raised. If the @scheme[#:context] argument is given,
|
||||
@scheme[context-expr] is used in reporting the error.
|
||||
@scheme[context-expr] is used in reporting the error; otherwise
|
||||
@scheme[stx-expr] is used.
|
||||
|
||||
@(myexamples
|
||||
(syntax-parse #'(a b 3)
|
||||
[(x:id ...) 'ok])
|
||||
(syntax-parse #'(a b 3)
|
||||
#:context #'(lambda (a b 3) (+ a b))
|
||||
[(x:id ...) 'ok]))
|
||||
|
||||
The @scheme[#:literals] option specifies identifiers that should match
|
||||
as literals, rather than simply being pattern variables. A literal in
|
||||
the literals list has two components: the identifier used within the
|
||||
pattern to signify the positions to be matched (@scheme[pattern-id]),
|
||||
and the identifier expected to occur in those positions
|
||||
(@scheme[literal-id]). If the single-identifier form is used, the same
|
||||
identifier is used for both purposes.
|
||||
as @tech{literals}, rather than simply being @tech{pattern
|
||||
variables}. A literal in the literals list has two components: the
|
||||
identifier used within the pattern to signify the positions to be
|
||||
matched (@scheme[pattern-id]), and the identifier expected to occur in
|
||||
those positions (@scheme[literal-id]). If the single-identifier form
|
||||
is used, the same identifier is used for both purposes.
|
||||
|
||||
@bold{Note:} Unlike @scheme[syntax-case], @scheme[syntax-parse]
|
||||
requires all literals to have a binding. To match identifiers by their
|
||||
symbolic names, consider using the @scheme[atom-in-list] syntax class
|
||||
instead.
|
||||
|
||||
Many literals can be declared at once via one or more @tech{literal sets},
|
||||
imported with the @scheme[#:literal-sets] option. The literal-set
|
||||
definition determines the literal identifiers to recognize and the
|
||||
names used in the patterns to recognize those literals.
|
||||
Many literals can be declared at once via one or more @tech{literal
|
||||
sets}, imported with the @scheme[#:literal-sets] option. The
|
||||
literal-set definition determines the literal identifiers to recognize
|
||||
and the names used in the patterns to recognize those literals.
|
||||
|
||||
The @scheme[#:conventions] option imports @tech{convention}s that give
|
||||
default syntax classes to pattern variables that do not explicitly
|
||||
|
@ -167,9 +192,9 @@ like the following form.
|
|||
@specsubform[pvar-id:syntax-class-id]{
|
||||
|
||||
Matches only subterms specified by the @svar[syntax-class-id]. The
|
||||
syntax class's attributes are computed for the subterm and bound to
|
||||
the pattern variables formed by prefixing @svar[pvar-id.] to the
|
||||
name of the attribute. @svar[pvar-id] is bound to the matched
|
||||
syntax class's @tech{attributes} are computed for the subterm and
|
||||
bound to the pattern variables formed by prefixing @svar[pvar-id.] to
|
||||
the name of the attribute. @svar[pvar-id] is bound to the matched
|
||||
subterm.
|
||||
|
||||
If @svar[pvar-id] is @scheme[_], no attributes are bound.
|
||||
|
@ -179,19 +204,27 @@ If @svar[pvar-id] is empty (that is, if the pattern is of the form
|
|||
bound, but their names are not prefixed first.
|
||||
|
||||
@myexamples[
|
||||
(syntax-parse #'x
|
||||
(syntax-parse #'a
|
||||
[var:id (syntax-e #'var)])
|
||||
(syntax-parse #'12
|
||||
[var:id (syntax-e #'var)])
|
||||
(syntax-parse #'(x y z)
|
||||
[var:id (syntax-e #'var)])]
|
||||
(define-syntax-class two
|
||||
#:attributes (x y)
|
||||
(pattern (x y)))
|
||||
(syntax-parse #'(a b)
|
||||
[t:two (syntax->datum #'(t t.x t.y))])
|
||||
(syntax-parse #'(a b)
|
||||
[t
|
||||
#:declare t two
|
||||
(syntax->datum #'(t t.x t.y))])]
|
||||
|
||||
}
|
||||
|
||||
@specsubform[literal-id]{
|
||||
|
||||
An identifier that appears in the literals list is not a pattern
|
||||
variable; instead, it is a literal that matches any identifier
|
||||
@scheme[free-identifier=?] to it.
|
||||
variable; instead, it is a @deftech{literal} that matches any
|
||||
identifier @scheme[free-identifier=?] to it.
|
||||
|
||||
Specifically, if @scheme[literal-id] is the ``pattern'' name of an
|
||||
entry in the literals list, then it represents a pattern that matches
|
||||
|
|
Loading…
Reference in New Issue
Block a user