aboutsummaryrefslogtreecommitdiff
path: root/new-luxc/source/luxc/lang/synthesis/case.lux
blob: 968c35561cc16f2258764dad9a3043e21a29d1d8 (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
(.module:
  lux
  (lux (data [bool "bool/" Eq<Bool>]
             [text "text/" Eq<Text>]
             text/format
             [number]
             (coll [list "list/" Fold<List> Monoid<List>]))
       (macro [code "code/" Eq<Code>]))
  (luxc (lang [".L" variable #+ Variable]
              ["la" analysis]
              ["ls" synthesis]
              (synthesis [".S" function]))))

(def: popPS ls.Path (' ("lux case pop")))

(def: (path' arity num-locals pattern)
  (-> ls.Arity Nat la.Pattern [Nat (List ls.Path)])
  (case pattern
    (^code ("lux case tuple" [(~+ membersP)]))
    (case membersP
      #.Nil
      [num-locals
       (list popPS)]

      (#.Cons singletonP #.Nil)
      (path' arity num-locals singletonP)

      (#.Cons _)
      (let [last-idx (n/dec (list.size membersP))
            [_ output] (list/fold (: (-> la.Pattern [Nat [Nat (List ls.Path)]] [Nat [Nat (List ls.Path)]])
                                     (function (_ current-pattern [current-idx num-locals' next])
                                       (let [[num-locals'' current-path] (path' arity num-locals' current-pattern)]
                                         [(n/dec current-idx)
                                          num-locals''
                                          (|> (list (if (n/= last-idx current-idx)
                                                      (` ("lux case tuple right" (~ (code.nat current-idx))))
                                                      (` ("lux case tuple left" (~ (code.nat current-idx))))))
                                              (list/compose current-path)
                                              (list/compose next))])))
                                  [last-idx num-locals (list popPS)]
                                  (list.reverse membersP))]
        output))

    (^code ("lux case variant" (~ [_ (#.Nat tag)]) (~ [_ (#.Nat num-tags)]) (~ memberP)))
    (let [[num-locals' member-path] (path' arity num-locals memberP)]
      [num-locals' (|> (list (if (n/= (n/dec num-tags) tag)
                               (` ("lux case variant right" (~ (code.nat tag))))
                               (` ("lux case variant left" (~ (code.nat tag))))))
                       (list/compose member-path)
                       (list& popPS))])

    (^code ("lux case bind" (~ [_ (#.Nat register)])))
    [(n/inc num-locals)
     (list popPS
           (` ("lux case bind" (~ (code.nat (if (functionS.nested? arity)
                                              (n/+ (n/dec arity) register)
                                              register))))))]

    _
    [num-locals
     (list popPS pattern)]))

(def: (clean-unnecessary-pops paths)
  (-> (List ls.Path) (List ls.Path))
  (case paths
    (#.Cons path paths')
    (if (is? popPS path)
      (clean-unnecessary-pops paths')
      paths)

    #.Nil
    paths))

(def: #export (path arity num-locals synthesize pattern bodyA)
  (->  ls.Arity Nat (-> Nat la.Analysis ls.Synthesis) la.Pattern la.Analysis ls.Path)
  (let [[num-locals' pieces] (path' arity num-locals pattern)]
    (|> pieces
        clean-unnecessary-pops
        (list/fold (function (_ pre post)
                     (` ("lux case seq" (~ pre) (~ post))))
                   (` ("lux case exec" (~ (synthesize num-locals' bodyA))))))))

(def: #export (weave leftP rightP)
  (-> ls.Path ls.Path ls.Path)
  (with-expansions [<default> (as-is (` ("lux case alt" (~ leftP) (~ rightP))))]
    (case [leftP rightP]
      (^ [(^code ("lux case seq" (~ preL) (~ postL)))
          (^code ("lux case seq" (~ preR) (~ postR)))])
      (case (weave preL preR)
        (^code ("lux case alt" (~ thenP) (~ elseP)))
        <default>

        weavedP
        (` ("lux case seq" (~ weavedP) (~ (weave postL postR)))))

      _
      (if (code/= leftP rightP)
        rightP
        <default>))))