aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/macro/poly.lux
blob: a9f4a574493b17cd4be273d2bdc20845970cc0a2 (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
(.module:
  [library
   [lux #*
    ["." meta]
    ["." type]
    [abstract
     ["." monad (#+ do)]]
    [control
     ["<>" parser
      ["<.>" type (#+ Env)]
      ["<.>" code]]]
    [data
     ["." product]
     ["." maybe]
     ["." text]
     [collection
      ["." list ("#\." fold functor)]
      ["." dictionary]]]
    [macro (#+ with_gensyms)
     ["." code]
     [syntax (#+ syntax:)
      ["|.|" export]]]
    [math
     [number
      ["n" nat]]]]])

(syntax: #export (poly: {export |export|.parser}
                   {name <code>.local_identifier}
                   body)
  (with_gensyms [g!_ g!type g!output]
    (let [g!name (code.identifier ["" name])]
      (wrap (.list (` ((~! syntax:) (~+ (|export|.format export)) ((~ g!name) {(~ g!type) (~! <code>.identifier)})
                       ((~! do) (~! meta.monad)
                        [(~ g!type) ((~! meta.find_type_def) (~ g!type))]
                        (case (: (.Either .Text .Code)
                                 ((~! <type>.run) ((~! <>.rec)
                                                   (function ((~ g!_) (~ g!name))
                                                     (~ body)))
                                  (~ g!type)))
                          (#.Left (~ g!output))
                          ((~! meta.failure) (~ g!output))

                          (#.Right (~ g!output))
                          ((~' wrap) (.list (~ g!output))))))))))))

(def: (common_poly_name? poly_func)
  (-> Text Bit)
  (text.contains? "?" poly_func))

(def: (derivation_name poly args)
  (-> Text (List Text) (Maybe Text))
  (if (common_poly_name? poly)
    (#.Some (list\fold (text.replace_once "?") poly args))
    #.None))

(syntax: #export (derived: {export |export|.parser}
                   {?name (<>.maybe <code>.local_identifier)}
                   {[poly_func poly_args] (<code>.form (<>.and <code>.identifier (<>.many <code>.identifier)))}
                   {?custom_impl (<>.maybe <code>.any)})
  (do {! meta.monad}
    [poly_args (monad.map ! meta.normal poly_args)
     name (case ?name
            (#.Some name)
            (wrap name)

            (^multi #.None
                    {(derivation_name (product.right poly_func) (list\map product.right poly_args))
                     (#.Some derived_name)})
            (wrap derived_name)

            _
            (<>.failure "derived: was given no explicit name, and cannot generate one from given information."))
     #let [impl (case ?custom_impl
                  (#.Some custom_impl)
                  custom_impl

                  #.None
                  (` ((~ (code.identifier poly_func)) (~+ (list\map code.identifier poly_args)))))]]
    (wrap (.list (` (def: (~+ (|export|.format export))
                      (~ (code.identifier ["" name]))
                      {#.implementation? #1}
                      (~ impl)))))))

(def: #export (to_code env type)
  (-> Env Type Code)
  (`` (case type
        (#.Primitive name params)
        (` (#.Primitive (~ (code.text name))
                        (list (~+ (list\map (to_code env) params)))))

        (^template [<tag>]
          [(<tag> idx)
           (` (<tag> (~ (code.nat idx))))])
        ([#.Var] [#.Ex])

        (#.Parameter idx)
        (let [idx (<type>.adjusted_idx env idx)]
          (if (n.= 0 idx)
            (|> (dictionary.get idx env) maybe.assume product.left (to_code env))
            (` (.$ (~ (code.nat (dec idx)))))))

        (#.Apply (#.Named [(~~ (static .prelude_module)) "Nothing"] _) (#.Parameter idx))
        (let [idx (<type>.adjusted_idx env idx)]
          (if (n.= 0 idx)
            (|> (dictionary.get idx env) maybe.assume product.left (to_code env))
            (undefined)))
        
        (^template [<tag>]
          [(<tag> left right)
           (` (<tag> (~ (to_code env left))
                     (~ (to_code env right))))])
        ([#.Function] [#.Apply])

        (^template [<macro> <tag> <flattener>]
          [(<tag> left right)
           (` (<macro> (~+ (list\map (to_code env) (<flattener> type)))))])
        ([| #.Sum type.flat_variant]
         [& #.Product type.flat_tuple])

        (#.Named name sub_type)
        (code.identifier name)

        (^template [<tag>]
          [(<tag> scope body)
           (` (<tag> (list (~+ (list\map (to_code env) scope)))
                     (~ (to_code env body))))])
        ([#.UnivQ] [#.ExQ])
        )))