(ns nal.reader
  (:require [clojure.string :as s])
  (:import (clojure.lang LispReader)))
(defn dispatch-reader-macro [ch fun]
  (let [dm (.get
             (doto
               (.getDeclaredField LispReader "dispatchMacros")
               (.setAccessible true))
             nil)]
    (aset dm (int ch) fun)))
(defn fetch-rule
  ([rdr] (fetch-rule rdr  0))
  ([rdr prev cnt]
   (let [c (.read rdr)
         cnt (case (char c)
               \] (dec cnt)
               \[ (inc cnt)
               cnt)]
     (if (neg? cnt)
       prev
       (recur rdr (str prev (char c)) cnt)))))
(defn add-brackets [s]
  (str "[" s "]"))
(defn replacements [s]
  (-> s
      (s/replace #"\{([^\}]*)\}" "(ext-set $1)")
      (s/replace #"\[([^\]]*)]" "(int-set $1)")
      (s/replace #"=\\>" "retro-impl")
      (s/replace #"=/>" "pred-impl")
      (s/replace #"~" "int-dif")
      (s/replace #"&/" "seq-conj ")
      (s/replace #"\(&\s" "(ext-inter ")
      (s/replace #"\s&\s" " ext-inter ")
      (s/replace #"&&" "conj")
      (s/replace #"\{--" "inst")
      (s/replace #"--]" "prop")
      (s/replace #"\{-\]" "inst-prop")
      (s/replace #"\(\\" "(int-image")
      (s/replace #"\(/" "(ext-image")
      (s/replace #"\$([A-Z])" "(ind-var $1)")
      (s/replace #"#([A-Z])" "(dep-var $1)")))
(defn read-rule [s]
  (-> s replacements add-brackets read-string))
(defn rule [rdr letter-R opts & other]
  (let [c (.read rdr)]
    (if (= c (int \[))
      (read-rule (fetch-rule rdr))
      (throw (Exception. (str "Reader barfed on " (char c)))))))
(dispatch-reader-macro \R rule)