aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/test/lux/meta/macro/local.lux
blob: 1aa793639e23e9ca4ba6313f0ff49649fdf630ff (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
129
130
(.require
 [library
  [lux (.except with)
   ["_" test (.only Test)]
   [abstract
    [monad (.only do)]]
   [control
    ["<>" parser]
    ["[0]" try]
    ["[0]" exception]]
   [data
    [text
     ["%" \\format]]
    [collection
     ["[0]" list
      ["[0]" property]]]]
   [math
    ["[0]" random (.only Random)]
    [number
     ["n" nat]]]
   ["[0]" meta (.only)
    ["[0]" code (.only)
     ["<[1]>" \\parser]]
    ["[0]" macro (.only)
     [syntax (.only syntax)]]]]]
 [\\library
  ["[0]" /]])

(/.let [!pow/2 (template (_ <scalar>)
                 [(n.* <scalar> <scalar>)])]
  (def pow/2
    (-> Nat Nat)
    (|>> !pow/2)))

(def macro_error
  (syntax (_ [macro <code>.any])
    (function (_ compiler)
      (case ((macro.expansion macro) compiler)
        {try.#Failure error}
        {try.#Success [compiler (list (code.text error))]}
        
        {try.#Success _}
        {try.#Failure "OOPS!"}))))

(def (constant output)
  (-> Code Macro)
  ("lux macro"
   (function (_ inputs lux)
     {try.#Success [lux (list output)]})))

(def with
  (syntax (_ [name (<code>.tuple (<>.and <code>.text <code>.text))
              constant <code>.any
              pre_remove <code>.bit
              body <code>.any])
    (macro.with_symbols [g!output]
      (do meta.monad
        [pop! (/.push (list [name (..constant constant)]))
         [module short] (meta.normal name)
         _ (if pre_remove
             (let [remove_macro! (is (-> .Module .Module)
                                     (revised .#definitions (property.lacks short)))]
               (function (_ lux)
                 {try.#Success [(revised .#modules (property.revised module remove_macro!) lux)
                                []]}))
             (in []))]
        (let [pre_expansion (` (let [(, g!output) (, body)]
                                 (exec
                                   (, pop!)
                                   (, g!output))))]
          (if pre_remove
            (macro.full_expansion pre_expansion)
            (in (list pre_expansion))))))))

(def .public test
  Test
  (<| (_.covering /._)
      (do [! random.monad]
        [expected random.nat]
        (all _.and
             (_.coverage [/.push]
               (..with ["" "actual"] expected #0
                 (n.= expected (..actual))))
             (_.coverage [/.unknown_module]
               (exception.match? /.unknown_module
                                 (..macro_error
                                  (..with ["123yolo456" "actual"] expected #0
                                    (n.= expected (..actual))))))
             (_.coverage [/.cannot_shadow_definition]
               (exception.match? /.cannot_shadow_definition
                                 (..macro_error
                                  (..with ["" "with"] expected #0
                                    (n.= expected (..actual))))))
             (_.coverage [/.unknown_definition]
               (exception.match? /.unknown_definition
                                 (<| ..macro_error
                                     (..with ["" "actual"] expected #1)
                                     (n.= expected (..actual)))))
             (do !
               [scalar random.nat]
               (_.coverage [/.let]
                 (let [can_use_with_statements!
                       (n.= (all n.* scalar scalar)
                            (..pow/2 scalar))]
                   (and can_use_with_statements!
                        (/.let [pow/3 (template (_ <scalar>)
                                        [(all n.* <scalar> <scalar> <scalar>)])
                                pow/9 (template (_ <scalar>)
                                        [(pow/3 (pow/3 <scalar>))])]
                          (let [can_use_with_expressions!
                                (n.= (all n.* scalar scalar scalar)
                                     (pow/3 scalar))

                                can_refer!
                                (n.= (all n.*
                                          scalar scalar scalar
                                          scalar scalar scalar
                                          scalar scalar scalar)
                                     (pow/9 scalar))

                                can_shadow!
                                (let [pow/3 (function (_ scalar)
                                              (all n.+ scalar scalar scalar))]
                                  (n.= (all n.+ scalar scalar scalar)
                                       (pow/3 scalar)))]
                            (and can_use_with_expressions!
                                 can_refer!
                                 can_shadow!)))
                        ))))
             ))))