added #:datum-literals, like #:literals but for ~datum patterns

This commit is contained in:
Ryan Culpepper 2013-01-22 19:49:49 -05:00
parent 40d2fd65b0
commit d5fe602131
10 changed files with 226 additions and 77 deletions

View File

@ -14,6 +14,7 @@
[syntax/parse/private/rep ;; keep abs. path [syntax/parse/private/rep ;; keep abs. path
(parse-kw-formals (parse-kw-formals
check-conventions-rules check-conventions-rules
check-datum-literals-list
create-aux-def)])) create-aux-def)]))
;; FIXME: workaround for phase>0 bug in racket/runtime-path (and thus lazy-require) ;; FIXME: workaround for phase>0 bug in racket/runtime-path (and thus lazy-require)
;; Without this, dependencies don't get collected. ;; Without this, dependencies don't get collected.
@ -79,6 +80,7 @@
(raise-syntax-error #f "expected phase-level (exact integer or #f)" ctx stx)) (raise-syntax-error #f "expected phase-level (exact integer or #f)" ctx stx))
stx) stx)
;; check-litset-list : stx stx -> (listof (cons id literalset))
(define-for-syntax (check-litset-list stx ctx) (define-for-syntax (check-litset-list stx ctx)
(syntax-case stx () (syntax-case stx ()
[(litset-id ...) [(litset-id ...)
@ -101,17 +103,23 @@
(list #'id #'id)] (list #'id #'id)]
[_ (raise-syntax-error #f "expected literal entry" ctx stx)])) [_ (raise-syntax-error #f "expected literal entry" ctx stx)]))
(define-for-syntax (check-duplicate-literals stx imports lits) (define-for-syntax (check-duplicate-literals ctx imports lits datum-lits)
(let ([lit-t (make-hasheq)]) ;; sym => #t (let ([lit-t (make-hasheq)]) ;; sym => #t
(define (check+enter! key blame-stx) (define (check+enter! key blame-stx)
(when (hash-ref lit-t key #f) (when (hash-ref lit-t key #f)
(raise-syntax-error #f (format "duplicate literal: ~a" key) stx blame-stx)) (raise-syntax-error #f (format "duplicate literal: ~a" key) ctx blame-stx))
(hash-set! lit-t key #t)) (hash-set! lit-t key #t))
(for ([id+litset (in-list imports)]) (for ([id+litset (in-list imports)])
(let ([litset-id (car id+litset)] (let ([litset-id (car id+litset)]
[litset (cdr id+litset)]) [litset (cdr id+litset)])
(for ([entry (in-list (literalset-literals litset))]) (for ([entry (in-list (literalset-literals litset))])
(check+enter! (car entry) litset-id)))) (cond [(lse:lit? entry)
(check+enter! (lse:lit-internal entry) litset-id)]
[(lse:datum-lit? entry)
(check+enter! (lse:datum-lit-internal entry) litset-id)]))))
(for ([datum-lit (in-list datum-lits)])
(let ([internal (den:datum-lit-internal datum-lit)])
(check+enter! (syntax-e internal) internal)))
(for ([lit (in-list lits)]) (for ([lit (in-list lits)])
(check+enter! (syntax-e (car lit)) (car lit))))) (check+enter! (syntax-e (car lit)) (car lit)))))
@ -122,6 +130,7 @@
(parse-keyword-options (parse-keyword-options
#'rest #'rest
`((#:literal-sets ,check-litset-list) `((#:literal-sets ,check-litset-list)
(#:datum-literals ,check-datum-literals-list)
(#:phase ,check-phase-level) (#:phase ,check-phase-level)
(#:for-template) (#:for-template)
(#:for-syntax) (#:for-syntax)
@ -136,28 +145,35 @@
[(assq '#:for-syntax chunks) 1] [(assq '#:for-syntax chunks) 1]
[(assq '#:for-label chunks) #f] [(assq '#:for-label chunks) #f]
[else (options-select-value chunks '#:phase #:default 0)])] [else (options-select-value chunks '#:phase #:default 0)])]
[datum-lits
(options-select-value chunks '#:datum-literals #:default null)]
[lits (syntax-case rest () [lits (syntax-case rest ()
[( (lit ...) ) [( (lit ...) )
(for/list ([lit (in-list (syntax->list #'(lit ...)))]) (for/list ([lit (in-list (syntax->list #'(lit ...)))])
(check-literal-entry/litset lit stx))] (check-literal-entry/litset lit stx))]
[_ (raise-syntax-error #f "bad syntax" stx)])] [_ (raise-syntax-error #f "bad syntax" stx)])]
[imports (options-select-value chunks '#:literal-sets #:default null)]) [imports (options-select-value chunks '#:literal-sets #:default null)])
(check-duplicate-literals stx imports lits) (check-duplicate-literals stx imports lits datum-lits)
(with-syntax ([((internal external) ...) lits] (with-syntax ([((internal external) ...) lits]
[(datum-internal ...) (map den:datum-lit-internal datum-lits)]
[(datum-external ...) (map den:datum-lit-external datum-lits)]
[(litset-id ...) (map car imports)] [(litset-id ...) (map car imports)]
[relphase relphase]) [relphase relphase])
#`(begin #`(begin
(define phase-of-literals (define phase-of-literals
(if 'relphase (and 'relphase
(+ (phase-of-enclosing-module) 'relphase) (+ (variable-reference->module-base-phase (#%variable-reference))
'relphase)) 'relphase)))
(define-syntax name (define-syntax name
(make-literalset (make-literalset
(append (literalset-literals (syntax-local-value (quote-syntax litset-id))) (append (literalset-literals (syntax-local-value (quote-syntax litset-id)))
... ...
(list (list 'internal (list (make-lse:lit 'internal
(quote-syntax external) (quote-syntax external)
(quote-syntax phase-of-literals)) (quote-syntax phase-of-literals))
...
(make-lse:datum-lit 'datum-internal
'datum-external)
...)))) ...))))
(begin-for-syntax/once (begin-for-syntax/once
(for ([x (in-list (syntax->list #'(external ...)))]) (for ([x (in-list (syntax->list #'(external ...)))])
@ -174,26 +190,42 @@
(quote-syntax #,stx) x))))))))])) (quote-syntax #,stx) x))))))))]))
#| #|
Literal sets: The goal is for literals to refer to their bindings at NOTES ON PHASES AND BINDINGS
phase 0 relative to the enclosing module (module M ....
.... (define-literal-set LS #:phase PL ....)
....)
Use cases, explained: For the expansion of the define-literal-set form, the bindings of the literals
1) module X with def-lit-set is required-for-syntax can be accessed by (identifier-binding lit PL), because the phase of the enclosing
phase-of-mod-inst = 1 module (M) is 0.
phase-of-def = 0
literals looked up at abs phase 1 LS may be used, however, in a context where the phase of the enclosing
which is phase 0 rel to module X module is not 0, so each instantiation of LS needs to calculate the
2) module X with local def-lit-set within define-syntax phase of M and add that to PL.
phase-of-mod-inst = 1 (mod at 0, but +1 within define-syntax)
phase-of-def = 1 --
literals looked up at abs phase 0
which is phase 0 rel to module X Normally, literal sets that define the same name conflict. But it
3) module X with def-lit-set in phase-2 position (really uncommon case!) would be nice to allow them to both be imported in the case where they
phase-of-mod-inst = 1 (not 2, apparently) refer to the same binding.
phase-of-def = 2
literals looked up at abs phase 0 Problem: Can't do the check eagerly, because the binding of L may
(that's why the weird (if (z?) 0 1) term) change between when define-literal-set is compiled and the comparison
involving L. For example:
(module M racket
(require syntax/parse)
(define-literal-set LS (lambda))
(require (only-in some-other-lang lambda))
.... LS ....)
The expansion of the LS definition sees a different lambda than the
one that the literal in LS actually refers to.
Similarly, a literal in LS might not be defined when the expander
runs, but might get defined later. (Although I think that will already
cause an error, so don't worry about that case.)
|# |#
;; FIXME: keep one copy of each identifier (?) ;; FIXME: keep one copy of each identifier (?)
@ -205,7 +237,10 @@ Use cases, explained:
(syntax-local-value/record #'litset-id literalset?))]) (syntax-local-value/record #'litset-id literalset?))])
(unless val (raise-syntax-error #f "expected literal set name" stx #'litset-id)) (unless val (raise-syntax-error #f "expected literal set name" stx #'litset-id))
(let ([lits (literalset-literals val)]) (let ([lits (literalset-literals val)])
(with-syntax ([((_sym lit phase-var) ...) lits]) (with-syntax ([((lit phase-var) ...)
(for/list ([lit (in-list lits)]
#:when (lse:lit? lit))
(list (lse:lit-external lit) (lse:lit-phase lit)))])
#'(make-literal-set-predicate (list (list (quote-syntax lit) phase-var) ...)))))])) #'(make-literal-set-predicate (list (list (quote-syntax lit) phase-var) ...)))))]))
(define (make-literal-set-predicate lits) (define (make-literal-set-predicate lits)

View File

@ -72,6 +72,7 @@ DeclEnv =
DeclEntry = DeclEntry =
(den:lit id id ct-phase ct-phase) (den:lit id id ct-phase ct-phase)
(den:datum-lit id symbol)
(den:class id id Arguments) (den:class id id Arguments)
(den:magic-class id id Arguments stx) (den:magic-class id id Arguments stx)
(den:parser id (listof SAttr) bool bool bool) (den:parser id (listof SAttr) bool bool bool)
@ -82,6 +83,7 @@ Arguments is defined in rep-patterns.rkt
A DeclEnv is built up in stages: A DeclEnv is built up in stages:
1) syntax-parse (or define-syntax-class) directives 1) syntax-parse (or define-syntax-class) directives
#:literals -> den:lit #:literals -> den:lit
#:datum-literals -> den:datum-lit
#:local-conventions -> den:class #:local-conventions -> den:class
#:conventions -> den:delayed #:conventions -> den:delayed
#:literal-sets -> den:lit #:literal-sets -> den:lit
@ -101,20 +103,22 @@ expressions are duplicated, and may be evaluated in different scopes.
(define-struct declenv (table conventions)) (define-struct declenv (table conventions))
(define-struct den:lit (internal external input-phase lit-phase))
(define-struct den:class (name class argu)) (define-struct den:class (name class argu))
(define-struct den:magic-class (name class argu role)) (define-struct den:magic-class (name class argu role))
(define-struct den:parser (parser attrs splicing? commit? delimit-cut?)) (define-struct den:parser (parser attrs splicing? commit? delimit-cut?))
;; and from residual.rkt: (define-struct den:delayed (parser class)) ;; and from residual.rkt:
;; (define-struct den:lit (internal external input-phase lit-phase))
;; (define-struct den:datum-lit (internal external))
;; (define-struct den:delayed (parser class))
(define (new-declenv literals #:conventions [conventions null]) (define (new-declenv literals #:conventions [conventions null])
(make-declenv (let* ([table (make-immutable-bound-id-table)]
(for/fold ([table (make-immutable-bound-id-table)]) [table (for/fold ([table table]) ([literal (in-list literals)])
([literal (in-list literals)]) (let ([id (cond [(den:lit? literal) (den:lit-internal literal)]
(bound-id-table-set table (car literal) [(den:datum-lit? literal) (den:datum-lit-internal literal)])])
(make den:lit (first literal) (second literal) ;;(eprintf ">> added ~e\n" id)
(third literal) (fourth literal)))) (bound-id-table-set table id literal)))])
conventions)) (make-declenv table conventions)))
(define (declenv-lookup env id #:use-conventions? [use-conventions? #t]) (define (declenv-lookup env id #:use-conventions? [use-conventions? #t])
(or (bound-id-table-ref (declenv-table env) id #f) (or (bound-id-table-ref (declenv-table env) id #f)
@ -129,6 +133,8 @@ expressions are duplicated, and may be evaluated in different scopes.
(match val (match val
[(den:lit _i _e _ip _lp) [(den:lit _i _e _ip _lp)
(wrong-syntax id "identifier previously declared as literal")] (wrong-syntax id "identifier previously declared as literal")]
[(den:datum-lit _i _e)
(wrong-syntax id "identifier previously declared as literal")]
[(den:magic-class name _c _a _r) [(den:magic-class name _c _a _r)
(if (and blame-declare? stxclass-name) (if (and blame-declare? stxclass-name)
(wrong-syntax name (wrong-syntax name
@ -191,7 +197,7 @@ expressions are duplicated, and may be evaluated in different scopes.
(define DeclEnv/c declenv?) (define DeclEnv/c declenv?)
(define DeclEntry/c (define DeclEntry/c
(or/c den:lit? den:class? den:magic-class? den:parser? den:delayed?)) (or/c den:lit? den:datum-lit? den:class? den:magic-class? den:parser? den:delayed?))
(define SideClause/c (define SideClause/c
(or/c clause:fail? clause:with? clause:attr? clause:do?)) (or/c clause:fail? clause:with? clause:attr? clause:do?))
@ -200,11 +206,12 @@ expressions are duplicated, and may be evaluated in different scopes.
;; usually = #'(syntax-local-phase-level) ;; usually = #'(syntax-local-phase-level)
(define ct-phase/c syntax?) (define ct-phase/c syntax?)
(provide (struct-out den:lit) (provide (struct-out den:class)
(struct-out den:class)
(struct-out den:magic-class) (struct-out den:magic-class)
(struct-out den:parser) (struct-out den:parser)
;; from residual.rkt: ;; from residual.rkt:
(struct-out den:lit)
(struct-out den:datum-lit)
(struct-out den:delayed)) (struct-out den:delayed))
(provide/contract (provide/contract
@ -218,7 +225,7 @@ expressions are duplicated, and may be evaluated in different scopes.
[stxclass-colon-notation? (parameter/c boolean?)] [stxclass-colon-notation? (parameter/c boolean?)]
[new-declenv [new-declenv
(->* [(listof (list/c identifier? identifier? ct-phase/c ct-phase/c))] (->* [(listof (or/c den:lit? den:datum-lit?))]
[#:conventions list?] [#:conventions list?]
DeclEnv/c)] DeclEnv/c)]
[declenv-lookup [declenv-lookup

View File

@ -4,6 +4,7 @@
syntax/parse/private/keywords syntax/parse/private/keywords
syntax/parse/private/residual ;; keep abs. path syntax/parse/private/residual ;; keep abs. path
syntax/parse/private/runtime) syntax/parse/private/runtime)
racket/list
racket/contract/base racket/contract/base
"minimatch.rkt" "minimatch.rkt"
syntax/private/id-table syntax/private/id-table
@ -61,6 +62,9 @@
[check-conventions-rules [check-conventions-rules
(-> syntax? syntax? (-> syntax? syntax?
(listof (list/c regexp? any/c)))] (listof (list/c regexp? any/c)))]
[check-datum-literals-list
(-> syntax? syntax?
(listof den:datum-lit?))]
[check-attr-arity-list [check-attr-arity-list
(-> syntax? syntax? (-> syntax? syntax?
(listof sattr?))]) (listof sattr?))])
@ -220,11 +224,12 @@
;; get-decls : chunks -> (values DeclEnv (listof syntax)) ;; get-decls : chunks -> (values DeclEnv (listof syntax))
(define (get-decls chunks strict?) (define (get-decls chunks strict?)
(define lits (options-select-value chunks '#:literals #:default null)) (define lits (options-select-value chunks '#:literals #:default null))
(define datum-lits (options-select-value chunks '#:datum-literals #:default null))
(define litsets (options-select-value chunks '#:literal-sets #:default null)) (define litsets (options-select-value chunks '#:literal-sets #:default null))
(define convs (options-select-value chunks '#:conventions #:default null)) (define convs (options-select-value chunks '#:conventions #:default null))
(define localconvs (options-select-value chunks '#:local-conventions #:default null)) (define localconvs (options-select-value chunks '#:local-conventions #:default null))
(define literals (define literals
(append-lits+litsets lits litsets)) (append/check-lits+litsets lits datum-lits litsets))
(define-values (convs-rules convs-defs) (define-values (convs-rules convs-defs)
(for/fold ([convs-rules null] [convs-defs null]) (for/fold ([convs-rules null] [convs-defs null])
([conv-entry (in-list convs)]) ([conv-entry (in-list convs)])
@ -260,6 +265,8 @@
(match entry (match entry
[(den:lit _i _e _ip _lp) [(den:lit _i _e _ip _lp)
(values entry null)] (values entry null)]
[(den:datum-lit _i _e)
(values entry null)]
[(den:magic-class name class argu role) [(den:magic-class name class argu role)
(values entry null)] (values entry null)]
[(den:class name class argu) [(den:class name class argu)
@ -288,14 +295,39 @@
[(den:delayed _p _c) [(den:delayed _p _c)
(values entry null)])) (values entry null)]))
(define (append-lits+litsets lits litsets) ;; append/check-lits+litsets : .... -> (listof (U den:lit den:datum-lit))
(define seen (make-bound-id-table lits)) (define (append/check-lits+litsets lits datum-lits litsets)
(for ([litset (in-list litsets)]) (define seen (make-bound-id-table))
(for ([lit (in-list litset)]) (define (check-id id [blame-ctx id])
(when (bound-id-table-ref seen (car lit) #f) (if (bound-id-table-ref seen id #f)
(wrong-syntax (car lit) "duplicate literal declaration")) (wrong-syntax blame-ctx "duplicate literal declaration: ~s" (syntax-e id))
(bound-id-table-set! seen (car lit) #t))) (bound-id-table-set! seen id #t))
(apply append lits litsets)) id)
(let* ([litsets*
(for/list ([entry (in-list litsets)])
(let ([litset-id (first entry)]
[litset (second entry)]
[lctx (third entry)]
[input-phase (fourth entry)])
(define (get/check-id sym)
(check-id (datum->syntax lctx sym) litset-id))
(for/list ([lse (in-list (literalset-literals litset))])
(match lse
[(lse:lit internal external lit-phase)
(let ([internal (get/check-id internal)])
(make den:lit internal external input-phase lit-phase))]
[(lse:datum-lit internal external)
(let ([internal (get/check-id internal)])
(make den:datum-lit internal external))]))))]
[lits*
(for/list ([lit (in-list lits)])
(check-id (den:lit-internal lit))
lit)]
[datum-lits*
(for/list ([datum-lit (in-list datum-lits)])
(check-id (den:datum-lit-internal datum-lit))
datum-lit)])
(apply append lits* datum-lits* litsets*)))
;; parse-variant : stx boolean DeclEnv #f/(listof Sattr) -> RHS ;; parse-variant : stx boolean DeclEnv #f/(listof Sattr) -> RHS
(define (parse-variant stx splicing? decls0 expected-attrs) (define (parse-variant stx splicing? decls0 expected-attrs)
@ -609,6 +641,8 @@
(match entry (match entry
[(den:lit internal literal input-phase lit-phase) [(den:lit internal literal input-phase lit-phase)
(create-pat:literal literal input-phase lit-phase)] (create-pat:literal literal input-phase lit-phase)]
[(den:datum-lit internal sym)
(create-pat:datum sym)]
[(den:magic-class name class argu role) [(den:magic-class name class argu role)
(let* ([pos-count (length (arguments-pargs argu))] (let* ([pos-count (length (arguments-pargs argu))]
[kws (arguments-kws argu)] [kws (arguments-kws argu)]
@ -1222,24 +1256,20 @@
[_ [_
(raise-syntax-error #f "expected attribute name with optional depth declaration" ctx stx)])) (raise-syntax-error #f "expected attribute name with optional depth declaration" ctx stx)]))
;; check-literals-list : stx stx -> (listof (list id id ct-phase ct-phase)) ;; check-literals-list : stx stx -> (listof den:lit)
;; - txlifts defs of phase expressions ;; - txlifts defs of phase expressions
;; - txlifts checks that literals are bound ;; - txlifts checks that literals are bound
(define (check-literals-list stx ctx) (define (check-literals-list stx ctx)
(unless (stx-list? stx) (unless (stx-list? stx)
(raise-syntax-error #f "expected literals list" ctx stx)) (raise-syntax-error #f "expected literals list" ctx stx))
(let ([lits
(for/list ([x (in-list (stx->list stx))]) (for/list ([x (in-list (stx->list stx))])
(check-literal-entry x ctx))]) (check-literal-entry x ctx)))
(let ([dup (check-duplicate-identifier (map car lits))])
(when dup (raise-syntax-error #f "duplicate literal identifier" ctx dup)))
lits))
;; check-literal-entry : stx stx -> (list id id ct-phase ct-phase) ;; check-literal-entry : stx stx -> den:lit
(define (check-literal-entry stx ctx) (define (check-literal-entry stx ctx)
(define (go internal external phase) (define (go internal external phase)
(txlift #`(check-literal #,external #,phase #,ctx)) (txlift #`(check-literal #,external #,phase #,ctx))
(list internal external phase phase)) (make den:lit internal external phase phase))
(syntax-case stx () (syntax-case stx ()
[(internal external #:phase phase) [(internal external #:phase phase)
(and (identifier? #'internal) (identifier? #'external)) (and (identifier? #'internal) (identifier? #'external))
@ -1251,32 +1281,44 @@
(identifier? #'id) (identifier? #'id)
(go #'id #'id #'(syntax-local-phase-level))] (go #'id #'id #'(syntax-local-phase-level))]
[_ [_
(raise-syntax-error #f "expected literal entry" (raise-syntax-error #f "expected literal entry" ctx stx)]))
ctx stx)]))
;; check-datum-literals-list : stx stx -> (listof den:datum-lit)
(define (check-datum-literals-list stx ctx)
(unless (stx-list? stx)
(raise-syntax-error #f "expected datum-literals list" ctx stx))
(for/list ([x (in-list (stx->list stx))])
(check-datum-literal-entry x ctx)))
;; check-datum-literal-entry : stx stx -> den:datum-lit
(define (check-datum-literal-entry stx ctx)
(syntax-case stx ()
[(internal external)
(and (identifier? #'internal) (identifier? #'external))
(make den:datum-lit #'internal (syntax-e #'external))]
[id
(identifier? #'id)
(make den:datum-lit #'id (syntax-e #'id))]
[_
(raise-syntax-error #f "expected datum-literal entry" ctx stx)]))
;; Literal sets - Import ;; Literal sets - Import
;; check-literal-sets-list : stx stx -> (listof (listof (list id id ct-phase^2))) ;; check-literal-sets-list : stx stx -> (listof (list id literalset stx stx))
(define (check-literal-sets-list stx ctx) (define (check-literal-sets-list stx ctx)
(unless (stx-list? stx) (unless (stx-list? stx)
(raise-syntax-error #f "expected literal-set list" ctx stx)) (raise-syntax-error #f "expected literal-set list" ctx stx))
(for/list ([x (in-list (stx->list stx))]) (for/list ([x (in-list (stx->list stx))])
(check-literal-set-entry x ctx))) (check-literal-set-entry x ctx)))
;; check-literal-set-entry : stx stx -> (listof (list id id ct-phase^2)) ;; check-literal-set-entry : stx stx -> (list id literalset stx stx)
(define (check-literal-set-entry stx ctx) (define (check-literal-set-entry stx ctx)
(define (elaborate litset-id lctx phase) (define (elaborate litset-id lctx phase)
(let ([litset (syntax-local-value/record litset-id literalset?)]) (let ([litset (syntax-local-value/record litset-id literalset?)])
(unless litset (unless litset
(raise-syntax-error #f "expected identifier defined as a literal-set" (raise-syntax-error #f "expected identifier defined as a literal-set"
ctx litset-id)) ctx litset-id))
(elaborate2 litset lctx phase))) (list litset-id litset lctx phase)))
(define (elaborate2 litset lctx phase)
(for/list ([entry (in-list (literalset-literals litset))])
(list (datum->syntax lctx (car entry) stx)
(cadr entry)
phase
(caddr entry))))
(syntax-case stx () (syntax-case stx ()
[(litset . more) [(litset . more)
(and (identifier? #'litset)) (and (identifier? #'litset))
@ -1483,6 +1525,7 @@
(define common-parse-directive-table (define common-parse-directive-table
(list (list '#:disable-colon-notation) (list (list '#:disable-colon-notation)
(list '#:literals check-literals-list) (list '#:literals check-literals-list)
(list '#:datum-literals check-datum-literals-list)
(list '#:literal-sets check-literal-sets-list) (list '#:literal-sets check-literal-sets-list)
(list '#:conventions check-conventions-list) (list '#:conventions check-conventions-list)
(list '#:local-conventions check-conventions-rules))) (list '#:local-conventions check-conventions-rules)))

View File

@ -5,8 +5,12 @@
(struct-out integrate) (struct-out integrate)
(struct-out conventions) (struct-out conventions)
(struct-out literalset) (struct-out literalset)
(struct-out lse:lit)
(struct-out lse:datum-lit)
(struct-out eh-alternative-set) (struct-out eh-alternative-set)
(struct-out eh-alternative) (struct-out eh-alternative)
(struct-out den:lit)
(struct-out den:datum-lit)
(struct-out den:delayed)) (struct-out den:delayed))
;; == from rep-attr.rkt ;; == from rep-attr.rkt
@ -38,9 +42,14 @@ A ConventionRule is (list regexp DeclEntry)
#| #|
A LiteralSet is A LiteralSet is
(make-literalset (listof (list symbol id phase-var-id))) (make-literalset (listof LiteralSetEntry))
An LiteralSetEntry is one of
- (make-lse:lit symbol id ct-phase)
- (make-lse:datum-lit symbol symbol)
|# |#
(define-struct literalset (literals) #:transparent) (define-struct literalset (literals) #:transparent)
(define-struct lse:lit (internal external phase) #:transparent)
(define-struct lse:datum-lit (internal external) #:transparent)
#| #|
An EH-alternative-set is An EH-alternative-set is
@ -51,4 +60,6 @@ An EH-alternative is
(define-struct eh-alternative-set (alts)) (define-struct eh-alternative-set (alts))
(define-struct eh-alternative (repc attrs parser)) (define-struct eh-alternative (repc attrs parser))
(define-struct den:lit (internal external input-phase lit-phase) #:transparent)
(define-struct den:datum-lit (internal external) #:transparent)
(define-struct den:delayed (parser class)) (define-struct den:delayed (parser class))

View File

@ -15,7 +15,8 @@ As a remedy, @racketmodname[syntax/parse] offers @deftech{literal
sets}. A literal set is defined via @racket[define-literal-set] and sets}. A literal set is defined via @racket[define-literal-set] and
used via the @racket[#:literal-set] option of @racket[syntax-parse]. used via the @racket[#:literal-set] option of @racket[syntax-parse].
@defform/subs[(define-literal-set id maybe-phase maybe-imports (literal ...)) @defform/subs[(define-literal-set id maybe-phase maybe-imports maybe-datum-literals
(literal ...))
([literal literal-id ([literal literal-id
(pattern-id literal-id)] (pattern-id literal-id)]
[maybe-phase (code:line) [maybe-phase (code:line)
@ -23,6 +24,8 @@ used via the @racket[#:literal-set] option of @racket[syntax-parse].
(code:line #:for-syntax) (code:line #:for-syntax)
(code:line #:for-label) (code:line #:for-label)
(code:line #:phase phase-level)] (code:line #:phase phase-level)]
[maybe-datum-literals (code:line)
(code:line #:datum-literals (datum-literal ...))]
[maybe-imports (code:line) [maybe-imports (code:line)
(code:line #:literal-sets (imported-litset-id ...))])]{ (code:line #:literal-sets (imported-litset-id ...))])]{

View File

@ -23,6 +23,7 @@ Two parsing forms are provided: @racket[syntax-parse] and
@defform/subs[(syntax-parse stx-expr parse-option ... clause ...+) @defform/subs[(syntax-parse stx-expr parse-option ... clause ...+)
([parse-option (code:line #:context context-expr) ([parse-option (code:line #:context context-expr)
(code:line #:literals (literal ...)) (code:line #:literals (literal ...))
(code:line #:datum-literals (datum-literal ...))
(code:line #:literal-sets (literal-set ...)) (code:line #:literal-sets (literal-set ...))
(code:line #:conventions (convention-id ...)) (code:line #:conventions (convention-id ...))
(code:line #:local-conventions (convention-rule ...)) (code:line #:local-conventions (convention-rule ...))
@ -30,6 +31,8 @@ Two parsing forms are provided: @racket[syntax-parse] and
[literal literal-id [literal literal-id
(pattern-id literal-id) (pattern-id literal-id)
(pattern-id literal-id #:phase phase-expr)] (pattern-id literal-id #:phase phase-expr)]
[datum-literal literal-id
(pattern-id literal-id)]
[literal-set literal-set-id [literal-set literal-set-id
(literal-set-id literal-set-option ...)] (literal-set-id literal-set-option ...)]
[literal-set-option (code:line #:at context-id) [literal-set-option (code:line #:at context-id)
@ -76,10 +79,12 @@ failures; otherwise @racket[stx-expr] is used. The
(pattern-id literal-id) (pattern-id literal-id)
(pattern-id literal-id #:phase phase-expr)]) (pattern-id literal-id #:phase phase-expr)])
#:contracts ([phase-expr (or/c exact-integer? #f)])]{ #:contracts ([phase-expr (or/c exact-integer? #f)])]{
@margin-note*{ @margin-note*{
Unlike @racket[syntax-case], @racket[syntax-parse] requires all Unlike @racket[syntax-case], @racket[syntax-parse] requires all
literals to have a binding. To match identifiers by their symbolic literals to have a binding. To match identifiers by their symbolic
names, use the @racket[~datum] pattern form instead. names, use @racket[#:datum-literals] or the @racket[~datum] pattern
form instead.
} }
@; @;
The @racket[#:literals] option specifies identifiers that should be The @racket[#:literals] option specifies identifiers that should be
@ -94,6 +99,23 @@ If the @racket[#:phase] option is given, then the literal is compared
at phase @racket[phase-expr]. Specifically, the binding of the at phase @racket[phase-expr]. Specifically, the binding of the
@racket[literal-id] at phase @racket[phase-expr] must match the @racket[literal-id] at phase @racket[phase-expr] must match the
input's binding at phase @racket[phase-expr]. input's binding at phase @racket[phase-expr].
In other words, the @racket[syntax-pattern]s are interpreted as if each
occurrence of @racket[pattern-id] were replaced with the following pattern:
@racketblock[(~literal literal-id #:phase phase-expr)]
}
@specsubform/subs[(code:line #:datum-literals (datum-literal ...))
([datum-literal literal-id
(pattern-id literal-id)])]{
Like @racket[#:literals], but the literals are matched as symbols
instead of as identifiers.
In other words, the @racket[syntax-pattern]s are interpreted as if each
occurrence of @racket[pattern-id] were replaced with the following
pattern:
@racketblock[(~datum literal-id)]
} }
@specsubform/subs[(code:line #:literal-sets (literal-set ...)) @specsubform/subs[(code:line #:literal-sets (literal-set ...))

View File

@ -40,7 +40,7 @@ means specifically @tech{@Spattern}.
(@#,ref[~var s-] id) (@#,ref[~var s-] id)
(@#,ref[~var s+] id syntax-class-id maybe-role) (@#,ref[~var s+] id syntax-class-id maybe-role)
(@#,ref[~var s+] id (syntax-class-id arg ...) maybe-role) (@#,ref[~var s+] id (syntax-class-id arg ...) maybe-role)
(~literal literal-id) (~literal literal-id maybe-phase)
atomic-datum atomic-datum
(~datum datum) (~datum datum)
(H-pattern . S-pattern) (H-pattern . S-pattern)
@ -298,7 +298,9 @@ combined with the syntax class's description in error messages.
] ]
} }
@specsubform[(@#,defhere[~literal] literal-id)]{ @specsubform/subs[(@#,defhere[~literal] literal-id maybe-phase)
([maybe-phase (code:line)
(code:line #:phase phase-expr)])]{
A @deftech{literal} identifier pattern. Matches any identifier A @deftech{literal} identifier pattern. Matches any identifier
@racket[free-identifier=?] to @racket[literal-id]. @racket[free-identifier=?] to @racket[literal-id].
@ -309,6 +311,10 @@ A @deftech{literal} identifier pattern. Matches any identifier
(syntax-parse #'(lambda x 12) (syntax-parse #'(lambda x 12)
[((~literal define) var:id body:expr) 'ok]) [((~literal define) var:id body:expr) 'ok])
] ]
The identifiers are compared at the phase given by
@racket[phase-expr], if it is given, or
@racket[(syntax-local-phase-level)] otherwise.
} }
@specsubform[atomic-datum]{ @specsubform[atomic-datum]{

View File

@ -29,6 +29,7 @@ structures can share syntax class definitions.
(code:line #:commit) (code:line #:commit)
(code:line #:no-delimit-cut) (code:line #:no-delimit-cut)
(code:line #:literals (literal-entry ...)) (code:line #:literals (literal-entry ...))
(code:line #:datum-literals (datum-literal-entry ...))
(code:line #:literal-sets (literal-set ...)) (code:line #:literal-sets (literal-set ...))
(code:line #:conventions (convention-id ...)) (code:line #:conventions (convention-id ...))
(code:line #:local-conventions (convention-rule ...)) (code:line #:local-conventions (convention-rule ...))
@ -107,7 +108,8 @@ It is an error to use both @racket[#:commit] and
@racket[#:no-delimit-cut]. @racket[#:no-delimit-cut].
} }
@specsubform[(code:line #:literals (literal-entry))] @specsubform[(code:line #:literals (literal-entry ...))]
@specsubform[(code:line #:datum-literals (datum-literal-entry ...))]
@specsubform[(code:line #:literal-sets (literal-set ...))] @specsubform[(code:line #:literal-sets (literal-set ...))]
@specsubform[(code:line #:conventions (convention-id ...))]{ @specsubform[(code:line #:conventions (convention-id ...))]{

View File

@ -97,6 +97,18 @@
(go #'begin #f) (go #'begin #f)
(void))) (void)))
;; Litsets with datum-lits
(test-case "litset, datum-lits"
(let ([one 1])
(define-literal-set lits-d #:datum-literals (one two) ())
(syntax-parse #'one #:literal-sets (lits-d)
[one (void)])
(let ([one 2])
(syntax-parse #'one #:literal-sets (lits-d) [one (void)]))))
;; literal-set->predicate
(require (for-label '#%kernel)) (require (for-label '#%kernel))
(test-case "litset->pred" (test-case "litset->pred"

View File

@ -79,6 +79,14 @@
[+ (void)] [+ (void)]
[_ (error 'wrong)])) [_ (error 'wrong)]))
(test-case "datum literals"
(syntax-parse #'one #:datum-literals (one)
[one (void)]))
(test-case "datum literals (not id=?)"
(let ([one 1])
(syntax-parse (let ([one 2]) #'one) #:datum-literals (one)
[one (void)])))
;; compound patterns ;; compound patterns
(tok (a b c) (x y z) (tok (a b c) (x y z)
(and (bound (x 0) (y 0) (z 0)) (s= x 'a) (s= y 'b)) (and (bound (x 0) (y 0) (z 0)) (s= x 'a) (s= y 'b))