2013-04-17 90 views
3

我有一個宏,當一個參數傳遞時工作,我想擴大它接受n個參數使用...,但我無法弄清楚語法。球拍宏省略號語法

該宏接受自定義語法,即key:val key:val,或者它接受一個過程。

例如:(3不同的用途)

(schema-properties [(name:first-name type:string)]) 
(schema-properties [(name:age type:number required:#t)]) 
(schema-properties [(my-custom-fn arg1 arg2 arg3)]) 

定義:

(define-syntax (schema-properties stx) 
    (syntax-parse stx 
    [(_ [(prop:expr ...)]) 
    (with-syntax ([prop0 (make-prop-hash #'(prop ...))]) 
     #'(list prop0))])) 

(define-for-syntax (make-prop-hash stx) 
    (with-syntax ([(props ...) stx]) 
    (if (regexp-match #px":" 
         (symbol->string (car (syntax->datum #'(props ...))))) 
     #'(pairs->hash 'props ...) 
     #'(props ...)))) 

這工作,即它檢查道具:EXPR語法的presense 「:」,並且如果它存在,將它傳遞給函數(pairs-> hash'props ...),否則,它只是調用它(道具...)。現在

,我希望能夠通過在:

(schema-properties [(name:first-name type:string) 
        (name:last-name type:string) 
        (my-fn arg1 arg2 arg3)]) 

,並有它的工作方式相同。但我目前處於省略號的地獄,我的大腦不再正常工作。

任何見解都值得讚賞。

回答

3

建議:使用幫助函數來幫助處理嵌套。您的schema-properties宏知道如何處理一個級別的嵌套,並且您想將其應用於多個子句。這與我們處理事物清單時的原理相同:請幫助人員處理事情,然後將其應用於您的清單。它有助於降低複雜性。

爲您的代碼,我們可以做這樣的:

#lang racket 
(require (for-syntax syntax/parse)) 

(define-syntax (schema-properties stx) 
    (syntax-parse stx 
    [(_ [clause ...]) 
    (with-syntax ([(transformed-clauses ...) 
        (map handle-clause (syntax->list #'(clause ...)))]) 
     #'(list transformed-clauses ...))])) 


;; handle-clause: clause-stx -> stx 
(define-for-syntax (handle-clause a-clause) 
    (syntax-parse a-clause 
    [(prop:expr ...) 
    (make-prop-hash #'(prop ...))])) 


(define-for-syntax (make-prop-hash stx) 
    (with-syntax ([(props ...) stx]) 
    (if (regexp-match #px":" 
         (symbol->string (car (syntax->datum #'(props ...))))) 
     #'(pairs->hash 'props ...) 
     #'(props ...)))) 


;;; Let's try it out. I don't know what your definition of pairs->hash is, 
;;; but it probably looks something like this: 
(define (pairs->hash . pairs) 
    (define ht (make-hash)) 
    (for ([p pairs]) 
    (match (symbol->string p) 
     [(regexp #px"([-\\w]+):([-\\w]+)" 
       (list _ key value)) 
     (hash-set! ht key value)])) 
    ht) 

(schema-properties [(name:first-name type:string) 
        (name:last-name type:string) 
        (list 1 2 3)]) 
+0

像往常一樣,從丹尼徹底和立即響應!非常感激。 – Scott

4

另一項建議:使用語法類,以幫助處理嵌套:

首先,定義識別鍵語法類:數值標識符(並使得可作爲keyvalue屬性及其組件串):

(begin-for-syntax 
    (define-syntax-class key-value-id 
    #:attributes (key value) 
    (pattern x:id 
      #:do [(define m (regexp-match "^([^:]*):([^:]*)$" 
              (symbol->string (syntax-e #'x))))] 
      #:fail-unless m #f 
      #:with (_ key value) m))) 

現在定義一個子句任一系列(被單向處理)或其他任何東西(被視爲表達式,必須產生一個過程)。 code屬性包含每種子句的解釋

(begin-for-syntax 
    (define-syntax-class clause 
    #:attributes (code) 
    (pattern (x:key-value-id ...) 
      #:with code #'(make-immutable-hash '((x.key . x.value) ...))) 
    (pattern proc 
      #:declare proc (expr/C#'(-> any)) 
      #:with code #'(proc.c)))) 

現在宏觀只是把拼在一起:

(define-syntax (schema-properties stx) 
    (syntax-parse stx 
    [(_ [c:clause ...]) 
    #'(list c.code ...)])) 
+0

這更好,謝謝。對我的技能水平來說,有點概念上很密集,但我想現在是時候更深入地學習語法類。 :) – Scott