stxparse-info:   Track syntax-parse and syntax-case pattern vars
1 Tracking currently-bound pattern variables with syntax-parse
syntax-parse
syntax-parser
define/  syntax-parse
...+
attribute
boolean
char
character
define-conventions
define-eh-alternative-set
define-literal-set
define-splicing-syntax-class
define-syntax-class
exact-integer
exact-nonnegative-integer
exact-positive-integer
expr
expr/  c
id
identifier
integer
kernel-literals
keyword
literal-set->predicate
nat
number
pattern
prop:  syntax-class
static
str
syntax-parse-state-cons!
syntax-parse-state-ref
syntax-parse-state-set!
syntax-parse-state-update!
syntax-parse-track-literals
this-syntax
~!
~and
~between
~bind
~commit
~datum
~delimit-cut
~describe
~do
~fail
~literal
~not
~once
~optional
~or
~parse
~peek
~peek-not
~post
~rest
~seq
~undo
~var
~alt
~or*
pattern-expander?
pattern-expander
prop:  pattern-expander
syntax-local-syntax-parse-pattern-introduce
2 Tracking currently-bound pattern variables with syntax-case
syntax-case
syntax-case*
with-syntax
datum-case
with-datum
define/  with-syntax
3 Reading and updating the list of currently-bound pattern variables
current-pvars
current-pvars+  unique
with-pvars
define-pvars
4 Extensions to syntax/  parse/  experimental/  template
define-template-metafunction
syntax-local-template-metafunction-introduce
template
quasitemplate
template/  loc
quasitemplate/  loc
??
?@
8.6

stxparse-info: Track syntax-parse and syntax-case pattern vars

Suzanne Soy <racket@suzanne.soy>

Source code: https://github.com/jsmaniac/stxparse-info

 (require stxparse-info) package: stxparse-info

This library provides some patched versions of syntax-parse and of the syntax-case family. These patched versions track which syntax pattern variables are bound. This allows some libraries to change the way syntax pattern variables work.

For example, subtemplate automatically derives temporary identifiers when a template contains yᵢ , and xᵢ is a pattern variable. To know from which varᵢ the yᵢ identifiers must be derived, subtemplate needs to know which syntax pattern variables are within scope.

1 Tracking currently-bound pattern variables with syntax-parse

 (require stxparse-info/parse) package: stxparse-info

The module stxparse-info/parse provides patched versions of syntax-parse, syntax-parser and define/syntax-parse which track which syntax pattern variables are bound.

Overloaded version of syntax-parse from syntax/parse.
Overloaded version of syntax-parser from syntax/parse.
Overloaded version of define/syntax-parse from syntax/parse.

Additionally, the following identifiers are overridden as they are part of the duplicated implementation of syntax/parse.

syntax

...+

Overloaded version of ...+ from syntax/parse.

syntax

attribute

Overloaded version of attribute from syntax/parse.

syntax

boolean

Overloaded version of boolean from syntax/parse.

syntax

char

Overloaded version of char from syntax/parse.

syntax

character

Overloaded version of character from syntax/parse.
Overloaded version of define-conventions from syntax/parse.
Overloaded version of define-eh-alternative-set from syntax/parse.
Overloaded version of define-literal-set from syntax/parse.
Overloaded version of define-splicing-syntax-class from syntax/parse.
Overloaded version of define-syntax-class from syntax/parse.
Overloaded version of exact-integer from syntax/parse.
Overloaded version of exact-nonnegative-integer from syntax/parse.
Overloaded version of exact-positive-integer from syntax/parse.

syntax

expr

Overloaded version of expr from syntax/parse.

syntax

expr/c

Overloaded version of expr/c from syntax/parse.

syntax

id

Overloaded version of id from syntax/parse.
Overloaded version of identifier from syntax/parse.

syntax

integer

Overloaded version of integer from syntax/parse.
Overloaded version of kernel-literals from syntax/parse.

syntax

keyword

Overloaded version of keyword from syntax/parse.
Overloaded version of literal-set->predicate from syntax/parse.

syntax

nat

Overloaded version of nat from syntax/parse.

syntax

number

Overloaded version of number from syntax/parse.

syntax

pattern

Overloaded version of pattern from syntax/parse.
Overloaded version of prop:syntax-class from syntax/parse.

syntax

static

Overloaded version of static from syntax/parse.

syntax

str

Overloaded version of str from syntax/parse.
Overloaded version of syntax-parse-state-cons! from syntax/parse.
Overloaded version of syntax-parse-state-ref from syntax/parse.
Overloaded version of syntax-parse-state-set! from syntax/parse.
Overloaded version of syntax-parse-state-update! from syntax/parse.
Overloaded version of syntax-parse-track-literals from syntax/parse.
Overloaded version of this-syntax from syntax/parse.

syntax

~!

Overloaded version of ~! from syntax/parse.

syntax

~and

Overloaded version of ~and from syntax/parse.

syntax

~between

Overloaded version of ~between from syntax/parse.

syntax

~bind

Overloaded version of ~bind from syntax/parse.

syntax

~commit

Overloaded version of ~commit from syntax/parse.

syntax

~datum

Overloaded version of ~datum from syntax/parse.
Overloaded version of ~delimit-cut from syntax/parse.

syntax

~describe

Overloaded version of ~describe from syntax/parse.

syntax

~do

Overloaded version of ~do from syntax/parse.

syntax

~fail

Overloaded version of ~fail from syntax/parse.

syntax

~literal

Overloaded version of ~literal from syntax/parse.

syntax

~not

Overloaded version of ~not from syntax/parse.

syntax

~once

Overloaded version of ~once from syntax/parse.

syntax

~optional

Overloaded version of ~optional from syntax/parse.

syntax

~or

Overloaded version of ~or from syntax/parse.

syntax

~parse

Overloaded version of ~parse from syntax/parse.

syntax

~peek

Overloaded version of ~peek from syntax/parse.

syntax

~peek-not

Overloaded version of ~peek-not from syntax/parse.

syntax

~post

Overloaded version of ~post from syntax/parse.

syntax

~rest

Overloaded version of ~rest from syntax/parse.

syntax

~seq

Overloaded version of ~seq from syntax/parse.

syntax

~undo

Overloaded version of ~undo from syntax/parse.

syntax

~var

Overloaded version of ~var from syntax/parse.

syntax

~alt

Overloaded version of ~alt from syntax/parse.

syntax

~or*

Overloaded version of ~or* from syntax/parse.

Overloaded version of pattern-expander? from syntax/parse.
Overloaded version of pattern-expander from syntax/parse.
Overloaded version of prop:pattern-expander from syntax/parse.

2 Tracking currently-bound pattern variables with syntax-case

 (require stxparse-info/case) package: stxparse-info

The module stxparse-info/case provides patched versions of syntax-case, syntax-case*, with-syntax, define/with-syntax, datum-case and with-datum which track which syntax or datum pattern variables are bound.

Overloaded version of syntax-case from racket/base.
Overloaded version of syntax-case* from racket/base.
Overloaded version of with-syntax from racket/base.

Overloaded version of datum-case from syntax/datum.
Overloaded version of with-datum from syntax/datum.

Overloaded version of define/with-syntax from racket/syntax.

3 Reading and updating the list of currently-bound pattern variables

 (require stxparse-info/current-pvars)
  package: stxparse-info

procedure at phase 1

(current-pvars)  (listof identifier?)

This for-syntax procedure returns the list of syntax pattern variables which are known to be bound. The most recently bound variables are at the beginning of the list.

It is the responsibility of the reader to check that the identifiers are bound, and that they are bound to syntax pattern variables, for example using identifier-binding and syntax-pattern-variable?. This allows libraries to also track variables bound by match-like forms, for example.

procedure at phase 1

(current-pvars+unique)

  (listof (pairof identifier? identifier?))
This for-syntax procedure works like current-pvars, but associates each syntax pattern variable with an identifier containing a unique symbol which is generated at each execution of the code recording the pattern variable via with-pvars or define-pvars.

The car of each pair in the returned list is the syntax pattern variable (as produced by current-pvars). It is the responsibility of the reader to check that the identifiers present in the car of each element of the returned list are bound, and that they are bound to syntax pattern variables, for example using identifier-binding and syntax-pattern-variable?. This allows libraries to also track variables bound by match-like forms, for example.

The cdr of each pair is the identifier of a temporary variable. Reading that temporary variable produces a gensym-ed symbol, which was generated at run-time at the point where with-pvars or define-pvars was used to record the corresponding pattern variable.

This can be used to associate run-time data with each syntax pattern variable, via a weak hash table created with make-weak-hasheq. For example, the subtemplate library implicitly derives identifiers (similarly to generate-temporaries) for uses of yᵢ ... from a xᵢ pattern variable bearing the same subscript. The generated identifiers are associated with xᵢ via this weak hash table mechanism, so that two uses of yᵢ ... within the scope of the same xᵢ binding derive the same identifiers.

The code (with-pvars (v) body) roughly expands to:

(let-values ([(tmp) (gensym 'v)]) (letrec-syntaxes+values ([(shadow-current-pvars) (list* (cons (quote-syntax v) (quote-syntax tmp)) old-current-pvars)]) body))

Caveat: this entails that the fresh symbol stored in tmp is generated when with-pvars or define-pvars is called, not when the syntax pattern variable is actually bound. For example:

(define-syntax (get-current-pvars+unique stx) #`'#,(current-pvars+unique)) (require racket/private/sc) (let ([my-valvar (quote-syntax x)]) (let-syntax ([my-pvar (make-syntax-mapping 0 (quote-syntax my-valvar))]) (with-pvars (x) (get-current-pvars+unique)) ; '([x . g123]) (with-pvars (x) (get-current-pvars+unique)))) ; '([x . g124])

Under normal circumstances, with-pvars define-pvars should be called immediately after binding the syntax pattern variable, but the code above shows that it is technically possible to do otherwise.

This caveat is not meant to dissuade the use of current-pvars+unique, it rather serves as an explanation of the behaviour encountered when with-pvars or define-pvars are incorrectly used more than once to record the same pattern variable.

syntax

(with-pvars (pvar ...)  . body)

 
  pvar : identifier?
Prepends the given pvar ... to the list of pattern variables which are known to be bound. The pvar ... are prepended in reverse order, so within the body of

(with-pvars (v₁ v₂ v₃)  . body)

a call to the for-syntax function (current-pvars) returns:

(list* (quote-syntax v₃) (quote-syntax v₂) (quote-syntax v₁) old-current-pvars)

This can be used to implement macros which work similarly to syntax-parse or syntax-case, and have them record the syntax pattern variables which they bind.

Note that the identifiers pvar ... must already be bound to syntax pattern variables when with-pvars is used, e.g.

(let-syntax ([v₁ (make-syntax-mapping depth (quote-syntax valvar))] [v₂ (make-syntax-mapping depth (quote-syntax valvar))]) (with-pvars (v₁ v₂) code))

instead of:

(with-pvars (v₁ v₂) (let-syntax ([v₁ (make-syntax-mapping depth (quote-syntax valvar))] [v₂ (make-syntax-mapping depth (quote-syntax valvar))]) code))

syntax

(define-pvars pvar ...)

 
  pvar : identifier?
Prepends the given pvar ... to the list of pattern variables which are known to be bound, in the same way as with-pvars. Whereas with-pvars makes the modified list visible in the body, define-pvars makes the modified list visible in the statements following define-pvars. define-pvars can be used multiple times within the same let or equivalent.

This can be used to implement macros which work similarly to define/syntax-parse or define/with-syntax, and have them record the syntax pattern variables which they bind.

Example:
> (let () ; Alternate version of define/syntax-parse which ; contains (define-pvars x) in its expanded form. (define/syntax-parse x #'1) (define/syntax-parse y #'2) (define-syntax (get-pvars stx) #`'#,(current-pvars)) (get-pvars))

'(y x)

4 Extensions to syntax/parse/experimental/template

 (require stxparse-info/parse/experimental/template)
  package: stxparse-info

Note that currently, template metafunctions defined via stxparse-info/parse/experimental/template are not compatible with the forms from syntax/parse/experimental/template, and vice versa. There is a pending Pull Request which would make the necessary primitives from syntax/parse/experimental/template public, so hopefully this problem will be solved in future versions.

syntax

(syntax-local-template-metafunction-introduce stx)

This change is also available in the package "backport-template-pr1514". It has been submitted as a Pull Request to Racket, but can already be used in stxparse-info/parse/experimental/template right now.

syntax

template

Overloaded version of template from syntax/parse/experimental/template.

Additionally, the following identifiers are overridden as they are part of the duplicated implementation of syntax/parse.

syntax

??

Overloaded version of ?? from syntax/parse/experimental/template.

syntax

?@

Overloaded version of ?@ from syntax/parse/experimental/template.