aboutsummaryrefslogtreecommitdiff
path: root/luxc/src/lux/analyser/record.clj
blob: 3d3d8169fd2b4603e9a27243b81ea2b0de3815cb (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
(ns lux.analyser.record
  (:require clojure.core.match
            clojure.core.match.array
            (lux [base :as & :refer [|let |do return |case]]
                 [type :as &type])
            (lux.analyser [base :as &&]
                          [module :as &&module])))

;; [Exports]
(defn order-record [pairs]
  "(-> (List (, Syntax Syntax)) (Lux (List Syntax)))"
  (|do [[tag-group tag-type] (|case pairs
                               (&/$Nil)
                               (return (&/T [&/$Nil &type/Any]))
                               
                               (&/$Cons [[_ (&/$Tag tag1)] _] _)
                               (|do [[module name] (&&/resolved-ident tag1)
                                     tags (&&module/tag-group module name)
                                     type (&&module/tag-type module name)]
                                 (return (&/T [tags type])))

                               _
                               (&/fail-with-loc "[Analyser Error] Wrong syntax for records. Odd elements must be tags."))
        =pairs (&/map% (fn [kv]
                         (|case kv
                           [[_ (&/$Tag k)] v]
                           (|do [=k (&&/resolved-ident k)]
                             (return (&/T [(&/ident->text =k) v])))

                           _
                           (&/fail-with-loc "[Analyser Error] Wrong syntax for records. Odd elements must be tags.")))
                       pairs)
        _ (let [num-expected (&/|length tag-group)
                num-got (&/|length =pairs)]
            (&/assert! (= num-expected num-got)
                       (str "[Analyser Error] Wrong number of record members. Expected " num-expected ", but got " num-got ".")))
        =members (&/map% (fn [tag]
                           (if-let [member (&/|get tag =pairs)]
                             (return member)
                             (&/fail-with-loc (str "[Analyser Error] Missing tag: " tag))))
                         (&/|map &/ident->text tag-group))]
    (return (&/T [=members tag-type]))))