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

时间:2017-08-20 19:46:56

标签: racket

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

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

然而,这阻止我在语言中使用define。我得到错误"定义:表达式上下文中不允许"。

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

1 个答案:

答案 0 :(得分:3)

简答

使用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)]))

更改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)]))

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