-
-
Notifications
You must be signed in to change notification settings - Fork 3
Description
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/