aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/tool/compiler/phase/analysis/function.lux
blob: 76effa0dca3cffc8979c9eec61c598bfb0d0d5e7 (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 (#- function)
   [abstract
    monad]
   [control
    ["ex" exception (#+ exception:)]]
   [data
    ["." maybe]
    ["." text
     format]
    [collection
     ["." list ("#@." fold monoid monad)]]]
   ["." type
    ["." check]]
   ["." macro]]
  ["." // #_
   ["#." scope]
   ["#." type]
   ["#." inference]
   ["#/" //
    ["#." extension]
    [//
     ["/" analysis (#+ Analysis Operation Phase)]]]])

(exception: #export (cannot-analyse {expected Type} {function Text} {argument Text} {body Code})
  (ex.report ["Type" (%type expected)]
             ["Function" function]
             ["Argument" argument]
             ["Body" (%code body)]))

(exception: #export (cannot-apply {functionT Type} {functionC Code} {arguments (List Code)})
  (ex.report ["Function type" (%type functionT)]
             ["Function" (%code functionC)]
             ["Arguments" (|> arguments
                              list.enumerate
                              (list@map (.function (_ [idx argC])
                                          (format (%n idx) " " (%code argC))))
                              (text.join-with text.new-line))]))

(def: #export (function analyse function-name arg-name body)
  (-> Phase Text Text Code (Operation Analysis))
  (do ///.monad
    [functionT (///extension.lift macro.expected-type)]
    (loop [expectedT functionT]
      (/.with-stack cannot-analyse [expectedT function-name arg-name body]
        (case expectedT
          (#.Named name unnamedT)
          (recur unnamedT)

          (#.Apply argT funT)
          (case (type.apply (list argT) funT)
            (#.Some value)
            (recur value)

            #.None
            (/.fail (ex.construct cannot-analyse [expectedT function-name arg-name body])))

          (^template [<tag> <instancer>]
            (<tag> _)
            (do @
              [[_ instanceT] (//type.with-env <instancer>)]
              (recur (maybe.assume (type.apply (list instanceT) expectedT)))))
          ([#.UnivQ check.existential]
           [#.ExQ check.var])
          
          (#.Var id)
          (do @
            [?expectedT' (//type.with-env
                           (check.read id))]
            (case ?expectedT'
              (#.Some expectedT')
              (recur expectedT')

              ## Inference
              _
              (do @
                [[input-id inputT] (//type.with-env check.var)
                 [output-id outputT] (//type.with-env check.var)
                 #let [functionT (#.Function inputT outputT)]
                 functionA (recur functionT)
                 _ (//type.with-env
                     (check.check expectedT functionT))]
                (wrap functionA))
              ))

          (#.Function inputT outputT)
          (<| (:: @ map (.function (_ [scope bodyA])
                          (#/.Function (//scope.environment scope) bodyA)))
              /.with-scope
              ## Functions have access not only to their argument, but
              ## also to themselves, through a local variable.
              (//scope.with-local [function-name expectedT])
              (//scope.with-local [arg-name inputT])
              (//type.with-type outputT)
              (analyse body))
          
          _
          (/.fail "")
          )))))

(def: #export (apply analyse functionT functionA functionC argsC+)
  (-> Phase Type Analysis Code (List Code) (Operation Analysis))
  (<| (/.with-stack cannot-apply [functionT functionC argsC+])
      (do ///.monad
        [[applyT argsA+] (//inference.general analyse functionT argsC+)])
      (wrap (/.apply [functionA argsA+]))))