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.
@@ -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
@@ -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({ sources, target, machineBits: options.machineBits ?? 64 });
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
- adapterHashes[artifact.path] = digest(artifact.content);
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]