aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/compiler/default/phase/synthesis/function.lux
blob: 3c89ae063579e1bf630661e2c30ef8892ceadc87 (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
(.module:
  [lux (#- function)
   [control
    ["." monad (#+ do)]]
   [data
    ["." maybe]
    [collection
     ["." list ("list/." Functor<List> Monoid<List> Fold<List>)]
     ["dict" dictionary (#+ Dictionary)]]]]
  ["." // (#+ Synthesis Operation Phase)
   ["." loop (#+ Transform)]
   ["/." //
    ["." analysis (#+ Environment Arity Analysis)]
    [//
     ["." reference (#+ Variable)]]]])

(def: #export nested?
  (-> Arity Bit)
  (n/> 1))

(def: #export (adjust up-arity after? var)
  (-> Arity Bit Variable Variable)
  (case var
    (#reference.Local register)
    (if (and after? (n/>= up-arity register))
      (#reference.Local (n/+ (dec up-arity) register))
      var)

    _
    var))

(def: (unfold apply)
  (-> Analysis [Analysis (List Analysis)])
  (loop [apply apply
         args (list)]
    (case apply
      (#analysis.Apply arg func)
      (recur func (#.Cons arg args))

      _
      [apply args])))

(def: #export (apply synthesize)
  (-> Phase Phase)
  (.function (_ exprA)
    (let [[funcA argsA] (unfold exprA)]
      (do ///.Monad<Operation>
        [funcS (synthesize funcA)
         argsS (monad.map @ synthesize argsA)
         locals //.locals]
        (case funcS
          (^ (//.function/abstraction functionS))
          (wrap (|> functionS
                    (loop.loop (get@ #//.environment functionS) locals argsS)
                    (maybe.default (//.function/apply [funcS argsS]))))

          (^ (//.function/apply [funcS' argsS']))
          (wrap (//.function/apply [funcS' (list/compose argsS' argsS)]))

          _
          (wrap (//.function/apply [funcS argsS])))))))

(def: (prepare up down body)
  (-> Arity Arity Synthesis Synthesis)
  (if (nested? up)
    body
    (maybe.default body (loop.recursion down body))))

(def: #export (function synthesize environment body)
  (-> Phase Environment Analysis (Operation Synthesis))
  (do ///.Monad<Operation>
    [direct? //.direct?
     arity //.scope-arity
     resolver //.resolver
     #let [function-arity (if direct?
                            (inc arity)
                            1)
           up-environment (if (nested? arity)
                            (list/map (.function (_ closure)
                                        (case (dict.get closure resolver)
                                          (#.Some resolved)
                                          (adjust arity #1 resolved)

                                          #.None
                                          (adjust arity #0 closure)))
                                      environment)
                            environment)
           down-environment (: (List Variable)
                               (case environment
                                 #.Nil
                                 (list)
                                 
                                 _
                                 (|> environment
                                     list.size
                                     list.indices
                                     (list/map (|>> #reference.Foreign)))))
           resolver' (if (and (nested? function-arity)
                              direct?)
                       (list/fold (.function (_ [from to] resolver')
                                    (dict.put from to resolver'))
                                  //.fresh-resolver
                                  (list.zip2 down-environment up-environment))
                       (list/fold (.function (_ var resolver')
                                    (dict.put var var resolver'))
                                  //.fresh-resolver
                                  down-environment))]
     bodyS (//.with-abstraction function-arity resolver'
             (synthesize body))]
    (case bodyS
      (^ (//.function/abstraction [env' down-arity' bodyS']))
      (let [arity' (inc down-arity')]
        (|> (prepare function-arity arity' bodyS')
            [up-environment arity'] //.function/abstraction
            wrap))

      _
      (|> (prepare function-arity 1 bodyS)
          [up-environment 1] //.function/abstraction
          wrap))))