Macro
The original macro: https://github.com/racket/racket/blob/8e83dc25f7f5767d9e975f20982fdbb82f62415a/racket/collects/racket/syntax.rkt#L22-#L59
A new implementation using syntax-parse:
#lang racket/base (require syntax/parse/define syntax/datum (for-syntax racket/base racket/syntax racket/private/sc)) (provide define/with-datum) (begin-for-syntax (define-syntax-class (fresh-temporary fresh-stx) #:attributes (fresh-var) (pattern name #:with fresh-var (format-id fresh-stx "~a" (generate-temporary #'name)))) (define (count-ellipses-depth var...^n) (for/fold ([var...^n var...^n] [depth 0]) ([current-depth (in-naturals 1)] #:break (not (pair? var...^n))) (values (car var...^n) current-depth)))) #| Source: https://github.com/racket/racket/blob/8e83dc25f7f5767d9e975f20982fdbb82f62415a/racket/collects/racket/syntax.rkt#L22-#L59 racket/collects/racket/syntax.rktracket/collects/racket/syntax.rkt Commit SHA: 8e83dc25f7f5767 Line: 22-59 |# (define-syntax-parse-rule (define/with-datum pattern rhs) #:attr matched-vars (get-match-vars #'define/with-datum this-syntax #'pattern '()) #:with (((~var pvar (fresh-temporary #'here)) . depth) ...) (for/list ([x (attribute matched-vars)]) (define-values (var depth) (count-ellipses-depth x)) (cons var depth)) (begin (define-values (pvar.fresh-var ...) (with-datum ([pattern rhs]) (values (pvar-value pvar) ...))) (define-syntax pvar (make-s-exp-mapping 'depth (quote-syntax pvar.fresh-var))) ...)) ;; auxiliary macro (define-syntax-parse-rule (pvar-value pvar:id) #:attr mapping (syntax-local-value #'pvar) #:do [(unless (s-exp-pattern-variable? (attribute mapping)) (raise-syntax-error #f "not a datum variable" #'pvar))] #:with value-var (s-exp-mapping-valvar (attribute mapping)) value-var)
Example
(define/with-datum (x ((y z ...) ...)) '("X" (("Y1" "Z11" "Z12") ("Y2" "Z21"))))
This code uses define/with-datum, the counterpart of define/with-syntax, to define pattern variables bound to plain data. Just like define/with-syntax, define/with-datum allows arbitrary patterns (with ellipses) that syntax-case supports.
In this example, the pattern variable x matches "X" in the list while the pattern ((y z ...) ...) defines the pattern variables y, z and matches (("Y1" "Z11" "Z12") ("Y2" "Z21")). The variable y at ellipsis depth 1 is bound to the value ("Y1" "Y2") and the variable z at ellipsis depth 2 is bound to the value (("Z11" "Z12") ("Z21")).
Here are a few examples using the defined pattern variables in datum templates:
(datum x) (with-datum ([w "W"]) ;; currently supported (datum ((y w) ...))) (datum ((^ z ... $) ...))
Before and After
The original macro: https://github.com/racket/racket/blob/8e83dc25f7f5767d9e975f20982fdbb82f62415a/racket/collects/racket/syntax.rkt#L22-#L59
All the procedural code in the original macro can be expressed in the pattern directives, #:attr, #:do and #:with. These pattern directives allow escaping into arbitrary expansion-time computation while retaining appropriate semantical meanings such as binding a pattern variable (#:with) or performing an imperative action (#:do).
Licence
I hereby license the code in this issue under the same MIT License that the Racket language uses:
https://github.com/racket/racket/blob/master/racket/src/LICENSE-MIT.txt
All the associated text in this issue is licensed under the Creative Commons Attribution 4.0 International License http://creativecommons.org/licenses/by/4.0/