diff options
Diffstat (limited to 'stdlib/source/lux/control/contract.lux')
-rw-r--r-- | stdlib/source/lux/control/contract.lux | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/stdlib/source/lux/control/contract.lux b/stdlib/source/lux/control/contract.lux new file mode 100644 index 000000000..2f347dfa5 --- /dev/null +++ b/stdlib/source/lux/control/contract.lux @@ -0,0 +1,37 @@ +(;module: + lux + (lux (control monad) + (data text/format) + [compiler #+ Monad<Lux>] + (macro [ast] + ["s" syntax #+ syntax:]))) + +(def: #export (assert! message test) + (-> Text Bool []) + (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! (~ (ast;text (format "Pre-condition failed: " (%ast 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 true, returns the value of the expression." + "Otherwise, an error is raised." + (@post i.even? + (i.+ 2 2)))} + (do @ + [g!output (compiler;gensym "")] + (wrap (list (` (let [(~ g!output) (~ expr)] + (exec (assert! (~ (ast;text (format "Post-condition failed: " (%ast test)))) + ((~ test) (~ g!output))) + (~ g!output)))))))) |