aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/tool/compiler/analysis/macro.lux
blob: 9e191e514da2c0c76ec5ed80392d5abb17b9012c (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
(.module:
  [lux #*
   [abstract
    [monad (#+ do)]]
   [control
    ["." try (#+ Try)]
    ["." exception (#+ exception:)]]
   [data
    ["." text
     ["%" format (#+ format)]]
    [collection
     [array (#+ Array)]
     ["." list ("#@." functor)]]]
   ["." macro]]
  [///
   ["." phase]])

(exception: #export (expansion-failed {macro Name} {inputs (List Code)} {error Text})
  (exception.report
   ["Macro" (%.name macro)]
   ["Inputs" (exception.enumerate %.code inputs)]
   ["Error" error]))

(exception: #export (must-have-single-expansion {macro Name} {inputs (List Code)} {outputs (List Code)})
  (exception.report
   ["Macro" (%.name macro)]
   ["Inputs" (exception.enumerate %.code inputs)]
   ["Outputs" (exception.enumerate %.code outputs)]))

(type: #export Expander
  (-> Macro (List Code) Lux (Try (Try [Lux (List Code)]))))

(def: #export (expand expander name macro inputs)
  (-> Expander Name Macro (List Code) (Meta (List Code)))
  (function (_ state)
    (do try.monad
      [output (expander macro inputs state)]
      (case output
        (#try.Success output)
        (#try.Success output)
        
        (#try.Failure error)
        ((phase.throw ..expansion-failed [name inputs error]) state)))))

(def: #export (expand-one expander name macro inputs)
  (-> Expander Name Macro (List Code) (Meta Code))
  (do macro.monad
    [expansion (expand expander name macro inputs)]
    (case expansion
      (^ (list single))
      (wrap single)

      _
      (phase.throw ..must-have-single-expansion [name inputs expansion]))))