aboutsummaryrefslogtreecommitdiff
path: root/lux-bootstrapper/src/lux/compiler/core.clj
blob: 5ba14e3edd448f792d7ae36bb6b3c698aa900910 (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
(ns lux.compiler.core
  (:require (clojure [template :refer [do-template]]
                     [string :as string])
            [clojure.java.io :as io]
            [clojure.core.match :as M :refer [matchv]]
            clojure.core.match.array
            (lux [base :as & :refer [|case |let |do return* return fail*]])
            (lux.analyser [base :as &a]
                          [module :as &a-module])
            (lux.compiler.cache [type :as &&&type]))
  (:import (java.io File
                    BufferedOutputStream
                    FileOutputStream)))

;; [Constants]
(def !output-dir (atom nil))

(def ^:const section-separator (->> 29 char str))
(def ^:const datum-separator (->> 31 char str))
(def ^:const entry-separator (->> 30 char str))

;; [Utils]
(defn write-file [^String file-name ^bytes data]
  (do (assert (not (.exists (File. file-name))) (str "Cannot overwrite file: " file-name))
    (with-open [stream (BufferedOutputStream. (FileOutputStream. file-name))]
      (.write stream data)
      (.flush stream))))

;; [Exports]
(def ^String lux-module-descriptor-name "lux_module_descriptor")

(defn write-module-descriptor! [^String name ^String descriptor]
  (|do [_ (return nil)
        :let [lmd-dir (str @!output-dir java.io.File/separator (.replace name "/" java.io.File/separator))
              _ (.mkdirs (File. lmd-dir))
              _ (write-file (str lmd-dir java.io.File/separator lux-module-descriptor-name) (.getBytes descriptor java.nio.charset.StandardCharsets/UTF_8))]]
    (return nil)))

(defn read-module-descriptor! [^String name]
  (|do [_ (return nil)]
    (return (slurp (str @!output-dir java.io.File/separator (.replace name "/" java.io.File/separator) java.io.File/separator lux-module-descriptor-name)
                   :encoding "UTF-8"))))

(defn generate-module-descriptor [file-hash]
  (|do [module-name &/get-module-name
        defs &a-module/defs
        imports &a-module/imports
        :let [def-entries (&/fold (fn [def-entries _def]
                                    (|let [[?name _definition] _def]
                                      (|case _definition
                                        (&/$AliasG [_dmodule _dname])
                                        (str "A"
                                             datum-separator ?name
                                             datum-separator _dmodule &/+name-separator+ _dname
                                             ;; Next
                                             entry-separator def-entries)
                                        
                                        (&/$DefinitionG [exported? ?def-type ?def-value])
                                        (str "D"
                                             datum-separator ?name
                                             datum-separator (if exported? "1" "0")
                                             datum-separator (&&&type/serialize-type ?def-type)
                                             ;; Next
                                             entry-separator def-entries)

                                        (&/$TypeG [exported? value labels])
                                        (let [[record? head tail] (|case labels
                                                                    (&/$Left [head tail])
                                                                    [false head tail]
                                                                    
                                                                    (&/$Right [head tail])
                                                                    [true head tail])]
                                          (str ":"
                                               datum-separator ?name
                                               datum-separator (if exported? "1" "0")
                                               datum-separator (if record? "1" "0")
                                               datum-separator head
                                               datum-separator (->> tail
                                                                    (&/|interpose &/+name-separator+)
                                                                    (&/fold str ""))
                                               ;; Next
                                               entry-separator def-entries))

                                        (&/$TagG [?export ?type ?group ?index])
                                        def-entries
                                        ;; (str "T"
                                        ;;      datum-separator ?name
                                        ;;      datum-separator (if ?export "1" "0")
                                        ;;      datum-separator (&&&type/serialize-type ?type)
                                        ;;      datum-separator ?index
                                        ;;      datum-separator (->> ?group
                                        ;;                           (&/|interpose &/+name-separator+)
                                        ;;                           (&/fold str "")))

                                        (&/$SlotG [?export ?type ?group ?index])
                                        def-entries
                                        ;; (str "S"
                                        ;;      datum-separator ?name
                                        ;;      datum-separator (if ?export "1" "0")
                                        ;;      datum-separator (&&&type/serialize-type ?type)
                                        ;;      datum-separator ?index
                                        ;;      datum-separator (->> ?group
                                        ;;                           (&/|interpose &/+name-separator+)
                                        ;;                           (&/fold str "")))
                                        )))
                                  ""
                                  defs)
              import-entries (->> imports
                                  (&/|map (fn [import]
                                            (|let [[_module _hash] import]
                                              (str _module datum-separator _hash))))
                                  (&/|interpose entry-separator)
                                  (&/fold str ""))
              module-descriptor (->> (&/|list &/version
                                              (Long/toUnsignedString file-hash)
                                              import-entries
                                              def-entries)
                                     (&/|interpose section-separator)
                                     (&/fold str ""))]]
    (return module-descriptor)))