@fraczak/k 6.2.3 → 6.3.1

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/AGENTS.md CHANGED
@@ -12,7 +12,7 @@
12
12
  - `npm run prepare` regenerates `parser.mjs` and `valueParser.mjs` from `.jison` grammars.
13
13
  - `npm test` runs the full suite through `scripts/run-tests.mjs`.
14
14
  - `node repl.mjs` (or `k-repl`) starts the interactive REPL.
15
- - `./k.mjs -k <file.k>` executes a k script on binary pattern+value stream input from stdin or a file; use `k-parse` and `k-print` at the boundaries.
15
+ - `./k.mjs <file.k>` executes a k source/object file on binary pattern+value stream input from stdin or a file; if the argument is not an existing file, it is treated as an inline k expression.
16
16
 
17
17
  ## Coding Style & Naming Conventions
18
18
  - JavaScript uses ES modules (`.mjs`) with 2-space indentation and semicolons.
package/CLAUDE.md CHANGED
@@ -20,7 +20,7 @@ npm test # Run comprehensive test suite (unit tests, derivation tests, shell te
20
20
 
21
21
  **Running k programs:**
22
22
  ```bash
23
- ./k.mjs -k <file.k> # Execute k script
23
+ ./k.mjs <file.k> # Execute k source/object file
24
24
  ./repl.mjs # Start interactive REPL (or: k-repl)
25
25
  ```
26
26
 
@@ -133,12 +133,12 @@ Loading an object hydrates the type-pattern graphs back into runtime
133
133
  Object execution through `k.mjs`:
134
134
 
135
135
  ```sh
136
- echo "..." | some-codec --parse | k -k path/to/program.ko | some-codec --print
136
+ echo "..." | some-codec --parse | k path/to/program.ko | some-codec --print
137
137
  ```
138
138
 
139
- The `-k` option accepts either an object file or a source `.k` file. `k.mjs`
140
- tries to load the file as an object first, then falls back to source parsing and
141
- compilation.
139
+ When the first positional argument names an existing file, `k.mjs` loads it as
140
+ either an object file or a source `.k` file. It tries to load the file as an
141
+ object first, then falls back to source parsing and compilation.
142
142
 
143
143
  Standalone helpers live in `objects/`:
144
144
 
package/README.md CHANGED
@@ -163,7 +163,7 @@ program for backend inspection and execution experiments.
163
163
 
164
164
  | Command | Purpose |
165
165
  | --- | --- |
166
- | `k` | Execute a k expression, or `-k` source/object file, over a binary stream |
166
+ | `k` | Execute a k expression, or an existing source/object file, over a binary stream |
167
167
  | `k-repl` | Start the interactive interpreter |
168
168
 
169
169
  **Serialization boundaries**
package/Value.mjs CHANGED
@@ -16,9 +16,9 @@ function fromObject(obj) {
16
16
  const fields = getFields(obj);
17
17
  if (fields.length === 1) {
18
18
  const field = fields[0];
19
- return new Variant(field, fromObject(obj[field]));
19
+ return Value.variant(field, fromObject(obj[field]));
20
20
  }
21
- return new Product(
21
+ return Value.product(
22
22
  fields.reduce( (result, field) => {
23
23
  result[field] = fromObject(obj[field]);
24
24
  return result;
@@ -26,17 +26,26 @@ function fromObject(obj) {
26
26
  );
27
27
  };
28
28
 
29
- class Value {
30
- constructor(type, pattern = null) {
31
- this.type = type;
32
- this.pattern = pattern;
33
- }
34
- toString() {
35
- return `${this.constructor.name}(type: ${this.type})`;
36
- }
37
- toJSON() {
38
- return { type: this.type };
39
- }
29
+ function isObject(value) {
30
+ return value !== null && typeof value === "object";
31
+ }
32
+
33
+ function isProduct(value) {
34
+ return isObject(value) &&
35
+ value.type === "{}" &&
36
+ isObject(value.product) &&
37
+ !Array.isArray(value.product);
38
+ }
39
+
40
+ function isVariant(value) {
41
+ return isObject(value) &&
42
+ value.type === "<>" &&
43
+ typeof value.tag === "string" &&
44
+ Object.hasOwn(value, "value");
45
+ }
46
+
47
+ function isValue(value) {
48
+ return isProduct(value) || isVariant(value);
40
49
  }
41
50
 
42
51
  function toVector(m) {
@@ -147,46 +156,47 @@ function mergePatterns(declared, observed) {
147
156
  function withPattern(value, pattern) {
148
157
  if (!pattern) return value;
149
158
  if (value.pattern === pattern) return value;
150
- if (value instanceof Product) return new Product(value.product, pattern);
151
- if (value instanceof Variant) return new Variant(value.tag, value.value, pattern);
159
+ if (isProduct(value)) return Value.product(value.product, pattern);
160
+ if (isVariant(value)) return Value.variant(value.tag, value.value, pattern);
152
161
  return value;
153
162
  }
154
163
 
155
- class Product extends Value {
156
- constructor(product, pattern = null) {
157
- super("{}", pattern);
158
- this.product = product;
159
- }
160
-
161
- toString() {
162
- return `{${Object.entries(this.product).map(([k, v]) => `${JSON.stringify(k)}:${v.toString()}`).join(',')}}`;
164
+ class Value {
165
+ constructor(fields) {
166
+ Object.assign(this, fields);
163
167
  }
164
168
 
165
- toJSON() {
166
- let vector = toVector(this.product);
167
- if (vector.length > 0) return vector;
168
- return this.product;
169
+ static product(product, pattern = null) {
170
+ return new Value({ type: "{}", pattern, product });
169
171
  }
170
- }
171
172
 
172
- class Variant extends Value {
173
- constructor(tag, value, pattern = null) {
174
- super("<>", pattern);
175
- this.tag = tag;
176
- this.value = value;
173
+ static variant(tag, value, pattern = null) {
174
+ return new Value({ type: "<>", pattern, tag, value });
177
175
  }
178
176
 
179
177
  toString() {
180
- // return `{${JSON.stringify(this.tag)}:${this.value.toString()}}`;
181
- return `${this.value.toString()}|${pLabel(this.tag)}`;
178
+ if (isVariant(this)) {
179
+ // return `{${JSON.stringify(this.tag)}:${this.value.toString()}}`;
180
+ return `${this.value.toString()}|${pLabel(this.tag)}`;
181
+ }
182
+ if (isProduct(this)) {
183
+ return `{${Object.entries(this.product).map(([k, v]) => `${JSON.stringify(k)}:${v.toString()}`).join(',')}}`;
184
+ }
185
+ return String(this.type);
182
186
  }
183
187
 
184
188
  toJSON() {
185
- if (this.value instanceof Product && Object.keys(this.value.product).length === 0) {
186
- return this.tag;
189
+ if (isVariant(this)) {
190
+ if (isProduct(this.value) && Object.keys(this.value.product).length === 0) {
191
+ return this.tag;
192
+ }
193
+ return {[this.tag]: this.value.toJSON()};
187
194
  }
188
- return {[this.tag]: this.value.toJSON()};
195
+ if (!isProduct(this)) return { type: this.type };
196
+ let vector = toVector(this.product);
197
+ if (vector.length > 0) return vector;
198
+ return this.product;
189
199
  }
190
200
  }
191
- export { Value, Product, Variant, fromObject, cloneSubpattern, edgeSubpattern, composePattern, mergePatterns, withPattern };
192
- export default { Value, Product, Variant, fromObject, cloneSubpattern, edgeSubpattern, composePattern, mergePatterns, withPattern };
201
+ export { Value, fromObject, cloneSubpattern, edgeSubpattern, composePattern, mergePatterns, withPattern, isProduct, isVariant, isValue };
202
+ export default { Value, fromObject, cloneSubpattern, edgeSubpattern, composePattern, mergePatterns, withPattern, isProduct, isVariant, isValue };
package/backend-api.mjs CHANGED
@@ -3,7 +3,7 @@ export { lowerToKVM, executeKVM } from "./kvm.mjs";
3
3
  export { decodeWire, encodeToWire } from "./codecs/runtime/prefix-codec.mjs";
4
4
  export { exportPatternGraph, NODE_KIND } from "./codecs/runtime/codec.mjs";
5
5
  export { patternToPropertyList, propertyListToPattern } from "./codecs/runtime/pattern-json.mjs";
6
- export { Product, Variant, fromObject } from "./Value.mjs";
6
+ export { Value, fromObject, isProduct, isVariant, isValue } from "./Value.mjs";
7
7
  export { decodeObject, loadLibrary } from "./object.mjs";
8
8
  export { createState, evaluateInput } from "./repl.mjs";
9
9
  export { parse as parseFloat64, print as printFloat64 } from "./codecs/ieee.mjs";
@@ -14,7 +14,7 @@
14
14
  import { deriveClosedPattern } from './runtime/codec.mjs';
15
15
  import { encodeToWire, decodeWire } from './runtime/prefix-codec.mjs';
16
16
  import { patternToPropertyList } from './runtime/pattern-json.mjs';
17
- import { Product, Variant } from '../Value.mjs';
17
+ import { Value, isVariant } from '../Value.mjs';
18
18
  import hash from '../hash.mjs';
19
19
  import { argv, exit } from 'node:process';
20
20
 
@@ -84,9 +84,9 @@ function resolveType(typeName) {
84
84
  // Step 3: Create input value: Maybe Bool = something(true)
85
85
  // ============================================================================
86
86
 
87
- const inputValue = new Variant(
87
+ const inputValue = Value.variant(
88
88
  'something',
89
- new Variant('true', new Product({}))
89
+ Value.variant('true', Value.product({}))
90
90
  );
91
91
 
92
92
  console.log('Input value:', inputValue.toString());
@@ -119,14 +119,14 @@ console.log('Program sees value:', programInput.toString());
119
119
 
120
120
  // Example transformation: NOT operation (flip bool inside Maybe)
121
121
  let programOutput;
122
- if (programInput instanceof Variant && programInput.tag === 'something') {
122
+ if (isVariant(programInput) && programInput.tag === 'something') {
123
123
  const innerBool = programInput.value;
124
- if (innerBool instanceof Variant) {
125
- const flipped = new Variant(
124
+ if (isVariant(innerBool)) {
125
+ const flipped = Value.variant(
126
126
  innerBool.tag === 'true' ? 'false' : 'true',
127
127
  innerBool.value
128
128
  );
129
- programOutput = new Variant('something', flipped);
129
+ programOutput = Value.variant('something', flipped);
130
130
  }
131
131
  } else {
132
132
  programOutput = programInput; // nothing → nothing
package/codecs/ieee.mjs CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { stdin, stdout, argv, exit } from "node:process";
4
- import { Product, Variant } from "../Value.mjs";
4
+ import { Value, isProduct, isVariant } from "../Value.mjs";
5
5
  import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
6
6
  import { decodeWire, encodeToWire } from "./runtime/prefix-codec.mjs";
7
7
  import { FLOAT64_PATTERN } from "./runtime/ieee-pattern.mjs";
8
- const UNIT = new Product({});
8
+ const UNIT = Value.product({});
9
9
  const name = "ieee";
10
10
  const patterns = [FLOAT64_PATTERN];
11
11
 
@@ -17,7 +17,7 @@ function usage(stream = console.error) {
17
17
  }
18
18
 
19
19
  function bitValue(bit) {
20
- return new Variant(bit === 0 ? "0" : "1", UNIT);
20
+ return Value.variant(bit === 0 ? "0" : "1", UNIT);
21
21
  }
22
22
 
23
23
  function bitsProduct(width, value) {
@@ -26,7 +26,7 @@ function bitsProduct(width, value) {
26
26
  for (let i = width - 1; i >= 0; i--) {
27
27
  product[String(i)] = bitValue(Number((big >> BigInt(i)) & 1n));
28
28
  }
29
- return new Product(product);
29
+ return Value.product(product);
30
30
  }
31
31
 
32
32
  function encodeNumberToValue(number) {
@@ -37,22 +37,22 @@ function encodeNumberToValue(number) {
37
37
  const exponent = Number((bits >> 52n) & 0x7ffn);
38
38
  const fraction = bits & ((1n << 52n) - 1n);
39
39
 
40
- return new Product({
41
- sign: new Variant(sign === 0 ? "+" : "-", UNIT),
40
+ return Value.product({
41
+ sign: Value.variant(sign === 0 ? "+" : "-", UNIT),
42
42
  exponent: bitsProduct(11, exponent),
43
43
  fraction: bitsProduct(52, fraction)
44
44
  });
45
45
  }
46
46
 
47
47
  function requireProduct(value, where) {
48
- if (!(value instanceof Product)) {
48
+ if (!isProduct(value)) {
49
49
  throw new Error(`${where}: expected Product`);
50
50
  }
51
51
  return value.product;
52
52
  }
53
53
 
54
54
  function requireVariant(value, where) {
55
- if (!(value instanceof Variant)) {
55
+ if (!isVariant(value)) {
56
56
  throw new Error(`${where}: expected Variant`);
57
57
  }
58
58
  return value;
package/codecs/int.mjs CHANGED
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  import { stdin, stdout, argv, exit } from "node:process";
17
- import { Product, Variant } from "../Value.mjs";
17
+ import { Value, isVariant } from "../Value.mjs";
18
18
  import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
19
19
  import { decodeWire, encodeToWire } from "./runtime/prefix-codec.mjs";
20
20
 
@@ -47,9 +47,9 @@ function readAll(stream) {
47
47
  // Build bits Value (MSB outermost) from a non-negative BigInt.
48
48
  function buildBits(n) {
49
49
  const bitChars = n === 0n ? ["0"] : n.toString(2).split("");
50
- let v = new Variant("_", new Product({}));
50
+ let v = Value.variant("_", Value.product({}));
51
51
  for (let i = bitChars.length - 1; i >= 0; i--) {
52
- v = new Variant(bitChars[i], v);
52
+ v = Value.variant(bitChars[i], v);
53
53
  }
54
54
  return v;
55
55
  }
@@ -65,18 +65,18 @@ function parseIntStr(str) {
65
65
  }
66
66
  const n = BigInt(str);
67
67
  if (n === 0n) sign = "+"; // zero is always '+'
68
- return new Variant(sign, buildBits(n));
68
+ return Value.variant(sign, buildBits(n));
69
69
  }
70
70
 
71
71
  // Walk a decoded int Value (Variant sign → bits) and return a decimal string.
72
72
  function printIntValue(value) {
73
- if (!(value instanceof Variant) || (value.tag !== "+" && value.tag !== "-")) {
73
+ if (!isVariant(value) || (value.tag !== "+" && value.tag !== "-")) {
74
74
  throw new Error("Not a valid k int value");
75
75
  }
76
76
  const sign = value.tag;
77
77
  let bits = "";
78
78
  let node = value.value;
79
- while (node instanceof Variant && node.tag !== "_") {
79
+ while (isVariant(node) && node.tag !== "_") {
80
80
  bits += node.tag;
81
81
  node = node.value;
82
82
  }
@@ -1,8 +1,8 @@
1
- import { Product, Variant } from "../Value.mjs";
1
+ import { Value, isProduct, isVariant } from "../Value.mjs";
2
2
  import { STRING_PATTERN_PROPERTY_LIST, textToStringValue, stringValueToText } from "./string-codec.mjs";
3
3
  import { FLOAT64_PATTERN } from "./runtime/ieee-pattern.mjs";
4
4
 
5
- const UNIT = new Product({});
5
+ const UNIT = Value.product({});
6
6
  const BOOL_PATTERN = [
7
7
  ["closed-union", [["false", 1], ["true", 1]]],
8
8
  ["closed-product", []]
@@ -13,7 +13,7 @@ const NULL_PATTERN = [
13
13
  ];
14
14
 
15
15
  function bitValue(bit) {
16
- return new Variant(bit === 0 ? "0" : "1", UNIT);
16
+ return Value.variant(bit === 0 ? "0" : "1", UNIT);
17
17
  }
18
18
 
19
19
  function bitsProduct(width, value) {
@@ -22,7 +22,7 @@ function bitsProduct(width, value) {
22
22
  for (let i = width - 1; i >= 0; i--) {
23
23
  product[String(i)] = bitValue(Number((big >> BigInt(i)) & 1n));
24
24
  }
25
- return new Product(product);
25
+ return Value.product(product);
26
26
  }
27
27
 
28
28
  function encodeNumberToValue(number) {
@@ -33,22 +33,22 @@ function encodeNumberToValue(number) {
33
33
  const exponent = Number((bits >> 52n) & 0x7ffn);
34
34
  const fraction = bits & ((1n << 52n) - 1n);
35
35
 
36
- return new Product({
37
- sign: new Variant(sign === 0 ? "+" : "-", UNIT),
36
+ return Value.product({
37
+ sign: Value.variant(sign === 0 ? "+" : "-", UNIT),
38
38
  exponent: bitsProduct(11, exponent),
39
39
  fraction: bitsProduct(52, fraction)
40
40
  });
41
41
  }
42
42
 
43
43
  function requireProduct(value, where) {
44
- if (!(value instanceof Product)) {
44
+ if (!isProduct(value)) {
45
45
  throw new Error(`${where}: expected Product`);
46
46
  }
47
47
  return value.product;
48
48
  }
49
49
 
50
50
  function requireVariant(value, where) {
51
- if (!(value instanceof Variant)) {
51
+ if (!isVariant(value)) {
52
52
  throw new Error(`${where}: expected Variant`);
53
53
  }
54
54
  return value;
@@ -88,10 +88,10 @@ function decodeValueToNumber(value) {
88
88
 
89
89
  function fromJsonValue(value) {
90
90
  if (value === null) {
91
- return new Variant("null", UNIT);
91
+ return Value.variant("null", UNIT);
92
92
  }
93
93
  if (typeof value === "boolean") {
94
- return new Variant(value ? "true" : "false", UNIT);
94
+ return Value.variant(value ? "true" : "false", UNIT);
95
95
  }
96
96
  if (typeof value === "number") {
97
97
  if (!Number.isFinite(value)) {
@@ -103,7 +103,7 @@ function fromJsonValue(value) {
103
103
  return textToStringValue(value);
104
104
  }
105
105
  if (Array.isArray(value)) {
106
- return new Product(
106
+ return Value.product(
107
107
  value.reduce((product, item, index) => {
108
108
  product[String(index)] = fromJsonValue(item);
109
109
  return product;
@@ -111,7 +111,7 @@ function fromJsonValue(value) {
111
111
  );
112
112
  }
113
113
  if (value && typeof value === "object") {
114
- return new Product(
114
+ return Value.product(
115
115
  Object.keys(value).reduce((product, key) => {
116
116
  product[key] = fromJsonValue(value[key]);
117
117
  return product;
@@ -161,7 +161,7 @@ function patternFromJsonValue(value) {
161
161
  }
162
162
 
163
163
  function toJsonValue(value) {
164
- if (value instanceof Variant) {
164
+ if (isVariant(value)) {
165
165
  if (value.tag === "null") {
166
166
  requireProduct(value.value, "json.null");
167
167
  return null;
@@ -184,8 +184,8 @@ function toJsonValue(value) {
184
184
  if (isArray) {
185
185
  return keys.map((key) => {
186
186
  const child = product[key];
187
- if (child instanceof Variant) return toJsonValue(child);
188
- if (child instanceof Product) {
187
+ if (isVariant(child)) return toJsonValue(child);
188
+ if (isProduct(child)) {
189
189
  try {
190
190
  return decodeValueToNumber(child);
191
191
  } catch {}
@@ -2,7 +2,7 @@
2
2
  * K pattern graph runtime helpers.
3
3
  */
4
4
 
5
- import { Product, Variant } from "../../Value.mjs";
5
+ import { Value, isProduct, isVariant } from "../../Value.mjs";
6
6
  import { TypePatternGraph } from "../../TypePatternGraph.mjs";
7
7
  import { getCompressed } from "../../typing.mjs";
8
8
  import { finalize as finalizeCodes } from "../../codes.mjs";
@@ -501,7 +501,7 @@ function refinePatternForValue(pattern, value) {
501
501
 
502
502
  case NODE_KIND.CLOSED_PRODUCT:
503
503
  case NODE_KIND.OPEN_PRODUCT: {
504
- if (!(frame.currentValue instanceof Product)) {
504
+ if (!isProduct(frame.currentValue)) {
505
505
  throw new Error(`Expected Product for pattern node ${frame.patternNodeId}`);
506
506
  }
507
507
  const actualLabels = Object.keys(frame.currentValue.product).sort();
@@ -542,7 +542,7 @@ function refinePatternForValue(pattern, value) {
542
542
 
543
543
  case NODE_KIND.CLOSED_UNION:
544
544
  case NODE_KIND.OPEN_UNION: {
545
- if (!(frame.currentValue instanceof Variant)) {
545
+ if (!isVariant(frame.currentValue)) {
546
546
  throw new Error(`Expected Variant for pattern node ${frame.patternNodeId}`);
547
547
  }
548
548
  const explicitTargets = new Map(patternNode.edges.map((edge) => [edge.label, edge.target]));
@@ -583,8 +583,8 @@ function refinePatternForValue(pattern, value) {
583
583
  return { kind: NODE_KIND.ANY, edges: [] };
584
584
  }
585
585
 
586
- const allProducts = values.every((node) => node instanceof Product);
587
- const allVariants = values.every((node) => node instanceof Variant);
586
+ const allProducts = values.every(isProduct);
587
+ const allVariants = values.every(isVariant);
588
588
  if (!allProducts && !allVariants) {
589
589
  throw new Error("Cannot refine pattern from mixed product/union values");
590
590
  }
@@ -642,7 +642,7 @@ function refinePatternForValue(pattern, value) {
642
642
  let labels = [...explicit.keys()].sort();
643
643
  if (values.length > 0) {
644
644
  const actual = sameSortedKeys(values, "product pattern", (node) => {
645
- if (!(node instanceof Product)) throw new Error("Expected Product while refining product pattern");
645
+ if (!isProduct(node)) throw new Error("Expected Product while refining product pattern");
646
646
  return Object.keys(node.product);
647
647
  });
648
648
  if (baseNode.kind === NODE_KIND.CLOSED_PRODUCT) {
@@ -673,7 +673,7 @@ function refinePatternForValue(pattern, value) {
673
673
  let tags = [...explicit.keys()].sort((a, b) => Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8")));
674
674
  if (values.length > 0) {
675
675
  const observed = [...new Set(values.map((node) => {
676
- if (!(node instanceof Variant)) throw new Error("Expected Variant while refining union pattern");
676
+ if (!isVariant(node)) throw new Error("Expected Variant while refining union pattern");
677
677
  return node.tag;
678
678
  }))].sort((a, b) => Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8")));
679
679
  if (baseNode.kind === NODE_KIND.CLOSED_UNION) {
@@ -764,16 +764,16 @@ function coerceValueForPattern(pattern, value) {
764
764
  case NODE_KIND.CLOSED_PRODUCT:
765
765
  case NODE_KIND.OPEN_PRODUCT: {
766
766
  let productValue = frame.currentValue;
767
- if (frame.currentValue instanceof Variant) {
768
- productValue = new Product({ [frame.currentValue.tag]: frame.currentValue.value });
767
+ if (isVariant(frame.currentValue)) {
768
+ productValue = Value.product({ [frame.currentValue.tag]: frame.currentValue.value });
769
769
  }
770
- if (!(productValue instanceof Product)) {
770
+ if (!isProduct(productValue)) {
771
771
  throw new Error(`Expected Product for pattern node ${frame.patternNodeId}`);
772
772
  }
773
773
 
774
774
  const explicitTargets = new Map(patternNode.edges.map((edge) => [edge.label, edge.target]));
775
775
  const product = {};
776
- frame.assign(new Product(product));
776
+ frame.assign(Value.product(product));
777
777
  const entries = Object.entries(productValue.product);
778
778
  for (let i = entries.length - 1; i >= 0; i--) {
779
779
  const [label, childValue] = entries[i];
@@ -800,11 +800,11 @@ function coerceValueForPattern(pattern, value) {
800
800
 
801
801
  case NODE_KIND.CLOSED_UNION:
802
802
  case NODE_KIND.OPEN_UNION: {
803
- if (!(frame.currentValue instanceof Variant)) {
803
+ if (!isVariant(frame.currentValue)) {
804
804
  throw new Error(`Expected Variant for pattern node ${frame.patternNodeId}`);
805
805
  }
806
806
  const target = patternNode.edges.find((edge) => edge.label === frame.currentValue.tag)?.target;
807
- const variant = new Variant(frame.currentValue.tag, undefined);
807
+ const variant = Value.variant(frame.currentValue.tag, undefined);
808
808
  frame.assign(variant);
809
809
  if (target == null) {
810
810
  variant.value = frame.currentValue.value;
@@ -1,4 +1,4 @@
1
- import { Product, Variant, withPattern } from "../../Value.mjs";
1
+ import { Value, withPattern, isProduct, isVariant } from "../../Value.mjs";
2
2
  import { refinePatternForValue, coerceValueForPattern, NODE_KIND } from "./codec.mjs";
3
3
  import { patternToPropertyList, propertyListToPattern } from "./pattern-json.mjs";
4
4
  import { textToStringValue, stringValueToText } from "./unicode-string.mjs";
@@ -33,7 +33,7 @@ const CORE_PATTERN_PROPERTY_LIST = [
33
33
  ];
34
34
 
35
35
  const CORE_PATTERN_PATTERN = propertyListToPattern(CORE_PATTERN_PROPERTY_LIST);
36
- const UNIT = new Product({});
36
+ const UNIT = Value.product({});
37
37
 
38
38
  class BitWriter {
39
39
  constructor() {
@@ -135,7 +135,7 @@ function encodeNode(writer, value, pattern, patternNodeId) {
135
135
 
136
136
  case NODE_KIND.OPEN_PRODUCT:
137
137
  case NODE_KIND.CLOSED_PRODUCT: {
138
- if (!(frame.value instanceof Product)) {
138
+ if (!isProduct(frame.value)) {
139
139
  throw new Error(`Expected Product for pattern node ${frame.patternNodeId}`);
140
140
  }
141
141
  const actual = Object.keys(frame.value.product).sort((a, b) => Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8")));
@@ -152,7 +152,7 @@ function encodeNode(writer, value, pattern, patternNodeId) {
152
152
 
153
153
  case NODE_KIND.OPEN_UNION:
154
154
  case NODE_KIND.CLOSED_UNION: {
155
- if (!(frame.value instanceof Variant)) {
155
+ if (!isVariant(frame.value)) {
156
156
  throw new Error(`Expected Variant for pattern node ${frame.patternNodeId}`);
157
157
  }
158
158
  const tagOrdinal = patternNode.edges.findIndex((edge) => edge.label === frame.value.tag);
@@ -194,7 +194,7 @@ function decodeNode(reader, pattern, patternNodeId) {
194
194
  case NODE_KIND.OPEN_PRODUCT:
195
195
  case NODE_KIND.CLOSED_PRODUCT: {
196
196
  const product = {};
197
- frame.assign(new Product(product));
197
+ frame.assign(Value.product(product));
198
198
  for (let i = patternNode.edges.length - 1; i >= 0; i--) {
199
199
  const edge = patternNode.edges[i];
200
200
  stack.push({
@@ -218,7 +218,7 @@ function decodeNode(reader, pattern, patternNodeId) {
218
218
  throw new Error(`Choice ${tagOrdinal} is out of range for pattern node ${frame.patternNodeId}`);
219
219
  }
220
220
  const edge = patternNode.edges[tagOrdinal];
221
- const variant = new Variant(edge.label, undefined);
221
+ const variant = Value.variant(edge.label, undefined);
222
222
  frame.assign(variant);
223
223
  stack.push({
224
224
  patternNodeId: edge.target,
@@ -250,7 +250,7 @@ function deriveClosedPatternFromValue(value) {
250
250
 
251
251
  function visit(node) {
252
252
  const nodeId = nodes.length;
253
- if (node instanceof Product) {
253
+ if (isProduct(node)) {
254
254
  const placeholder = { kind: NODE_KIND.CLOSED_PRODUCT, edges: [] };
255
255
  nodes.push(placeholder);
256
256
  const labels = Object.keys(node.product).sort((a, b) => Buffer.compare(Buffer.from(a, "utf8"), Buffer.from(b, "utf8")));
@@ -261,7 +261,7 @@ function deriveClosedPatternFromValue(value) {
261
261
  }));
262
262
  return nodeId;
263
263
  }
264
- if (node instanceof Variant) {
264
+ if (isVariant(node)) {
265
265
  const placeholder = { kind: NODE_KIND.OPEN_UNION, edges: [] };
266
266
  nodes.push(placeholder);
267
267
  placeholder.edges = [{
@@ -291,23 +291,23 @@ function deriveClosedPatternFromValue(value) {
291
291
  }
292
292
 
293
293
  function requireProduct(value, where) {
294
- if (!(value instanceof Product)) {
294
+ if (!isProduct(value)) {
295
295
  throw new Error(`${where}: expected Product`);
296
296
  }
297
297
  return value.product;
298
298
  }
299
299
 
300
300
  function requireVariant(value, where) {
301
- if (!(value instanceof Variant)) {
301
+ if (!isVariant(value)) {
302
302
  throw new Error(`${where}: expected Variant`);
303
303
  }
304
304
  return value;
305
305
  }
306
306
 
307
307
  function listToK(items) {
308
- let result = new Variant("nil", UNIT);
308
+ let result = Value.variant("nil", UNIT);
309
309
  for (let i = items.length - 1; i >= 0; i--) {
310
- result = new Variant("cons", new Product({
310
+ result = Value.variant("cons", Value.product({
311
311
  car: items[i],
312
312
  cdr: result
313
313
  }));
@@ -354,7 +354,7 @@ function integerToBits(value) {
354
354
  if (!Number.isSafeInteger(value) || value < 0) {
355
355
  throw new Error(`bits target must be a non-negative safe integer, got ${value}`);
356
356
  }
357
- if (value === 0) return new Variant("_", UNIT);
357
+ if (value === 0) return Value.variant("_", UNIT);
358
358
 
359
359
  const bits = [];
360
360
  let n = value;
@@ -363,15 +363,15 @@ function integerToBits(value) {
363
363
  n = Math.floor(n / 2);
364
364
  }
365
365
 
366
- let result = new Variant("_", UNIT);
366
+ let result = Value.variant("_", UNIT);
367
367
  for (let i = bits.length - 1; i >= 0; i--) {
368
- result = new Variant(bits[i] ? "1" : "0", result);
368
+ result = Value.variant(bits[i] ? "1" : "0", result);
369
369
  }
370
370
  return result;
371
371
  }
372
372
 
373
373
  function edgeToK([label, target]) {
374
- return new Product({
374
+ return Value.product({
375
375
  label: textToStringValue(label),
376
376
  target: integerToBits(target)
377
377
  });
@@ -395,9 +395,9 @@ function patternToKValue(propertyList) {
395
395
  }
396
396
  const [kind, edges] = node;
397
397
  if (kind === "any") {
398
- return new Variant("any", UNIT);
398
+ return Value.variant("any", UNIT);
399
399
  }
400
- return new Variant(kind, listToK(edges.map(edgeToK)));
400
+ return Value.variant(kind, listToK(edges.map(edgeToK)));
401
401
  }));
402
402
  }
403
403