aboutsummaryrefslogtreecommitdiff
path: root/stdlib/source/library/lux/control/function/contract.lux
blob: 0fb706a145826632081317af9bba9e3f7793ce1a (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
(.module:
  [library
   [lux #*
    [control
     ["." exception (#+ exception:)]
     [parser
      ["<.>" code]]]
    [data
     [text
      ["%" format (#+ format)]]]
    [macro (#+ with_identifiers)
     [syntax (#+ syntax:)]
     ["." code]]
    [math
     [number
      ["i" int]]]]])

(template [<name>]
  [(exception: (<name> {condition Code})
     (exception.report
      ["Condition" (%.code condition)]))]

  [pre_condition_failed]
  [post_condition_failed]
  )

(def: (assert! message test)
  (-> Text Bit [])
  (if test
    []
    (panic! message)))

(syntax: .public (pre [test <code>.any
                       expr <code>.any])
  {#.doc (example "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)))}
  (in (list (` (exec
                 ((~! ..assert!) (~ (code.text (exception.error ..pre_condition_failed test)))
                  (~ test))
                 (~ expr))))))

(syntax: .public (post [test <code>.any
                        expr <code>.any])
  {#.doc (example "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_identifiers [g!output]
    (in (list (` (let [(~ g!output) (~ expr)]
                   (exec
                     ((~! ..assert!) (~ (code.text (exception.error ..post_condition_failed test)))
                      ((~ test) (~ g!output)))
                     (~ g!output))))))))