开发者

How to transform this function into macro?

开发者 https://www.devze.com 2023-03-29 05:36 出处:网络
I have difficulties understanding the new macro system of Scheme. Somewhere along the path I began to write my \"macro\" as a function first, and then later apply it as a macro.

I have difficulties understanding the new macro system of Scheme. Somewhere along the path I began to write my "macro" as a function first, and then later apply it as a macro.

So my mission is to turn the following structure:

;; highlight-rules: rule id, color and the regexp matches
(define highlight-rules
  `((important   ,(with-esc "[1;33m") ("foo"
                                       "bob"))
    (unimportant ,(with-esc "[1;30m") ("case of unimport"))
    (urgent      ,(with-esc "[1;31m") ("urgents"))))

Into this kind of cond series with match strings compiled to regexpes:

;; just an example. `line` is an argument bound by the function application
(cond
  ((string-match (regexp ".*sudo:session.*") line)
     (with-color *important* line))
  (else line))

I have written a function that seems to do the trick:

;; (cdar highlight-rules) -> (colorstring   list-of-rules)
(define (parse-highlight-rules rules)
  ;; aux function to do one 'class' of patterns
  (define (class-of-rules colorstr rulelist)
    (map (lambda (rule)
        `((string-match ,(regexp rule)) (with-color ,colorstr line)))
        rulelist))
  (define (do-loop accumulator rules)
    (let* ((highlight-group (cdar rules))
           (colorstr        (car highlight-group))
           (grouprules      (cadr highlight-group))
           (acc*            (append (class-of-rules colorstr grouprules) accumulator))
           (rest            (cdr rules)))
    (if (null? rest)
        acc*
        (do-loop acc* rest))))
  ; wrap the list in cond.
  `(apply cond ,(do-loop '() rules)))

With given highlight-rules the function returns correct-looking list (well apart from applying the apply -- in clojure one would use splicing):

CSI> (parse-highlight-rul开发者_Go百科es highlight-rules)
(apply cond (((string-match #<regexp>) (with-color "\x1b[1;31m" line))
            ((string-match #<regexp>) (with-color "\x1b[1;30m" line))
            ((string-match #<regexp>) (with-color #0="\x1b[1;33m" line))
            ((string-match #<regexp>) (with-color #0# line))))

But how to proceed with this? I've been stuck with this for a while. Chicken Scheme is my dialect.


The easiest way of transforming your function into a macro is by using Chicken's explicit-renaming macro facility, which works similarly to Clojure's defmacro (except that an explicit-renaming macro takes some additional arguments that can be used to preserve hygiene).

Splicing works basically the same way as it does in Clojure. The syntax is ,@. Therefore, the following should work:

(define-for-syntax (parse-highlight-rules rules)
  ;; ... insert missing code here ...
  `(cond ,@(do-loop '() rules)))

(define-syntax highlight
  (er-macro-transformer
    (lambda (form rename compare)
      (parse-highlight-rules (cdr form)))))
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号