Skip to content

Instantly share code, notes, and snippets.

@anishathalye
Created February 10, 2020 16:35
Show Gist options
  • Save anishathalye/0fca51025a70cc9af5a86e4fe796290c to your computer and use it in GitHub Desktop.
Save anishathalye/0fca51025a70cc9af5a86e4fe796290c to your computer and use it in GitHub Desktop.
#lang racket
(require (for-syntax syntax/parse))
; a bit of an artificial example, but probably more usable
; than the real code I'm working with
(begin-for-syntax
(define-splicing-syntax-class field
(pattern [name:id component:id num:nat]))
(define (field->struct field-stx)
(syntax-parse field-stx
[(field:field)
#'(struct field.name (field.component))]))
; suppose I have some more of these field->foo functions
; to transform an individual field into something else,
; and for modularity, I don't want to inline all of this stuff
; into the define-syntax form below
)
(define-syntax (parse-fields stx)
(syntax-parse stx
[(_ field:field ...)
#`(begin
#,@(map field->struct (syntax-e #'(field ...))))
]))
; usage
(parse-fields
[foo bar 3]
[baz qux 4])
(define x (foo "hi"))
(foo-bar x) ; => "hi"
@soegaard
Copy link

#lang racket

(require (for-syntax syntax/parse syntax/stx))

(begin-for-syntax
  (define-splicing-syntax-class field
    (pattern [name:id component:id num:nat]))

  (define (field->struct field-stx)
    (syntax-parse field-stx
      [(field:field)
       #'(struct field.name (field.component))])))

(define-syntax (parse-fields stx)
  (syntax-parse stx
    [(_ field:field ...)
     (with-syntax ([(struct-declaration ...) (stx-map field->struct #'(field ...))])
       (syntax/loc stx       
         (begin struct-declaration ...)))]))

; usage
(parse-fields
 [foo bar 3]
 [baz qux 4])

(define x (foo "hi"))
(foo-bar x) ; => "hi"

@rmculpepper
Copy link

This is one purpose that syntax-class attributes are designed for. You can bind attributes with #:with or #:attr. It's a good idea to declare a syntax class's attributes (including pattern variables, if you want to refer to them in templates elsewhere) using #:attributes.

(begin-for-syntax
  (define-splicing-syntax-class field
    #:attributes (name component struct-decl)
    (pattern [name:id component:id num:nat]
             #:with struct-decl #'(struct name (component)))))

(define-syntax (parse-fields stx)
  (syntax-parse stx
    [(_ field:field ...)
     #'(begin field.struct-decl ...)]))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment