aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/tool/compiler/language/lux/phase/generation/scheme/case.lux
blob: a1f679836f1dc02646e13b1b0f8662b97383e30c (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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
(.require
 [library
  [lux (.except case let if)
   [abstract
    ["[0]" monad (.only do)]]
   [data
    ["[0]" product]
    ["[0]" text (.only)
     ["%" \\format (.only format)]]
    [collection
     ["[0]" list (.use "[1]#[0]" functor mix)]
     ["[0]" set]]]
   [math
    [number
     ["i" int]]]
   [meta
    [macro
     ["^" pattern]
     ["[0]" template]]
    [target
     ["_" scheme (.only Expression Computation Var)]]]]]
 ["[0]" //
  ["[1][0]" runtime (.only Operation Phase Generator)]
  ["[1][0]" reference]
  ["[1][0]" primitive]
  ["/[1]" //
   ["[1][0]" reference]
   ["/[1]" //
    ["[1][0]" synthesis
     ["[1]/[0]" case]]
    ["/[1]" //
     ["[1][0]" synthesis (.only Member Synthesis Path)]
     ["[1][0]" generation]
     ["//[1]" ///
      [reference
       ["[1][0]" variable (.only Register)]]
      ["[1][0]" phase (.use "[1]#[0]" monad)]
      [meta
       [archive (.only Archive)]]]]]]])

(def .public register
  (-> Register Var)
  (|>> (///reference.local //reference.system) as_expected))

(def .public capture
  (-> Register Var)
  (|>> (///reference.foreign //reference.system) as_expected))

(def .public (let expression archive [valueS register bodyS])
  (Generator [Synthesis Register Synthesis])
  (do ///////phase.monad
    [valueO (expression archive valueS)
     bodyO (expression archive bodyS)]
    (in (_.let (list [(..register register) valueO])
          bodyO))))

(def .public (if expression archive [testS thenS elseS])
  (Generator [Synthesis Synthesis Synthesis])
  (do ///////phase.monad
    [testO (expression archive testS)
     thenO (expression archive thenS)
     elseO (expression archive elseS)]
    (in (_.if testO thenO elseO))))

(def .public (get expression archive [pathP valueS])
  (Generator [(List Member) Synthesis])
  (do ///////phase.monad
    [valueO (expression archive valueS)]
    (in (list#mix (function (_ side source)
                    (.let [method (.case side
                                    (^.with_template [<side> <accessor>]
                                      [(<side> lefts)
                                       (<accessor> (_.int (.int lefts)))])
                                    ([.#Left  //runtime.tuple//left]
                                     [.#Right //runtime.tuple//right]))]
                      (method source)))
                  valueO
                  (list.reversed pathP)))))

(def @savepoint (_.var "lux_pm_cursor_savepoint"))
(def @cursor (_.var "lux_pm_cursor"))
(def @temp (_.var "lux_pm_temp"))
(def @alt_error (_.var "alt_error"))

(def (push! value var)
  (-> Expression Var Computation)
  (_.set! var (_.cons/2 value var)))

(def (push_cursor! value)
  (-> Expression Computation)
  (push! value @cursor))

(def (pop! var)
  (-> Var Computation)
  (_.set! var (_.cdr/1 var)))

(def save_cursor!
  Computation
  (push! @cursor @savepoint))

(def restore_cursor!
  Computation
  (_.begin (list (_.set! @cursor (_.car/1 @savepoint))
                 (_.set! @savepoint (_.cdr/1 @savepoint)))))

(def peek
  Computation
  (_.car/1 @cursor))

(def pop_cursor!
  Computation
  (pop! @cursor))

(def pm_error
  (_.string (template.with_locals [pm_error]
              (template.text [pm_error]))))

(def fail!
  (_.raise/1 pm_error))

(def (try_pm on_failure happy_path)
  (-> Expression Expression Computation)
  (_.guard @alt_error
           (list [(_.and (list (_.string?/1 @alt_error)
                               (_.string=?/2 ..pm_error @alt_error)))
                  on_failure])
           {.#None}
           happy_path))

(def (pattern_matching' expression archive)
  (Generator Path)
  (function (again pathP)
    (.case pathP
      {/////synthesis.#Then bodyS}
      (expression archive bodyS)

      {/////synthesis.#Pop}
      (///////phase#in pop_cursor!)

      {/////synthesis.#Bind register}
      (///////phase#in (_.define_constant (..register register) ..peek))

      {/////synthesis.#Bit_Fork when thenP elseP}
      (do [! ///////phase.monad]
        [then! (again thenP)
         else! (.case elseP
                 {.#Some elseP}
                 (again elseP)

                 {.#None}
                 (in ..fail!))]
        (in (.if when
              (_.if ..peek
                then!
                else!)
              (_.if ..peek
                else!
                then!))))

      (^.with_template [<tag> <format> <=>]
        [{<tag> item}
         (do [! ///////phase.monad]
           [clauses (monad.each ! (function (_ [match then])
                                    (do !
                                      [then! (again then)]
                                      (in [(<=> (|> match <format>)
                                                ..peek)
                                           then!])))
                                {.#Item item})]
           (in (list#mix (function (_ [when then] else)
                           (_.if when then else))
                         ..fail!
                         clauses)))])
      ([/////synthesis.#I64_Fork //primitive.i64 _.=/2]
       [/////synthesis.#F64_Fork //primitive.f64 _.=/2]
       [/////synthesis.#Text_Fork //primitive.text _.string=?/2])

      (^.with_template [<pm> <flag> <prep>]
        [(<pm> idx)
         (///////phase#in (_.let (list [@temp (|> idx <prep> .int _.int (//runtime.sum//get ..peek (_.bool <flag>)))])
                            (_.if (_.null?/1 @temp)
                              ..fail!
                              (push_cursor! @temp))))])
      ([/////synthesis.side/left  false (<|)]
       [/////synthesis.side/right true  ++])

      (/////synthesis.member/left 0)
      (///////phase#in (..push_cursor! (_.vector_ref/2 ..peek (_.int +0))))

      (^.with_template [<pm> <getter>]
        [(<pm> lefts)
         (///////phase#in (|> ..peek (<getter> (_.int (.int lefts))) ..push_cursor!))])
      ([/////synthesis.member/left  //runtime.tuple//left]
       [/////synthesis.member/right //runtime.tuple//right])

      (/////synthesis.path/seq leftP rightP)
      (do ///////phase.monad
        [leftO (again leftP)
         rightO (again rightP)]
        (in (_.begin (list leftO
                           rightO))))
      
      (/////synthesis.path/alt leftP rightP)
      (do [! ///////phase.monad]
        [leftO (again leftP)
         rightO (again rightP)]
        (in (try_pm (_.begin (list restore_cursor!
                                   rightO))
                    (_.begin (list save_cursor!
                                   leftO)))))
      )))

(def (pattern_matching expression archive pathP)
  (Generator Path)
  (at ///////phase.monad each
      (try_pm (_.raise/1 (_.string "Invalid expression for pattern-matching.")))
      (pattern_matching' expression archive pathP)))

(def .public (case expression archive [valueS pathP])
  (Generator [Synthesis Path])
  (do [! ///////phase.monad]
    [valueO (expression archive valueS)]
    (<| (at ! each (_.let (list [@cursor (_.list/* (list valueO))]
                                [@savepoint (_.list/* (list))])))
        (pattern_matching expression archive pathP))))