aboutsummaryrefslogtreecommitdiff
path: root/luxc/src/lux/repl.clj
blob: 195f3dc3e23c1f2ca3224d07a7d753503fb5a53b (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
;;  Copyright (c) Eduardo Julian. All rights reserved.
;;  This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
;;  If a copy of the MPL was not distributed with this file,
;;  You can obtain one at http://mozilla.org/MPL/2.0/.

(ns lux.repl
  (:require clojure.core.match
            clojure.core.match.array
            (lux [base :as & :refer [|let |do return* return fail fail* |case]]
                 [type :as &type]
                 [analyser :as &analyser]
                 [optimizer :as &optimizer]
                 [compiler :as &compiler])
            [lux.compiler.cache :as &cache]
            [lux.analyser.base :as &a-base]
            [lux.analyser.lux :as &a-lux]
            [lux.analyser.module :as &module])
  (:import (java.io InputStreamReader
                    BufferedReader)))

;; [Utils]
(def ^:private repl-module "REPL")

(defn ^:private repl-cursor [repl-line]
  (&/T [repl-module repl-line 0]))

(defn ^:private init [source-dirs]
  (do (&compiler/init!)
    (|case ((|do [_ (&compiler/compile-module source-dirs "lux")
                  _ (&cache/delete repl-module)
                  _ (&module/create-module repl-module 0)
                  _ (fn [?state]
                      (return* (&/set$ &/$source
                                       (&/|list (&/T [(repl-cursor -1) "(;import lux)"]))
                                       ?state)
                               nil))
                  analysed-tokens (&analyser/repl-analyse &optimizer/optimize &compiler/eval! (partial &compiler/compile-module source-dirs) &compiler/all-compilers)
                  eval-values (->> analysed-tokens (&/|map &optimizer/optimize) (&/map% &compiler/eval!))]
              (return nil))
            (&/init-state &/$REPL))
      (&/$Right ?state _)
      (do (println)
        (println "Welcome to the REPL!")
        (println "Type \"exit\" to leave.")
        (println)
        ?state)

      (&/$Left ?message)
      (assert false ?message))
    ))

;; [Values]
(defn repl [source-dirs]
  (with-open [input (->> System/in (new InputStreamReader) (new BufferedReader))]
    (loop [state (init source-dirs)
           repl-line 0
           multi-line? false]
      (let [_ (if (not multi-line?)
                (.print System/out "> ")
                (.print System/out "  "))
            line (.readLine input)]
        (if (= "exit" line)
          (println "Till next time...")
          (let [line* (&/|list (&/T [(repl-cursor repl-line) line]))
                state* (&/update$ &/$source
                                  (fn [_source] (&/|++ _source line*))
                                  state)]
            (|case ((|do [analysed-tokens (&analyser/repl-analyse &optimizer/optimize &compiler/eval! (partial &compiler/compile-module source-dirs) &compiler/all-compilers)
                          eval-values (->> analysed-tokens (&/|map &optimizer/optimize) (&/map% &compiler/eval!))
                          :let [outputs (map (fn [analysis value]
                                               (|let [[[_type _cursor] _term] analysis]
                                                 [_type value]))
                                             (&/->seq analysed-tokens)
                                             (&/->seq eval-values))]]
                      (return outputs))
                    state*)
              (&/$Right state** outputs)
              (do (doseq [[_type _value] outputs]
                    (.println System/out (str "=> " (pr-str _value) "\n:: " (&type/show-type _type)"\n")))
                (recur state** (inc repl-line) false))

              (&/$Left ^String ?message)
              (if (or (= "[Reader Error] EOF" ?message)
                      (.contains ?message "[Parser Error] Unbalanced "))
                (recur state* (inc repl-line) true)
                (do (println ?message)
                  (recur state (inc repl-line) false)))
              ))))
      )))