aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/control/exception.lux
blob: b36c97268231f53522d29bc8ae9caa47839b64ce (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
(;module: {#;doc "Exception-handling functionality built on top of the Result type."}
  lux
  (lux (control monad)
       (data ["R" result]
             [maybe]
             [text "text/" Monoid<Text>])
       [macro]
       (macro [code]
              ["s" syntax #+ syntax: Syntax]
              (syntax ["cs" common]
                      (common ["csr" reader]
                              ["csw" writer])))))

## [Types]
(type: #export Exception
  {#;doc "An exception provides a way to decorate error messages."}
  (-> Text Text))

## [Values]
(def: #hidden _text/append_
  (-> Text Text Text)
  text/append)

(def: #export (match? exception error)
  (-> Exception Text Bool)
  (text;starts-with? (exception "") error))

(def: #export (catch exception then try)
  {#;doc "If a particular exception is detected on a possibly-erroneous value, handle it.

          If no exception was detected, or a different one from the one being checked, then pass along the original value."}
  (All [a]
    (-> Exception (-> Text a) (R;Result a)
        (R;Result a)))
  (case try
    (#R;Success output)
    (#R;Success output)

    (#R;Error error)
    (let [reference (exception "")]
      (if (text;starts-with? reference error)
        (#R;Success (|> error
                        (text;clip (text;size reference) (text;size error))
                        maybe;assume
                        then))
        (#R;Error error)))))

(def: #export (otherwise to-do try)
  {#;doc "If no handler could be found to catch the exception, then run a function as a last-resort measure."}
  (All [a]
    (-> (-> Text a) (R;Result a) a))
  (case try
    (#R;Success output)
    output

    (#R;Error error)
    (to-do error)))

(def: #export (return value)
  {#;doc "A way to lift normal values into the result-handling context."}
  (All [a] (-> a (R;Result a)))
  (#R;Success value))

(def: #export (throw exception message)
  {#;doc "Decorate an error message with an Exception and lift it into the result-handling context."}
  (All [a] (-> Exception Text (R;Result a)))
  (#R;Error (exception message)))

(syntax: #export (exception: [_ex-lev csr;export] [name s;local-symbol])
  {#;doc (doc "Define a new exception type."
              "It moslty just serves as a way to tag error messages for later catching."
              (exception: #export Some-Exception))}
  (do @
    [current-module macro;current-module-name
     #let [descriptor ($_ text/append "{" current-module ";" name "}" "\n")
           g!message (code;symbol ["" "message"])]]
    (wrap (list (` (def: (~@ (csw;export _ex-lev)) ((~ (code;symbol ["" name])) (~ g!message))
                     Exception
                     (_text/append_ (~ (code;text descriptor)) (~ g!message))))))))