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)))))
精彩评论