-
-
Save bitemyapp/051142e1af427a231815 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns parser) | |
(defn read-char [rdr] | |
(let [ch (.read rdr)] | |
(if-not (== -1 ch) (char ch)))) | |
(def expr-tags | |
{:if #(str "if tag args: " (clojure.string/join ", " %1))}) | |
(defn expr-tag [{:keys [tag-name args] :as tag} rdr] | |
(if-let [handler (get expr-tags tag-name)] | |
(handler args) | |
(throw (Exception. (str "unrecognized tag: " tag-name))))) | |
(defn filter-tag [{:keys [tag-value]}] | |
(str "filter tag value: " tag-value)) | |
(defn read-tag-info [rdr] | |
(let [buf (StringBuilder.) | |
tag-type (if (= \{ (read-char rdr)) :filter :expr)] | |
(loop [ch1 (read-char rdr) | |
ch2 (read-char rdr)] | |
(when-not (and (or (= \} ch1) (= \% ch1)) | |
(= \} ch2)) | |
(.append buf ch1) | |
(recur ch2 (read-char rdr)))) | |
(let [content (->> (.split (.toString buf ) " ") (remove empty?) (map (memfn trim)))] | |
(merge {:tag-type tag-type} | |
(if (= :filter tag-type) | |
{:tag-value (first content)} | |
{:tag-name (keyword (first content)) | |
:args (rest content)}))))) | |
(defn parse-tag [{:keys [tag-type] :as tag} rdr] | |
(if (= :filter tag-type) | |
(filter-tag tag) | |
(expr-tag tag rdr))) | |
(defn handle-tag [rdr] | |
(let [tag (read-tag-info rdr)] | |
(parse-tag tag rdr))) | |
(defn parse [file] | |
(with-open [rdr (clojure.java.io/reader file)] | |
(let [template (transient []) | |
buf (StringBuilder.)] | |
(loop [ch (read-char rdr)] | |
(when ch | |
(if (= \{ ch) | |
(do | |
(conj! template (.toString buf)) | |
(.setLength buf 0) | |
(conj! template (handle-tag rdr)) | |
(recur (read-char rdr))) | |
(do | |
(.append buf ch) | |
(recur (read-char rdr)))))) | |
(conj! template (.toString buf)) | |
(persistent! template)))) | |
(defn render [template args] | |
(let [buf (StringBuilder.)] | |
(doseq [element template] | |
(when element | |
(.append buf (if (string? element) element (element args))))) | |
(.toString buf))) | |
(defn render-file [filename args] | |
(render (parse filename) args)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment