aboutsummaryrefslogtreecommitdiff
path: root/src/lux/reader.clj
blob: 6a954d5ffb67f857fef7925a10b425aabed1621f (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
(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))
      )))

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

(defn ^:private re-find3! [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 (re-find! regex line)]
        (let [match-length (.length match)
              line* (.substring line match-length)]
          (if (empty? 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 (empty? 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-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)))))