Advertisement
Guest User

Untitled

a guest
Sep 8th, 2019
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. (ns forg.parser.core
  2.   (:refer-clojure :exclude [Box ->Box])
  3.   #?(:cljs
  4.      (:require
  5.       [cljs.pprint :as pprint]
  6.       [instaparse.core :as insta :include-macros true]))
  7.   #?(:clj
  8.      (:require
  9.       [clojure.pprint :as pprint]
  10.       [instaparse.core :as insta]))
  11.   (:require
  12.    [clojure.string :as s]
  13.    [clojure.walk :as walk]))
  14.  
  15. (def ^:private ^:dynamic *with-box-annotation* true)
  16.  
  17. (insta/defparser ^:private parser
  18.   "page = settings* <non-todo-text>* task*
  19.   settings = #'#+.*:.*' <EOL>*
  20.   non-todo-text = (<EOL>*) !settings #'(?:(?!\\*)).+'* <EOL>*
  21.   EOL = '\n' | '\r\n' | #'$'
  22.   SPC = ' '
  23.   priority = (<'[#'> 'A' <']'>) | <'[#'> 'B' <']'> | <'[#'> 'B' <']'>
  24.   level = #'\\*+'
  25.   status = 'TODO' | 'DONE'
  26.   date = #'[a-zA-Z0-9-:]+'
  27.   weekday = #'\\w+'
  28.   hour = #'\\d{2}:\\d{2}'
  29.   type = 'm' | 'y' | 'd' | 'w'
  30.   times = #'\\d+'
  31.   repeat = <'+'> times type
  32.   time = (<'['> date <SPC>? weekday? <SPC>? hour? <SPC>? repeat? <']'>) | (<'<'> date <SPC>? weekday? <SPC>? hour? <SPC>? repeat? <'>'>)
  33.   name = <':'> (#'[a-zA-Z_]+' ) <':'>
  34.   value = time / #'.*'
  35.   properties = (name <SPC> value <EOL>?)
  36.   <properties-header> = <':PROPERTIES:'> <EOL> properties* <':END:'>
  37.   action = #'[^: \n]*(?: *[^: \n]*)*'
  38.   category = !SPC <':'>? #'[a-zA-Z]*' <':'>
  39.   scheduled = <'SCHEDULED:'> <SPC> time <EOL>?
  40.   visible = time
  41.   deadline = <'DEADLINE:'> <SPC> time <EOL>?
  42.   scheduled = <'SCHEDULED:'> <SPC> time <EOL>?
  43.   text = (#'[^:*/= \\n]*(?: *[^:*/= \n\n]*)*' | bold | italic | special)*
  44.   italic = <'/'> #'[^/]*' <'/'>
  45.   bold = <'*'> #'[^*]*' <'*'>
  46.   special = <'='> #'[^=]*' <'='>
  47.   inner = (header / text)*
  48.   sentence = #'[^: \n]*(?: *[^: \n]*)*'
  49.   header = level <SPC> sentence <EOL>? text* inner*
  50.   dates = (deadline* scheduled* visible*) | (deadline* visible* scheduled*) | (visible* deadline* scheduled*) | (visible* scheduled* deadline*) | (scheduled* visible* deadline*) | (scheduled* deadline* visible*)
  51.   task = level <SPC> status? <SPC> priority? <SPC> action <SPC>? category* <EOL>* properties-header? <EOL>* dates* <EOL>* inner? task*
  52. "
  53.   :auto-whitespace :standard
  54.   :output-format :enlive)
  55.  
  56. (defprotocol IChainable
  57.   (chain
  58.     [this vf]
  59.     [this f1 f2]
  60.     [this f1 f2 f3]
  61.     [this f1 f2 f3 f4]
  62.     [this f1 f2 f3 f4 f5]
  63.     [this f1 f2 f3 f4 f5 f6]
  64.     [this f1 f2 f3 f4 f5 f6 f7]
  65.     [this f1 f2 f3 f4 f5 f6 f7 f8]
  66.     "Passes the object over the sequence of the functions"))
  67.  
  68. (declare unwrap) ;; To let the box use the unwrap function
  69.  
  70. (deftype ^:private Box [x _meta]
  71.   #?@(:clj
  72.       [clojure.lang.IObj
  73.        (meta [_] _meta)
  74.        (withMeta [nx nm] (Box. @nx nm))]
  75.       :cljs
  76.       [IMeta
  77.        (-meta [_] _meta)
  78.        IWithMeta
  79.        (-with-meta [nx nm] (Box. @nx nm))])
  80.  
  81.   #?@(:clj
  82.       [clojure.lang.IDeref
  83.        (deref [this] x)]
  84.       :cljs
  85.       [IDeref
  86.        (-deref [_] x)])
  87.  
  88.   #?@(:clj
  89.       [clojure.lang.IPersistentCollection
  90.        (empty [this]
  91.                (clojure.core/empty x))])
  92.  
  93.   #?@(:clj
  94.       [clojure.lang.IPersistentMap
  95.        (containsKey [this k]
  96.                     (clojure.core/contains? x k))
  97.        (assoc [this k v]
  98.               (Box. (clojure.core/assoc x k v) _meta))
  99.        (without [this k]
  100.                 (Box. (clojure.core/dissoc x k) _meta))]
  101.       :cljs
  102.       [IAssociative
  103.        (-contains-key? [this k] (contains? x k))
  104.        (-assoc [this k v] (Box. (assoc x k v) _meta))
  105.        IMap
  106.        (-dissoc [this k] (Box. (dissoc x k) _meta))])
  107.  
  108.   #?@(:clj
  109.       [java.lang.Object
  110.        (toString [this]
  111.                  (str x))
  112.        (equals [this o]
  113.                (= x (unwrap o)))]
  114.       :cljs
  115.       [IEquiv
  116.        (-equiv [this o]
  117.                (= x (unwrap o)))])
  118.   #?@(:clj
  119.       [clojure.lang.Seqable
  120.        (seq [_] (seq x))]),
  121.  
  122.   #?@(:clj
  123.       [clojure.lang.ILookup
  124.        (valAt [this k]
  125.               (get x k))
  126.        (valAt [this k defval]
  127.               (get x k defval))]
  128.      :cljs
  129.      [ILookup
  130.       (-lookup [this k]
  131.                (get x k))
  132.       (-lookup [this k defval]
  133.                (get x k defval))])
  134.  
  135.   #?@(:clj
  136.       [clojure.core.protocols.CollReduce
  137.        (coll-reduce [this f]
  138.                     (clojure.core.protocols/coll-reduce x f))
  139.        (coll-reduce [this f xval]
  140.                     (clojure.core.protocols/coll-reduce x f xval))])
  141.  
  142.   IChainable
  143.   (chain [this vf]
  144.     (as-> (if (sequential? vf) vf (vector vf)) vf
  145.       (reduce (fn [val f] (Box. (f @val) (meta val)))
  146.               (Box. ((first vf) x) _meta)
  147.               (rest vf))))
  148.   (chain [this f1 f2]
  149.     (chain this [f1 f2]))
  150.   (chain [this f1 f2 f3]
  151.     (chain this [f1 f2 f3])) (chain [this f1 f2 f3 f4]
  152.     (chain this [f1 f2 f3 f4]))
  153.   (chain [this f1 f2 f3 f4 f5]
  154.     (chain this [f1 f2 f3 f4 f5]))
  155.   (chain [this f1 f2 f3 f4 f5 f6]
  156.     (chain this [f1 f2 f3 f4 f5 f6]))
  157.   (chain [this f1 f2 f3 f4 f5 f6 f7]
  158.     (chain this [f1 f2 f3 f4 f5 f6 f7]))
  159.   (chain [this f1 f2 f3 f4 f5 f6 f7 f8]
  160.     (chain this [f1 f2 f3 f4 f5 f6 f7 f8])))
  161.  
  162. (defn box
  163.   ([x]
  164.    (if (instance? Box x)
  165.      x
  166.      (box x (or (meta x) {}))))
  167.   ([x ameta]
  168.    (if (instance? Box x)
  169.      x
  170.      (->Box x ameta))))
  171.  
  172. (defn unwrap
  173.   [x]
  174.   (if (instance? Box x)
  175.     @x
  176.     x))
  177.  
  178. (defn- pp-box
  179.   [x]
  180.   (cond-> (with-out-str (pprint/pprint @x))
  181.     (not *print-readably*) (-> (s/replace "\n" "")
  182.                                (s/replace #"(?:(?: ){2,}|\\t*)" " "))))
  183. #?(:cljs
  184.    (extend-protocol IPrintWithWriter
  185.      Box
  186.      (-pr-writer [x writer _]
  187.        (write-all writer (pp-box x)))))
  188.  
  189. (defmulti tag-normalizer
  190.   "Normalize {:tag something} structures"
  191.   (fn [node] (or (:tag node) :default)))
  192.  
  193. (defmethod tag-normalizer :default
  194.   [node]
  195.   node)
  196.  
  197. (defn inner-tag-normalizer
  198.   [inner]
  199.   (if-not (sequential? inner)
  200.     inner
  201.     (-> (reduce (fn [acc [k v]]
  202.                   (assoc acc k (vec (flatten (map vals v)))))
  203.                 {}
  204.                 (group-by ffirst inner))
  205.         (dissoc nil))))
  206.  
  207. (defmethod tag-normalizer :task
  208.   [node]
  209.   (cond-> node
  210.     (get-in node [:content :inner] nil) (update-in [:content :inner] inner-tag-normalizer)))
  211.  
  212. #?(:clj
  213.    (defmethod print-method Box
  214.      [x ^java.io.Writer w]
  215.      (.write w (pp-box x))))
  216.  
  217. (defmethod pprint/simple-dispatch Box
  218.   [x]
  219.   (if *with-box-annotation*
  220.     (pprint/pprint-logical-block :prefix "#Box " :suffix ""
  221.                                  (pprint/simple-dispatch @x))
  222.     (pprint/simple-dispatch @x)))
  223.  
  224. (defn parse
  225.   [s]
  226.   (let [normalize-v-value #(if (= (count %) 1) (first %) (vec %))
  227.         normalize-meta (fn [from] (reduce (fn [acc [k v]]
  228.                                            (into acc [[(keyword (name k)) v]]))
  229.                                          {}
  230.                                          (dissoc (meta from) :instaparse.gll/start-column :instaparse.gll/end-column)))
  231.         group-with-normalization-n-meta (fn [node]
  232.                                           (reduce (fn [acc [k vv]]
  233.                                                     (into acc [[k (as-> (mapv #(with-meta (dissoc (unwrap %) :tag) (meta %)) vv) m-nval
  234.                                                                     (if (= (count m-nval) 1)
  235.                                                                       (box (:content (first m-nval)) (meta (first m-nval)))
  236.                                                                       (mapv #(box (:content %) (meta %)) m-nval)))]]))
  237.                                                   {}
  238.                                                   (group-by (comp :tag unwrap) node)))]
  239.     (->> (insta/add-line-and-column-info-to-metadata s (parser s))
  240.          (walk/postwalk (fn [node]
  241.                           (as-> (unwrap node) node
  242.                             (if (sequential? node)
  243.                               (cond
  244.                                 ;; Like (quote (1 2 3 4))
  245.                                 (and (symbol? (unwrap (first (seq node)))))
  246.                                 (normalize-v-value (unwrap (second node)))
  247.  
  248.                                 ;; Regular vectors, lists [] '()
  249.                                 (not (:content (unwrap (first node))))
  250.                                 (normalize-v-value node)
  251.  
  252.                                 ;; [{:content {} :tag a}] | [{:content {} :tag a}, {:content {} :tag b}]
  253.                                 (:content (unwrap (first node)))
  254.                                 (group-with-normalization-n-meta node)
  255.  
  256.                                 :else node)
  257.                               (cond
  258.                                 ;; {:status {}} | {:tag :task} etc..
  259.                                 (and (map? node) (meta node))
  260.                                 (box (tag-normalizer node) (normalize-meta node))
  261.  
  262.                                 ;; "  String with trailing whitespaces   "
  263.                                 (string? node)
  264.                                 (s/trim node)
  265.  
  266.                                 :else node)))))
  267.          (#(-> % unwrap :content)))))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement