-
Notifications
You must be signed in to change notification settings - Fork 3
/
util.clj
48 lines (40 loc) · 1.91 KB
/
util.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
(ns docopt.util
(:require [clojure.string :as s]))
;; macros
(defmacro err [err-clause type & err-strs]
`(when ~err-clause
(throw
(ex-info (str "DOCOPT ERROR "
~(case type :syntax "(syntax) " :parse "(parse) ")
"| " ~@err-strs)
{:docopt.error/type ~type
:docopt.error/msg (str ~@err-strs)}))))
(defmacro defmultimethods
"Syntactic sugar for defmulti + multiple defmethods."
[method-name docstring args dispatch-fn-body & body]
`(do (defmulti ~method-name ~docstring (fn ~args (do ~dispatch-fn-body)))
~@(map (fn [[dispatched-key dispatched-body]]
`(defmethod ~method-name ~dispatched-key ~args (do ~dispatched-body)))
(apply array-map body))))
(defmacro specialize
"Syntactic sugar for derive."
[m]
`(do ~@(mapcat (fn [[parent children]] (map (fn [child] `(derive ~child ~parent)) children)) m)))
;; tokenization
(def re-arg-str "(<[^<>]*>|[A-Z_0-9]*[A-Z_][A-Z_0-9]*)") ; argument pattern
(defn re-tok
"Generates tokenization regexp, bounded by whitespace or string beginning / end."
[& patterns]
(re-pattern (str "(?<=^| )" (apply str patterns) "(?=$| )")))
(defn tokenize
"Repeatedly extracts tokens from string according to sequence of [re tag];
tokens are of the form [tag & groups] as captured by the corresponding regex."
[string pairs]
(letfn [(tokfn [[re tag] source]
(if (string? source)
(let [substrings (map s/trim (s/split (str " " (s/trim source) " ") re))
new-tokens (map #(into [tag] (when (vector? %) (filter seq (rest %))))
(re-seq re source))]
(filter seq (interleave substrings (concat (when tag new-tokens) (repeat nil)))))
[source]))]
(reduce #(mapcat (partial tokfn %2) %1) [string] pairs)))