lawspec 0.8.0 → 0.10.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 +180 -3
- package/GO.md +144 -0
- package/HASKELL.md +171 -0
- package/JAVA.md +113 -0
- package/KOTLIN.md +214 -0
- package/LANGUAGE.md +240 -12
- package/NATIVE-BINDINGS.md +1046 -0
- package/PRIMITIVES.md +1 -1
- package/PYTHON.md +152 -0
- package/README.md +86 -23
- package/REFINEMENTS.md +289 -3
- package/RELEASE-0.10.md +60 -0
- package/RELEASE-0.9.md +61 -0
- package/RUST.md +115 -1
- package/WEB.md +144 -0
- package/api.mjs +28 -2
- package/bin/lawspec.mjs +23 -7
- package/build.json +199 -37
- package/core.wasm +0 -0
- package/examples/native-payments/go/example/payments/domain.go +38 -0
- package/examples/native-payments/go/example/payments/native_generators_test.go +13 -0
- package/examples/native-payments/go/lawspec.json +136 -0
- package/examples/native-payments/haskell/lawspec.json +149 -0
- package/examples/native-payments/haskell/src/PaymentsDomain.hs +21 -0
- package/examples/native-payments/haskell/test/PaymentGenerators.hs +12 -0
- package/examples/native-payments/java/lawspec.json +165 -0
- package/examples/native-payments/java/src/main/java/domain/PaymentsDomain.java +32 -0
- package/examples/native-payments/java/src/test/java/domain/PaymentGenerators.java +16 -0
- package/examples/native-payments/javascript/lawspec.json +149 -0
- package/examples/native-payments/javascript/src/payments_domain.mjs +44 -0
- package/examples/native-payments/javascript/test/lawspec_generators.mjs +6 -0
- package/examples/native-payments/kotlin/lawspec.json +165 -0
- package/examples/native-payments/kotlin/src/main/kotlin/domain/PaymentsDomain.kt +17 -0
- package/examples/native-payments/kotlin/src/test/kotlin/domain/PaymentGenerators.kt +12 -0
- package/examples/native-payments/python/lawspec.json +149 -0
- package/examples/native-payments/python/src/payments_domain.py +60 -0
- package/examples/native-payments/python/tests/lawspec_generators.py +15 -0
- package/examples/native-payments/rust/lawspec.json +167 -0
- package/examples/native-payments/rust/src/domain.rs +37 -0
- package/examples/native-payments/rust/src/lib.rs +2 -0
- package/examples/native-payments/rust/tests/support/lawspec_generators.rs +11 -0
- package/examples/native-payments/typescript/lawspec.json +149 -0
- package/examples/native-payments/typescript/src/payments_domain.ts +42 -0
- package/examples/native-payments/typescript/test/lawspec_generators.ts +8 -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/payments.lawspec +76 -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 +11 -1
- package/files.mjs +16 -7
- package/index.d.ts +297 -27
- package/native-examples.mjs +81 -0
- package/package.json +2 -2
- package/templates.mjs +107 -17
|
@@ -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
|
@@ -3,11 +3,16 @@ import path from "node:path";
|
|
|
3
3
|
import { createCompiler } from "./api.mjs";
|
|
4
4
|
import { targets } from "./templates.mjs";
|
|
5
5
|
import { safePath, planWrites, applyWrites } from "./files.mjs";
|
|
6
|
+
import { exportNativePayments } from "./native-examples.mjs";
|
|
6
7
|
|
|
7
8
|
export async function generateExamples(options) {
|
|
8
9
|
const selected = options.target ? [options.target] : targets;
|
|
9
10
|
if (selected.some((t) => !targets.includes(t)))
|
|
10
11
|
throw new Error(`Unknown target: ${options.target}`);
|
|
12
|
+
if (options.example !== undefined) {
|
|
13
|
+
if (options.example !== "payments") throw new Error(`Unknown example: ${options.example}`);
|
|
14
|
+
return exportNativePayments(options, selected);
|
|
15
|
+
}
|
|
11
16
|
const directory = new URL("./examples/specs/", import.meta.url);
|
|
12
17
|
const sources = await Promise.all(
|
|
13
18
|
(await readdir(directory))
|
|
@@ -21,7 +26,12 @@ export async function generateExamples(options) {
|
|
|
21
26
|
const compiler = await createCompiler();
|
|
22
27
|
const artifacts = [];
|
|
23
28
|
for (const target of selected) {
|
|
24
|
-
const result = await compiler.planGeneration({
|
|
29
|
+
const result = await compiler.planGeneration({
|
|
30
|
+
sources,
|
|
31
|
+
target,
|
|
32
|
+
machineBits: options.machineBits ?? 64,
|
|
33
|
+
minify: options.minify === true,
|
|
34
|
+
});
|
|
25
35
|
if (result.diagnostics.length)
|
|
26
36
|
throw Object.assign(new Error("Bundled examples failed to compile"), {
|
|
27
37
|
diagnostics: result.diagnostics,
|
package/files.mjs
CHANGED
|
@@ -63,8 +63,8 @@ export async function atomicWrite(file, content, exclusive = false) {
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
-
export async function planWrites(root, artifacts) {
|
|
67
|
-
const manifestPath = await safePath(root,
|
|
66
|
+
export async function planWrites(root, artifacts, {manifest = ".lawspec/generated.json"} = {}) {
|
|
67
|
+
const manifestPath = await safePath(root, manifest);
|
|
68
68
|
const previousText = await readOptional(manifestPath);
|
|
69
69
|
const previous =
|
|
70
70
|
previousText === null
|
|
@@ -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]
|
|
@@ -135,18 +144,18 @@ export async function planWrites(root, artifacts) {
|
|
|
135
144
|
throw new Error(`Refusing to remove edited generated file: ${relative}`);
|
|
136
145
|
changes.push({ action: "remove", file, relative, expected: old });
|
|
137
146
|
}
|
|
138
|
-
const
|
|
147
|
+
const manifestContent =
|
|
139
148
|
JSON.stringify(
|
|
140
149
|
{ version: 1, files: next, adapters: adapterHashes },
|
|
141
150
|
null,
|
|
142
151
|
2,
|
|
143
152
|
) + "\n";
|
|
144
|
-
if (
|
|
153
|
+
if (manifestContent !== previousText)
|
|
145
154
|
changes.push({
|
|
146
155
|
action: previousText === null ? "create" : "update",
|
|
147
156
|
file: manifestPath,
|
|
148
|
-
relative:
|
|
149
|
-
content:
|
|
157
|
+
relative: manifest,
|
|
158
|
+
content: manifestContent,
|
|
150
159
|
expected: previousText,
|
|
151
160
|
});
|
|
152
161
|
return { root, changes, preserved, adapterUpdates };
|
package/index.d.ts
CHANGED
|
@@ -1,29 +1,299 @@
|
|
|
1
1
|
// Generated from LawSpec.Gen. Do not edit.
|
|
2
|
-
export type Target =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export interface
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
export interface
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
export interface
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export interface
|
|
2
|
+
export type Target =
|
|
3
|
+
'java' |
|
|
4
|
+
'python' |
|
|
5
|
+
'javascript' |
|
|
6
|
+
'typescript' |
|
|
7
|
+
'go' |
|
|
8
|
+
'haskell' |
|
|
9
|
+
'kotlin' |
|
|
10
|
+
'rust';
|
|
11
|
+
|
|
12
|
+
export interface Source {
|
|
13
|
+
path: string;
|
|
14
|
+
content: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface Location {
|
|
18
|
+
file: string;
|
|
19
|
+
line: number;
|
|
20
|
+
column: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface Span {
|
|
24
|
+
start: Location;
|
|
25
|
+
end: Location;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface Diagnostic {
|
|
29
|
+
code: string;
|
|
30
|
+
message: string;
|
|
31
|
+
at: Location | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface Artifact {
|
|
35
|
+
path: string;
|
|
36
|
+
content: string;
|
|
37
|
+
ownership: 'user' | 'generated';
|
|
38
|
+
placement: 'source' | 'test';
|
|
39
|
+
adapterReference?: string;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type Type =
|
|
43
|
+
{kind: 'constructor'; name: string; arguments: TypeArgument[];} |
|
|
44
|
+
{kind: 'variable'; id: string;} |
|
|
45
|
+
{kind: 'function'; parameter: Type; result: Type;};
|
|
46
|
+
|
|
47
|
+
export type TypeArgument =
|
|
48
|
+
{kind: 'type'; type: Type;} |
|
|
49
|
+
{kind: 'natural'; value: string;} |
|
|
50
|
+
{kind: 'indexVariable'; id: string;};
|
|
51
|
+
|
|
52
|
+
export type Origin =
|
|
53
|
+
{kind: 'source'; span: Span;} | {kind: 'generated'; declaration: string;};
|
|
54
|
+
|
|
55
|
+
export type Evidence = {kind: 'numeric' | 'structural'; type: Type;};
|
|
56
|
+
|
|
57
|
+
export interface Expr {
|
|
58
|
+
type: Type;
|
|
59
|
+
origin: Origin;
|
|
60
|
+
text: string;
|
|
61
|
+
node: ExprNode;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type ExprNode =
|
|
65
|
+
{kind: 'constant'; value: ScalarValue;} |
|
|
66
|
+
{kind: 'match'; value: Expr; cases: MatchCase[];} |
|
|
67
|
+
{kind: 'allElements'; value: Expr; binder: Binder; predicate: Expr;} |
|
|
68
|
+
{kind: 'allPayloads'; value: Expr; predicates: PayloadPredicate[];} |
|
|
69
|
+
{kind: 'construct'; constructor: string; arguments: Expr[];} |
|
|
70
|
+
{kind: 'local'; id: string;} |
|
|
71
|
+
{kind: 'call'; declaration: string; arguments: Expr[];} |
|
|
72
|
+
{
|
|
73
|
+
kind: 'binary';
|
|
74
|
+
operator: string;
|
|
75
|
+
evidence: Evidence;
|
|
76
|
+
left: Expr;
|
|
77
|
+
right: Expr;
|
|
78
|
+
} |
|
|
79
|
+
{kind: 'unary'; operator: '-' | '!'; argument: Expr;} |
|
|
80
|
+
{kind: 'shortCircuit'; operator: '&&' | '||'; left: Expr; right: Expr;} |
|
|
81
|
+
{kind: 'convert'; conversion: 'explicit' | 'checked'; argument: Expr;} |
|
|
82
|
+
{kind: 'helper'; name: string; arguments: Expr[];};
|
|
83
|
+
|
|
84
|
+
export type Assertion =
|
|
85
|
+
{kind: 'equal'; evidence: Evidence; left: Expr; right: Expr;} |
|
|
86
|
+
{kind: 'implies'; guard: Expr; body: Assertion;} |
|
|
87
|
+
{kind: 'all'; items: Assertion[];};
|
|
88
|
+
|
|
89
|
+
export interface Generation {
|
|
90
|
+
cases: number;
|
|
91
|
+
maxAttempts: number;
|
|
92
|
+
maxShrinks: number;
|
|
93
|
+
exhaustiveLimit: number;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface Binder {
|
|
97
|
+
id: string;
|
|
98
|
+
name: string;
|
|
99
|
+
type: Type;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface Definition {
|
|
103
|
+
owner: string;
|
|
104
|
+
id: string;
|
|
105
|
+
arguments: Binder[];
|
|
106
|
+
body: Expr;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface Input extends Binder {
|
|
110
|
+
predicates: Expr[];
|
|
111
|
+
bounds: {operator: string; value: Expr;}[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface Example {
|
|
115
|
+
name: string;
|
|
116
|
+
bindings: (Binder & {value: DataValue;})[];
|
|
117
|
+
expectations: Assertion[];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface Law {
|
|
121
|
+
id: string;
|
|
122
|
+
owner: string;
|
|
123
|
+
name: string;
|
|
124
|
+
inputs: Input[];
|
|
125
|
+
assertion: Assertion;
|
|
126
|
+
examples: Example[];
|
|
127
|
+
description: string;
|
|
128
|
+
rationale: string;
|
|
129
|
+
references: string[];
|
|
130
|
+
location: Location;
|
|
131
|
+
trace: string[];
|
|
132
|
+
generation: Generation;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface Unit {
|
|
136
|
+
id: string;
|
|
137
|
+
declarations: (Binder & {origin: Origin;})[];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface DataTypeDeclaration {
|
|
141
|
+
id: string;
|
|
142
|
+
name: string;
|
|
143
|
+
parameters: string[];
|
|
144
|
+
origin: Origin;
|
|
145
|
+
constructors: {id: string; name: string; fields: Binder[]; origin: Origin;}[];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface Contract {
|
|
149
|
+
id: string;
|
|
150
|
+
name: string;
|
|
151
|
+
arguments: Binder[];
|
|
152
|
+
result: Binder;
|
|
153
|
+
preconditions: Expr[];
|
|
154
|
+
postconditions: Expr[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface Refinement {
|
|
158
|
+
owner: string;
|
|
159
|
+
name: string;
|
|
160
|
+
parameters: {name: string; kind: 'type' | 'value'; type: string;}[];
|
|
161
|
+
requirements: {capability: string; type: string;}[];
|
|
162
|
+
definition: string;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export type NativeReference = string[];
|
|
166
|
+
|
|
167
|
+
export interface NativeFieldBinding {
|
|
168
|
+
field: string;
|
|
169
|
+
native: string;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export interface NativeConstructorBinding {
|
|
173
|
+
constructor: string;
|
|
174
|
+
native: NativeReference;
|
|
175
|
+
fields?: NativeFieldBinding[];
|
|
176
|
+
style: 'record' | 'variant' | 'unit';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface NativeCodecBinding {
|
|
180
|
+
toNative: NativeReference;
|
|
181
|
+
fromNative: NativeReference;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface NativeTypeBinding {
|
|
185
|
+
type: string;
|
|
186
|
+
native: NativeReference;
|
|
187
|
+
constructors?: NativeConstructorBinding[];
|
|
188
|
+
codec?: NativeCodecBinding;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export interface NativeGeneratorBinding {
|
|
192
|
+
type: string;
|
|
193
|
+
factory: NativeReference;
|
|
194
|
+
stub?: boolean;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export interface NativeFunctionBinding {
|
|
198
|
+
declaration: string;
|
|
199
|
+
native: NativeReference;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface NativeGoImport {
|
|
203
|
+
alias: string;
|
|
204
|
+
path: string;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface NativeBindings {
|
|
208
|
+
types?: NativeTypeBinding[];
|
|
209
|
+
generators?: NativeGeneratorBinding[];
|
|
210
|
+
functions?: NativeFunctionBinding[];
|
|
211
|
+
rustCrate?: string;
|
|
212
|
+
goImports?: NativeGoImport[];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export interface CheckRequest {
|
|
216
|
+
sources: Source[];
|
|
217
|
+
schemaVersion?: 3 | 4;
|
|
218
|
+
machineBits?: 32 | 64;
|
|
219
|
+
generation?: Partial<Generation>;
|
|
220
|
+
nativeBindings?: NativeBindings;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface GenerationRequest extends CheckRequest {
|
|
224
|
+
target: Target;
|
|
225
|
+
sourceDir?: string;
|
|
226
|
+
testDir?: string;
|
|
227
|
+
minify?: boolean;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface Result {
|
|
231
|
+
schemaVersion: 3 | 4;
|
|
232
|
+
machineBits?: 32 | 64;
|
|
233
|
+
generation?: Generation;
|
|
234
|
+
units?: Unit[];
|
|
235
|
+
dataTypes?: DataTypeDeclaration[];
|
|
236
|
+
definitions?: Definition[];
|
|
237
|
+
laws?: Law[];
|
|
238
|
+
contracts?: {owner: string; contract: Contract;}[];
|
|
239
|
+
refinements?: Refinement[];
|
|
240
|
+
diagnostics: Diagnostic[];
|
|
241
|
+
expansions?: string[];
|
|
242
|
+
files?: Artifact[];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface PayloadPredicate {
|
|
246
|
+
binder: Binder;
|
|
247
|
+
predicate: Expr;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export interface MatchCase {
|
|
251
|
+
constructor: string;
|
|
252
|
+
binders: Binder[];
|
|
253
|
+
body: Expr;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export type DataValue =
|
|
257
|
+
ScalarValue |
|
|
258
|
+
{kind: 'data'; type: Type; constructor: string; fields: DataValue[];};
|
|
259
|
+
|
|
260
|
+
export type IntegerType =
|
|
261
|
+
'Int8' |
|
|
262
|
+
'Int16' |
|
|
263
|
+
'Int32' |
|
|
264
|
+
'Int64' |
|
|
265
|
+
'UInt8' |
|
|
266
|
+
'UInt16' |
|
|
267
|
+
'UInt32' |
|
|
268
|
+
'UInt64' |
|
|
269
|
+
'IntSize' |
|
|
270
|
+
'UIntSize' |
|
|
271
|
+
'UIntPtr' |
|
|
272
|
+
'Integer' |
|
|
273
|
+
'BigInt' |
|
|
274
|
+
'BigUInt';
|
|
275
|
+
|
|
276
|
+
export type ScalarValue =
|
|
277
|
+
{type: IntegerType; value: string;} |
|
|
278
|
+
{type: 'Bool'; value: boolean;} |
|
|
279
|
+
{type: 'Decimal'; coefficient: string; exponent: string;} |
|
|
280
|
+
{type: 'Rational'; numerator: string; denominator: string;} |
|
|
281
|
+
{type: 'Float32' | 'Float64'; bits: string;} |
|
|
282
|
+
{
|
|
283
|
+
type: 'Complex64' | 'Complex128';
|
|
284
|
+
real: ScalarValue;
|
|
285
|
+
imaginary: ScalarValue;
|
|
286
|
+
} |
|
|
287
|
+
{type: 'Char' | 'CodePoint' | 'CodeUnit16'; value: number;} |
|
|
288
|
+
{type: 'Text' | 'CodePointText' | 'Utf16Text' | 'Bytes'; units: number[];} |
|
|
289
|
+
{type: 'Symbol'; id: string; description: string;} |
|
|
290
|
+
{type: 'Unit' | 'Null' | 'Undefined';} |
|
|
291
|
+
{type: 'Nullable' | 'Optional'; value: ScalarValue | null;};
|
|
292
|
+
|
|
293
|
+
export interface Compiler {
|
|
294
|
+
check(input: CheckRequest): Promise<Result>;
|
|
295
|
+
expand(input: CheckRequest): Promise<Result>;
|
|
296
|
+
planGeneration(input: GenerationRequest): Promise<Result>;
|
|
297
|
+
}
|
|
298
|
+
|
|
29
299
|
export function createCompiler(): Promise<Compiler>;
|