lawspec 0.5.0 → 0.7.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,75 @@
1
+ unit example.refinements
2
+
3
+ refinement Between (T :: Type) (minimum :: T) (maximum :: T)
4
+ requires Ordered T is
5
+ (value :: T where minimum <= value && value <= maximum)
6
+ end
7
+
8
+ refinement Positive (T :: Type) requires Integer T is
9
+ (value :: T where value > 0)
10
+ end
11
+
12
+ refinement AdditionOverflows (T :: Type) (left :: T)
13
+ requires Integer T Bounded T is
14
+ (right :: T where left + right > T.max)
15
+ end
16
+
17
+ add :: (x :: Int8)
18
+ -> (y :: AdditionOverflows Int8 x)
19
+ -> (result :: Integer where result == x + y)
20
+ successor :: (x :: Int8) -> (result :: Integer where result == x + 1)
21
+ count :: (text :: Text where prelude.length text > 0)
22
+ -> (result :: Integer where result == prelude.length text)
23
+ preserve :: (x :: UInt64) -> (result :: Integer where result == x)
24
+ positive :: (x :: Positive Int8) -> (result :: Positive Int8 where result == x)
25
+
26
+ law `maximum input` is
27
+ definition is `for all` (x :: Int8) . successor x = x + 1 end
28
+ example `beyond Int8` is x = 127 expect successor x = 128 end
29
+ end
30
+
31
+ law `overflow pairs` is
32
+ definition is
33
+ `for all` (x :: Int8) (y :: AdditionOverflows Int8 x) .
34
+ add x y = x + y
35
+ end
36
+ example `smallest overflowing sum` is x = 127 y = 1 expect add x y = 128 end
37
+ example `largest sum` is x = 127 y = 127 expect add x y = 254 end
38
+ end
39
+
40
+ law `bounded input` is
41
+ definition is `for all` (x :: Between Int8 1 3) . positive x = x end
42
+ example `middle` is x = 2 expect positive x = 2 end
43
+ end
44
+
45
+ law `large integer` is
46
+ definition is `for all` (x :: UInt64) . preserve x = x end
47
+ example `maximum UInt64` is x = 18446744073709551615 expect preserve x = 18446744073709551615 end
48
+ end
49
+
50
+ abstractEcho :: (x :: Integer) -> (result :: Integer where result == x)
51
+
52
+ law `nested presence` is
53
+ definition is `for all` (x :: Optional (Nullable (Positive Int8))) . x = x end
54
+ end
55
+
56
+ law `finite positive floats` is
57
+ definition is
58
+ `for all` (x :: Float32 where prelude.isFinite x && x > 0) .
59
+ prelude.isFinite x
60
+ end
61
+ example `positive` is x = 0.5 expect x = 0.5 end
62
+ end
63
+
64
+ law `raw byte length` is
65
+ definition is `for all` (x :: Bytes where prelude.length x == 3) . prelude.length x = 3 end
66
+ example `arbitrary octets` is x = bytes([0,128,255]) expect prelude.length x = 3 end
67
+ end
68
+
69
+ law `guarded predicate arithmetic` is
70
+ definition is `for all` (x :: Int8) (y :: Int8 where x != 0 && y > 10 / x) . y > 10 / x end
71
+ end
72
+
73
+ law `machine bound` is
74
+ definition is `for all` (x :: IntSize where x == IntSize.max) . x = IntSize.max end
75
+ end
@@ -0,0 +1,83 @@
1
+ unit example.scalar_adapters
2
+ echoChar :: Char -> Char
3
+ echoCodePoint :: CodePoint -> CodePoint
4
+ echoCodeUnit :: CodeUnit16 -> CodeUnit16
5
+ echoBytes :: Bytes -> Bytes
6
+ echoComplex :: Complex64 -> Complex64
7
+ successor :: Int8 -> BigInt
8
+ narrow :: Int8 -> Int8
9
+ addDecimal :: Decimal -> Decimal -> Decimal
10
+ sameSymbol :: Symbol -> Symbol -> Bool
11
+ echoRaw :: Utf16Text -> Utf16Text
12
+ echoPresence :: Optional (Nullable Int8) -> Optional (Nullable Int8)
13
+ finish :: Unit -> Unit
14
+ preserveBig :: UInt64 -> UInt64
15
+ machineEcho :: IntSize -> IntSize
16
+
17
+ law `promoted successor` is
18
+ definition is `for all` (x :: Int8) . successor x = x + 1 end
19
+ example `no overflow` is x = 127 expect successor x = 128 end
20
+ end
21
+ law `checked bridge` is
22
+ definition is `for all` (x :: Int8) . narrow (x + 0) = x end
23
+ example `maximum` is x = 127 expect narrow (x + 0) = 127 end
24
+ end
25
+ law `exact decimal adapter` is
26
+ definition is `for all` (x :: Decimal) (y :: Decimal) . addDecimal x y = x + y end
27
+ example `tenths` is x = 0.1 y = 0.2 expect addDecimal x y = 0.3 end
28
+ end
29
+ law `symbol identity adapter` is
30
+ definition is `for all` (x :: Symbol) (y :: Symbol) . sameSymbol x x and sameSymbol y y end
31
+ example `same description distinct identities` is
32
+ x = symbol("a", "same") y = symbol("b", "same")
33
+ expect sameSymbol x y = false
34
+ expect sameSymbol x x = true
35
+ end
36
+ end
37
+ law `raw adapter` is
38
+ definition is `for all` (x :: Utf16Text) . echoRaw x = x end
39
+ example `lone surrogate` is x = utf16([55296]) expect echoRaw x = utf16([55296]) end
40
+ end
41
+ law `presence adapter` is
42
+ definition is `for all` (x :: Optional (Nullable Int8)) . echoPresence x = x end
43
+ example `missing` is x = undefined expect echoPresence x = undefined end
44
+ example `null present` is x = optional(null) expect echoPresence x = optional(null) end
45
+ end
46
+ law `unit adapter` is
47
+ definition is `for all` (x :: Unit) . finish x = unitValue end
48
+ example `completed` is x = unitValue expect finish x = unitValue end
49
+ end
50
+
51
+ law `no safe-number truncation` is
52
+ definition is `for all` (x :: UInt64) . preserveBig x = x end
53
+ example `unsigned maximum` is x = 18446744073709551615 expect preserveBig x = 18446744073709551615 end
54
+ end
55
+ law `machine profile binding` is
56
+ definition is `for all` (x :: IntSize) . machineEcho x = x end
57
+ example `portable width` is x = 2147483647 expect machineEcho x = 2147483647 end
58
+ end
59
+
60
+ law `Char native bridge` is
61
+ definition is `for all` (x :: Char) . echoChar x = x end
62
+ example `native value` is x = char(128512) expect echoChar x = char(128512) end
63
+ end
64
+
65
+ law `CodePoint native bridge` is
66
+ definition is `for all` (x :: CodePoint) . echoCodePoint x = x end
67
+ example `native value` is x = codePoint(55296) expect echoCodePoint x = codePoint(55296) end
68
+ end
69
+
70
+ law `CodeUnit16 native bridge` is
71
+ definition is `for all` (x :: CodeUnit16) . echoCodeUnit x = x end
72
+ example `native value` is x = codeUnit16(65535) expect echoCodeUnit x = codeUnit16(65535) end
73
+ end
74
+
75
+ law `Bytes native bridge` is
76
+ definition is `for all` (x :: Bytes) . echoBytes x = x end
77
+ example `native value` is x = bytes([0,128,255]) expect echoBytes x = bytes([0,128,255]) end
78
+ end
79
+
80
+ law `Complex64 native bridge` is
81
+ definition is `for all` (x :: Complex64) . prelude.isNaN (prelude.real (echoComplex x)) = prelude.isNaN (prelude.real x) end
82
+ example `native value` is x = complex64(1,2) expect echoComplex x = complex64(1,2) end
83
+ end
@@ -0,0 +1,166 @@
1
+ unit example.scalar_catalog
2
+
3
+ law `Bool representation` is
4
+ definition is `for all` (x :: Bool) . x = x end
5
+ example `explicit value` is x = true expect x = true end
6
+ end
7
+
8
+ law `Int8 representation` is
9
+ definition is `for all` (x :: Int8) . x = x end
10
+ example `explicit value` is x = -128 expect x = -128 end
11
+ end
12
+
13
+ law `Int16 representation` is
14
+ definition is `for all` (x :: Int16) . x = x end
15
+ example `explicit value` is x = 32767 expect x = 32767 end
16
+ end
17
+
18
+ law `Int32 representation` is
19
+ definition is `for all` (x :: Int32) . x = x end
20
+ example `explicit value` is x = 2147483647 expect x = 2147483647 end
21
+ end
22
+
23
+ law `Int64 representation` is
24
+ definition is `for all` (x :: Int64) . x = x end
25
+ example `explicit value` is x = 9223372036854775807 expect x = 9223372036854775807 end
26
+ end
27
+
28
+ law `UInt8 representation` is
29
+ definition is `for all` (x :: UInt8) . x = x end
30
+ example `explicit value` is x = 255 expect x = 255 end
31
+ end
32
+
33
+ law `UInt16 representation` is
34
+ definition is `for all` (x :: UInt16) . x = x end
35
+ example `explicit value` is x = 65535 expect x = 65535 end
36
+ end
37
+
38
+ law `UInt32 representation` is
39
+ definition is `for all` (x :: UInt32) . x = x end
40
+ example `explicit value` is x = 4294967295 expect x = 4294967295 end
41
+ end
42
+
43
+ law `UInt64 representation` is
44
+ definition is `for all` (x :: UInt64) . x = x end
45
+ example `explicit value` is x = 18446744073709551615 expect x = 18446744073709551615 end
46
+ end
47
+
48
+ law `IntSize representation` is
49
+ definition is `for all` (x :: IntSize) . x = x end
50
+ example `explicit value` is x = 2147483647 expect x = 2147483647 end
51
+ end
52
+
53
+ law `UIntSize representation` is
54
+ definition is `for all` (x :: UIntSize) . x = x end
55
+ example `explicit value` is x = 4294967295 expect x = 4294967295 end
56
+ end
57
+
58
+ law `UIntPtr representation` is
59
+ definition is `for all` (x :: UIntPtr) . x = x end
60
+ example `explicit value` is x = 4294967295 expect x = 4294967295 end
61
+ end
62
+
63
+ law `BigInt representation` is
64
+ definition is `for all` (x :: BigInt) . x = x end
65
+ example `explicit value` is x = -1234567890123456789012345678901234567890 expect x = -1234567890123456789012345678901234567890 end
66
+ end
67
+
68
+ law `BigUInt representation` is
69
+ definition is `for all` (x :: BigUInt) . x = x end
70
+ example `explicit value` is x = 1234567890123456789012345678901234567890 expect x = 1234567890123456789012345678901234567890 end
71
+ end
72
+
73
+ law `Decimal representation` is
74
+ definition is `for all` (x :: Decimal) . x = x end
75
+ example `explicit value` is x = 0.000000000000000000000000000000000001 expect x = 0.000000000000000000000000000000000001 end
76
+ end
77
+
78
+ law `Rational representation` is
79
+ definition is `for all` (x :: Rational) . x = x end
80
+ example `explicit value` is x = rational(-7, 11) expect x = rational(-7, 11) end
81
+ end
82
+
83
+ law `Float32 representation` is
84
+ definition is `for all` (x :: Float32) . prelude.isNaN x = prelude.isNaN x end
85
+ example `explicit value` is x = float32Bits("80000000") expect x = float32Bits("80000000") end
86
+ end
87
+
88
+ law `Float64 representation` is
89
+ definition is `for all` (x :: Float64) . prelude.isNaN x = prelude.isNaN x end
90
+ example `explicit value` is x = float64Bits("7ff0000000000000") expect x = float64Bits("7ff0000000000000") end
91
+ end
92
+
93
+ law `Complex64 representation` is
94
+ definition is `for all` (x :: Complex64) . prelude.isNaN (prelude.real x) = prelude.isNaN (prelude.real x) end
95
+ example `explicit value` is x = complex64(1, -2) expect x = complex64(1, -2) end
96
+ end
97
+
98
+ law `Complex128 representation` is
99
+ definition is `for all` (x :: Complex128) . prelude.isNaN (prelude.real x) = prelude.isNaN (prelude.real x) end
100
+ example `explicit value` is x = complex128(0.5, -3.5) expect x = complex128(0.5, -3.5) end
101
+ end
102
+
103
+ law `Char representation` is
104
+ definition is `for all` (x :: Char) . x = x end
105
+ example `explicit value` is x = char(128512) expect x = char(128512) end
106
+ end
107
+
108
+ law `CodePoint representation` is
109
+ definition is `for all` (x :: CodePoint) . x = x end
110
+ example `explicit value` is x = codePoint(55296) expect x = codePoint(55296) end
111
+ end
112
+
113
+ law `CodeUnit16 representation` is
114
+ definition is `for all` (x :: CodeUnit16) . x = x end
115
+ example `explicit value` is x = codeUnit16(65535) expect x = codeUnit16(65535) end
116
+ end
117
+
118
+ law `Text representation` is
119
+ definition is `for all` (x :: Text) . x = x end
120
+ example `explicit value` is x = "λ日本語😀" expect x = "λ日本語😀" end
121
+ end
122
+
123
+ law `CodePointText representation` is
124
+ definition is `for all` (x :: CodePointText) . x = x end
125
+ example `explicit value` is x = codePoints([55296, 1114111]) expect x = codePoints([55296, 1114111]) end
126
+ end
127
+
128
+ law `Utf16Text representation` is
129
+ definition is `for all` (x :: Utf16Text) . x = x end
130
+ example `explicit value` is x = utf16([55296, 0, 65535]) expect x = utf16([55296, 0, 65535]) end
131
+ end
132
+
133
+ law `Bytes representation` is
134
+ definition is `for all` (x :: Bytes) . x = x end
135
+ example `explicit value` is x = bytes([0, 128, 255]) expect x = bytes([0, 128, 255]) end
136
+ end
137
+
138
+ law `Symbol representation` is
139
+ definition is `for all` (x :: Symbol) . x = x end
140
+ example `explicit value` is x = symbol("catalog", "same") expect x = symbol("catalog", "same") end
141
+ end
142
+
143
+ law `Unit representation` is
144
+ definition is `for all` (x :: Unit) . x = x end
145
+ example `explicit value` is x = unitValue expect x = unitValue end
146
+ end
147
+
148
+ law `Null representation` is
149
+ definition is `for all` (x :: Null) . x = x end
150
+ example `explicit value` is x = null expect x = null end
151
+ end
152
+
153
+ law `Undefined representation` is
154
+ definition is `for all` (x :: Undefined) . x = x end
155
+ example `explicit value` is x = undefined expect x = undefined end
156
+ end
157
+
158
+ law `Nullable Int8 representation` is
159
+ definition is `for all` (x :: Nullable Int8) . x = x end
160
+ example `explicit value` is x = nullable(127) expect x = nullable(127) end
161
+ end
162
+
163
+ law `Optional Int8 representation` is
164
+ definition is `for all` (x :: Optional Int8) . x = x end
165
+ example `explicit value` is x = undefined expect x = undefined end
166
+ end
@@ -0,0 +1,138 @@
1
+ unit example.scalars
2
+
3
+ law `integer promotion` is
4
+ definition is `for all` (x :: Int8) . x + 1 = 1 + x end
5
+ example `overflow is preserved` is
6
+ x = 127
7
+ expect x + 1 = 128
8
+ end
9
+ end
10
+
11
+ law `unsigned precision` is
12
+ definition is `for all` (x :: UInt64) . x + 0 = x end
13
+ example `maximum` is
14
+ x = 18446744073709551615
15
+ expect x + 1 = 18446744073709551616
16
+ end
17
+ end
18
+
19
+ law `decimal exactness` is
20
+ definition is `for all` (x :: Decimal) . x + 0.1 = 0.1 + x end
21
+ example `tenths` is
22
+ x = 0.1
23
+ expect x + 0.2 = 0.3
24
+ end
25
+ end
26
+
27
+ law `exact division` is
28
+ definition is `for all` (x :: Int16) . x / 2 = x / 2 end
29
+ example `one half` is
30
+ x = 1
31
+ expect x / 2 = rational(1, 2)
32
+ expect prelude.quot -7 3 = -2
33
+ expect prelude.rem -7 3 = -1
34
+ expect prelude.round rational(125, 100) 1 = 1.2
35
+ end
36
+ end
37
+
38
+ law `IEEE classification` is
39
+ definition is `for all` (x :: Float32) . prelude.isNaN x = prelude.isNaN x end
40
+ example `NaN` is
41
+ x = float32Bits("7fc00000")
42
+ expect prelude.isNaN x = true
43
+ end
44
+ example `negative zero` is
45
+ x = float32Bits("80000000")
46
+ expect prelude.isNegativeZero x = true
47
+ expect x = (0 :: Float32)
48
+ end
49
+ example `infinity` is
50
+ x = float32Bits("7f800000")
51
+ expect prelude.isInfinite x = true
52
+ expect prelude.Float32 0.1 = (0.1 :: Float32)
53
+ end
54
+ end
55
+
56
+ law `complex arithmetic` is
57
+ definition is `for all` (x :: Unit) . complex64(1, 2) * complex64(3, 4) = complex64(-5, 10) end
58
+ example `product` is
59
+ x = unitValue
60
+ expect complex64(1, 2) * complex64(3, 4) = complex64(-5, 10)
61
+ end
62
+ end
63
+
64
+ law `raw units survive` is
65
+ definition is `for all` (x :: Utf16Text) . x = x end
66
+ example `unpaired surrogate` is
67
+ x = utf16([55296, 0, 56320])
68
+ expect x = utf16([55296, 0, 56320])
69
+ end
70
+ end
71
+
72
+ law `arbitrary bytes` is
73
+ definition is `for all` (x :: Bytes) . x = x end
74
+ example `octets` is
75
+ x = bytes([0, 128, 255])
76
+ expect x = bytes([0, 128, 255])
77
+ end
78
+ end
79
+
80
+ law `symbol fixture identity` is
81
+ definition is `for all` (x :: Symbol) . x = x end
82
+ example `same reference` is
83
+ x = symbol("first", "description")
84
+ expect x = symbol("first", "description")
85
+ end
86
+ end
87
+
88
+ law `nested absence` is
89
+ definition is `for all` (x :: Optional (Nullable Int8)) . x = x end
90
+ example `undefined` is
91
+ x = undefined
92
+ expect x = undefined
93
+ end
94
+ example `present null` is
95
+ x = optional(null)
96
+ expect x = optional(null)
97
+ end
98
+ example `present integer` is
99
+ x = optional(nullable(7))
100
+ expect x = optional(nullable(7))
101
+ end
102
+ end
103
+
104
+ law `supplementary scalar` is
105
+ definition is `for all` (x :: Char) . x = x end
106
+ example `emoji` is
107
+ x = char(128512)
108
+ expect x = char(128512)
109
+ end
110
+ end
111
+
112
+ law `surrogate code point` is
113
+ definition is `for all` (x :: CodePointText) . x = x end
114
+ example `surrogate` is
115
+ x = codePoints([55296, 128512])
116
+ expect x = codePoints([55296, 128512])
117
+ end
118
+ end
119
+
120
+ law `explicit float rounding` is
121
+ definition is `for all` (x :: Unit) . x = x end
122
+ example `IEEE halfway cases` is
123
+ x = unitValue
124
+ expect prelude.Complex128 complex64(1, 2) = complex128(1, 2)
125
+ expect prelude.Complex64 complex128(1.25, -2.5) = complex64(1.25, -2.5)
126
+ expect prelude.Float32 rational(16777217, 16777216) = float32Bits("3f800000")
127
+ expect prelude.Float32 rational(1208925891672223212634113, 1208925819614629174706176) = float32Bits("3f800001")
128
+ expect prelude.Float64 rational(9007199254740993, 9007199254740992) = float64Bits("3ff0000000000000")
129
+ expect prelude.Float64 rational(1606938044258990453947923680586147734807949174969684883144705, 1606938044258990275541962092341162602522202993782792835301376) = float64Bits("3ff0000000000001")
130
+ expect prelude.Float32 rational(1, 1427247692705959881058285969449495136382746624) = float32Bits("00000000")
131
+ expect prelude.Float32 rational(1125899906842625, 1606938044258990275541962092341162602522202993782792835301376) = float32Bits("00000001")
132
+ end
133
+ end
134
+
135
+ law `short circuit exact failures` is
136
+ definition is `for all` (x :: Unit) . false implies 1 / 0 = rational(1, 2) end
137
+ example `guard prevents division` is x = unitValue expect x = unitValue end
138
+ end
@@ -21,7 +21,7 @@ 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 });
24
+ const result = await compiler.planGeneration({ sources, target, machineBits: options.machineBits ?? 64 });
25
25
  if (result.diagnostics.length)
26
26
  throw Object.assign(new Error("Bundled examples failed to compile"), {
27
27
  diagnostics: result.diagnostics,
package/index.d.ts CHANGED
@@ -3,16 +3,27 @@ export type Target = 'java' | 'python' | 'javascript' | 'typescript' | 'go' | 'h
3
3
  export interface Source { path: string; content: string }
4
4
  export interface Location { file: string; line: number; column: number }
5
5
  export interface Diagnostic { code: string; message: string; at: Location | null }
6
- export interface Artifact { path: string; content: string; ownership: 'user' | 'generated' }
7
- export type Type = {tag: 'Named' | 'Variable'; contents: string} | {tag: 'Arrow'; contents: [Type, Type]};
8
- export type Expr = {tag: 'Var' | 'StringLit'; contents: string} | {tag: 'Number'; contents: number} | {tag: 'BoolLit'; contents: boolean} | {tag: 'Apply' | 'Compose'; contents: [Expr, Expr]};
9
- export type Definition = {tag: 'Forall'; contents: [[string, Type][], Definition]} | {tag: 'Equal'; contents: [Expr, Expr]} | {tag: 'Holds'; contents: Expr} | {tag: 'Implies'; contents: [Expr, Definition]} | {tag: 'Invoke'; contents: [string, Expr[]]};
10
- export interface Expectation { actual: Expr; expected: number | string | boolean }
11
- export interface Example { exampleName: string; bindings: [string, number | string | boolean][]; expectations: Expectation[] }
12
- export interface Law { lawName: string; parameters: [string, Type][]; requirements: Type[]; definition: Definition; description: string; rationale: string; examples: Example[]; references: string[]; location: Location }
13
- export interface Expanded { owner: string; name: string; inputs: {inputName: string; inputId: string; inputType: Type}[]; left: Expr; right: Expr; guards: Expr[]; trace: string[]; original: Law }
14
- export interface CheckRequest { sources: Source[] }
6
+ export interface Artifact { path: string; content: string; ownership: 'user' | 'generated'; placement: 'source' | 'test' }
7
+ export type Type = {tag: 'Named' | 'Variable'; contents: string} | {tag: 'Arrow'; contents: [Type, Type]} | {tag: 'Applied'; contents: ['Nullable' | 'Optional', Type]} | {tag:'Refined'; contents:[string, Type, Expr | null]} | {tag:'Qualified'; contents:[Constraint[],Type]} | {tag:'CheckedType'; contents:[Expr[],Type]} | {tag:'RefinementApp'; contents:[string,RefinementArgument[]]};
8
+ export interface Constraint {tag:'Capability'; contents:['Eq'|'Integer'|'Ordered'|'Bounded',Type]}
9
+ export type RefinementArgument = {tag:'TypeArgument'; contents:Type} | {tag:'ValueArgument'; contents:Expr};
10
+ export interface Refinement {refinementName:string; refinementParameters:[string,Type][]; refinementRequirements:Constraint[]; refinementBody:Type}
11
+ export interface Contract {contractName:string; contractArguments:[string,Type][]; contractResult:[string,Type]; contractPreconditions:Expr[]; contractPostconditions:Expr[]}
12
+ export interface Generation {cases:number; maxAttempts:number; maxShrinks:number; exhaustiveLimit:number}
13
+ export interface Input {inputName:string; inputId:string; inputType:Type; inputRefinements:Expr[]}
14
+ export interface DomainPlan {domainInput:Input; domainBounds:[string,Expr][]}
15
+ export type IntegerType = 'Int8' | 'Int16' | 'Int32' | 'Int64' | 'UInt8' | 'UInt16' | 'UInt32' | 'UInt64' | 'IntSize' | 'UIntSize' | 'UIntPtr' | 'Integer' | 'BigInt' | 'BigUInt';
16
+ export type ScalarValue = {type: IntegerType; value: string} | {type: 'Bool'; value: boolean} | {type: 'Decimal'; coefficient: string; exponent: string} | {type: 'Rational'; numerator: string; denominator: string} | {type: 'Float32' | 'Float64'; bits: string} | {type: 'Complex64' | 'Complex128'; real: ScalarValue; imaginary: ScalarValue} | {type: 'Char' | 'CodePoint' | 'CodeUnit16'; value: number} | {type: 'Text' | 'CodePointText' | 'Utf16Text' | 'Bytes'; units: number[]} | {type: 'Symbol'; id: string; description: string} | {type: 'Unit' | 'Null' | 'Undefined'} | {type: 'Nullable' | 'Optional'; value: ScalarValue | null};
17
+ export type Expr = {tag: 'Var' | 'StringLit'; contents: string} | {tag: 'Number'; contents: string} | {tag: 'DecimalNumber'; contents: [string, string]} | {tag: 'BoolLit'; contents: boolean} | {tag: 'Apply' | 'Compose'; contents: [Expr, Expr]} | {tag: 'ScalarLit'; contents: ScalarValue} | {tag: 'Annotate'; contents: [Expr, Type]} | {tag: 'Unary'; contents: [string, Expr]} | {tag: 'Binary'; contents: [string, Expr, Expr]} | {tag:'TypeBound'; contents:['min'|'max',Type]};
18
+ export type Definition = {tag: 'Forall'; contents: [[string, Type][], Definition]} | {tag: 'Equal'; contents: [Expr, Expr]} | {tag: 'Holds'; contents: Expr} | {tag: 'Implies'; contents: [Expr, Definition]} | {tag: 'And'; contents: [Definition, Definition]} | {tag: 'Invoke'; contents: [string, Expr[]]};
19
+ export interface Expectation { actual: Expr; expected: ScalarValue }
20
+ export interface Example { exampleName: string; bindings: [string, ScalarValue][]; expectations: Expectation[] }
21
+ export interface Law { lawName: string; parameters: [string, Type][]; requirements: Constraint[]; definition: Definition; description: string; rationale: string; examples: Example[]; references: string[]; location: Location }
22
+ export type Assertion = {tag: 'AssertEqual'; contents: [Expr, Expr]} | {tag: 'AssertImplies'; contents: [Expr, Assertion]} | {tag: 'AssertAll'; contents: Assertion[]};
23
+ export interface Expanded { owner: string; name: string; inputs: Input[]; left: Expr; right: Expr; guards: Expr[]; assertion: Assertion; trace: string[]; original: Law; typedExpressions: TypedExpr[]; propertyKind: 'law'|'contract'; generation:Generation; generationPlan:DomainPlan[] }
24
+ export interface TypedExpr { expressionType: Type; expression: Expr; operands: TypedExpr[]; requiredConversion: Type | null }
25
+ export interface CheckRequest { sources: Source[]; schemaVersion?: 2; machineBits?: 32 | 64; generation?:Partial<Generation> }
15
26
  export interface GenerationRequest extends CheckRequest { target: Target; sourceDir?: string; testDir?: string }
16
- export interface Result { diagnostics: Diagnostic[]; laws?: Expanded[]; expansions?: string[]; files?: Artifact[] }
27
+ export interface Result { schemaVersion: 2; machineBits?: 32 | 64; generation?:Generation; refinements?:{owner:string; declaration:Refinement}[]; contracts?:{owner:string; contract:Contract}[]; diagnostics: Diagnostic[]; laws?: Expanded[]; expansions?: string[]; files?: Artifact[] }
17
28
  export interface Compiler { check(input: CheckRequest): Promise<Result>; expand(input: CheckRequest): Promise<Result>; planGeneration(input: GenerationRequest): Promise<Result> }
18
29
  export function createCompiler(): Promise<Compiler>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lawspec",
3
- "version": "0.5.0",
3
+ "version": "0.7.0",
4
4
  "description": "State the law once. Check it everywhere.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,6 +8,6 @@
8
8
  "bin": { "lawspec": "bin/lawspec.mjs" },
9
9
  "exports": { ".": { "types": "./index.d.ts", "import": "./api.mjs" } },
10
10
  "types": "index.d.ts",
11
- "files": ["*.mjs", "*.json", "index.d.ts", "bin", "core.wasm", "core_jsffi.js", "README.md", "LICENSE", "starter.lawspec", "examples"],
11
+ "files": ["*.mjs", "*.json", "index.d.ts", "bin", "core.wasm", "core_jsffi.js", "README.md", "PRIMITIVES.md", "REFINEMENTS.md", "API-MIGRATION.md", "LICENSE", "starter.lawspec", "examples"],
12
12
  "scripts": { "test": "node --test test/*.test.mjs" }
13
13
  }
package/scalars.mjs ADDED
@@ -0,0 +1,13 @@
1
+ // Human-readable, lossless API v2 scalar display.
2
+ export function showScalar(v) {
3
+ if (!v || typeof v !== 'object') throw new TypeError('Expected an API v2 scalar');
4
+ if ('coefficient' in v) return `${v.coefficient}e${v.exponent}`;
5
+ if ('numerator' in v) return `rational(${v.numerator}, ${v.denominator})`;
6
+ if ('bits' in v) return `${v.type === 'Float32' ? 'float32Bits' : 'float64Bits'}(${JSON.stringify(v.bits)})`;
7
+ if ('real' in v) return `${v.type}(${showScalar(v.real)}, ${showScalar(v.imaginary)})`;
8
+ if ('units' in v) return v.type === 'Text' ? JSON.stringify(v.units.map(c => String.fromCodePoint(c)).join('')) : `${v.type}([${v.units.join(', ')}])`;
9
+ if (v.type === 'Symbol') return `symbol(${JSON.stringify(v.id)}, ${JSON.stringify(v.description)})`;
10
+ if (v.type === 'Optional' || v.type === 'Nullable') return v.value === null ? (v.type === 'Optional' ? 'undefined' : 'null') : `${v.type.toLowerCase()}(${showScalar(v.value)})`;
11
+ if ('value' in v) return String(v.value);
12
+ return {Unit:'unitValue', Null:'null', Undefined:'undefined'}[v.type] ?? v.type;
13
+ }
package/templates.mjs CHANGED
@@ -100,7 +100,7 @@ export function templates(target) {
100
100
  case "haskell":
101
101
  return {
102
102
  "stack.yaml": "snapshot: lts-24.58\npackages: [.]\n",
103
- "package.yaml": `name: lawspec-example\nversion: 0.1.0\ndependencies: [base, text]\nlibrary:\n source-dirs: src\ntests:\n laws:\n main: Spec.hs\n source-dirs: test\n dependencies: [lawspec-example, hspec, hedgehog, hspec-hedgehog]\n build-tools: [hspec-discover]\n`,
103
+ "package.yaml": `name: lawspec-example\nversion: 0.1.0\ndependencies: [base, text, bytestring]\nlibrary:\n source-dirs: src\ntests:\n laws:\n main: Spec.hs\n source-dirs: test\n dependencies: [lawspec-example, hspec, hedgehog, hspec-hedgehog]\n build-tools: [hspec-discover]\n`,
104
104
  "test/Spec.hs": "{-# OPTIONS_GHC -F -pgmF hspec-discover #-}\n",
105
105
  };
106
106
  case "kotlin":