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/API-MIGRATION.md CHANGED
@@ -1,11 +1,67 @@
1
- # Compiler API migration: schema 2 → schema 3
1
+ # Compiler API migration
2
2
 
3
- LawSpec 0.8 uses API schema version **3**. Requests may omit `schemaVersion` or
4
- send `3`. An explicit `2` (or any other version) receives a request diagnostic;
3
+ This document covers the published schema-3 interface and the schema-4 native
4
+ binding interface introduced in 0.10. See
5
+ [schema 4 native bindings](#schema-4-native-bindings) when adding
6
+ application types or generators to an existing project.
7
+
8
+ ## Schema 2 → schema 3
9
+
10
+ LawSpec 0.8 introduced API schema version **3**, which 0.9 continues to use.
11
+ Requests may omit `schemaVersion` or
12
+ send `3`. An explicit `2` receives a request diagnostic;
5
13
  it is never silently reinterpreted. LawSpec specification syntax remains compatible.
6
14
  The generated `index.d.ts` describes the public protocol. Internal Haskell
7
15
  constructors and record fields are no longer the wire format.
8
16
 
17
+ ## 0.9 structural data and definition metadata
18
+
19
+ Successful results also expose `dataTypes: DataTypeDeclaration[]`. Each named
20
+ declaration has a resolved `id`, a display `name`, parameter IDs, an origin, and
21
+ constructors with resolved IDs and ordered typed fields. Use resolved IDs to
22
+ join references; constructors with the same display name can belong to different
23
+ units. Built-in container types do not need user declarations in this array.
24
+
25
+ Example bindings now use `DataValue`: either an existing tagged scalar or
26
+ `{kind: "data", type: Type, constructor: string, fields: DataValue[]}`. List values
27
+ use `List::Nil` and `List::Cons`, with head and tail fields; Maybe and Either use
28
+ their qualified constructor IDs. Do not flatten these values to JSON arrays or
29
+ nullable fields: that would lose constructor and nested-presence distinctions.
30
+
31
+ Expressions add `construct` nodes with a constructor ID and argument expressions,
32
+ and `match` nodes with a scrutinee and cases. Each case has a constructor ID,
33
+ ordered typed binders, and a body. Its binders are local to that case. Structural
34
+ expressions are represented by these nodes, not by scalar `constant` nodes.
35
+ Exhaustive API visitors must handle the added expression variants even though
36
+ the protocol continues to use schema version 3.
37
+
38
+ Successful results add `definitions: Definition[]`. Each entry contains `owner`,
39
+ the resolved declaration `id`, typed `arguments: Binder[]`, and a typed `body`.
40
+ The matching entry in `units[].declarations` supplies the signature and origin.
41
+ Calls retain their declaration ID; consumers can join against `definitions` to
42
+ distinguish checked bodies from external adapters. An empty array means the
43
+ program has no definitions.
44
+
45
+ The native frontend checks these bodies for typing, exhaustive matching,
46
+ structural termination, and potentially failing operations. Native reference
47
+ execution and source emission for Rust, Java, Kotlin, Python, JavaScript,
48
+ TypeScript, Go, and Haskell are implemented, including generic definitions
49
+ specialized to concrete signatures. The API exposes concrete instances with
50
+ generated names and resolved IDs, not unspecialized templates. Calls sharing a
51
+ signature reuse an instance; unused templates emit none. Consumers should join
52
+ by ID rather than parse generated names. Refinement-bearing definitions are
53
+ checked and emitted by both the native compiler and bundled WASM distribution.
54
+ Definition bodies produce generated source rather than
55
+ user-owned adapter stubs. Haskell native entry points take an `LS.SymbolContext`
56
+ and return `Either String a`; generated tests allocate a context per example or
57
+ property iteration so Symbol fixture identity does not escape its scope.
58
+
59
+ Refinement and contract expressions may now contain calls whose IDs resolve to
60
+ checked `definitions`. Validation still rejects calls to external adapters in
61
+ these expressions. Test planning evaluates the closed definitions when filtering
62
+ finite cases, boundaries, and concrete example inputs. Calls remain ordinary
63
+ typed call nodes; consumers need no source-level refinement interpreter.
64
+
9
65
  ## Laws and typed expressions
10
66
 
11
67
  Read `result.laws[i].examples` instead of `law.original.examples`. A binding is
@@ -101,3 +157,124 @@ All nonempty test plans now emit the portable scalar runtime. Existing Haskell
101
157
  projects must include `text` and `bytestring` in the component that compiles
102
158
  that source. Doctor reports the missing dependencies before generation. Build
103
159
  files remain user-owned; new scaffolds already include these dependencies.
160
+
161
+ ## Formatting requests and adapter references (0.9)
162
+
163
+ `GenerationRequest` accepts `minify?: boolean`, defaulting to `false`. The CLI
164
+ passes an explicit `--minify` from `generate` and `examples`. `init --minify`
165
+ also compacts newly created scaffolds and the configuration JSON; the choice is
166
+ not saved as a project setting. Existing project build files stay user-owned. Source/test placement is independent of
167
+ formatting. Compact rendering preserves mandatory newlines, indentation, token
168
+ separators, comments, and literal contents.
169
+
170
+ User-owned artifacts may include `adapterReference`, the compiler's canonical
171
+ readable scaffold. It is comparison data, not the user's implementation and not
172
+ an additional file to write. Manifest writers should hash this reference when
173
+ present, falling back to `content` for older producers. Continue hashing actual
174
+ `content` for generated-file ownership. This keeps a switch of formatting mode
175
+ from producing false adapter-update reports, while declared interface changes
176
+ still request review. Never normalize, overwrite, or hash user implementations
177
+ as the required adapter interface. Existing version-1 manifests remain readable.
178
+
179
+ Native and bundled WASM requests share this formatting behavior. CLI scaffolds,
180
+ generated sources, and tests preserve the same ownership rules in both modes.
181
+
182
+
183
+ Scoped List payload predicates use the schema-3 expression node
184
+ `{kind: "allElements", value: Expr, binder: Binder, predicate: Expr}`. The binder
185
+ is local to `predicate`; `value` is evaluated in the surrounding scope. The
186
+ predicate and result have type Bool. Visitors must handle this node alongside
187
+ `match`, including empty-list truth and short-circuit evaluation.
188
+
189
+ The Core also defines a scoped recursive payload operation:
190
+ `{kind: "allPayloads", value: Expr, predicates: PayloadPredicate[]}`, where each
191
+ `PayloadPredicate` contains a `binder: Binder` and `predicate: Expr`. Entries
192
+ correspond, in order, to the root data type's type arguments. Each binder has
193
+ that argument's type and is local only to its own predicate; sibling predicates
194
+ cannot refer to it. The scrutinee is evaluated in the surrounding scope, and
195
+ both each predicate and the whole operation have type Bool.
196
+
197
+ Traversal follows stored parameter occurrences through recursive declarations,
198
+ including nested containers and changing type arguments. It does not constrain
199
+ unrelated fixed fields that happen to have the same concrete type. Empty and
200
+ phantom occurrences are vacuously true; rejection short-circuits traversal.
201
+
202
+ Source named-payload refinements now elaborate to this discriminator, including
203
+ recursive applications. API consumers should handle it in checked Core views.
204
+ All eight Core emitters support this operation in definitions, properties and
205
+ constructor predicates.
206
+ The internal surface predicate node is type checked and lowered through
207
+ specialization and template proofs into this same Core operation. Internal
208
+ definition and constructor contracts support recursive payload proof facts. Constructor predicates are audited in order, and callback
209
+ matches/constructions participate in the constructor dependency-cycle check.
210
+ The TypeScript declarations now include both
211
+ `allElements` and `allPayloads`; exhaustive visitors should handle both.
212
+
213
+ ## Schema 4 native bindings
214
+
215
+ Binding requests use `schemaVersion: 4`. Schema-3 requests remain supported for
216
+ existing specifications without bindings. This negotiation is deliberate: an
217
+ older compiler must reject a binding request rather than silently use generated
218
+ types in place of application types.
219
+
220
+ The JavaScript API selects schema 4 when `nativeBindings` is provided, unless an
221
+ explicit `schemaVersion` overrides it. A nonempty binding configuration with
222
+ schema 3 is rejected. Results and diagnostics report the negotiated schema.
223
+
224
+ `nativeBindings` contains optional `types`, `functions`, `generators`,
225
+ `rustCrate` and `goImports` fields. Native symbols use arrays of identifier segments; unknown
226
+ configuration fields are rejected. See [the native-binding scope and current
227
+ implementation status](NATIVE-BINDINGS.md). Rust, Python, JavaScript, TypeScript,
228
+ Java and Kotlin support application type bridges and native generator factories.
229
+ Go supports package-local and imported application types with native Rapid
230
+ factories. Haskell supports application types and native Hedgehog factories.
231
+ Custom codec hooks are available on all eight targets; see the native-binding
232
+ reference for target-specific signatures and current integration limitations.
233
+
234
+ ### Go imports in schema 4 binding requests
235
+
236
+ `nativeBindings.goImports` is an optional array of `{alias, path}` entries.
237
+ References such as `["domain", "Price"]` select exported names from that alias's
238
+ Go import path. One-component references continue to select package-local names.
239
+ Types, constructors, functions and generator factories share the import table;
240
+ only imports used by each generated file are emitted. Other targets reject this
241
+ option. Paths must be module import paths without empty or traversal segments.
242
+
243
+ Go reserves local application symbols before generating canonical data names.
244
+ Colliding generated families receive a fresh `Canonical` prefix (and a numeric
245
+ suffix in that prefix if necessary). Logical type and constructor IDs do not
246
+ change. Hooks that name generated data types should use the emitted canonical
247
+ names; imported application types keep their original names.
248
+
249
+ ### Codec hooks in schema 4 type bindings
250
+
251
+ `NativeTypeBinding` now accepts either `constructors` or
252
+ `codec: {toNative: NativeReference, fromNative: NativeReference}`. Both hook
253
+ references are required and constructor mappings cannot be combined with hooks.
254
+ The canonical side uses generated LawSpec data types, while the native side uses
255
+ `native`; generic hooks receive one directional child converter per type argument.
256
+ All eight targets implement emission. Go hooks return `(value, error)` and the
257
+ verified fixture places them beside the generated canonical types to avoid package
258
+ import cycles. See `NATIVE-BINDINGS.md` for signatures and
259
+ validation behavior.
260
+
261
+ ### Native-binding ownership transitions
262
+
263
+ Existing user adapters are protected when their paths become generated bridges.
264
+ Move application implementations into the configured native modules and save the
265
+ old adapters elsewhere before adopting bindings. Removing bindings preserves the
266
+ old bridge as user-owned content and reports a required adapter update; it does
267
+ not silently replace that content with a stub. Generated layout changes do not
268
+ move application-owned model, hook or factory files. See `NATIVE-BINDINGS.md` for
269
+ the migration sequence and all-target filesystem acceptance checks.
270
+
271
+ ### Optional generator scaffolds in schema 4
272
+
273
+ `NativeGeneratorBinding` accepts `stub?: boolean`, defaulting to false. Python,
274
+ Rust, JavaScript, TypeScript, Java, Kotlin, Go and Haskell support `stub: true` to
275
+ create a user-owned factory in the test directory. Go
276
+ requires a package-local factory and a quantified use to determine placement.
277
+ Existing factory files remain untouched. Factory signature changes
278
+ use the existing `adapterUpdates` reporting channel. See `NATIVE-BINDINGS.md`
279
+ for grouping, module collision checks, and layout
280
+ migration behavior.
package/GO.md ADDED
@@ -0,0 +1,144 @@
1
+ # Native Go data
2
+
3
+ LawSpec 0.9 generates native named Go types for parameterized products and sums.
4
+ The compiler consumes checked Core declarations, plans names across all units,
5
+ and emits sealed interfaces plus named variant structs, following Go+'s enum
6
+ lowering approach.
7
+
8
+ For example:
9
+
10
+ ```lawspec
11
+ unit example.trees
12
+
13
+ type Tree (a :: Type) is
14
+ Leaf value :: a
15
+ Branch children :: List (Tree a)
16
+ end
17
+
18
+ echo :: Tree Int8 -> Tree Int8
19
+
20
+ law `echo preserves the tree` is
21
+ definition is `for all` (x :: Tree Int8) . echo x = x end
22
+ end
23
+ ```
24
+
25
+ The adapter receives `Tree[int8]`. Its native variants are `TreeLeaf[int8]`,
26
+ with an exported `Value` field, and `TreeBranch[int8]`, with an exported
27
+ `Children []Tree[int8]` field. The interface's private marker method includes
28
+ the type parameters, so even a nullary or phantom variant retains its generic
29
+ identity. Go rejects a `TreeLeaf[bool]` where `Tree[int8]` is required.
30
+
31
+ A correct identity adapter is:
32
+
33
+ ```go
34
+ func Echo(value0 Tree[int8]) Tree[int8] {
35
+ return value0
36
+ }
37
+ ```
38
+
39
+ Adapters remain user-owned. Generated files belong to the same unit package;
40
+ custom Go layouts keep source and tests in a shared directory tree. Duplicate
41
+ type names across units receive qualified generated names. The compiler rejects
42
+ adapter names that collide with generated native declarations or runtime names.
43
+
44
+ ## Containers and presence
45
+
46
+ - `List a` uses `[]T`. Nil and empty slices represent the same empty list.
47
+ - `Maybe a` uses `LawSpecMaybe[T]`, constructed with `LawSpecNothing[T]()` or
48
+ `LawSpecJust(value)`. `Value()` returns the payload and its presence flag.
49
+ - `Either a b` uses `LawSpecEither[L, R]`, constructed with
50
+ `LawSpecLeft[L, R](value)` or `LawSpecRight[L, R](value)`. Its zero value is
51
+ invalid and checked conversion rejects it.
52
+ - `Nullable a` and `Optional a` use distinct generic support structs with
53
+ `Present` and `Value` fields. These tags preserve nested absence states.
54
+
55
+ Native scalar fields retain their domains: UInt64 uses `uint64`, arbitrary
56
+ integers use `*LawSpecBigInt`, rational values use `*LawSpecRational`, and raw
57
+ UTF-16 text uses `[]uint16`. Text uses a valid UTF-8 Go string; arbitrary bytes
58
+ use `[]byte`. Unit, Null, and Undefined have distinct named support types when
59
+ stored inside data. Native void adapter results continue to normalize to Unit.
60
+
61
+ ## Total definitions
62
+
63
+ Checked source definitions emit native methods on `LawSpecDefinitions` in the
64
+ unit's package:
65
+
66
+ ```lawspec
67
+ unit example.total
68
+
69
+ definition increment (x :: Int8) :: BigInt is x + 1 end
70
+ ```
71
+
72
+ ```go
73
+ symbols := map[string]*LawSpecSymbol{}
74
+ result := LawSpecDefinitions.Increment(symbols, 127) // big integer 128
75
+ ```
76
+
77
+ The method accepts `int8` and returns `*LawSpecBigInt`. Lists, products, sums, and
78
+ nested presence retain their native parameterized types. A dedicated method
79
+ namespace allows a definition named `architecture` to coexist with the native
80
+ `Architecture` data type. Ordinary adapter functions retain their existing names.
81
+
82
+ Reuse the Symbol context within one example. Checked codecs copy and validate
83
+ native arguments and results; failures panic with the resolved definition name.
84
+ Machine-sized native bindings check the architecture across the complete type,
85
+ including alternatives not selected by the current value. Logical evaluation
86
+ still follows the explicitly selected machine profile.
87
+
88
+ `lawspec_definitions.go` belongs in source directories and does not import Rapid.
89
+ It contains the unit's native entry points and checked logical bodies. Properties
90
+ call the bodies directly; definitions never become user-owned adapter stubs.
91
+ Definitions and properties share typed expression rendering, preserving lazy
92
+ branches, short-circuit guards, single evaluation of match inputs, exact
93
+ arithmetic, and structural equality.
94
+
95
+ The frontend checks structural termination and potentially failing operations.
96
+ Generic definitions specialize to concrete uses. Refined signatures become
97
+ checked contracts, and refinement predicates may call checked definitions.
98
+
99
+ `tools/go-definitions-integration.mjs` checks source-only packages, four rejected
100
+ native type mismatches, both profiles and architecture diagnostics, recursive
101
+ properties, incorrect adapters, custom layouts, compact execution, and
102
+ regeneration protection. Readable definition source matches `gofmt` exactly.
103
+ Compact Go documents retain tabs rather than expanding them into spaces.
104
+
105
+ ## Checked bridges and tests
106
+
107
+ Generated codecs validate both conversion directions and copy mutable payloads.
108
+ An adapter cannot mutate a list, byte slice, or big integer in a test fixture
109
+ through an input alias. Unexpected or nil native variants, invalid scalar
110
+ representations, and cyclic values fail with type/field context. Shared acyclic
111
+ subtrees remain valid. Native machine-sized fields require the selected
112
+ `machineBits` profile to match the Go architecture.
113
+
114
+ Generated equality follows LawSpec semantics, including componentwise floating
115
+ comparison and Symbol identity. It does not substitute Go pointer identity or
116
+ reflection-based equality for structural equality.
117
+
118
+ Rapid generation composes native generators and shrinkers. A structural node
119
+ budget bounds recursive values, reserves each product field's minimum cost,
120
+ and permits list lengths supported by the remaining budget. Empty domains,
121
+ nullary constructors, and nested absence states are handled explicitly.
122
+
123
+ The reusable source files (`lawspec_runtime.go`, `lawspec_schema.go`,
124
+ `lawspec_codecs.go`, and generated data/schema/codec declarations) do not import
125
+ Rapid. Framework-specific generation lives in
126
+ `lawspec_data_strategies_test.go`; generated laws live in `lawspec_test.go`.
127
+
128
+ Native declarations, schema descriptions, codecs, runtime support, and generated
129
+ tests use structured formatting that matches `gofmt`. The bundled examples and
130
+ total-definition fixture are checked against `gofmt` under both machine profiles.
131
+ No external formatter is needed when generating code.
132
+
133
+ The compiler and CLI accept explicit `--minify` for generated output.
134
+ Readable output remains the default; formatting changes preserve adapter ownership
135
+ and edited-file protection. The bundled WASM uses the same layout.
136
+
137
+ Internal typed Core definitions with attached contracts are proved before Go
138
+ emission. Generated logical entry points validate arguments, check preconditions
139
+ in order, validate the result, and check postconditions; native wrappers share
140
+ these checks. The standalone contract fixture exercises both machine profiles
141
+ and formatting modes, including exact division, checked narrowing, nested calls,
142
+ and rejection of deliberately corrupted results. Readable contract bodies match
143
+ `gofmt`. Refined source definition signatures now produce these contracts through
144
+ template proof and specialization.
package/HASKELL.md ADDED
@@ -0,0 +1,171 @@
1
+ # Native Haskell data
2
+
3
+ LawSpec 0.9 emits ordinary parameterized algebraic data types from checked Core
4
+ products and sums. Constructors and record selectors have stable names planned
5
+ across all units. For example:
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 generated `LawSpecData` module supplies `Tree a`, `TreeLeaf`, and
19
+ `TreeBranch`. An adapter can implement identity directly:
20
+
21
+ ```haskell
22
+ echo :: Data.Tree I.Int8 -> Data.Tree I.Int8
23
+ echo value = value
24
+ ```
25
+
26
+ The generated adapter imports `LawSpecData` as `Data` and `Data.Int` as `I`.
27
+ Adapters remain user-owned. Recursive and mutually recursive fields use native
28
+ Haskell recursion; phantom parameters remain in signatures. Empty data types
29
+ have no constructors. They can appear in inhabited containers such as
30
+ `Maybe Empty`, but cannot supply a standalone generated argument.
31
+
32
+ ## Containers and scalar representations
33
+
34
+ | LawSpec | Haskell |
35
+ | --- | --- |
36
+ | `List a` | `[a]` |
37
+ | `Text` | `Data.Text.Text` |
38
+ | `List Char` | `[Char]`, the linked-list representation |
39
+ | `Maybe a` | `Maybe a`, with `Nothing` and `Just` |
40
+ | `Either a b` | `Either a b`, with `Left` and `Right` |
41
+ | `Nullable a` | `LS.Nullable a`, with `NullValue` and `NullableValue` |
42
+ | `Optional a` | `LS.Optional a`, with `UndefinedValue` and `OptionalValue` |
43
+ | `BigInt`, `BigUInt`, `Integer` | `Integer`, with domain checks |
44
+ | `Decimal` | `LS.Decimal`, wrapping an exact finite base-ten `Rational` |
45
+ | `Rational` | `Rational` |
46
+ | `Complex64`, `Complex128` | `Complex Float`, `Complex Double` |
47
+ | `CodePoint` | `Char`, including surrogate code points |
48
+ | `CodeUnit16` | `Word16` |
49
+ | `CodePointText`, `Utf16Text` | `LS.CodePointText [Char]`, `LS.Utf16Text [Word16]` |
50
+ | `Bytes` | `ByteString` |
51
+ | `Symbol` | `LS.Symbol`, with scoped fixture identities |
52
+ | `Unit` | `()` |
53
+ | `Null`, `Undefined` | `LS.Null`, `LS.Undefined` |
54
+
55
+ `Char` and `Text` exclude surrogate code points. Checked codecs reject invalid
56
+ native values rather than replacing characters. `Symbol` equality uses its
57
+ identity; matching descriptions alone do not establish equality. Distinct
58
+ presence wrappers preserve nested absence states. IEEE NaN and signed-zero
59
+ equality remain the same inside containers and custom types.
60
+
61
+ ## Generated support and testing
62
+
63
+ `LawSpecData`, `LawSpecDataSchema`, `LawSpecDataCodecs`, `LawSpecSchema`,
64
+ `LawSpecCodecs`, and `LawSpecRuntime` belong in the source directory. They have no
65
+ property-framework dependency. Native conversion returns contextual failures for
66
+ invalid domains, fields, tags, or arities. Binding machine-sized native types
67
+ requires the selected `machineBits` profile to match the host, including fields
68
+ of unselected variants.
69
+
70
+ `LawSpecDataStrategies` belongs in the test directory and composes native Hedgehog
71
+ generators and shrinkers. Bounded recursive generation reserves every product
72
+ field's minimum size before distributing spare nodes. Lists have variable lengths
73
+ within the available budget. Shrinking uses Hedgehog's choices, integers, and
74
+ lists, retaining schema-valid representations.
75
+
76
+ The Haskell scaffold uses Hspec, Hedgehog, hspec-hedgehog, containers, and mtl in
77
+ its test component. Source and test roots can be customized independently.
78
+ Readable/compact declaration fixtures are covered by
79
+ `tools/haskell-data-integration.mjs`; main compiler output and incorrect adapters
80
+ are covered by `tools/haskell-data-properties.mjs`.
81
+
82
+ ## Formatting
83
+
84
+ Haskell output uses an 80-column layout with spaces for indentation. Runtime
85
+ sources, native declarations, adapter stubs, definitions, and property files are
86
+ readable by default. Explicit `--minify` selects compact documents while retaining
87
+ the layout required by Haskell. Generation uses the same deterministic document
88
+ renderer in native and WASM builds; it does not invoke a downloaded formatter.
89
+
90
+ `tools/haskell-formatting-integration.mjs` checks the bundled corpus at both
91
+ machine widths for line length, tabs, and trailing whitespace. It compares
92
+ readable and compact parsed syntax using `tools/HaskellSyntaxCheck.hs`, built
93
+ against the installed GHC parser. The comparison discards source locations and
94
+ layout annotations while retaining literals, operators, and program structure.
95
+ Set `LAWSPEC_CORE`, `LAWSPEC_GHC`, and `LAWSPEC_HASKELL_SYNTAX_CHECK` to the
96
+ corresponding executables. This is a development check, not a package dependency.
97
+
98
+ ## Total definitions
99
+
100
+ Checked definitions become native functions in `LawSpecDefinitions.<Unit>`:
101
+
102
+ ```lawspec
103
+ unit example.total
104
+
105
+ definition increment (x :: Int8) :: BigInt is x + 1 end
106
+ ```
107
+
108
+ The generated native signature is equivalent to:
109
+
110
+ ```haskell
111
+ increment :: LS.SymbolContext -> I.Int8 -> Either String Integer
112
+ ```
113
+
114
+ Create a context with `LS.newSymbolContext`, then pass it to calls belonging to
115
+ the same example. A repeated Symbol fixture ID has the same identity in that
116
+ context; separate contexts remain distinct even when IDs and descriptions match.
117
+ Codecs preserve the identity of already-scoped native Symbols. Creating the
118
+ context uses IO; evaluating a definition is pure.
119
+
120
+ Native entry points check arguments and results and return contextual `Left`
121
+ diagnostics for invalid native representations. Native machine-sized bindings
122
+ check the whole type, including unselected constructors, against `machineBits`.
123
+ `LawSpecDefinitionBodies` contains the shared logical implementation, which uses
124
+ the configured machine profile independently of the host architecture.
125
+
126
+ Definitions do not create adapter stubs. Their source modules and scalar/schema
127
+ support have no Hspec or Hedgehog dependency. Generated tests allocate a context
128
+ per example, boundary, or property iteration. Properties and definitions share a
129
+ typed expression renderer with lazy guards, exhaustive matching, structural
130
+ equality, checked conversions, and exact integer promotion.
131
+
132
+ `tools/haskell-definitions-integration.mjs` exercises native and property calls,
133
+ both machine profiles, readable/compact definitions, complete minified projects,
134
+ custom source/test roots,
135
+ native type errors, incorrect adapters, generic specialization, and regeneration
136
+ protection. Refined definition signatures are checked before emission and
137
+ enforced at native entry points.
138
+
139
+
140
+ Hspec property files now use structured documents for helpers, examples,
141
+ boundaries/finite cases, native Hedgehog strategies, dependent refinement domains,
142
+ guarded assertions and contract wrappers. Adapter bridges compose checked codecs
143
+ and force argument values before calling native code. Contracts retain lazy
144
+ precondition checks and force the result before checking postconditions. Fresh
145
+ Symbol contexts cover refined properties as well as ordinary native strategies.
146
+ Scalar literals and diagnostic strings now use document-level encoding. Long
147
+ strings concatenate independently escaped chunks; large integers parse exact
148
+ decimal strings with their required Integer type.
149
+
150
+ `tools/haskell-data-properties.mjs` accepts `LAWSPEC_MINIFY=1` and
151
+ `LAWSPEC_MACHINE_BITS=32,64`. Its scalar scenario includes bundled examples and
152
+ shared arithmetic conformance vectors; its refinements scenario includes four
153
+ faulty adapters. Native machine-sized adapter bindings require a matching host
154
+ architecture; the scalar scenario defaults to 64 bits.
155
+
156
+ `tools/haskell-message-integration.mjs` uses native code-point strings and integer
157
+ constants independent of the emitter to check Unicode, escapes, whitespace,
158
+ large signed integers and diagnostic prefixes in readable and compact modes.
159
+ Its executable fixture lines fit within 80 columns. Long metadata comments wrap
160
+ to the output width.
161
+
162
+ Internal typed Core definitions with attached contracts are proved before Haskell
163
+ emission. Generated source checks preconditions after argument validation and
164
+ postconditions after result validation, without property-framework dependencies.
165
+ Checks sequence through Either, so a rejected precondition prevents later
166
+ predicates and the body from running. Results are forced and validated before
167
+ postconditions. Readable contract fixtures fit within 80 columns.
168
+ The shared native fixture passes both machine profiles and formatting modes,
169
+ including exact division, narrowing, nested calls, direct logical entry checks,
170
+ and rejection of corrupted results. Refined source definition signatures now
171
+ produce these contracts through template proof and specialization.
package/JAVA.md ADDED
@@ -0,0 +1,113 @@
1
+ # Java backend (0.9)
2
+
3
+ Java targets Java 25+, JUnit, and JetCheck. The compiler emits native named
4
+ products and sums, checked scalar/data codecs, reusable runtime sources, and
5
+ separate property-test helpers. Native type parameters remain visible in public
6
+ data declarations and adapter signatures.
7
+
8
+ ## Total definitions
9
+
10
+ A unit-level definition supplies its implementation together with its signature:
11
+
12
+ ```lawspec
13
+ unit example.total
14
+
15
+ definition size (xs :: List Int8) :: BigInt is
16
+ match xs with
17
+ | Nil -> 0
18
+ | Cons head tail -> 1 + size tail
19
+ end
20
+ end
21
+ ```
22
+
23
+ The compiler checks the body even when no law uses it. It requires exhaustive
24
+ matching, established structural descent for recursion, and proof that partial
25
+ operations are defined. Calls may target other checked definitions, including
26
+ forward declarations; definitions cannot call external adapters. Generic definitions specialize to concrete uses. Refined signatures become
27
+ checked contracts, and refinement predicates may call checked definitions.
28
+
29
+ Java writes native entry points beneath `lawspec.definitions`, preserving the
30
+ unit's package and class mapping. The example above provides
31
+ `lawspec.definitions.example.Total.size`:
32
+
33
+ ```java
34
+ var symbols = new java.util.HashMap<String, Object>();
35
+ var count = lawspec.definitions.example.Total.size(symbols, java.util.List.of((byte) 1, (byte) 2));
36
+ ```
37
+
38
+ Arguments and results use the same checked native representations as generated
39
+ data codecs: `List<Byte>` and `BigInteger` in this example. Domains without a
40
+ faithful Java representation retain their tagged runtime support values,
41
+ including nested Nullable/Optional states and machine-profile integers. Share
42
+ the Symbol map when fixture IDs should refer to the same identity.
43
+
44
+ `LawSpecDefinitionBodies.java` contains generated checked implementation helpers.
45
+ Generated properties call those same bodies. The native entry points validate
46
+ and copy values through codecs, and invalid native values report the definition
47
+ identity in an `IllegalArgumentException`. Logical machine integers enforce the
48
+ selected 32- or 64-bit range independently of the JVM architecture.
49
+
50
+ These files belong to source directories and have no JUnit or JetCheck dependency.
51
+ Definitions never receive user-owned adapter stubs. External declarations still
52
+ receive stubs, and regeneration preserves edited adapters. Edits to generated
53
+ definition files are protected by the generation manifest.
54
+
55
+ ## Verification and layout
56
+
57
+ `tools/java-definitions-integration.mjs` executes recursive list/tree definitions,
58
+ forward calls, scalars, sums, raw code units, Symbol identity, and nested absence
59
+ under both profiles. It checks custom source/test roots, typed native misuse,
60
+ incorrect adapters, framework-independent compilation, and ownership.
61
+
62
+ Readable generated sources and tests use structured formatting that matches
63
+ Google Java Format. `tools/java-formatting-integration.mjs` checks all bundled
64
+ examples and the total-definition fixture under both machine profiles. The
65
+ compiler emits this layout directly; generation does not invoke a formatter.
66
+ JetCheck combinators retain native shrinking and the existing scalar domains.
67
+
68
+ The CLI/API accept explicit minify. Native integration checks run
69
+ both readable and fully minified generation plans, including properties and
70
+ contracts. Independent Java execution checks preserve long diagnostics,
71
+ supplementary Unicode, escaping and arbitrary integers when literals wrap.
72
+ The bundled WASM package is checked against the native compiler.
73
+
74
+
75
+ For internal checked Core definitions, shared JVM implementation bodies now
76
+ prove attached contracts before emission and enforce ordered preconditions and
77
+ validated-result postconditions at runtime. Native wrappers and direct logical
78
+ entry points both use those checks. `tools/jvm-definition-contract-integration.mjs`
79
+ verifies both JVM languages, profiles and layouts without a test-framework
80
+ dependency, including corrupted-result rejection. Refined source signatures
81
+ now produce these contracts through template proof and specialization.
82
+
83
+
84
+ ## Constructor contracts
85
+
86
+ Public Java generation supports typed constructor callbacks, context-aware codecs
87
+ and definition boundaries. Property emission supplies validated witnesses and one
88
+ Symbol context shared by generation, adapter conversions and assertions.
89
+ Required conjunctive Symbol equalities can use fixture/prior-input values;
90
+ equalities beneath disjunctions contribute candidates without restricting the
91
+ whole domain to one alternative.
92
+
93
+ The test helper's `checkedGenerator` composes JetCheck generators with native
94
+ `suchThat` filtering at nested and outer value boundaries. False predicates reject
95
+ candidates; predicate evaluation errors are retained for the property to report.
96
+ Each filter respects the smaller of `maxAttempts` and JetCheck 0.3's native
97
+ 100-attempt limit. The counter for smaller budgets is recreated on replay, so
98
+ native filtering still discards invalid shrinks. Validated witnesses contribute typed nested seeds. Sampled seeds
99
+ can limit payload shrinking; native list and constructor generation remains an
100
+ alternative, and shrinking does not promise a globally minimal counterexample.
101
+
102
+ `tools/java-checked-strategies.mjs` verifies valid generation/shrinking, nested
103
+ witness use, exhaustion, error classification and shared Symbol identity at both
104
+ machine widths, with compiled behavioral mutants. These helpers depend on
105
+ JetCheck; the value/schema/codec runtime remains framework-independent.
106
+
107
+ Constructor-contract properties run the requested case count as one-iteration
108
+ JetCheck sessions with increasing size hints. This preserves native shrinking and
109
+ avoids session-wide draw-uniqueness exhaustion for fixture-identity domains. It
110
+ does not claim those domains are finite; domains proven finite by Core retain
111
+ exhaustive cases. `tools/java-field-properties.mjs` executes public generation at
112
+ both widths and layouts, including custom placement, adapter mutants, disjunctive
113
+ Symbol candidates and generation-time evaluator errors.