aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/lux/control/contract.lux
blob: 1add3be8faf12a7c1e1513ffce8f0c39eec51a3c (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
(.module:
  [lux #*
   [abstract
    monad]
   [data
    [text
     format]]
   [macro (#+ with-gensyms)
    ["." code]
    ["s" syntax (#+ syntax:)]]])

(def: #export (assert! message test)
  (-> Text Bit [])
  (if test
    []
    (error! message)))

(syntax: #export (pre test expr)
  {#.doc (doc "Pre-conditions."
              "Given a test and an expression to run, only runs the expression if the test passes."
              "Otherwise, an error is raised."
              (pre (i/= +4 (i/+ +2 +2))
                   (foo +123 +456 +789)))}
  (wrap (list (` (exec (assert! (~ (code.text (format "Pre-condition failed: " (%code test))))
                                (~ test))
                   (~ expr))))))

(syntax: #export (post test expr)
  {#.doc (doc "Post-conditions."
              "Given a predicate and an expression to run, evaluates the expression and then tests the output with the predicate."
              "If the predicate returns #1, returns the value of the expression."
              "Otherwise, an error is raised."
              (post i/even?
                    (i/+ +2 +2)))}
  (with-gensyms [g!output]
    (wrap (list (` (let [(~ g!output) (~ expr)]
                     (exec (assert! (~ (code.text (format "Post-condition failed: " (%code test))))
                                    ((~ test) (~ g!output)))
                       (~ g!output))))))))