Skip to content

host-interface/definitions: "unbound identifier" when generating define-syntax #92

@countvajhula

Description

@countvajhula

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!

cc @dzoep @eutro

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions