lawspec 0.9.0 → 0.11.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 (46) hide show
  1. package/API-MIGRATION.md +78 -2
  2. package/HASKELL.md +1 -0
  3. package/KOTLIN.md +5 -0
  4. package/LANGUAGE.md +70 -11
  5. package/NATIVE-BINDINGS.md +1049 -0
  6. package/PRIMITIVES.md +1 -1
  7. package/README.md +86 -23
  8. package/REFINEMENTS.md +6 -1
  9. package/RELEASE-0.10.md +60 -0
  10. package/RELEASE-0.11.md +62 -0
  11. package/api.mjs +23 -3
  12. package/bin/lawspec.mjs +17 -4
  13. package/build.json +60 -38
  14. package/core.wasm +0 -0
  15. package/examples/native-payments/go/example/payments/domain.go +38 -0
  16. package/examples/native-payments/go/example/payments/native_generators_test.go +13 -0
  17. package/examples/native-payments/go/lawspec.json +136 -0
  18. package/examples/native-payments/haskell/lawspec.json +149 -0
  19. package/examples/native-payments/haskell/src/PaymentsDomain.hs +21 -0
  20. package/examples/native-payments/haskell/test/PaymentGenerators.hs +12 -0
  21. package/examples/native-payments/java/lawspec.json +165 -0
  22. package/examples/native-payments/java/src/main/java/domain/PaymentsDomain.java +32 -0
  23. package/examples/native-payments/java/src/test/java/domain/PaymentGenerators.java +16 -0
  24. package/examples/native-payments/javascript/lawspec.json +149 -0
  25. package/examples/native-payments/javascript/src/payments_domain.mjs +44 -0
  26. package/examples/native-payments/javascript/test/lawspec_generators.mjs +6 -0
  27. package/examples/native-payments/kotlin/lawspec.json +165 -0
  28. package/examples/native-payments/kotlin/src/main/kotlin/domain/PaymentsDomain.kt +17 -0
  29. package/examples/native-payments/kotlin/src/test/kotlin/domain/PaymentGenerators.kt +12 -0
  30. package/examples/native-payments/python/lawspec.json +149 -0
  31. package/examples/native-payments/python/src/payments_domain.py +60 -0
  32. package/examples/native-payments/python/tests/lawspec_generators.py +15 -0
  33. package/examples/native-payments/rust/lawspec.json +167 -0
  34. package/examples/native-payments/rust/src/domain.rs +37 -0
  35. package/examples/native-payments/rust/src/lib.rs +2 -0
  36. package/examples/native-payments/rust/tests/support/lawspec_generators.rs +11 -0
  37. package/examples/native-payments/typescript/lawspec.json +149 -0
  38. package/examples/native-payments/typescript/src/payments_domain.ts +42 -0
  39. package/examples/native-payments/typescript/test/lawspec_generators.ts +8 -0
  40. package/examples/specs/indexed_families.lawspec +59 -0
  41. package/examples/specs/payments.lawspec +76 -0
  42. package/examples-command.mjs +5 -0
  43. package/files.mjs +6 -6
  44. package/index.d.ts +53 -2
  45. package/native-examples.mjs +81 -0
  46. package/package.json +2 -2
package/API-MIGRATION.md CHANGED
@@ -1,8 +1,15 @@
1
- # Compiler API migration: schema 2 → schema 3
1
+ # Compiler API migration
2
+
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
2
9
 
3
10
  LawSpec 0.8 introduced API schema version **3**, which 0.9 continues to use.
4
11
  Requests may omit `schemaVersion` or
5
- send `3`. An explicit `2` (or any other version) receives a request diagnostic;
12
+ send `3`. An explicit `2` receives a request diagnostic;
6
13
  it is never silently reinterpreted. LawSpec specification syntax remains compatible.
7
14
  The generated `index.d.ts` describes the public protocol. Internal Haskell
8
15
  constructors and record fields are no longer the wire format.
@@ -202,3 +209,72 @@ definition and constructor contracts support recursive payload proof facts. Cons
202
209
  matches/constructions participate in the constructor dependency-cycle check.
203
210
  The TypeScript declarations now include both
204
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/HASKELL.md CHANGED
@@ -41,6 +41,7 @@ have no constructors. They can appear in inhabited containers such as
41
41
  | `Nullable a` | `LS.Nullable a`, with `NullValue` and `NullableValue` |
42
42
  | `Optional a` | `LS.Optional a`, with `UndefinedValue` and `OptionalValue` |
43
43
  | `BigInt`, `BigUInt`, `Integer` | `Integer`, with domain checks |
44
+ | `Integer` adapter result | `LS.IntegerValue`, built from any `Integral` with `LS.integerValue` |
44
45
  | `Decimal` | `LS.Decimal`, wrapping an exact finite base-ten `Rational` |
45
46
  | `Rational` | `Rational` |
46
47
  | `Complex64`, `Complex128` | `Complex Float`, `Complex Double` |
package/KOTLIN.md CHANGED
@@ -61,6 +61,11 @@ arbitrary integers, and machine-profile integers use `BigInteger` with explicit
61
61
  domain checks. These portable machine-profile representations do not bind a
62
62
  host machine-sized primitive.
63
63
 
64
+ An adapter whose result is the abstract `Integer` returns Kotlin `Number`.
65
+ `Integer` is the top of the integral tower, so an implementation may return
66
+ `Int`, `Long` or `BigInteger`; the result bridge rejects non-integral values
67
+ such as `Double` and checks the logical domain. Arguments remain `BigInteger`.
68
+
64
69
  Decimal uses exact `BigDecimal`; Rational uses the normalized
65
70
  `LawSpecRuntime.Ratio`. Complex components use `LawSpecRuntime.Complex`, with
66
71
  Float32 precision validated for Complex64. Raw code-point text uses `IntArray`,
package/LANGUAGE.md CHANGED
@@ -1,4 +1,4 @@
1
- # LawSpec language and compiler boundary (0.9)
1
+ # LawSpec language and compiler boundary (0.11)
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,
@@ -102,7 +102,8 @@ scrutinee once; each branch binds that constructor's fields in the same order.
102
102
  Bindings are scoped to the branch. Matching must be exhaustive and cannot repeat
103
103
  a constructor. Lists match with `Nil` and `Cons head tail`; Maybe and Either use
104
104
  their constructors above. Recursive declarations must be strictly positive.
105
- General indexed constructors and GADT result signatures are not supported.
105
+ Constructors may refine natural indices; see [indexed families](#natural-indexed-families).
106
+ GADT result signatures that refine type arguments are not supported.
106
107
 
107
108
  Equality is structural and type-directed, including named fields and nested
108
109
  containers. Native public declarations retain their names and type parameters;
@@ -129,6 +130,58 @@ of recursive and nonrecursive named type constructors are supported; see
129
130
  constructor fields use checked constructor contracts. Recursive payload predicates
130
131
  follow stored type arguments and preserve outer dependent inputs.
131
132
 
133
+ ## Natural-indexed families
134
+
135
+ A data declaration may take `Natural` parameters. Each constructor states how it
136
+ determines them with `where <index> = <expression>`:
137
+
138
+ ```lawspec
139
+ type Vec (n :: Natural) (a :: Type) is
140
+ | VNil where n = 0
141
+ | VCons head :: a tail :: Vec m a where n = m + 1
142
+ end
143
+
144
+ type Tree (n :: Natural) (a :: Type) is
145
+ | Tip where n = 0
146
+ | Bin left :: Tree l a value :: a right :: Tree r a where n = l + r + 1
147
+ end
148
+
149
+ append :: (xs :: Vec n Int8) -> (ys :: Vec m Int8) -> (r :: Vec (n + m) Int8)
150
+ zip :: (xs :: Vec n Int8) -> (ys :: Vec n Bool) -> (r :: Vec n Bool)
151
+ ```
152
+
153
+ Index expressions are sums of natural literals and index variables. A variable
154
+ such as `m` is bound by the field whose type mentions it, and every index needs
155
+ exactly one equation in every constructor. `Natural` is also an ordinary value
156
+ type: an unbounded integer that is at least zero.
157
+
158
+ Indices are evidence, not a second type system. The compiler elaborates a family
159
+ before inference into three ordinary declarations:
160
+
161
+ - erased data `Vec a` with the same constructors, which is the native
162
+ representation on every target;
163
+ - a checked structural measure for each index, named `<index>Of<Type>` (here
164
+ `nOfVec` and `nOfTree`), recomputed from the constructor equations;
165
+ - a refinement, so `Vec e a` in any signature or quantifier means
166
+ `(v :: Vec a where nOfVec v == e)`.
167
+
168
+ `append` above is therefore an adapter contract: its result must have length
169
+ `nOfVec xs + nOfVec ys`, and a native implementation that drops an element
170
+ fails with the postcondition. An index variable that is otherwise unbound, like
171
+ `n` and `m` in `append`, is implicit. It is determined by the first binder whose
172
+ family type mentions it alone, and later occurrences read that binder's measure.
173
+ Implicit indices must not first appear inside an expression, and a result cannot
174
+ introduce one.
175
+
176
+ Generation follows the index. For a free index, as in `append`, values come from
177
+ the erased type and the index is their measure. For a fixed index (`Vec 3 Int8`)
178
+ or a shared one (`zip`'s `ys`), the target is solved backwards through the
179
+ constructor equations: `VCons` for `n = 3` needs a tail with index 2, and `Bin`
180
+ splits `n - 1` between its subtrees. Samples are constructed, not filtered, and
181
+ shrinking stays within the index on every target. The same planning applies to
182
+ any user-written measure over declared data whose branches are a constant plus
183
+ the same measure of that branch's fields.
184
+
132
185
  ## Total definitions
133
186
 
134
187
  A unit can supply an implementation as a checked total definition:
@@ -332,14 +385,20 @@ API schema v3 uses separately defined wire views, with lossless tagged scalar
332
385
  values. It does not serialize internal AST constructors. See the
333
386
  [API migration guide](API-MIGRATION.md).
334
387
 
335
- ## Beyond 0.9
336
-
337
- GADTs, indexed families, and general dependent types are planned after 0.9.
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. External
341
- type bindings, custom generator bindings, and cross-unit packages are separate
342
- future features.
388
+ ## Beyond 0.11
389
+
390
+ Natural-indexed families are implemented in 0.11 by elaboration to erased data,
391
+ measures and refinements. GADTs that refine type arguments, non-linear or
392
+ non-natural indices, index equalities between sibling fields (such as perfect
393
+ trees whose subtrees share one index), and general dependent types remain future
394
+ work. The Core type model distinguishes type arguments from index arguments, but
395
+ that representation is not a claim that arbitrary dependent programs are
396
+ accepted.
397
+ External type bindings and custom generator bindings are implemented in the
398
+ 0.10 release; see [the binding reference](NATIVE-BINDINGS.md) for their
399
+ interface and acceptance status. They configure native representations alongside
400
+ the typed testing plan and do not change source-language typing or equality.
401
+ Cross-unit packages remain future work.
343
402
 
344
403
  ## Generated project formatting
345
404
 
@@ -357,5 +416,5 @@ code, and 72-column prose. Other targets follow Google language guidance where
357
416
  applicable, with standard Rust formatting. Formatting is deterministic in the
358
417
  native and WASM compilers; generation does not download or invoke a formatter.
359
418
 
360
- See [the release notes](RELEASE-0.9.md) for compatibility and scope, and the target
419
+ See [the release notes](RELEASE-0.10.md) for compatibility and scope, and the target
361
420
  guides for formatting verification and native representation details.