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.
Files changed (61) hide show
  1. package/API-MIGRATION.md +180 -3
  2. package/GO.md +144 -0
  3. package/HASKELL.md +171 -0
  4. package/JAVA.md +113 -0
  5. package/KOTLIN.md +214 -0
  6. package/LANGUAGE.md +240 -12
  7. package/NATIVE-BINDINGS.md +1046 -0
  8. package/PRIMITIVES.md +1 -1
  9. package/PYTHON.md +152 -0
  10. package/README.md +86 -23
  11. package/REFINEMENTS.md +289 -3
  12. package/RELEASE-0.10.md +60 -0
  13. package/RELEASE-0.9.md +61 -0
  14. package/RUST.md +115 -1
  15. package/WEB.md +144 -0
  16. package/api.mjs +28 -2
  17. package/bin/lawspec.mjs +23 -7
  18. package/build.json +199 -37
  19. package/core.wasm +0 -0
  20. package/examples/native-payments/go/example/payments/domain.go +38 -0
  21. package/examples/native-payments/go/example/payments/native_generators_test.go +13 -0
  22. package/examples/native-payments/go/lawspec.json +136 -0
  23. package/examples/native-payments/haskell/lawspec.json +149 -0
  24. package/examples/native-payments/haskell/src/PaymentsDomain.hs +21 -0
  25. package/examples/native-payments/haskell/test/PaymentGenerators.hs +12 -0
  26. package/examples/native-payments/java/lawspec.json +165 -0
  27. package/examples/native-payments/java/src/main/java/domain/PaymentsDomain.java +32 -0
  28. package/examples/native-payments/java/src/test/java/domain/PaymentGenerators.java +16 -0
  29. package/examples/native-payments/javascript/lawspec.json +149 -0
  30. package/examples/native-payments/javascript/src/payments_domain.mjs +44 -0
  31. package/examples/native-payments/javascript/test/lawspec_generators.mjs +6 -0
  32. package/examples/native-payments/kotlin/lawspec.json +165 -0
  33. package/examples/native-payments/kotlin/src/main/kotlin/domain/PaymentsDomain.kt +17 -0
  34. package/examples/native-payments/kotlin/src/test/kotlin/domain/PaymentGenerators.kt +12 -0
  35. package/examples/native-payments/python/lawspec.json +149 -0
  36. package/examples/native-payments/python/src/payments_domain.py +60 -0
  37. package/examples/native-payments/python/tests/lawspec_generators.py +15 -0
  38. package/examples/native-payments/rust/lawspec.json +167 -0
  39. package/examples/native-payments/rust/src/domain.rs +37 -0
  40. package/examples/native-payments/rust/src/lib.rs +2 -0
  41. package/examples/native-payments/rust/tests/support/lawspec_generators.rs +11 -0
  42. package/examples/native-payments/typescript/lawspec.json +149 -0
  43. package/examples/native-payments/typescript/src/payments_domain.ts +42 -0
  44. package/examples/native-payments/typescript/test/lawspec_generators.ts +8 -0
  45. package/examples/specs/collections.lawspec +67 -0
  46. package/examples/specs/data_types.lawspec +66 -0
  47. package/examples/specs/finite_data.lawspec +37 -0
  48. package/examples/specs/list_contracts.lawspec +136 -0
  49. package/examples/specs/list_refinements.lawspec +51 -0
  50. package/examples/specs/matching.lawspec +49 -0
  51. package/examples/specs/payments.lawspec +76 -0
  52. package/examples/specs/recursive_refinements.lawspec +41 -0
  53. package/examples/specs/refined_definitions.lawspec +44 -0
  54. package/examples/specs/sum_refinements.lawspec +49 -0
  55. package/examples/specs/total_functions.lawspec +101 -0
  56. package/examples-command.mjs +11 -1
  57. package/files.mjs +16 -7
  58. package/index.d.ts +297 -27
  59. package/native-examples.mjs +81 -0
  60. package/package.json +2 -2
  61. package/templates.mjs +107 -17
package/KOTLIN.md ADDED
@@ -0,0 +1,214 @@
1
+ # Native Kotlin data
2
+
3
+ LawSpec 0.9 emits Kotlin sealed interfaces and named generic variant classes from
4
+ checked Core declarations. Generated schemas and codecs share the JVM scalar
5
+ runtime, independently of Kotest.
6
+
7
+ ```lawspec
8
+ unit example.trees
9
+
10
+ type Tree (a :: Type) is
11
+ Leaf value :: a
12
+ Branch children :: List (Tree a)
13
+ end
14
+
15
+ echo :: Tree Int8 -> Tree Int8
16
+ ```
17
+
18
+ The public type is `lawspec.data.Tree<Byte>`. Its variants are
19
+ `Tree.LeafCase<Byte>`, with a typed `value` property, and
20
+ `Tree.BranchCase<Byte>`, with `children: List<Tree<Byte>>`. Recursive and mutually
21
+ recursive fields retain native types. Generic parameters also remain on nullary
22
+ variants. Empty types have a private constructor and cannot supply generated
23
+ arguments, but can occur inside inhabited types such as `Maybe Empty`.
24
+
25
+ A correct adapter is:
26
+
27
+ ```kotlin
28
+ fun echo(value: lawspec.data.Tree<Byte>): lawspec.data.Tree<Byte> = value
29
+ ```
30
+
31
+ Adapter files remain user-owned. Duplicate type names across units receive
32
+ qualified generated names. Kotlin built-ins are qualified in generated signatures
33
+ to avoid shadowing by domain types. Adapters that collide with generated JVM
34
+ runtime classes are rejected before output.
35
+
36
+ ## Containers and absence
37
+
38
+ `List a` uses Kotlin `List<T>`. `Maybe a` uses `LawSpecRuntime.Maybe<T>` with
39
+ `Nothing<T>` and `Just<T>`. `Either a b` uses `LawSpecRuntime.Either<L, R>` with
40
+ `Left<L, R>` and `Right<L, R>`.
41
+
42
+ Interoperability absence remains separate:
43
+
44
+ - `Nullable a`: `LawSpecKotlin.Nullable<T>`, with `Null<T>` and `Present<T>`.
45
+ - `Optional a`: `LawSpecKotlin.Optional<T>`, with `Undefined<T>` and `Present<T>`.
46
+ - `Null` and `Undefined`: distinct singleton support values.
47
+ - `Unit`: Kotlin `Unit`, including adapter operations without a meaningful result.
48
+
49
+ These representations preserve every state of `Nullable (Optional a)` and other
50
+ nested combinations. Checked codecs validate both native adapter arguments and
51
+ results. Containers and raw arrays are copied across the logical/native boundary.
52
+ LawSpec equality is schema-directed, including IEEE component equality and
53
+ Symbol identity; generated variant classes do not substitute Kotlin data-class
54
+ equality for those rules.
55
+
56
+ ## Scalars
57
+
58
+ Fixed signed integers use Kotlin `Byte`, `Short`, `Int`, and `Long`. UInt8,
59
+ UInt16, and UInt32 use the next sufficiently wide signed JVM type. UInt64,
60
+ arbitrary integers, and machine-profile integers use `BigInteger` with explicit
61
+ domain checks. These portable machine-profile representations do not bind a
62
+ host machine-sized primitive.
63
+
64
+ Decimal uses exact `BigDecimal`; Rational uses the normalized
65
+ `LawSpecRuntime.Ratio`. Complex components use `LawSpecRuntime.Complex`, with
66
+ Float32 precision validated for Complex64. Raw code-point text uses `IntArray`,
67
+ raw UTF-16 uses `String`, and bytes use `ByteArray`. `Char` uses a one-scalar
68
+ `String`, allowing supplementary characters; `CodePoint` uses `Int` and
69
+ `CodeUnit16` uses Kotlin `Char`.
70
+
71
+ `LawSpecKotlin.Symbol` preserves the underlying fixture identity through checked
72
+ round trips. Its native equality compares that identity, so two Symbols with the
73
+ same description remain distinct.
74
+
75
+ ## Total definitions
76
+
77
+ Checked source definitions produce native Kotlin entry points and shared Java
78
+ implementation bodies in source directories. Neither requires Kotest. For example:
79
+
80
+ ```lawspec
81
+ unit example.total
82
+
83
+ definition increment (value :: Int8) :: BigInt is
84
+ value + 1
85
+ end
86
+ ```
87
+
88
+ The native call is `lawspec.definitions.example.Total.increment(symbols, value)`;
89
+ `value` is a Kotlin `Byte`, the result is `BigInteger`, and `symbols` is a
90
+ `MutableMap<String, Any>` shared by calls in one example. An input of 127 returns
91
+ 128. Native signatures retain typed lists, custom variants, and nested presence
92
+ payloads. Checked codecs validate inputs and results; failures include the
93
+ resolved definition name.
94
+
95
+ Properties call the generated implementation directly. Definitions never become
96
+ user-owned adapter stubs. Recursive definitions must pass the frontend's
97
+ structural termination and definedness checks. Generic definitions specialize to concrete uses. Refined signatures become
98
+ checked contracts, and refinement predicates may call checked definitions.
99
+
100
+ `tools/kotlin-definitions-integration.mjs` checks both machine profiles, standalone
101
+ source calls, native type errors, recursive properties, incorrect adapters,
102
+ compact source and complete minified generation plans, custom layouts, and
103
+ regeneration protection. Java implementation
104
+ bodies are checked against Google Java Format; Kotlin uses structured document
105
+ layout checked by the independent compiler-parser audit described below.
106
+
107
+ ## Generated tests
108
+
109
+ Native declarations, schema metadata, and codecs belong in source directories.
110
+ `LawSpecStrategies` and `LawSpecKotlinStrategies` belong in test directories and
111
+ compose Kotest arbitraries and shrink trees. Bounded recursive generation reserves
112
+ each product field's minimum cost before distributing remaining nodes. Dependent
113
+ generation retains source shrink trees, including list lengths and constructor
114
+ choices, which Kotest 5.9's flatMap otherwise discards.
115
+
116
+ `tools/kotlin-data-integration.mjs` checks native declarations, codecs, and
117
+ shrinking in readable/compact layouts. `tools/kotlin-data-properties.mjs` compiles
118
+ and runs actual compiler output through Kotest with correct and incorrect
119
+ adapters, both profiles, and custom source/test roots. It accepts
120
+ `LAWSPEC_MINIFY=1` and includes the shared arithmetic conformance vectors in its
121
+ scalar scenario. The refinements scenario checks dependent domains, guarded
122
+ arithmetic, standalone contracts and four faulty adapters. It uses cached
123
+ compiler/library dependencies directly.
124
+
125
+ Generated property files now use structured documents throughout: imports,
126
+ helpers, examples, boundaries, native Kotest strategies, dependent refinement
127
+ domains, guarded assertions and contract wrappers. Blocks use two-space
128
+ indentation and continuation arguments use four spaces. Checked native codecs,
129
+ short-circuiting, Symbol context, single-evaluation matches and framework
130
+ generation/shrinking remain intact. The corpus audit below covers both machine
131
+ profiles and readable/compact syntax equivalence.
132
+
133
+
134
+ For internal checked Core definitions, shared JVM implementation bodies now
135
+ prove attached contracts before emission and enforce ordered preconditions and
136
+ validated-result postconditions at runtime. Native wrappers and direct logical
137
+ entry points both use those checks. `tools/jvm-definition-contract-integration.mjs`
138
+ verifies both JVM languages, profiles and layouts without a test-framework
139
+ dependency, including corrupted-result rejection. Refined source signatures
140
+ now produce these contracts through template proof and specialization.
141
+
142
+ ## Source formatting and independent parsing
143
+
144
+ Kotlin output follows the published [Google Android Kotlin style guide](https://developer.android.com/kotlin/style-guide):
145
+ four-space blocks and wrapped arguments/parameters, with a 100-column code limit.
146
+ This corrects the earlier two-space Kotlin layout. Java support files continue to
147
+ use Google Java Format conventions. Python independently follows PEP 8.
148
+
149
+ `tools/kotlin-formatting-integration.mjs` generates the bundled corpus and the
150
+ total-definition fixture in both machine profiles and formatting modes, plus both
151
+ Gradle Kotlin scaffold files. An
152
+ independently installed Kotlin compiler parses both outputs. The checker compares
153
+ syntax trees, retaining operators, declaration modifiers, type arguments, and
154
+ string-template contents; it ignores whitespace, comments, semicolons and optional
155
+ trailing commas. Negative fixtures distinguish changed signs, val/var, string
156
+ contents and escaped dollars from template interpolation.
157
+
158
+ The audit also checks block/argument indentation, line lengths, tabs, trailing
159
+ whitespace, explicit ASCII-sorted imports, breaks after binary operators,
160
+ multiline conditional/when braces, and loop braces. Set `LAWSPEC_CORE` to the native compiler and optionally set
161
+ `LAWSPEC_KOTLIN_HOME` to a Kotlin installation containing `lib/kotlin-compiler.jar`.
162
+ The tool detects ordinary and Homebrew installations of `kotlinc`. Positional
163
+ arguments select specification files. All parser and formatting tooling remains
164
+ development-only; generated projects do not download it.
165
+
166
+ The audit checks the rules listed above. It does not compare byte-for-byte with
167
+ an external Kotlin formatter. No formatter is required to generate projects.
168
+
169
+
170
+ ## Constructor contracts
171
+
172
+ Kotlin data emission uses profile-aware typed JVM schema callbacks.
173
+ Generated named codecs and native definition arguments/results preserve a caller's
174
+ Symbol context through nested List, Maybe, Either, Nullable and Optional values.
175
+ Kotlin-specific construct/match helpers also accept an explicit context; existing
176
+ Kotlin calls retain overloads or default arguments. Scalar-only bridges remain
177
+ framework-independent.
178
+
179
+ `tools/kotlin-constructor-native-integration.mjs` compiles and executes dependent
180
+ fields, generic/refined lists, sums, guarded arithmetic, machine ranges, nested
181
+ absence, fixture Symbols and raw UTF-16 units at both widths and layouts. It also
182
+ checks context-reset mutants, Google-formatted Java companions and independent
183
+ Kotlin parsing/layout/compact syntax parity.
184
+
185
+ Public Kotlin constructor-contract properties use the checked strategies and
186
+ share one Symbol context across witnesses, input generation, definitions, adapter
187
+ bridges and structural assertions. A context is allocated once per sampled case
188
+ and remains stable when the framework reads its shrink tree. Required conjunctive
189
+ Symbol equalities can draw fixture/prior-input values; disjunctions preserve both
190
+ alternatives and retain their predicate check.
191
+
192
+
193
+ The internal `LawSpecKotlinStrategies.checkedGenerator` validates supplied witnesses
194
+ and indexes their typed nested values. Native Kotest list/product/choice trees
195
+ remain the source of candidates and shrinks. A bounded sampling wrapper retries
196
+ false predicates up to `maxAttempts` at each value boundary; Kotest's `RTree.filter`
197
+ removes invalid shrink nodes. This avoids Kotest 5.9's unbounded arbitrary-filter
198
+ sampling without changing global framework settings. Evaluator errors are retained
199
+ as checked errors, including errors discovered during shrinking. Sampled witness
200
+ branches can limit payload shrinking; a globally minimal result is not promised.
201
+
202
+ `tools/kotlin-checked-strategies.mjs` checks both profiles, bounded exhaustion,
203
+ valid shrinking, nested witnesses, error classification and Symbol identity, with
204
+ compiled behavioral mutants. The legacy unchecked generator rejects schemas with
205
+ constructor contracts rather than bypassing their checks.
206
+
207
+
208
+ Generated dependent-input chains retain evaluator errors as case state, skip
209
+ subsequent draws after an error, and report the original failure before reading
210
+ input bindings. Input filtering accepts failed cases for reporting instead of
211
+ silently discarding them. Core-proven finite domains still emit exhaustive cases.
212
+ `tools/kotlin-field-properties.mjs` runs public generation at both widths and
213
+ layouts, with custom placement, finite domains, typed native adapters, nested
214
+ presence and lists, disjunctive fixtures, evaluator errors and incorrect adapters.
package/LANGUAGE.md CHANGED
@@ -1,13 +1,208 @@
1
- # LawSpec language and compiler boundary (0.8)
1
+ # LawSpec language and compiler boundary (0.10)
2
2
 
3
3
  LawSpec describes portable laws, concrete examples, and adapter contracts. The
4
4
  compiler is written in Haskell. Rust is an output backend alongside Java, Python,
5
5
  JavaScript, TypeScript, Go, Haskell, and Kotlin.
6
6
 
7
+ ## Lists and algebraic containers
8
+
9
+ `List a` is an ordered, finite sequence of values of one type. Lists nest and
10
+ retain duplicates. Literals use brackets; their element type comes from the
11
+ surrounding signature, quantifier, or annotation. An unconstrained empty list
12
+ needs an annotation such as `([] :: List Int8)`.
13
+
14
+ ```lawspec
15
+ unit guide.lists
16
+
17
+ reverse :: List Int32 -> List Int32
18
+
19
+ law `reverse preserves length` is
20
+ definition is
21
+ `for all` (xs :: List Int32) .
22
+ prelude.length (reverse xs) = prelude.length xs
23
+ end
24
+ example `duplicates count separately` is
25
+ xs = [3, 1, 3]
26
+ expect prelude.length xs = 3
27
+ expect reverse xs = [3, 1, 3]
28
+ end
29
+ end
30
+ ```
31
+
32
+ `prelude.length` returns an exact integer. List equality compares corresponding
33
+ values in order and requires equal lengths. It preserves scalar equality rules:
34
+ NaN still differs from itself, signed zeros compare equal, and Symbols compare
35
+ by identity. Generic list equality requires `Eq a`.
36
+
37
+ `Maybe a` has constructors `Nothing` and `Just value`. `Either a b` has
38
+ constructors `Left value` and `Right value`. These are algebraic sums, separate
39
+ from the interoperability types `Nullable a` and `Optional a`.
40
+
41
+ ```lawspec
42
+ unit guide.presence
43
+
44
+ echo :: Maybe (Either Int8 Bool) -> Maybe (Either Int8 Bool)
45
+
46
+ law `preserve every alternative` is
47
+ definition is `for all` (x :: Maybe (Either Int8 Bool)) . echo x = x end
48
+ example `absent` is x = Nothing expect echo x = Nothing end
49
+ example `left integer` is x = Just (Left 127) expect echo x = Just (Left 127) end
50
+ example `right boolean` is x = Just (Right false) expect echo x = Just (Right false) end
51
+ end
52
+ ```
53
+
54
+ For `Maybe (Maybe Bool)`, `Nothing`, `Just Nothing`, and `Just (Just false)`
55
+ remain distinct. Nesting a constructor application as an argument generally
56
+ requires parentheses, as in `Just (Left 127)`.
57
+
58
+ The [collections example](examples/specs/collections.lawspec) combines reverse
59
+ involution, sorting idempotence, sortedness, length, and permutation preservation.
60
+ `sorted` and `permutation` in that example are adapters supplied by the user;
61
+ they are not built-in helpers. Sortedness and length alone cannot establish that
62
+ a sorting adapter retained the original elements.
63
+
64
+ ## Products, sums, and pattern matching
65
+
66
+ A `type` declaration names its constructors and each constructor's fields. One
67
+ constructor describes a product; multiple constructors describe a sum. Type
68
+ parameters are declared explicitly with `:: Type`.
69
+
70
+ ```lawspec
71
+ unit guide.trees
72
+
73
+ type Pair (a :: Type) (b :: Type) is
74
+ Pair
75
+ first :: a
76
+ second :: b
77
+ end
78
+
79
+ type Tree (a :: Type) is
80
+ Leaf value :: a
81
+ Branch children :: List (Tree a)
82
+ end
83
+
84
+ definition rebuild (tree :: Tree a) :: Tree a is
85
+ match tree with
86
+ | Leaf value -> Leaf value
87
+ | Branch children -> Branch children
88
+ end
89
+ end
90
+
91
+ law `preserve the constructor and its fields` is
92
+ definition is `for all` (tree :: Tree Int8) . rebuild tree = tree end
93
+ example `nested branches` is
94
+ tree = Branch [Leaf 127, Branch [], Leaf -128]
95
+ expect rebuild tree = Branch [Leaf 127, Branch [], Leaf -128]
96
+ end
97
+ end
98
+ ```
99
+
100
+ Constructors receive fields in declaration order. A match evaluates its
101
+ scrutinee once; each branch binds that constructor's fields in the same order.
102
+ Bindings are scoped to the branch. Matching must be exhaustive and cannot repeat
103
+ a constructor. Lists match with `Nil` and `Cons head tail`; Maybe and Either use
104
+ their constructors above. Recursive declarations must be strictly positive.
105
+ General indexed constructors and GADT result signatures are not supported.
106
+
107
+ Equality is structural and type-directed, including named fields and nested
108
+ containers. Native public declarations retain their names and type parameters;
109
+ schemas and checked codecs support them at runtime. They are not replacements
110
+ for the public data types. See the target guides for native representations:
111
+ [Java](JAVA.md), [Python](PYTHON.md), [JavaScript/TypeScript](WEB.md),
112
+ [Go](GO.md), [Haskell](HASKELL.md), [Kotlin](KOTLIN.md), and [Rust](RUST.md).
113
+ In Haskell, `Text` remains `Data.Text.Text`, while `List Char` becomes the linked
114
+ list `[Char]`. These are distinct LawSpec types even when they contain the same
115
+ characters.
116
+
117
+ Generators compose the target framework's generators and shrinkers. Recursive
118
+ values have a structural size budget; each constructor reserves enough budget
119
+ for its fields before distributing the remainder. Boundaries include empty and
120
+ singleton lists and constructor-specific values. Small finite domains are
121
+ enumerated. An empty type cannot supply a generated argument, but containers
122
+ such as `List Empty` and `Maybe Empty` can still be inhabited. An empty or
123
+ unreachable input domain never makes a property pass vacuously.
124
+
125
+ Whole-value refinements can inspect products and sums using exhaustive matches.
126
+ List element refinements, Maybe/Either payload refinements, and refined arguments
127
+ of recursive and nonrecursive named type constructors are supported; see
128
+ [refinements](REFINEMENTS.md#named-data-payloads). Direct refinements on named
129
+ constructor fields use checked constructor contracts. Recursive payload predicates
130
+ follow stored type arguments and preserve outer dependent inputs.
131
+
132
+ ## Total definitions
133
+
134
+ A unit can supply an implementation as a checked total definition:
135
+
136
+ ```lawspec
137
+ definition increment (x :: Int8) :: BigInt
138
+ requires Integer Int8
139
+ is
140
+ x + 1
141
+ end
142
+ ```
143
+
144
+ Parameters and the result have explicit types. The optional `requires` clause
145
+ uses the same `Eq`, `Integer`, `Ordered`, and `Bounded` capabilities as laws.
146
+ Requirements are checked even when the definition is unused. Bodies must have
147
+ exhaustive matches, proven structural descent for recursive calls, and guards
148
+ for operations that could otherwise fail. Calls may use other checked
149
+ definitions; external adapters cannot establish a definition's totality.
150
+
151
+ For exact arithmetic, the totality checker can combine linear bounds and Boolean
152
+ guards. For example, `x >= 0 && 1 / (x + 1) > 0` is safe for integer `x`: the
153
+ right side runs only when its denominator is positive. Proof arithmetic uses
154
+ arbitrary exact fractions, preserves strict boundaries, and has a bounded work
155
+ budget. An unproved obligation is rejected; IEEE expressions never acquire
156
+ rational identities such as `x - x = 0` from this checker.
157
+
158
+ Primitive integer ranges are available to the checker automatically, including
159
+ the selected machine width and BigUInt's nonnegative domain. Integer comparisons
160
+ retain integrality: for Int8 `x`, `x < 127 && prelude.Int8 (x + 1) > x` safely
161
+ narrows only on the guarded branch. The unguarded conversion is rejected because
162
+ `127 + 1` is outside Int8. Range bounds alone do not prove that a Rational or
163
+ Decimal input has no fractional part.
164
+ Pattern matching retains the primitive ranges of extracted fields within that
165
+ branch. For example, an Int8 list head still makes `head + 129` strictly positive;
166
+ that fact cannot be reused for an Int64 field in another constructor branch.
167
+
168
+ Definitions produce reusable generated source with checked native entry points
169
+ on all eight targets. They do not produce user-owned adapter stubs. Integer
170
+ arithmetic preserves the mathematical result; the example above returns `128`
171
+ for the largest Int8 input. See [the total-function example](examples/specs/total_functions.lawspec)
172
+ for recursive list counting, structural equality, and explicit expected values.
173
+
174
+ Definitions can quantify type variables implicitly through their signatures:
175
+
176
+ ```lawspec
177
+ definition same (x :: a) (y :: a) :: Bool requires Eq a is x == y end
178
+ definition count (xs :: List a) :: BigInt is
179
+ match xs with
180
+ | Nil -> 0
181
+ | Cons head tail -> 1 + count tail
182
+ end
183
+ end
184
+ ```
185
+
186
+ Each template is checked for typing, capabilities, termination, and definedness,
187
+ including unused templates. Calls specialize it to concrete argument and result
188
+ types before Core elaboration. Different calls can use different types; recursive
189
+ self-calls must retain the same types. Ambiguous calls require an annotation,
190
+ such as `count ([] :: List Int8)` to specify an empty list's element type.
191
+ Unused templates emit no instances.
192
+ Checked definitions may also appear in refinement predicates and adapter
193
+ preconditions or postconditions. Their closed call graphs contain only other
194
+ checked definitions; adapter calls remain forbidden in predicates. The compiler
195
+ uses the same concrete Core definitions to check example domains and plan finite
196
+ cases and boundaries that generated tests use at runtime.
197
+ Definition parameters and results may carry refinements. The compiler proves
198
+ body definedness and result claims under ordered input preconditions, checks
199
+ callee preconditions, and preserves the contracts through specialization. Native
200
+ entry points enforce the same contracts. See [refined definitions](REFINEMENTS.md#refined-definitions).
201
+
7
202
  ## Source and declarations
8
203
 
9
- A source has one named `unit`, function signatures, reusable refinements, and
10
- laws. Qualified unit names determine target module/package paths. Function
204
+ A source has one named `unit`, function signatures, data declarations, checked
205
+ definitions, reusable refinements, and laws. Qualified unit names determine target module/package paths. Function
11
206
  signatures are curried: `a -> b -> c` takes two inputs and returns `c`. Parentheses
12
207
  group types and expressions. Comments start with `--` and run to the line end.
13
208
 
@@ -16,10 +211,17 @@ compiler tests specify lexical details:
16
211
 
17
212
  ```text
18
213
  source = "unit" qualified-name declaration*
19
- declaration = name "::" type | law | refinement
214
+ declaration = name "::" type | law | refinement | data-type | function
215
+ data-type = "type" name ("(" name "::" "Type" ")")*
216
+ "is" constructor* "end"
217
+ constructor = name (name "::" type)*
218
+ function = "definition" name parameter* "::" type requirements?
219
+ "is" expression "end"
20
220
  type = type-atom ["->" type]
21
221
  type-atom = primitive | type-variable | "(" type ")"
22
- | ("Nullable" | "Optional") type-atom
222
+ | ("Nullable" | "Optional" | "List" | "Maybe") type-atom
223
+ | "Either" type-atom type-atom
224
+ | data-type-name type-atom*
23
225
  | refinement-name argument*
24
226
  | "(" name "::" type ["where" expression] ")"
25
227
  refinement = "refinement" name parameter* requirements?
@@ -35,6 +237,10 @@ proposition = "`for all`" parameter+ "." proposition
35
237
  | expression "implies" proposition
36
238
  | proposition "and" proposition
37
239
  | quoted-name expression* | expression
240
+ expression = ... | "[" [expression ("," expression)*] "]"
241
+ | constructor-name expression*
242
+ | "match" expression "with"
243
+ ("|" constructor-name name* "->" expression)+ "end"
38
244
  example = "example" quoted-name "is" (name "=" literal)+
39
245
  ("expect" expression "=" literal)+ "end"
40
246
  ```
@@ -126,11 +332,33 @@ API schema v3 uses separately defined wire views, with lossless tagged scalar
126
332
  values. It does not serialize internal AST constructors. See the
127
333
  [API migration guide](API-MIGRATION.md).
128
334
 
129
- ## Next language features
335
+ ## Beyond 0.10
336
+
337
+ GADTs, indexed families, and general dependent types are planned after 0.10.
338
+ The Core type model distinguishes type arguments from index arguments, but that
339
+ representation is not a claim that arbitrary dependent programs are accepted.
340
+ User-defined products and sums have ordinary uniform type parameters.
341
+ External type bindings and custom generator bindings are implemented in the
342
+ 0.10 release; see [the binding reference](NATIVE-BINDINGS.md) for their
343
+ interface and acceptance status. They configure native representations alongside
344
+ the typed testing plan and do not change source-language typing or equality.
345
+ Cross-unit packages remain future work.
346
+
347
+ ## Generated project formatting
348
+
349
+ `lawspec init --target java` creates a readable Maven scaffold; Kotlin init
350
+ likewise expands Gradle blocks with two-space indentation. `--minify` explicitly
351
+ selects compact scaffolds and configuration JSON. `generate` and `examples`
352
+ accept the same flag for generated source. The mode is per invocation and does
353
+ not become a project default. Init preserves existing build files, and generation
354
+ preserves user-owned adapters regardless of formatting mode.
355
+
356
+ Generated runtime support and checked definitions belong in source directories;
357
+ framework-specific property helpers belong in test directories. Both follow
358
+ custom layout settings. Python uses PEP 8: four-space indentation, 79-column
359
+ code, and 72-column prose. Other targets follow Google language guidance where
360
+ applicable, with standard Rust formatting. Formatting is deterministic in the
361
+ native and WASM compilers; generation does not download or invoke a formatter.
130
362
 
131
- `List`, algebraic `Maybe`/`Either`, user-defined sums and products, pattern
132
- matching, GADTs, and general dependent types are outside 0.8. The core type model
133
- supports arbitrary constructor arity and distinguishes type and index arguments
134
- so those features can be added without target-specific surface interpretation.
135
- `Nullable` and `Optional` retain their interoperability semantics; they do not
136
- stand in for future algebraic sum types.
363
+ See [the release notes](RELEASE-0.10.md) for compatibility and scope, and the target
364
+ guides for formatting verification and native representation details.