From b273e21463b46d3174f5ca0f27980b395af37f52 Mon Sep 17 00:00:00 2001 From: Nikita Prokopov Date: Fri, 28 Sep 2018 01:00:09 +0300 Subject: [PATCH] .glyphs format parser --- .gitignore | 2 + clojure/parse_glyphs.clj | 99 ++++++++++++++++++++++++++++++++++++++++ project.clj | 7 +++ 3 files changed, 108 insertions(+) create mode 100755 clojure/parse_glyphs.clj create mode 100644 project.clj diff --git a/.gitignore b/.gitignore index 9f8e1c2..07e1489 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ *.zip FiraCode_liga.glyphs FiraCode_mess.glyphs +target +clojure/FiraCode.edn \ No newline at end of file diff --git a/clojure/parse_glyphs.clj b/clojure/parse_glyphs.clj new file mode 100755 index 0000000..87bac14 --- /dev/null +++ b/clojure/parse_glyphs.clj @@ -0,0 +1,99 @@ +(ns parse-glyphs + (:require + [clojure.java.io :as io] + [fipp.edn :as fipp])) + +(def ^:dynamic *str) +(def ^:dynamic *pos) + +(defn current-char [] (nth @*str @*pos)) + +(defn advance! [] (swap! *pos inc)) + +(declare parse-anything!) + +(defn skip-ws! [] + (loop [] + (case (current-char) + \space (do (advance!) (recur)) + \newline (do (advance!) (recur)) + nil))) + +(defn parse-escaped-string! [] + (skip-ws!) + (when (= \" (current-char)) + (let [sb (StringBuilder.)] + (loop [] + (advance!) + (let [ch (current-char)] + (cond + (= ch \\) (do (.append sb \\) (advance!) (.append sb (current-char)) (recur)) + (= ch \") (do (advance!) (str sb)) + :else (do (.append sb ch) (recur)))))))) + +(defn parse-string! [] + (skip-ws!) + (let [sb (StringBuilder.)] + (loop [] + (let [ch (current-char)] + (cond + (#{\space \newline \{ \} \( \) \; \, \" \=} ch) sb + :else (do (.append sb ch) (advance!) (recur))))) + (let [res (str sb)] + (cond + (re-matches #"[0-9]+" res) (Integer/parseInt res) + (re-matches #"[0-9]+\.[0-9]+" res) (Double/parseDouble res) + (re-matches #"[a-zA-Z][a-zA-Z\.0-9]*" res) (keyword res) + :else res)))) + +(defn expect [c] + (assert (= c (current-char)) (str "Expected '" c "', found " (current-char) " at " @*pos))) + +(defn parse-map! [] + (skip-ws!) + (when (= \{ (current-char)) + (advance!) + (loop [m {}] + (skip-ws!) + (if (= \} (current-char)) + (do (advance!) m) + (let [k (or (parse-escaped-string!) (parse-string!)) + _ (do (skip-ws!) (expect \=) (advance!)) + v (parse-anything!) + v (if (keyword? v) (name v) v) + _ (do (skip-ws!) (expect \;) (advance!))] + (recur (assoc m k v))))))) + +(defn parse-list! [] + (skip-ws!) + (when (= \( (current-char)) + (advance!) + (loop [l []] + (skip-ws!) + (if (= \) (current-char)) + (do (advance!) l) + (let [v (parse-anything!) + _ (skip-ws!) + _ (when (not= \) (current-char)) + (expect \,) + (advance!))] + (recur (conj l v))))))) + +(defn parse-anything! [] + (skip-ws!) + (or + (parse-map!) + (parse-list!) + (parse-escaped-string!) + (parse-string!))) + +(defn parse [s] + (binding [*str (atom s) + *pos (atom 0)] + (parse-anything!))) + +(defn -main [& args] + (let [f (-> (slurp "FiraCode.glyphs") parse)] + (with-open [os (io/writer "clojure/FiraCode.edn")] + (binding [*out* os] + (fipp/pprint f {:width 200}))))) \ No newline at end of file diff --git a/project.clj b/project.clj new file mode 100644 index 0000000..7d2ca1a --- /dev/null +++ b/project.clj @@ -0,0 +1,7 @@ +(defproject org.example/sample "1.0.0-SNAPSHOT" + :dependencies [ + [org.clojure/clojure "1.10.0-alpha8"] + [fipp "0.6.12"] + ] + :source-paths ["clojure"] +) \ No newline at end of file