Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

define/with-datum -- defining pattern variables for datums #21

Open
shhyou opened this issue Sep 2, 2021 · 0 comments
Open

define/with-datum -- defining pattern variables for datums #21

shhyou opened this issue Sep 2, 2021 · 0 comments

Comments

@shhyou
Copy link

shhyou commented Sep 2, 2021

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/

bennn added a commit to syntax-objects/syntax-parse-example that referenced this issue Sep 21, 2021
bennn added a commit to syntax-objects/syntax-parse-example that referenced this issue Oct 27, 2021
bennn added a commit to syntax-objects/syntax-parse-example that referenced this issue Oct 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant