@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 +1 -1
- package/CLAUDE.md +1 -1
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +4 -4
- package/README.md +1 -1
- package/Value.mjs +50 -40
- package/backend-api.mjs +1 -1
- package/codecs/example-pipeline.mjs +7 -7
- package/codecs/ieee.mjs +8 -8
- package/codecs/int.mjs +6 -6
- package/codecs/json-codec.mjs +15 -15
- package/codecs/runtime/codec.mjs +13 -13
- package/codecs/runtime/prefix-codec.mjs +18 -18
- package/codecs/runtime/show-value.mjs +3 -3
- package/codecs/runtime/test-codec.mjs +7 -7
- package/codecs/runtime/typeFromValue.mjs +4 -4
- package/codecs/runtime/unicode-string.mjs +30 -30
- package/codecs/unit.mjs +4 -4
- package/index.mjs +2 -2
- package/k.mjs +15 -5
- package/kvm.mjs +10 -9
- package/objects/README.md +1 -1
- package/objects/compile.mjs +2 -1
- package/package.json +1 -1
- package/repl.mjs +2 -2
- package/run.mjs +33 -34
- package/scripts/run-tests.mjs +1 -0
- package/tests/code-derivation/codec-witness-pattern.mjs +4 -4
- package/tests/code-derivation/pattern-envelope.mjs +12 -12
- package/tests/integration.sh +26 -1
- package/tests/test-deep-wire-value.mjs +4 -4
- package/tests/test-ieee-arithmetic.mjs +3 -3
- package/tests/test-k-object.mjs +10 -10
- package/tests/test-kvm.mjs +1 -1
- package/tests/test-repl.mjs +4 -4
- package/tests/test-structural-values.mjs +27 -0
- package/valueIO.mjs +1 -1
- package/valueParser.jison +9 -9
- package/valueParser.mjs +7 -7
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
|
|
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
|
|
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
|
|
136
|
+
echo "..." | some-codec --parse | k path/to/program.ko | some-codec --print
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
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
|
|
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
|
|
19
|
+
return Value.variant(field, fromObject(obj[field]));
|
|
20
20
|
}
|
|
21
|
-
return
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
151
|
-
if (value
|
|
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
|
|
156
|
-
constructor(
|
|
157
|
-
|
|
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
|
-
|
|
166
|
-
|
|
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
|
-
|
|
173
|
-
|
|
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
|
-
|
|
181
|
-
|
|
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 (
|
|
186
|
-
|
|
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 {
|
|
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,
|
|
192
|
-
export default { Value,
|
|
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 {
|
|
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 {
|
|
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 =
|
|
87
|
+
const inputValue = Value.variant(
|
|
88
88
|
'something',
|
|
89
|
-
|
|
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
|
|
122
|
+
if (isVariant(programInput) && programInput.tag === 'something') {
|
|
123
123
|
const innerBool = programInput.value;
|
|
124
|
-
if (innerBool
|
|
125
|
-
const flipped =
|
|
124
|
+
if (isVariant(innerBool)) {
|
|
125
|
+
const flipped = Value.variant(
|
|
126
126
|
innerBool.tag === 'true' ? 'false' : 'true',
|
|
127
127
|
innerBool.value
|
|
128
128
|
);
|
|
129
|
-
programOutput =
|
|
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 {
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
41
|
-
sign:
|
|
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
|
|
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
|
|
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 {
|
|
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 =
|
|
50
|
+
let v = Value.variant("_", Value.product({}));
|
|
51
51
|
for (let i = bitChars.length - 1; i >= 0; i--) {
|
|
52
|
-
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
|
|
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
|
|
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
|
|
79
|
+
while (isVariant(node) && node.tag !== "_") {
|
|
80
80
|
bits += node.tag;
|
|
81
81
|
node = node.value;
|
|
82
82
|
}
|
package/codecs/json-codec.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
37
|
-
sign:
|
|
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
|
|
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
|
|
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
|
|
91
|
+
return Value.variant("null", UNIT);
|
|
92
92
|
}
|
|
93
93
|
if (typeof value === "boolean") {
|
|
94
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
188
|
-
if (child
|
|
187
|
+
if (isVariant(child)) return toJsonValue(child);
|
|
188
|
+
if (isProduct(child)) {
|
|
189
189
|
try {
|
|
190
190
|
return decodeValueToNumber(child);
|
|
191
191
|
} catch {}
|
package/codecs/runtime/codec.mjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* K pattern graph runtime helpers.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {
|
|
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
|
|
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
|
|
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(
|
|
587
|
-
const allVariants = values.every(
|
|
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
|
|
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
|
|
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
|
|
768
|
-
productValue =
|
|
767
|
+
if (isVariant(frame.currentValue)) {
|
|
768
|
+
productValue = Value.product({ [frame.currentValue.tag]: frame.currentValue.value });
|
|
769
769
|
}
|
|
770
|
-
if (!(productValue
|
|
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(
|
|
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
|
|
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 =
|
|
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 {
|
|
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 =
|
|
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
|
|
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
|
|
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(
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
308
|
+
let result = Value.variant("nil", UNIT);
|
|
309
309
|
for (let i = items.length - 1; i >= 0; i--) {
|
|
310
|
-
result =
|
|
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
|
|
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 =
|
|
366
|
+
let result = Value.variant("_", UNIT);
|
|
367
367
|
for (let i = bits.length - 1; i >= 0; i--) {
|
|
368
|
-
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
|
|
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
|
|
398
|
+
return Value.variant("any", UNIT);
|
|
399
399
|
}
|
|
400
|
-
return
|
|
400
|
+
return Value.variant(kind, listToK(edges.map(edgeToK)));
|
|
401
401
|
}));
|
|
402
402
|
}
|
|
403
403
|
|