aboutsummaryrefslogtreecommitdiff
path: root/src/lux/reader.clj
blob: c258701680e74f25a1015eeb6132f9ec6b066833 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
(ns lux.reader
  (:require [clojure.string :as string]
            [clojure.core.match :as M :refer [matchv]]
            clojure.core.match.array
            [lux.base :as & :refer [|do return* return fail fail* |let]]))

;; [Utils]
(defn ^:private with-line [body]
  (fn [state]
    (matchv ::M/objects [(&/get$ &/$SOURCE state)]
      [["lux;Nil" _]]
      (fail* "[Reader Error] EOF")

      [["lux;Cons" [["lux;Meta" [[file-name line-num column-num] line]]
                    more]]]
      (matchv ::M/objects [(body file-name line-num column-num line)]
        [["No" msg]]
        (fail* msg)

        [["Done" output]]
        (return* (&/set$ &/$SOURCE more state)
                 output)

        [["Yes" [output line*]]]
        (return* (&/set$ &/$SOURCE (&/|cons line* more) state)
                 output))
      )))

(defn ^:private with-lines [body]
  (fn [state]
    (matchv ::M/objects [(body (&/get$ &/$SOURCE state))]
      [["lux;Right" [reader* match]]]
      (return* (&/set$ &/$SOURCE reader* state)
               match)

      [["lux;Left" msg]]
      (fail* msg)
      )))

;; [Exports]
(defn ^:private re-find! [^java.util.regex.Pattern regex line]
  (let [matcher (.matcher regex line)]
    (when (.find matcher)
      (.group matcher 0))))

(defn ^:private re-find1! [^java.util.regex.Pattern regex line]
  (let [matcher (.matcher regex line)]
    (when (.find matcher)
      (.group matcher 1))))

(defn ^:private re-find3! [^java.util.regex.Pattern regex line]
  (let [matcher (.matcher regex line)]
    (when (.find matcher)
      (list (.group matcher 0)
            (.group matcher 1)
            (.group matcher 2)))))

(defn read-regex [regex]
  (with-line
    (fn [file-name line-num column-num ^String line]
      (if-let [^String match (do ;; (prn '[regex line] [regex line])
                               (re-find! regex line))]
        (let [;; _ (prn 'match match)
              match-length (.length match)
              line* (.substring line match-length)]
          (if (.isEmpty line*)
            (&/V "Done" (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) match)))
            (&/V "Yes" (&/T (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) match))
                            (&/V "lux;Meta" (&/T (&/T file-name line-num (+ column-num match-length)) line*))))))
        (&/V "No" (str "[Reader Error] Pattern failed: " regex))))))

(defn read-regex2 [regex]
  (with-line
    (fn [file-name line-num column-num ^String line]
      (if-let [[^String match tok1 tok2] (re-find3! regex line)]
        (let [match-length (.length match)
              line* (.substring line match-length)]
          (if (.isEmpty line*)
            (&/V "Done" (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) (&/T tok1 tok2))))
            (&/V "Yes" (&/T (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) (&/T tok1 tok2)))
                            (&/V "lux;Meta" (&/T (&/T file-name line-num (+ column-num match-length)) line*))))))
        (&/V "No" (str "[Reader Error] Pattern failed: " regex))))))

(defn read-regex+ [regex]
  (with-lines
    (fn [reader]
      (loop [prefix ""
             reader* reader]
        (matchv ::M/objects [reader*]
          [["lux;Nil" _]]
          (&/V "lux;Left" "[Reader Error] EOF")

          [["lux;Cons" [[_ [[file-name line-num column-num] ^String line]]
                        reader**]]]
          (if-let [^String match (do ;; (prn 'read-regex+ regex line)
                                   (re-find1! regex line))]
            (let [match-length (.length match)
                  line* (.substring line match-length)]
              (if (.isEmpty line*)
                (recur (str prefix match "\n") reader**)
                (&/V "lux;Right" (&/T (&/|cons (&/V "lux;Meta" (&/T (&/T file-name line-num (+ column-num match-length)) line*))
                                               reader**)
                                      (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) (str prefix match)))))))
            (&/V "lux;Left" (str "[Reader Error] Pattern failed: " regex))))))))

(defn read-text [^String text]
  (with-line
    (fn [file-name line-num column-num ^String line]
      (if (.startsWith line text)
        (let [match-length (.length text)
              line* (.substring line match-length)]
          (if (empty? line*)
            (&/V "Done" (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) text)))
            (&/V "Yes" (&/T (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) text))
                            (&/V "lux;Meta" (&/T (&/T file-name line-num (+ column-num match-length)) line*))))))
        (&/V "No" (str "[Reader Error] Text failed: " text))))))

(defn from [file-name]
  (let [lines (&/->list (string/split-lines (slurp file-name)))]
    (&/|map (fn [line+line-num]
              (|let [[line-num line] line+line-num]
                (&/V "lux;Meta" (&/T (&/T file-name line-num 0)
                                     line))))
            (&/|filter (fn [line+line-num]
                         (|let [[line-num line] line+line-num]
                           (not= "" line)))
                       (&/enumerate lines)))))