2015-12-31 23 views
6

syntax/parse का उपयोग करने वाले मैक्रो को लिखते समय, मैंने एक स्प्लिसिंग सिंटैक्स क्लास बनाया है जो मैक्रो को प्रदान किए जा सकने वाले विकल्पों को कैप्चर करता है। ये विकल्प सभी वैकल्पिक हैं, और उन्हें किसी भी क्रम में प्रदान किया जा सकता है। ~optional अंडाकार सिर पैटर्न का उपयोग करते हुए यह पर्याप्त आसान बनाता है:मैं सिंटैक्स-पार्स के साथ कैप्चर किए गए वैकल्पिक विशेषताओं को कैसे समूहित कर सकता हूं?

(define-splicing-syntax-class opts 
    (pattern (~seq (~or (~optional (~seq #:a a)) 
         (~optional (~seq #:b b)) 
         (~optional (~seq #:x x)) 
         (~optional (~seq #:y y))) 
       ...)) 

हालांकि, वहाँ एक कमी है: मैं दो समूहों में समूह इन विकल्पों में करने में सक्षम होना चाहता हूँ: समूह a और b, और समूह युक्त जिसमें x और y शामिल हैं। हालांकि, उपयोगकर्ता अभी भी किसी भी क्रम में विकल्प निर्दिष्ट है, तो हो सकता है इस उदाहरण इनपुट के लिए:

(foobar #:b 3 #:y 7 #:a 2) 

मैं निम्न विशेषताओं का उत्पादन करने में सक्षम होना चाहते:

first-opts: (#:a 2 #:b 3) 
second-opts: (#:y 7) 

अब तक, मैंने मैन्युअल #:with का उपयोग कर ऐसा करने में कामयाब रहे, लेकिन यह काफी नहीं है:

(define-splicing-syntax-class opts 
    #:attributes ([first-opts 1] [second-opts 1]) 
    (pattern (~seq (~or (~optional (~seq #:a a)) 
         (~optional (~seq #:b b)) 
         (~optional (~seq #:x x)) 
         (~optional (~seq #:y y))) 
       ...) 
      #:with (first-opts ...) 
      #`(#,@(if (attribute a) #'(#:a a) #'()) 
       #,@(if (attribute b) #'(#:b b) #'())) 
      #:with (second-opts ...) 
      #`(#,@(if (attribute x) #'(#:x x) #'()) 
       #,@(if (attribute y) #'(#:y y) #'())))) 

यह syntax/parse/experimental/template से template का उपयोग कर एक छोटा सा सरल किया जा सकता:

(define-splicing-syntax-class opts 
    #:attributes ([first-opts 1] [second-opts 1]) 
    (pattern (~seq (~or (~optional (~seq #:a a)) 
         (~optional (~seq #:b b)) 
         (~optional (~seq #:x x)) 
         (~optional (~seq #:y y))) 
       ...) 
      #:with (first-opts ...) 
      (template ((?? ([email protected] #:a a)) 
         (?? ([email protected] #:b b)))) 
      #:with (second-opts ...) 
      (template ((?? ([email protected] #:a x)) 
         (?? ([email protected] #:b y)))))) 

बहरहाल, यह वास्तव में सिर्फ ऊपर के लिए कुछ चीनी है, और यह वास्तव में एक खंड में प्रत्येक विकल्प की गणना करने में होने की समस्या का समाधान नहीं है। यदि मैंने, उदाहरण के लिए, #:c विकल्प जोड़ा, तो मुझे इसे first-opts समूह में जोड़ने की याद रखना होगा, अन्यथा इसे पूरी तरह अनदेखा कर दिया जाएगा।

मैं वास्तव में वैकल्पिक मानों के इन सेटों को समूहित करने के लिए कुछ घोषणात्मक तरीका चाहता हूं। उदाहरण के लिए, मैं इस तरह के वाक्य रचना चाहते हैं:

(define-splicing-syntax-class opts 
    #:attributes ([first-opts 1] [second-opts 1]) 
    (pattern (~seq (~or (~group first-opts 
           (~optional (~seq #:a a)) 
           (~optional (~seq #:b b))) 
         (~group second-opts 
           (~optional (~seq #:x x)) 
           (~optional (~seq #:y y)))) 
       ...))) 

या, और भी बेहतर है, यह अगर मैं मौजूदा पुरातन, कुछ इस तरह इस्तेमाल कर सकते हैं अच्छा होगा:

(define-splicing-syntax-class opts 
    #:attributes ([first-opts 1] [second-opts 1]) 
    (pattern (~seq (~or (~and first-opts 
          (~seq (~optional (~seq #:a a)) 
            (~optional (~seq #:b b)))) 
         (~and second-opts 
          (~seq (~optional (~seq #:x x)) 
            (~optional (~seq #:y y))))) 
       ...))) 

हालांकि, की न वो काम syntax/parse द्वारा प्रदान किए गए बिल्टिन का उपयोग करके ऐसा करने का कोई तरीका है? यदि नहीं, तो क्या ~group जैसे कुछ को परिभाषित करने का कोई आसान तरीका है?

उत्तर

0

मैं अभी तक यह सुनिश्चित नहीं कर रहा हूं कि आप ~group जैसे कुछ के साथ ऐसा कर सकते हैं, लेकिन #:with का उपयोग करने वाले आपके मौजूदा (काम करने वाले) समाधान का एक तरीका है जो बहुत अच्छा दिखता है। शायद यह आपके मामले के लिए काम करेगा, शायद नहीं।

~optional एक डिफ़ॉल्ट तर्क #:defaults, जो आप खाली वाक्य रचना सूची, #'#f, या कुछ अन्य प्रहरी मूल्य होने के लिए सेट कर सकते हैं, आपके आवश्यकता को हटाकर अपने #:with खंड में एक if बयान के लिए में ले जाता है। यह कुछ ऐसा दिखाई देगा:

(define-splicing-syntax-class opts 
    #:attributes ([first-opts 1] [second-opts 1]) 
    (pattern (~seq (~or (~optional (~seq #:a a) #:defaults ([a #'#f])) 
         (~optional (~seq #:b b) #:defaults ([b #'#f])) 
         (~optional (~seq #:x x) #:defaults ([x #'#f])) 
         (~optional (~seq #:y y) #:defaults ([y #'#f]))) 
       ...) 
      #:with (first-opts ...) #'(#:a a #:b b) 
      #:with (second-opts ...) #'(#:x x #:y y) 

आशा है कि मदद करता है।

+0

यह मेरे लिए काम नहीं करता है क्योंकि मेरे पास उपयोग करने के लिए डिफ़ॉल्ट मान नहीं है- मुझे उन कीवर्ड तर्कों की आवश्यकता है जो विस्तार में नहीं दिखाए गए हैं * नहीं। –

2

यहां करने के लिए एक तरीका है कि इस तरह की एक ~groups-no-order पैटर्न विस्तारक साथ:

(define-splicing-syntax-class opts 
    #:attributes ([first-opts 1] [second-opts 1]) 
    [pattern (~groups-no-order 
      [first-opts 
      (~optional (~seq #:a a)) 
      (~optional (~seq #:b b))] 
      [second-opts 
      (~optional (~seq #:x x)) 
      (~optional (~seq #:y y))])]) 

(syntax-parse #'(foobar #:b 3 #:y 7 #:a 2) 
    [(foobar opts:opts) 
    (values #'(opts.first-opts ...) 
      #'(opts.second-opts ...))]) 
; #<syntax (#:a 2 #:b 3)> 
; #<syntax (#:y 7)> 

कहाँ ~groups-no-order इस तरह परिभाषित किया जा सकता:

#lang racket 
(provide ~groups-no-order) 

(require syntax/parse 
     seq-no-order 
     (for-syntax racket/syntax 
        syntax/stx)) 

(define-syntax ~groups-no-order 
    (pattern-expander 
    (lambda (stx) 
    (syntax-case stx() 
     [(groups [group-name member-pat ...] ...) 
     (with-syntax ([ooo (quote-syntax ...)]) 
      (define/with-syntax [[member-tmp ...] ...] 
      (stx-map generate-temporaries #'[[member-pat ...] ...])) 
      (define/with-syntax [group-tmp ...] 
      (generate-temporaries #'[group-name ...])) 
      #'(~and (~seq-no-order (~and (~seq (~var member-tmp) ooo) 
             member-pat) 
           ... ...) 
        (~parse [[(~var group-tmp) ooo] ooo] #'[[member-tmp ooo] ...]) 
        ... 
        (~parse [group-name ooo] #'[group-tmp ooo ooo]) 
        ...))])))) 

यह आपका पहला समाधान के रूप में एक ही बात करता है #:with का उपयोग करके, लेकिन यह उस पुन: प्रयोज्य पैटर्न विस्तारक में सामान को बाहर निकाल देता है।

0

मुझे लगता है कि ~and का उपयोग सबसे सरल मैक्रो की ओर जाता है, लेकिन ~and का मुख्य पैटर्न संस्करण अधिक प्रतिबंधित है और यह काफी काम नहीं करता है इसलिए मैं हेड-पैटर्न भाग को अलग कर दूंगा।

क्या नीचे दिए गए कोड को पूरा करने के लिए आप क्या चाहते हैं?

सिर पैटर्न के बिना आप ~optional खो देते हैं तो मैं मैन्युअल रूप से डुप्लिकेट की जांच करता हूं।

इसके अलावा, first-opts और second-opts फ़्लैटेड नहीं हैं, लेकिन मुझे संदेह है कि यह ठीक है?

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

(define-for-syntax (check-duplicate-kws kws-stx) 
    (check-duplicates (syntax->list kws-stx) #:key syntax->datum)) 

(define-syntax test 
    (syntax-parser 
    [(_ (~seq k:keyword v) ...) 
    #:fail-when (check-duplicate-kws #'(k ...)) "duplicate keyword" 
    #:with ((~or (~and first-opts (~or (#:a _) (#:b _))) 
        (~and second-opts (~or (#:c _) (#:d _)))) ...) 
      #'((k v) ...) 
    #'(void)])) 
संबंधित मुद्दे

 संबंधित मुद्दे