aboutsummaryrefslogtreecommitdiff
path: root/src/lux/reader.clj
blob: b4824261a0ac430866c0292ee356799577482aa7 (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
(ns lux.reader
  (:require [clojure.string :as string]
            [clojure.core.match :as M :refer [matchv]]
            clojure.core.match.array
            [lux.base :as & :refer [exec return* return fail fail* |let]]))

;; [Utils]
(defn ^:private with-line [body]
  (fn [state]
    (matchv ::M/objects [(&/get$ "lux;source" state)]
      [["lux;None" _]]
      (fail* "[Reader Error] No source code.")

      [["lux;Some" ["lux;Nil" _]]]
      (fail* "[Reader Error] EOF")

      [["lux;Some" ["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)

        [["Yes" [meta ["lux;None" _]]]]
        (return* (&/set$ "lux;source" (&/V "lux;Some" more) state)
                 meta)

        [["Yes" [meta ["lux;Some" line-meta]]]]
        (return* (&/set$ "lux;source" (&/V "lux;Some" (&/|cons line-meta more)) state)
                 meta))
      )))

;; [Exports]
(defn read-regex [regex]
  (with-line
    (fn [file-name line-num column-num line]
      (if-let [[match] (re-find regex line)]
        (let [match-length (.length match)
              line* (.substring line match-length)]
          (&/V "Yes" (&/T (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) match))
                          (if (empty? line*)
                            (&/V "lux;None" nil)
                            (&/V "lux;Some" (&/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 line]
      (if-let [[match tok1 tok2] (re-find regex line)]
        (let [match-length (.length match)
              line* (.substring line match-length)]
          (&/V "Yes" (&/T (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) [tok1 tok2]))
                          (if (empty? line*)
                            (&/V "lux;None" nil)
                            (&/V "lux;Some" (&/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 [text]
  (with-line
    (fn [file-name line-num column-num line]
      ;; (prn 'read-text text line)
      (if (.startsWith line text)
        (let [match-length (.length text)
              line* (.substring line match-length)]
          (&/V "Yes" (&/T (&/V "lux;Meta" (&/T (&/T file-name line-num column-num) text))
                          (if (empty? line*)
                            (&/V "lux;None" nil)
                            (&/V "lux;Some" (&/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 line-num] line+line-num]
                (&/V "lux;Meta" (&/T (&/T file-name line-num 0)
                                     line))))
            (&/|filter (fn [line+line-num]
                         (|let [[line line-num] line+line-num]
                           (not (empty? line))))
                       (&/zip2 lines
                               (&/|range (&/|length lines)))))))