aboutsummaryrefslogtreecommitdiff
path: root/new-luxc/source/luxc/env.lux
blob: be68f84e98c5de2bf103ed90370679d20d20ff11 (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
(;module:
  lux
  (lux (control monad)
       (data [text "T/" Eq<Text>]
             text/format
             [maybe #+ Monad<Maybe> "Maybe/" Monad<Maybe>]
             [product]
             (coll [list "L/" Fold<List> Monoid<List>])))
  (luxc ["&" base]))

(type: Captured (Bindings Text [Type Ref]))

(def: (pl::contains? key mappings)
  (All [a] (-> Text (List [Text a]) Bool))
  (case mappings
    #;Nil
    false

    (#;Cons [k v] mappings')
    (or (T/= key k)
        (pl::contains? key mappings'))))

(def: (pl::get key mappings)
  (All [a] (-> Text (List [Text a]) (Maybe a)))
  (case mappings
    #;Nil
    #;None

    (#;Cons [k v] mappings')
    (if (T/= key k)
      (#;Some v)
      (pl::get key mappings'))))

(def: (pl::put key value mappings)
  (All [a] (-> Text a (List [Text a]) (List [Text a])))
  (case mappings
    #;Nil
    (list [key value])

    (#;Cons [k v] mappings')
    (if (T/= key k)
      (#;Cons [key value] mappings')
      (#;Cons [k v]
              (pl::put key value mappings')))))

(do-template [<slot> <is> <get> <then>]
  [(def: (<is> name scope)
     (-> Text Scope Bool)
     (|> scope
         (get@ [<slot> #;mappings])
         (pl::contains? name)))

   (def: (<get> name scope)
     (-> Text Scope (Maybe [Type Ref]))
     (|> scope
         (get@ [<slot> #;mappings])
         (pl::get name)
         (Maybe/map (function [[type value]]
                      [type (<then> value)]))))]

  [#;locals   is-local?    get-local    #;Local]
  [#;captured is-captured? get-captured id]
  )

(def: (is-ref? name scope)
  (-> Text Scope Bool)
  (or (is-local? name scope)
      (is-captured? name scope)))

(def: (get-ref name scope)
  (-> Text Scope (Maybe [Type Ref]))
  (case (get-local name scope)
    (#;Some type)
    (#;Some type)

    _
    (get-captured name scope)))

(def: #export (find name)
  (-> Text (Lux (Maybe [Type Ref])))
  (function [compiler]
    (let [[inner outer] (|> compiler
                            (get@ #;scopes)
                            (list;split-with (|>. (is-ref? name) not)))]
      (case outer
        #;Nil
        (#;Right [compiler #;None])

        (#;Cons top-outer _)
        (let [[ref-type init-ref] (default (undefined)
                                    (get-ref name top-outer))
              [ref inner'] (L/fold (: (-> Scope [Ref (List Scope)] [Ref (List Scope)])
                                      (function [scope [ref inner]]
                                        [(#;Captured (get@ [#;captured #;counter] scope))
                                         (#;Cons (update@ #;captured
                                                          (: (-> Captured Captured)
                                                             (|>. (update@ #;counter n.inc)
                                                                  (update@ #;mappings (pl::put name [ref-type ref]))))
                                                          scope)
                                                 inner)]))
                                   [init-ref #;Nil]
                                   (list;reverse inner))
              scopes (L/append inner' outer)]
          (#;Right [(set@ #;scopes scopes compiler)
                    (#;Some [ref-type ref])]))
        ))))