lawspec 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.
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.