lawspec 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API-MIGRATION.md +102 -1
- package/GO.md +144 -0
- package/HASKELL.md +171 -0
- package/JAVA.md +113 -0
- package/KOTLIN.md +214 -0
- package/LANGUAGE.md +237 -12
- package/PRIMITIVES.md +1 -1
- package/PYTHON.md +152 -0
- package/README.md +26 -13
- package/REFINEMENTS.md +289 -3
- package/RELEASE-0.9.md +61 -0
- package/RUST.md +115 -1
- package/WEB.md +144 -0
- package/api.mjs +8 -2
- package/bin/lawspec.mjs +9 -6
- package/build.json +179 -37
- package/core.wasm +0 -0
- package/examples/specs/collections.lawspec +67 -0
- package/examples/specs/data_types.lawspec +66 -0
- package/examples/specs/finite_data.lawspec +37 -0
- package/examples/specs/list_contracts.lawspec +136 -0
- package/examples/specs/list_refinements.lawspec +51 -0
- package/examples/specs/matching.lawspec +49 -0
- package/examples/specs/recursive_refinements.lawspec +41 -0
- package/examples/specs/refined_definitions.lawspec +44 -0
- package/examples/specs/sum_refinements.lawspec +49 -0
- package/examples/specs/total_functions.lawspec +101 -0
- package/examples-command.mjs +6 -1
- package/files.mjs +10 -1
- package/index.d.ts +246 -27
- package/package.json +2 -2
- package/templates.mjs +107 -17
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
unit example.finite_data
|
|
2
|
+
|
|
3
|
+
type Choice is Yes | No end
|
|
4
|
+
|
|
5
|
+
type Pair (a :: Type) (b :: Type) is
|
|
6
|
+
Pair first :: a second :: b
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
law `sum constructors remain distinct` is
|
|
10
|
+
definition is
|
|
11
|
+
`for all` (choice :: Choice) .
|
|
12
|
+
(match choice with
|
|
13
|
+
| Yes -> Yes
|
|
14
|
+
| No -> No
|
|
15
|
+
end) = choice
|
|
16
|
+
end
|
|
17
|
+
example `yes` is choice = Yes expect choice = Yes end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
law `products preserve both fields` is
|
|
21
|
+
definition is
|
|
22
|
+
`for all` (pair :: Pair Bool Bool) .
|
|
23
|
+
(match pair with
|
|
24
|
+
| Pair first second -> Pair first second
|
|
25
|
+
end) = pair
|
|
26
|
+
end
|
|
27
|
+
example `different fields` is
|
|
28
|
+
pair = Pair true false
|
|
29
|
+
expect pair = Pair true false
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
law `nested optional products keep presence states` is
|
|
34
|
+
definition is
|
|
35
|
+
`for all` (value :: Maybe (Pair Choice (Nullable Bool))) . value = value
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
unit example.list_contracts
|
|
2
|
+
|
|
3
|
+
definition keep (xs :: List (value :: Int8 where value > 0))
|
|
4
|
+
:: List (value :: Int8 where value > 0)
|
|
5
|
+
is xs end
|
|
6
|
+
|
|
7
|
+
definition stronger (xs :: List (value :: Int8 where value > 10)) :: List Int8 is
|
|
8
|
+
keep (copypositive xs)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
definition positive (value :: a) :: Bool requires Integer a is value > 0 end
|
|
12
|
+
|
|
13
|
+
definition keephelper (xs :: List (value :: a where positive value))
|
|
14
|
+
:: List a requires Integer a
|
|
15
|
+
is xs end
|
|
16
|
+
|
|
17
|
+
definition reuse (xs :: List (value :: Int8 where positive value)) :: List Int8 is
|
|
18
|
+
keephelper xs
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
definition empty (value :: Int8) :: List (element :: Int8 where false) is [] end
|
|
22
|
+
|
|
23
|
+
definition singleton (value :: Int8 where value > 0)
|
|
24
|
+
:: List (element :: Int8 where element > 0)
|
|
25
|
+
is [value] end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
law `stronger domains satisfy the callee` is
|
|
29
|
+
definition is `for all` (xs :: List (value :: Int8 where value > 10)) .
|
|
30
|
+
stronger xs = xs
|
|
31
|
+
end
|
|
32
|
+
example `positive input` is xs = [11, 127] expect stronger xs = [11, 127] end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
law `generic predicates keep their scope` is
|
|
36
|
+
definition is `for all` (xs :: List (value :: Int8 where value > 0)) .
|
|
37
|
+
reuse xs = xs
|
|
38
|
+
end
|
|
39
|
+
example `empty` is xs = [] expect reuse xs = [] end
|
|
40
|
+
example `nonempty` is xs = [1, 2] expect reuse xs = [1, 2] end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
law `empty output satisfies an impossible element domain` is
|
|
44
|
+
definition is `for all` (value :: Int8) . empty value = [] end
|
|
45
|
+
example `zero` is value = 0 expect empty value = [] end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
law `constructed output satisfies its contract` is
|
|
49
|
+
definition is `for all` (value :: Int8 where value > 0) . singleton value = [value] end
|
|
50
|
+
example `maximum` is value = 127 expect singleton value = [127] end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
definition sumreciprocal (xs :: List (value :: Int8 where value != 0)) :: Rational is
|
|
55
|
+
match xs with
|
|
56
|
+
| Nil -> 0
|
|
57
|
+
| Cons first rest -> unwrapnonzero (wrapnonzero (nonzero first)) + sumreciprocal rest
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
definition sumrows (rows :: List (List (value :: Int8 where value != 0))) :: Rational is
|
|
62
|
+
match rows with
|
|
63
|
+
| Nil -> 0
|
|
64
|
+
| Cons first rest -> sumreciprocal first + sumrows rest
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
definition positivetail (xs :: List (value :: Int8 where value > 0))
|
|
69
|
+
:: List (value :: Int8 where value > 0)
|
|
70
|
+
is
|
|
71
|
+
match xs with | Nil -> [] | Cons first rest -> rest end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
definition positivefirst (xs :: List (value :: Int8 where value > 0))
|
|
75
|
+
:: (result :: Int8 where result > 0)
|
|
76
|
+
is
|
|
77
|
+
match xs with | Nil -> 1 | Cons first rest -> first end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
law `reciprocal sum uses each nonzero head` is
|
|
82
|
+
definition is `for all` (value :: Int8 where value != 0) .
|
|
83
|
+
sumreciprocal [value] = 1 / value
|
|
84
|
+
end
|
|
85
|
+
example `half` is value = 2 expect sumreciprocal [value] = rational(1, 2) end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
law `nested membership keeps row contracts` is
|
|
89
|
+
definition is `for all` (value :: Int8 where value != 0) .
|
|
90
|
+
sumrows [[], [value]] = 1 / value
|
|
91
|
+
end
|
|
92
|
+
example `negative half` is value = -2 expect sumrows [[], [value]] = rational(-1, 2) end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
law `tail preserves its positive elements` is
|
|
96
|
+
definition is `for all` (first :: Int8 where first > 0)
|
|
97
|
+
(second :: Int8 where second > 0) . positivetail [first, second] = [second]
|
|
98
|
+
end
|
|
99
|
+
example `two values` is first = 1 second = 2 expect positivetail [first, second] = [2] end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
-- Recursive calls supply their verified result contract by structural induction.
|
|
103
|
+
definition copypositive (xs :: List (value :: Int8 where value > 0))
|
|
104
|
+
:: List (value :: Int8 where value > 0)
|
|
105
|
+
is
|
|
106
|
+
match xs with
|
|
107
|
+
| Nil -> []
|
|
108
|
+
| Cons first rest -> Cons first (copypositive rest)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
definition nonzero (value :: Int8 where value != 0)
|
|
113
|
+
:: (result :: Int8 where result != 0)
|
|
114
|
+
is value end
|
|
115
|
+
|
|
116
|
+
definition wrapnonzero (value :: Int8 where value != 0)
|
|
117
|
+
:: Maybe (result :: Int8 where result != 0)
|
|
118
|
+
is Just value end
|
|
119
|
+
|
|
120
|
+
definition unwrapnonzero (value :: Maybe (element :: Int8 where element != 0))
|
|
121
|
+
:: Rational
|
|
122
|
+
is
|
|
123
|
+
match value with
|
|
124
|
+
| Nothing -> 0
|
|
125
|
+
| Just element -> selectnonzero (Left element)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
definition selectnonzero (value :: Either (element :: Int8 where element != 0) Bool)
|
|
130
|
+
:: Rational
|
|
131
|
+
is
|
|
132
|
+
match value with
|
|
133
|
+
| Left element -> 1 / element
|
|
134
|
+
| Right ignored -> 0
|
|
135
|
+
end
|
|
136
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
unit example.list_refinements
|
|
2
|
+
|
|
3
|
+
definition above (floor :: Int8) (xs :: List Int8) :: Bool is
|
|
4
|
+
match xs with
|
|
5
|
+
| Nil -> true
|
|
6
|
+
| Cons first rest -> first > floor && above floor rest
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
definition positiveRows (rows :: List (List Int8)) :: Bool is
|
|
11
|
+
match rows with
|
|
12
|
+
| Nil -> true
|
|
13
|
+
| Cons first rest -> above 0 first && positiveRows rest
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
law `each element is positive` is
|
|
18
|
+
definition is `for all` (xs :: List (value :: Int8 where value > 0)) .
|
|
19
|
+
above 0 xs = true
|
|
20
|
+
end
|
|
21
|
+
example `empty` is xs = [] expect above 0 xs = true end
|
|
22
|
+
example `positive values` is xs = [1, 127] expect above 0 xs = true end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
law `nested element domains` is
|
|
26
|
+
definition is `for all` (rows :: List (List (value :: Int8 where value > 0))) .
|
|
27
|
+
positiveRows rows = true
|
|
28
|
+
end
|
|
29
|
+
example `empty rows` is rows = [[], [1, 2]] expect positiveRows rows = true end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
law `dependent elements` is
|
|
33
|
+
definition is `for all` (lawspecElement :: Int8)
|
|
34
|
+
(xs :: List (value :: Int8 where value > lawspecElement)) .
|
|
35
|
+
above lawspecElement xs = true
|
|
36
|
+
end
|
|
37
|
+
example `maximum prefix still permits empty` is
|
|
38
|
+
lawspecElement = 127 xs = [] expect above lawspecElement xs = true
|
|
39
|
+
end
|
|
40
|
+
example `nonempty continuation` is
|
|
41
|
+
lawspecElement = 0 xs = [1, 2] expect above lawspecElement xs = true
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
law `division stays behind its guard` is
|
|
46
|
+
definition is `for all`
|
|
47
|
+
(xs :: List (value :: Int8 where value != 0 && 1 / value > 0)) .
|
|
48
|
+
above 0 xs = true
|
|
49
|
+
end
|
|
50
|
+
example `positive denominator` is xs = [1] expect above 0 xs = true end
|
|
51
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
unit example.matching
|
|
2
|
+
|
|
3
|
+
-- Rebuilding values checks both constructor identity and every payload field.
|
|
4
|
+
law `list patterns preserve the head and tail` is
|
|
5
|
+
definition is
|
|
6
|
+
`for all` (xs :: List Int8) .
|
|
7
|
+
(match xs with
|
|
8
|
+
| Nil -> []
|
|
9
|
+
| Cons head tail -> Cons head tail
|
|
10
|
+
end) = xs
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
law `nested Maybe patterns preserve each absence state` is
|
|
15
|
+
definition is
|
|
16
|
+
`for all` (value :: Maybe (Maybe Bool)) .
|
|
17
|
+
(match value with
|
|
18
|
+
| Nothing -> Nothing
|
|
19
|
+
| Just inner -> Just (match inner with
|
|
20
|
+
| Nothing -> Nothing
|
|
21
|
+
| Just payload -> Just payload
|
|
22
|
+
end)
|
|
23
|
+
end) = value
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
law `Either patterns preserve their constructor` is
|
|
28
|
+
definition is
|
|
29
|
+
`for all` (value :: Either (List Int8) (Maybe Bool)) .
|
|
30
|
+
(match value with
|
|
31
|
+
| Left items -> Left items
|
|
32
|
+
| Right optional -> Right optional
|
|
33
|
+
end) = value
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
-- The annotation gives the empty-case literal the same primitive type as head.
|
|
38
|
+
law `matching can provide a default value` is
|
|
39
|
+
definition is
|
|
40
|
+
`for all` (value :: Maybe Int8) .
|
|
41
|
+
((match value with
|
|
42
|
+
| Nothing -> 0
|
|
43
|
+
| Just payload -> payload
|
|
44
|
+
end) :: Int8) = ((match value with
|
|
45
|
+
| Just payload -> payload
|
|
46
|
+
| Nothing -> 0
|
|
47
|
+
end) :: Int8)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
unit example.recursive_refinements
|
|
2
|
+
|
|
3
|
+
-- Refining a type argument follows its stored occurrences through recursion.
|
|
4
|
+
-- The fixed Int8 field remains independent of the refined argument.
|
|
5
|
+
type Tree (a :: Type) is
|
|
6
|
+
Leaf value :: a fixed :: Int8
|
|
7
|
+
Fork left :: Tree a right :: Tree a
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
refinement Positive is (value :: Int8 where value > 0) end
|
|
11
|
+
|
|
12
|
+
-- The payload guarantee is available when proving recursive definitions.
|
|
13
|
+
definition positiveSum (tree :: Tree Positive) :: (total :: BigInt where total > 0) is
|
|
14
|
+
match tree with
|
|
15
|
+
| Leaf value fixed -> value + 0
|
|
16
|
+
| Fork left right -> positiveSum left + positiveSum right
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
law `positive leaves have a positive total` is
|
|
21
|
+
definition is
|
|
22
|
+
`for all` (tree :: Tree Positive) . positiveSum tree > 0
|
|
23
|
+
end
|
|
24
|
+
example `fixed fields may be negative` is
|
|
25
|
+
tree = Fork (Leaf 1 -128) (Fork (Leaf 2 0) (Leaf 3 -1))
|
|
26
|
+
expect positiveSum tree = 6
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
-- Dependent predicates retain the enclosing input, even below several forks.
|
|
31
|
+
law `every stored argument exceeds the threshold` is
|
|
32
|
+
definition is
|
|
33
|
+
`for all` (threshold :: Int8 where threshold < 127)
|
|
34
|
+
(tree :: Tree (value :: Int8 where value > threshold)) . tree = tree
|
|
35
|
+
end
|
|
36
|
+
example `nested threshold` is
|
|
37
|
+
threshold = 4
|
|
38
|
+
tree = Fork (Leaf 5 -128) (Leaf 6 0)
|
|
39
|
+
expect tree = Fork (Leaf 5 -128) (Leaf 6 0)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
unit example.refined_definitions
|
|
2
|
+
|
|
3
|
+
refinement Nonzero (T :: Type) requires Integer T is
|
|
4
|
+
(value :: T where value != 0)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
-- The compiler proves division is defined under the input contract.
|
|
8
|
+
-- Native callers are checked before the body runs.
|
|
9
|
+
definition reciprocal (x :: Nonzero a) :: Rational
|
|
10
|
+
requires Integer a
|
|
11
|
+
is
|
|
12
|
+
1 / x
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
-- Arithmetic promotes before this explicit, proved narrowing conversion.
|
|
16
|
+
definition increment (x :: Int8 where x < 127)
|
|
17
|
+
:: (result :: Int8 where result > x)
|
|
18
|
+
is
|
|
19
|
+
prelude.Int8 (x + 1)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
-- Later argument refinements can depend on earlier arguments.
|
|
23
|
+
definition inverseGap (x :: Int8) (y :: Int8 where y > x) :: Rational is
|
|
24
|
+
1 / (y - x)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
law `exact reciprocal` is
|
|
28
|
+
definition is `for all` (x :: Nonzero Int8) . reciprocal x = 1 / x end
|
|
29
|
+
example `one half` is x = 2 expect reciprocal x = rational(1, 2) end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
law `checked increment` is
|
|
33
|
+
definition is `for all` (x :: Int8 where x < 127) . increment x = x + 1 end
|
|
34
|
+
example `largest admitted input` is x = 126 expect increment x = 127 end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
law `dependent gap` is
|
|
38
|
+
definition is `for all` (x :: Int8) (y :: Int8 where y > x) .
|
|
39
|
+
inverseGap x y = 1 / (y - x)
|
|
40
|
+
end
|
|
41
|
+
example `difference exceeds Int8` is
|
|
42
|
+
x = -128 y = 127 expect inverseGap x y = rational(1, 255)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
unit example.sum_refinements
|
|
2
|
+
|
|
3
|
+
law `positive Maybe payloads` is
|
|
4
|
+
definition is `for all` (x :: Maybe (value :: Int8 where value > 0)) .
|
|
5
|
+
(match x with | Nothing -> true | Just payload -> payload >= 1 end) = true
|
|
6
|
+
end
|
|
7
|
+
example `absent` is x = Nothing expect x = Nothing end
|
|
8
|
+
example `present` is x = Just 1 expect x = Just 1 end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
law `selected Either payload` is
|
|
12
|
+
definition is `for all`
|
|
13
|
+
(x :: Either (value :: Int8 where value > 0) (value :: Int8 where value < 0)) .
|
|
14
|
+
(match x with | Left payload -> payload >= 1 | Right payload -> payload <= -1 end) = true
|
|
15
|
+
end
|
|
16
|
+
example `left` is x = Left 1 expect x = Left 1 end
|
|
17
|
+
example `right` is x = Right -1 expect x = Right -1 end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
law `nested Maybe states` is
|
|
21
|
+
definition is `for all` (x :: Maybe (Maybe (value :: Bool where value))) .
|
|
22
|
+
(match x with | Nothing -> true | Just inner ->
|
|
23
|
+
match inner with | Nothing -> true | Just payload -> payload end
|
|
24
|
+
end) = true
|
|
25
|
+
end
|
|
26
|
+
example `outer absent` is x = Nothing expect x = Nothing end
|
|
27
|
+
example `inner absent` is x = Just Nothing expect x = Just Nothing end
|
|
28
|
+
example `present` is x = Just (Just true) expect x = Just (Just true) end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
law `finite Either variants` is
|
|
32
|
+
definition is `for all`
|
|
33
|
+
(x :: Either (value :: Bool where value) (value :: Bool where !value)) .
|
|
34
|
+
(match x with | Left payload -> payload | Right payload -> !payload end) = true
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
law `dependent payload keeps outer binding` is
|
|
39
|
+
definition is `for all` (lawspecElement :: Int8)
|
|
40
|
+
(x :: Maybe (value :: Int8 where value > lawspecElement)) .
|
|
41
|
+
(match x with | Nothing -> true | Just payload -> payload - lawspecElement >= 1 end) = true
|
|
42
|
+
end
|
|
43
|
+
example `maximum prefix has absent continuation` is
|
|
44
|
+
lawspecElement = 127 x = Nothing expect x = Nothing
|
|
45
|
+
end
|
|
46
|
+
example `present continuation` is
|
|
47
|
+
lawspecElement = 0 x = Just 1 expect x = Just 1
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
unit example.total_functions
|
|
2
|
+
|
|
3
|
+
-- These functions are implemented in the specification. LawSpec checks their
|
|
4
|
+
-- bodies and emits reusable source; they do not need adapter implementations.
|
|
5
|
+
definition increment (x :: a) :: BigInt
|
|
6
|
+
requires Integer a
|
|
7
|
+
is
|
|
8
|
+
x + 1
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
definition count (xs :: List a) :: BigInt is
|
|
12
|
+
match xs with
|
|
13
|
+
| Nil -> 0
|
|
14
|
+
| Cons head tail -> 1 + count tail
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
definition nonempty (xs :: List a) :: Bool is
|
|
19
|
+
match xs with
|
|
20
|
+
| Nil -> false
|
|
21
|
+
| Cons head tail -> true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
law `nonempty lists have positive length` is
|
|
26
|
+
definition is
|
|
27
|
+
`for all` (xs :: List Int8 where nonempty xs) . count xs > 0
|
|
28
|
+
end
|
|
29
|
+
example `singleton` is xs = [0] expect count xs = 1 end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
-- The exact guard proves that the promoted denominator cannot be zero.
|
|
33
|
+
definition positiveReciprocal (x :: a) :: Bool
|
|
34
|
+
requires Integer a
|
|
35
|
+
is
|
|
36
|
+
x >= 0 && 1 / (x + 1) > 0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
law `guarded exact arithmetic` is
|
|
40
|
+
definition is
|
|
41
|
+
`for all` (x :: Int8) . positiveReciprocal x = (x >= 0)
|
|
42
|
+
end
|
|
43
|
+
example `skip zero denominator` is
|
|
44
|
+
x = -1 expect positiveReciprocal x = false
|
|
45
|
+
end
|
|
46
|
+
example `promote before division` is
|
|
47
|
+
x = 127 expect positiveReciprocal x = true
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
definition guardedNarrow (x :: Int8) :: Bool is
|
|
52
|
+
x < 127 && prelude.Int8 (x + 1) > x
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
law `narrow only after proving the range` is
|
|
56
|
+
definition is
|
|
57
|
+
`for all` (x :: Int8) . guardedNarrow x = (x < 127)
|
|
58
|
+
end
|
|
59
|
+
example `largest valid conversion` is x = 126 expect guardedNarrow x = true end
|
|
60
|
+
example `overflow branch is skipped` is x = 127 expect guardedNarrow x = false end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
definition same (xs :: List a) (ys :: List a) :: Bool
|
|
64
|
+
requires Eq a
|
|
65
|
+
is
|
|
66
|
+
xs == ys
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
-- The same checked template produces independent concrete instances.
|
|
70
|
+
law `count also accepts text` is
|
|
71
|
+
definition is
|
|
72
|
+
`for all` (xs :: List Text) . count xs = prelude.length xs
|
|
73
|
+
end
|
|
74
|
+
example `two words` is xs = ["hello", "world"] expect count xs = 2 end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
law `increment preserves the mathematical result` is
|
|
78
|
+
definition is
|
|
79
|
+
`for all` (x :: Int8) . increment x = x + 1
|
|
80
|
+
end
|
|
81
|
+
example `maximum input` is
|
|
82
|
+
x = 127 expect increment x = 128
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
law `recursive count agrees with length` is
|
|
87
|
+
definition is
|
|
88
|
+
`for all` (xs :: List Int8) . count xs = prelude.length xs
|
|
89
|
+
end
|
|
90
|
+
example `empty` is xs = [] expect count xs = 0 end
|
|
91
|
+
example `duplicates still count` is xs = [7, 7, 7] expect count xs = 3 end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
law `list equality preserves duplicates and order` is
|
|
95
|
+
definition is
|
|
96
|
+
`for all` (xs :: List Int8) (ys :: List Int8) . same xs ys = (xs == ys)
|
|
97
|
+
end
|
|
98
|
+
example `different order` is
|
|
99
|
+
xs = [1, 2] ys = [2, 1] expect same xs ys = false
|
|
100
|
+
end
|
|
101
|
+
end
|
package/examples-command.mjs
CHANGED
|
@@ -21,7 +21,12 @@ export async function generateExamples(options) {
|
|
|
21
21
|
const compiler = await createCompiler();
|
|
22
22
|
const artifacts = [];
|
|
23
23
|
for (const target of selected) {
|
|
24
|
-
const result = await compiler.planGeneration({
|
|
24
|
+
const result = await compiler.planGeneration({
|
|
25
|
+
sources,
|
|
26
|
+
target,
|
|
27
|
+
machineBits: options.machineBits ?? 64,
|
|
28
|
+
minify: options.minify === true,
|
|
29
|
+
});
|
|
25
30
|
if (result.diagnostics.length)
|
|
26
31
|
throw Object.assign(new Error("Bundled examples failed to compile"), {
|
|
27
32
|
diagnostics: result.diagnostics,
|
package/files.mjs
CHANGED
|
@@ -89,7 +89,16 @@ export async function planWrites(root, artifacts) {
|
|
|
89
89
|
const file = await safePath(root, artifact.path);
|
|
90
90
|
const old = await readOptional(file);
|
|
91
91
|
if (artifact.ownership === "user") {
|
|
92
|
-
|
|
92
|
+
if (
|
|
93
|
+
artifact.adapterReference !== undefined &&
|
|
94
|
+
typeof artifact.adapterReference !== "string"
|
|
95
|
+
)
|
|
96
|
+
throw new Error(`Invalid adapter reference: ${artifact.path}`);
|
|
97
|
+
// Compare compiler-owned canonical scaffolds, never normalized user code.
|
|
98
|
+
// Older compilers and manifests used readable content as this reference.
|
|
99
|
+
adapterHashes[artifact.path] = digest(
|
|
100
|
+
artifact.adapterReference ?? artifact.content,
|
|
101
|
+
);
|
|
93
102
|
if (
|
|
94
103
|
old !== null &&
|
|
95
104
|
previous.adapters?.[artifact.path] !== adapterHashes[artifact.path]
|