aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/macro/local.lux
blob: 4eb9c35c6f91350daea033e646400b137e564fd3 (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:
  [library
   [lux #*
    ["." meta]
    [abstract
     ["." monad (#+ do)]]
    [control
     ["." try (#+ Try)]
     ["." exception (#+ exception:)]]
    [data
     ["." product]
     ["." text]
     [collection
      ["." list ("#\." functor)]
      [dictionary
       ["." plist (#+ PList)]]]]]]
  ["." //
   ["#." code]])

(exception: #export (unknown_module {module Text})
  (exception.report
   ["Module" (text.format module)]))

(template [<name>]
  [(exception: #export (<name> {module Text} {definition Text})
     (exception.report
      ["Module" (text.format module)]
      ["Definition" (text.format definition)]))]

  [cannot_shadow_definition]
  [unknown_definition]
  )

(def: (with_module name body)
  (All [a] (-> Text (-> Module (Try [Module a])) (Meta a)))
  (function (_ compiler)
    (case (|> compiler (get@ #.modules) (plist.get name))
      (#.Some module)
      (case (body module)
        (#try.Success [module' output])
        (#try.Success [(update@ #.modules (plist.put name module') compiler)
                       output])
        
        (#try.Failure error)
        (#try.Failure error))

      #.None
      (exception.throw ..unknown_module [name]))))

(def: (push_one [name macro])
  (-> [Name Macro] (Meta Any))
  (do meta.monad
    [[module_name definition_name] (meta.normalize name)
     #let [definition (: Global (#.Definition [false .Macro (' {}) macro]))
           add_macro! (: (-> (PList Global) (PList Global))
                         (plist.put definition_name definition))]]
    (..with_module module_name
      (function (_ module)
        (case (|> module (get@ #.definitions) (plist.get definition_name))
          #.None
          (#try.Success [(update@ #.definitions add_macro! module)
                         []])
          
          (#.Some _)
          (exception.throw ..cannot_shadow_definition [module_name definition_name]))))))

(def: (pop_one name)
  (-> Name (Meta Any))
  (do meta.monad
    [[module_name definition_name] (meta.normalize name)
     #let [remove_macro! (: (-> (PList Global) (PList Global))
                            (plist.remove definition_name))]]
    (..with_module module_name
      (function (_ module)
        (case (|> module (get@ #.definitions) (plist.get definition_name))
          (#.Some _)
          (#try.Success [(update@ #.definitions remove_macro! module)
                         []])

          #.None
          (exception.throw ..unknown_definition [module_name definition_name]))))))

(def: (pop_all macros self)
  (-> (List Name) Name Macro)
  ("lux macro"
   (function (_ _)
     (do {! meta.monad}
       [_ (monad.map ! ..pop_one macros)
        _ (..pop_one self)
        compiler meta.get_compiler]
       (wrap (case (get@ #.expected compiler)
               (#.Some _)
               (list (' []))
               
               #.None
               (list)))))))

(def: #export (push macros)
  (-> (List [Name Macro]) (Meta Code))
  (do meta.monad
    [_ (monad.map meta.monad ..push_one macros)
     seed meta.count
     g!pop (//.gensym "pop")
     _ (let [g!pop (: Name ["" (//code.format g!pop)])]
         (..push_one [g!pop (..pop_all (list\map product.left macros) g!pop)]))]
    (wrap (` ((~ g!pop))))))