2017-08-20 83 views
3

我想對我的自定義語言生成的字符串進行操作,例如顯示它們。我已經創建了一個模塊,像這樣開始:如何使用自定義#%module-begin來維護定義功能?

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

但是,這會阻止我在語言中使用define。我收到錯誤「定義:不允許在表達式上下文中」。

如何抓住字符串而不會失去使用define和其他頂級表達式的能力?我是否需要事先抓取所有的定義並將它們移動到開始處?

回答

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會自動爲你做。

+0

感謝您的詳細和全面的答案。我有一個後續問題,雖然這顯示我害怕我的無知。如何根據我的問題將表達式包裝到列表中?正如你所說,wrap-extension宏只能處理一次一個表達式。 –