如何使用自定义#%module-begin 维护定义功能?

Ric*_*ons 4 racket

我想对我的自定义语言生成的字符串做一些事情,例如显示它们。我创建了一个模块开始是这样的:

(define-syntax (module-begin stx)
  (syntax-case stx ()
    [(_ EXPR ...)
     #'(display (apply string-append (filter string? (list EXPR ...))))]))
Run Code Online (Sandbox Code Playgroud)

但是,这阻止了我在语言中使用定义。我收到错误“定义:在表达式上下文中不允许”。

如何在不失去使用定义和其他顶级表达式的能力的情况下获取字符串?我是否需要事先获取所有定义并将它们移到开头?

Rya*_*per 5

简短的回答

使用make-wrapping-module-begin做艰苦的工作适合你。

(require syntax/wrap-modbeg)
(define-syntax module-begin (make-wrapping-module-begin #'wrap-expression))
(define-syntax (wrap-expression stx)
  (syntax-case stx ()
    [(_ expr) #'(println expr)]))
Run Code Online (Sandbox Code Playgroud)

更改wrap-expression为使用表达式做任何您想做的事情。它不适用于定义、require表单等。请注意,您一次获得一个模块主体表达式,而不是一次全部。

长答案

您无权注册模块级定义、解释require表单等。只有宏扩展器和原始#%plain-module-begin表单可以做到这一点。所以你的module-begin宏必须与他们合作

您的宏必须用于local-expand部分展开每个模块级表单,以便您可以区分以下内容:

  • 模块级定义
  • requireprovide表格
  • begin 序列,需要拼接到模块体中
  • 表达

当你得到一个定义或requireprovide形式,只能把它折腾到真正的 #%plain-module-begin原始。你处理的表达式;再一次,不管你喜欢。对于begin表单,您会在子表单上重复出现。代码如下所示:

(define-syntax (module-begin stx)
  (syntax-case stx ()
    [(_ form ...)
     #'(#%plain-module-begin (wrap-module-form form) ...)]))

(define-syntax (wrap-module-form stx)
  (syntax-case stx ()
    [(_ form)
     (let ([e-form (local-expand #'form 'module #f)])
       (syntax-case e-form (begin define-syntaxes define-values #%require #%provide)
         [(define-syntaxes . _)
          e-form]
         [(define-values . _)
          e-form]
         [(#%require . _)
          e-form]
         [(#%provide . _)
          e-form]
         [(begin inner-form ...)
          #'(begin (wrap-module-form inner-form) ...)]
         [expr
          #'(wrap-expression expr)]))]))

(define-syntax (wrap-expression stx)
  (syntax-case stx ()
    [(_ expr) #'(println expr)]))
Run Code Online (Sandbox Code Playgroud)

所有的新代码基本上都是make-wrapping-module-begin自动为你做的。