-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_exception.ml
156 lines (133 loc) · 4.38 KB
/
test_exception.ml
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
(* name: test_exception.ml
* synopsis: test exception monad
* author: Lydia E. van Dijk
* last revision: Wed Oct 29 09:56:10 UTC 2008
* ocaml version: 3.11
*
* Copyright (C) 2006-2008 J. Carette, L. E. van Dijk, O. Kiselyov
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)
module type LIMIT =
sig
val min: int64
val max: int64
end
module ArithmeticFn (L: LIMIT) =
struct
type 'a extended =
Normal of 'a
| PosInf
| NegInf
| NotANumber
let string_of_extended =
function
Normal x -> Int64.to_string x
| PosInf -> "+Infinity"
| NegInf -> "-Infinity"
| NotANumber -> "Not a Number"
type reason =
NegOverflow
| PosOverflow
| DivByZero
let string_of_reason =
function
NegOverflow -> "negative overflow"
| PosOverflow -> "positive overflow"
| DivByZero -> "division by zero"
type failure = {
value: int64 extended;
func: string;
cause: reason
}
let op name f x y =
perform with Exception.bind in
x' <-- x;
y' <-- y;
let z' = f (Int64.of_int x') (Int64.of_int y') in
if z' < L.min then
Exception.throw {value = Normal z'; func = name; cause = NegOverflow}
else if z' > L.max then
Exception.throw {value = Normal z'; func = name; cause = PosOverflow}
else Exception.return (Int64.to_int z')
let add x y = op "add" Int64.add x y
let sub x y = op "sub" Int64.sub x y
let mul x y = op "mul" Int64.mul x y
let div x y =
let name = "div" in
perform with Exception.bind in
x' <-- x;
y' <-- y;
if y' = 0 then
Exception.throw
{value = if x' > 0 then PosInf else if x' < 0 then NegInf else NotANumber;
func = name;
cause = DivByZero}
else op name Int64.div x y
end
(**********************************************************************)
let min_number = (-128)
and max_number = 127
module Arithmetic =
ArithmeticFn (struct
let min = Int64.of_int min_number
let max = Int64.of_int max_number
end)
let result =
let zero = Exception.return 0
and one = Exception.return 1
and min = Exception.return min_number
and max = Exception.return max_number
and (+^) = Arithmetic.add
and (/^) = Arithmetic.div
in
Exception.catch
(one +^ one +^ max /^ zero)
(fun ({Arithmetic.value = _v; func = _f; cause = c} as e) ->
match c with
Arithmetic.NegOverflow -> max
| Arithmetic.PosOverflow -> min
| Arithmetic.DivByZero -> Exception.throw e)
let test_exception_monad _ =
Utest.expect_pass
"exception monad"
(fun () ->
Exception.run
(fun {Arithmetic.value = v; func = f; cause = c} ->
Printf.printf
"error: %s in function \"%s\"\nvalue: %s\n"
(Arithmetic.string_of_reason c)
f
(Arithmetic.string_of_extended v);
false)
(fun v -> v = max_number)
(Exception.catch
result
(fun ({Arithmetic.value = v; func = _f; cause = _c} as e) ->
match v with
Arithmetic.Normal n -> Exception.return (Int64.to_int n)
| Arithmetic.NegInf -> Exception.return min_number
| Arithmetic.PosInf -> Exception.return max_number
| Arithmetic.NotANumber -> Exception.throw e)))
(**********************************************************************)
let () =
let results =
Utest.run_tests Utest.PrintFailedTests [test_exception_monad]
in
Pervasives.exit
(if results.Utest.failed <> 0 ||
results.Utest.unresolved <> 0
then 1
else 0)