-
Notifications
You must be signed in to change notification settings - Fork 13
Description
In recent Qi meetings we've been trying to write a user-friendly multi-language macro system for #lang raqit, in Syntax Spec, allowing a single macro form to extend both host as well as DSLs.
We ran into an issue generating a define-syntax form via host-interface/definitions, which results in an "unbound identifier" error when attempting to use the newly defined macro.
It's possible that host-interface/definitions may not be intended to produce transformer bindings. Is a host-interface/syntax-definitions or similar interface required to support generating define-syntax?
MWE
Below is a minimum working example that shows the error encountered ("unbound identifier").
#lang racket/base
(provide defmacro)
(require syntax-spec-v3
(for-syntax racket/base
syntax/parse))
(syntax-spec
(extension-class defmacro-macro
#:binding-space defmacro)
(nonterminal macd
#:description "a macro definition"
#:allow-extension defmacro-macro
#:binding-space defmacro
((~datum host) name:expr val:expr)))
(begin-for-syntax
(define (compile-defmacro stx)
(syntax-parse stx
[((~datum host) name:id body)
#'(define-syntax name body)])))
(syntax-spec
(host-interface/definitions
(defmacro m:macd)
(compile-defmacro #'m)))
(defmacro (host my-mac
(syntax-parser [(_ a) #'a])))
;; This compiles to:
;; (define-syntax my-mac (syntax-parser ((_ a) #'a)))
;; Yet:
;; (my-mac 5) ;=> my-mac: unbound identifier
Context/Motivation
Assuming the above works, we can write a defmacro macro extending it to a DSL, e.g., Qi:
(require qi)
(define-dsl-syntax #%flow defmacro-macro
(syntax-parser
[(_ name:id body) #'(define-dsl-syntax name qi-macro body)]))
We should then be able to define Qi macros using defmacro:
(defmacro
(#%flow my-qi-mac
(syntax-parser
[(_ a) #'a])))
Finally, as this syntax is nonstandard, we need a superficial host-language macro, macro, that wraps defmacro and provides familiar syntax in both rule and case forms, enabling:
(macro (#%flow my-qi-mac)
[(_ a) #'a])
or even:
(macro (#%flow (my-qi-mac a))
#'a) ; or perhaps simply `a` here without syntax-quote
Note the pattern identifying the target language is part of the identifier serving as the name, and does not wrap the entire expression. This allows users to use the reader syntax for the DSL in macro definitions as well:
(macro ☯(my-qi-mac a)
#'a)
(~> (3) (my-qi-mac 5))
;; expected: 5
More details and other approaches we tried are in the most recent meeting notes.
Help appreciated!