2016-07-08 43 views
3

考慮兩個宏的情況:outer-macro定義了某個實體的一般結構,並且inner-macro擴展了外部宏的範圍。我的意圖被捕獲在下面的代碼中,其中預期的輸出是一個打印語句。此示例將引發內部宏的模式的以下錯誤:(_ value ...)通過嵌套宏中的省略號捕獲可變數目的參數;丟失模式變量錯誤

syntax: no pattern variables before ellipsis in template in: ... 

我打算用在value ...相同的方式外宏的body ...圖案。事實上,「價值」的清單正是我所需要的(不一定非常靈活的省略號模式)。可悲的是,這種方式不起作用。我如何在內部宏中捕獲可變數量的參數?

#lang racket 

(require 
    racket/stxparam 
    (for-syntax syntax/parse)) 

(define-syntax-parameter inner-macro 
    (lambda (stx) 
    (raise-syntax-error 'inner-macro "generic error message" stx))) 

(define-syntax (outter-macro stx) 
    (syntax-parse stx 
    [(_ body:expr ...+) 
    #'(syntax-parameterize 
     ([inner-macro 
      (lambda (stx) 
      (syntax-case stx() 
       [(_ value ...) 
       (printf "values are: ~a~n" (list value ...))]))]) 
     body ...)])) 

(outter-macro 
(inner-macro 'a 'b 'c)) 

; expected result 
; > "values are: (a b c)" 

回答

3

要在語法模板「逃離」省略號,你可以使用語法(... <form>),其中<form>就是...序列按原文的句法模板。因此,你可以用一塊語法包括文字橢圓:

> #'(... (syntax-rules() 
      [(x ...) (list x ...)])) 
#<syntax:4:9 (syntax-rules() ((x ...) (li...> 

您可以使用此包圍你內心的宏定義逃脫內橢圓:

(define-syntax (outer-macro stx) 
    (syntax-parse stx 
    [(_ body:expr ...+) 
    #'(syntax-parameterize 
     ([inner-macro 
      (lambda (stx) 
      (... (syntax-case stx() 
        [(_ value ...) 
        (printf "values are: ~a~n" (list value ...))])))]) 
     body ...)])) 

然而,這其實不是很正確,因爲你的syntax-case正文是錯誤的 - 它不返回語法對象。您在(printf ...)之前只是缺少一個#'(或者你可以使用syntax-rules),所以正確的實現應該是以下幾點:

(define-syntax (outer-macro stx) 
    (syntax-parse stx 
    [(_ body:expr ...+) 
    #'(syntax-parameterize 
     ([inner-macro 
      (lambda (stx) 
      (... (syntax-case stx() 
        [(_ value ...) 
        #'(printf "values are: ~a~n" (list value ...))])))]) 
     body ...)])) 

如預期這應該工作。

3

Alexis King的回答很好。然而,我認爲更簡單的另一種方法是使用#:with模式(或with-syntax)將ooo定義爲文字省略號。

您可以創建一個文字省略號quote-syntax,所以#:with子句看起來像#:with ooo (quote-syntax ...)。然後,只要您想在宏的輸出中生成省略號,就可以使用ooo

(define-syntax (outer-macro stx) 
    (syntax-parse stx 
    [(_ body:expr ...+) 
    #:with ooo (quote-syntax ...) 
    #'(syntax-parameterize 
     ([inner-macro 
      (lambda (stx) 
      (syntax-case stx() 
       [(_ value ooo) 
       #'(printf "values are: ~a~n" (list value ooo))]))]) 
    body ...)])) 
+0

這確實是一個很好的方法來做到這一點,儘管我還沒有確定*最好的方式。謝謝! – Sam