(ns mini-program-cljs.parser
  (:require [instaparse.core :as insta]))


(def as-and-bs
  (insta/parser
    "S = AB*
     AB = A B
     A = 'a'+
     B = 'b'+"))

(defn parser-test []
  (clj->js (as-and-bs "aaaaabbbaaaabb")))


(comment
  (parser2 "   [[我的]]  ")
  (parser2 "   ((aaaaaa))  ")
  (parser2 " asd321  ((aaaaaa)) dsa1 ")
  (parser2 " 大叔  ((我的)) 大神 [[aaa32大神]]")
  ;;=>
  [:S [:expr [:others " 大叔  "]]
   [:expr [:objs [:bref "我的"]]]
   [:expr [:others " 大神 "]]
   [:expr [:objs [:link "aaa32大神"]]]]
  )
;; 支持多个并排的引用和字符串的解析
(def parser2
  (insta/parser
    "S = c | link | bref | hash | expr* (* 对象可以是直接的四种对象,加上混合的表达式 *)
    <space> = <#'[ ]+'>
    others = space* c* space* (* 剩下的字符串,非目标 *)
    expr = others*  objs*  others* (* 混合的表达式 *)
    objs = link | hash | bref (* 匹配的目标 *)
    <c> = #'(\\w|\\s|[\u4e00-\u9fa5])+' (* 中英文字符串 *)
    link = <'[['> c <']]'> | <'[[]]'>
    hash = <'#'> c | <'#'> <'[['> c <']]'>
    bref = <'(('> c <'))'> | <'(())'>
   "))

(defn parser-test2 [stri]
  (clj->js (parser2 stri)))

(comment
  (parser->jsobj " 大叔  ((我的)) 大神 [[aaa32大神]]")
  ;; => #js [#js ["others" " 大叔  "] #js ["bref" "我的"] #js ["others" " 大神 "] #js ["link" "aaa32大神"]]
  )
(defn parser->jsobj
  "暂时只是支持列表的解析,递归的嵌套不支持先 => 给小程序的组件来使用,循环渲染引用note"
  [stri]
  (->> stri
    parser2
    rest
    (map
      (fn [item]
        (let [data (last item)]
          (cond (= (first data) :others)
                , [:others (last data)]
                (= (first data) :objs)
                , (last data)
                :else data))))
    clj->js))

(defn link-parse2 [str transform]
  (let [result (parser2 str)]
    (if (insta/failure? result)
      str
      (clj->js (transform result)))))

(defn link-transform2
  "将解析输出为hiccup"
  [tree expr objs others link hash bref]
  (insta/transform
    {:expr (fn [x] (expr x))
     :objs (fn [x] (objs x))
     :others (fn [x] (others x))
     :link (fn [x] (link x))
     :hash (fn [x] (hash x))
     :bref (fn [x] (bref x))}
    tree))
