@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.
@@ -1,4 +1,4 @@
1
- import { Product, Variant } from "../../Value.mjs";
1
+ import { isProduct, isVariant } from "../../Value.mjs";
2
2
 
3
3
  const nameRE = /^[a-zA-Z0-9_+-][a-zA-Z0-9_?!+-]*$/;
4
4
 
@@ -50,8 +50,8 @@ function propertyListToFilter(propertyList) {
50
50
  }
51
51
 
52
52
  function valueToK(v) {
53
- if (v instanceof Variant) return `${valueToK(v.value)}|${pLabel(v.tag).trimStart()}`;
54
- if (v instanceof Product) {
53
+ if (isVariant(v)) return `${valueToK(v.value)}|${pLabel(v.tag).trimStart()}`;
54
+ if (isProduct(v)) {
55
55
  const keys = Object.keys(v.product);
56
56
  if (keys.length === 0) return "{}";
57
57
  const fields = keys.map((k) => `${valueToK(v.product[k])}${pLabel(k)}`);
@@ -6,7 +6,7 @@
6
6
  import { deriveClosedPattern } from './codec.mjs';
7
7
  import { encodeToWire, decodeWire } from './prefix-codec.mjs';
8
8
  import { patternToPropertyList } from './pattern-json.mjs';
9
- import { Product, Variant } from '../../Value.mjs';
9
+ import { Value, isProduct, isVariant } from '../../Value.mjs';
10
10
  import hash from '../../hash.mjs';
11
11
 
12
12
  // Type repository
@@ -44,7 +44,7 @@ function resolveType(typeName) {
44
44
 
45
45
  // Test 1: Unit value
46
46
  console.log('\n=== Test 1: Unit ===');
47
- const unitValue = new Product({});
47
+ const unitValue = Value.product({});
48
48
  console.log('Encoding unit:', unitValue.toString());
49
49
 
50
50
  const unitPattern = patternToPropertyList(deriveClosedPattern(unitTypeName, unitTypeDef, resolveType));
@@ -54,12 +54,12 @@ console.log('Hex:', unitEncoded.toString('hex'));
54
54
 
55
55
  const unitDecoded = decodeWire(unitEncoded);
56
56
  console.log('Decoded value:', unitDecoded.value.toString());
57
- console.log('Match:', unitDecoded.value instanceof Product &&
57
+ console.log('Match:', isProduct(unitDecoded.value) &&
58
58
  Object.keys(unitDecoded.value.product).length === 0);
59
59
 
60
60
  // Test 2: Bool false
61
61
  console.log('\n=== Test 2: Bool (false) ===');
62
- const falseValue = new Variant('false', new Product({}));
62
+ const falseValue = Value.variant('false', Value.product({}));
63
63
  console.log('Encoding false:', falseValue.toString());
64
64
 
65
65
  const boolPattern = patternToPropertyList(deriveClosedPattern(boolTypeName, boolTypeDef, resolveType));
@@ -69,12 +69,12 @@ console.log('Hex:', falseEncoded.toString('hex'));
69
69
 
70
70
  const falseDecoded = decodeWire(falseEncoded);
71
71
  console.log('Decoded value:', falseDecoded.value.toString());
72
- console.log('Match:', falseDecoded.value instanceof Variant &&
72
+ console.log('Match:', isVariant(falseDecoded.value) &&
73
73
  falseDecoded.value.tag === 'false');
74
74
 
75
75
  // Test 3: Bool true
76
76
  console.log('\n=== Test 3: Bool (true) ===');
77
- const trueValue = new Variant('true', new Product({}));
77
+ const trueValue = Value.variant('true', Value.product({}));
78
78
  console.log('Encoding true:', trueValue.toString());
79
79
 
80
80
  const trueEncoded = encodeToWire(trueValue, boolPattern);
@@ -83,7 +83,7 @@ console.log('Hex:', trueEncoded.toString('hex'));
83
83
 
84
84
  const trueDecoded = decodeWire(trueEncoded);
85
85
  console.log('Decoded value:', trueDecoded.value.toString());
86
- console.log('Match:', trueDecoded.value instanceof Variant &&
86
+ console.log('Match:', isVariant(trueDecoded.value) &&
87
87
  trueDecoded.value.tag === 'true');
88
88
 
89
89
  console.log('\n=== All tests complete ===');
@@ -1,4 +1,4 @@
1
- import { Product, Variant } from "../../Value.mjs";
1
+ import { isProduct, isVariant } from "../../Value.mjs";
2
2
 
3
3
  function typeDefsFromValue(value) {
4
4
  let nextId = 0;
@@ -6,7 +6,7 @@ function typeDefsFromValue(value) {
6
6
 
7
7
  function visit(node) {
8
8
  const name = `:auto${nextId++}`;
9
- if (node instanceof Product) {
9
+ if (isProduct(node)) {
10
10
  const labels = Object.keys(node.product).sort();
11
11
  const product = {};
12
12
  for (const label of labels) {
@@ -16,7 +16,7 @@ function typeDefsFromValue(value) {
16
16
  return name;
17
17
  }
18
18
 
19
- if (node instanceof Variant) {
19
+ if (isVariant(node)) {
20
20
  const childName = visit(node.value);
21
21
  defs[name] = { code: "union", union: { [node.tag]: childName } };
22
22
  return name;
@@ -31,4 +31,4 @@ function typeDefsFromValue(value) {
31
31
  }
32
32
 
33
33
  export { typeDefsFromValue };
34
- export default { typeDefsFromValue };
34
+ export default { typeDefsFromValue };
@@ -1,22 +1,22 @@
1
- import { Product, Variant } from "../../Value.mjs";
1
+ import { Value, isProduct, isVariant } from "../../Value.mjs";
2
2
 
3
- const UNIT = new Product({});
4
- const BIT0 = new Variant("0", UNIT);
5
- const BIT1 = new Variant("1", UNIT);
3
+ const UNIT = Value.product({});
4
+ const BIT0 = Value.variant("0", UNIT);
5
+ const BIT1 = Value.variant("1", UNIT);
6
6
 
7
7
  function bitValue(bit) {
8
8
  return bit === 0 ? BIT0 : BIT1;
9
9
  }
10
10
 
11
11
  function requireProduct(value, where) {
12
- if (!(value instanceof Product)) {
12
+ if (!isProduct(value)) {
13
13
  throw new Error(`${where}: expected Product`);
14
14
  }
15
15
  return value.product;
16
16
  }
17
17
 
18
18
  function requireVariant(value, where) {
19
- if (!(value instanceof Variant)) {
19
+ if (!isVariant(value)) {
20
20
  throw new Error(`${where}: expected Variant`);
21
21
  }
22
22
  return value;
@@ -27,7 +27,7 @@ function bitsProduct(width, n) {
27
27
  for (let i = width - 1; i >= 0; i--) {
28
28
  product[String(i)] = bitValue((n >> i) & 1);
29
29
  }
30
- return new Product(product);
30
+ return Value.product(product);
31
31
  }
32
32
 
33
33
  function parseBitsProduct(value, maxBit, where) {
@@ -52,14 +52,14 @@ function parseByteProduct(value, where) {
52
52
  }
53
53
 
54
54
  function encodeBmpCommonHi(hi) {
55
- if (hi >= 0x08 && hi <= 0x0f) return new Variant("h08_0F", bitsProduct(3, hi - 0x08));
56
- if (hi >= 0x10 && hi <= 0x7f) return new Variant("h10_7F", bitsProduct(7, hi - 0x10));
57
- if (hi >= 0x80 && hi <= 0xcf) return new Variant("h80_CF", bitsProduct(7, hi - 0x80));
58
- if (hi >= 0xd0 && hi <= 0xd7) return new Variant("hD0_D7", bitsProduct(3, hi - 0xd0));
59
- if (hi === 0xf9) return new Variant("hF9", UNIT);
60
- if (hi >= 0xfa && hi <= 0xfb) return new Variant("hFA_FB", bitsProduct(1, hi - 0xfa));
61
- if (hi >= 0xfc && hi <= 0xfd) return new Variant("hFC_FD", bitsProduct(1, hi - 0xfc));
62
- if (hi >= 0xfe && hi <= 0xff) return new Variant("hFE_FF", bitsProduct(1, hi - 0xfe));
55
+ if (hi >= 0x08 && hi <= 0x0f) return Value.variant("h08_0F", bitsProduct(3, hi - 0x08));
56
+ if (hi >= 0x10 && hi <= 0x7f) return Value.variant("h10_7F", bitsProduct(7, hi - 0x10));
57
+ if (hi >= 0x80 && hi <= 0xcf) return Value.variant("h80_CF", bitsProduct(7, hi - 0x80));
58
+ if (hi >= 0xd0 && hi <= 0xd7) return Value.variant("hD0_D7", bitsProduct(3, hi - 0xd0));
59
+ if (hi === 0xf9) return Value.variant("hF9", UNIT);
60
+ if (hi >= 0xfa && hi <= 0xfb) return Value.variant("hFA_FB", bitsProduct(1, hi - 0xfa));
61
+ if (hi >= 0xfc && hi <= 0xfd) return Value.variant("hFC_FD", bitsProduct(1, hi - 0xfc));
62
+ if (hi >= 0xfe && hi <= 0xff) return Value.variant("hFE_FF", bitsProduct(1, hi - 0xfe));
63
63
  throw new Error(`Unsupported BMP common hi byte: 0x${hi.toString(16)}`);
64
64
  }
65
65
 
@@ -77,9 +77,9 @@ function decodeBmpCommonHi(value) {
77
77
  }
78
78
 
79
79
  function encodeBmpPrivateHi(hi) {
80
- if (hi >= 0xe0 && hi <= 0xef) return new Variant("hE0_EF", bitsProduct(4, hi - 0xe0));
81
- if (hi >= 0xf0 && hi <= 0xf7) return new Variant("hF0_F7", bitsProduct(3, hi - 0xf0));
82
- if (hi === 0xf8) return new Variant("hF8", UNIT);
80
+ if (hi >= 0xe0 && hi <= 0xef) return Value.variant("hE0_EF", bitsProduct(4, hi - 0xe0));
81
+ if (hi >= 0xf0 && hi <= 0xf7) return Value.variant("hF0_F7", bitsProduct(3, hi - 0xf0));
82
+ if (hi === 0xf8) return Value.variant("hF8", UNIT);
83
83
  throw new Error(`Unsupported BMP private-use hi byte: 0x${hi.toString(16)}`);
84
84
  }
85
85
 
@@ -92,10 +92,10 @@ function decodeBmpPrivateHi(value) {
92
92
  }
93
93
 
94
94
  function encodePlane2To16(plane) {
95
- if (plane >= 2 && plane <= 3) return new Variant("p02_03", bitsProduct(1, plane - 2));
96
- if (plane >= 4 && plane <= 7) return new Variant("p04_07", bitsProduct(2, plane - 4));
97
- if (plane >= 8 && plane <= 15) return new Variant("p08_0F", bitsProduct(3, plane - 8));
98
- if (plane === 16) return new Variant("p10", UNIT);
95
+ if (plane >= 2 && plane <= 3) return Value.variant("p02_03", bitsProduct(1, plane - 2));
96
+ if (plane >= 4 && plane <= 7) return Value.variant("p04_07", bitsProduct(2, plane - 4));
97
+ if (plane >= 8 && plane <= 15) return Value.variant("p08_0F", bitsProduct(3, plane - 8));
98
+ if (plane === 16) return Value.variant("p10", UNIT);
99
99
  throw new Error(`Plane out of range for supplementary_planes2_16: ${plane}`);
100
100
  }
101
101
 
@@ -117,34 +117,34 @@ function codePointToUnicodeValue(cp) {
117
117
  }
118
118
 
119
119
  if (cp <= 0x7f) {
120
- return new Variant("ascii", bitsProduct(7, cp));
120
+ return Value.variant("ascii", bitsProduct(7, cp));
121
121
  }
122
122
 
123
123
  if (cp <= 0x7ff) {
124
- return new Variant("plane0", bitsProduct(11, cp));
124
+ return Value.variant("plane0", bitsProduct(11, cp));
125
125
  }
126
126
 
127
127
  if (cp <= 0xffff) {
128
128
  const hi = (cp >> 8) & 0xff;
129
129
  const lo = cp & 0xff;
130
130
  if (hi >= 0xe0 && hi <= 0xf8) {
131
- return new Variant("bmp_private_use", new Product({ hi: encodeBmpPrivateHi(hi), lo: byteProduct(lo) }));
131
+ return Value.variant("bmp_private_use", Value.product({ hi: encodeBmpPrivateHi(hi), lo: byteProduct(lo) }));
132
132
  }
133
- return new Variant("bmp_common", new Product({ hi: encodeBmpCommonHi(hi), lo: byteProduct(lo) }));
133
+ return Value.variant("bmp_common", Value.product({ hi: encodeBmpCommonHi(hi), lo: byteProduct(lo) }));
134
134
  }
135
135
 
136
136
  const mid = (cp >> 8) & 0xff;
137
137
  const lo = cp & 0xff;
138
138
 
139
139
  if (cp <= 0x1ffff) {
140
- return new Variant("supplementary_plane1", new Product({
140
+ return Value.variant("supplementary_plane1", Value.product({
141
141
  mid: byteProduct(mid),
142
142
  lo: byteProduct(lo)
143
143
  }));
144
144
  }
145
145
 
146
146
  const plane = cp >> 16;
147
- return new Variant("supplementary_planes2_16", new Product({
147
+ return Value.variant("supplementary_planes2_16", Value.product({
148
148
  plane: encodePlane2To16(plane),
149
149
  mid: byteProduct(mid),
150
150
  lo: byteProduct(lo)
@@ -181,11 +181,11 @@ function unicodeValueToCodePoint(value) {
181
181
  }
182
182
 
183
183
  function textToStringValue(text) {
184
- let out = new Variant("nil", UNIT);
184
+ let out = Value.variant("nil", UNIT);
185
185
  const chars = Array.from(text);
186
186
  for (let i = chars.length - 1; i >= 0; i--) {
187
187
  const cp = chars[i].codePointAt(0);
188
- out = new Variant("cons", new Product({
188
+ out = Value.variant("cons", Value.product({
189
189
  car: codePointToUnicodeValue(cp),
190
190
  cdr: out
191
191
  }));
package/codecs/unit.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { stdin, stdout, argv, exit } from "node:process";
4
- import { Product } from "../Value.mjs";
4
+ import { Value, isProduct } from "../Value.mjs";
5
5
  import { isMainEntrypoint } from "./runtime/cli-entry.mjs";
6
6
  import { decodeWire, encodeToWire } from "./runtime/prefix-codec.mjs";
7
7
 
@@ -28,15 +28,15 @@ function readAll(stream) {
28
28
  }
29
29
 
30
30
  function unitEncoding() {
31
- return encodeToWire(new Product({}), UNIT_PATTERN);
31
+ return encodeToWire(Value.product({}), UNIT_PATTERN);
32
32
  }
33
33
 
34
34
  function parse() {
35
- return new Product({});
35
+ return Value.product({});
36
36
  }
37
37
 
38
38
  function print(value) {
39
- if (!(value instanceof Product) || Object.keys(value.product).length !== 0) {
39
+ if (!isProduct(value) || Object.keys(value.product).length !== 0) {
40
40
  throw new Error("Input is not a unit value");
41
41
  }
42
42
  return "{}";
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { parse } from "./parser.mjs";
2
- import { Value, fromObject } from "./Value.mjs";
2
+ import { fromObject, isValue } from "./Value.mjs";
3
3
  import { parseValue } from "./valueIO.mjs";
4
4
  import { compileTypes } from "./compiler.mjs";
5
5
  import run from "./run.mjs";
@@ -19,7 +19,7 @@ compile.doc = "Transforms k-script (string) into a function";
19
19
 
20
20
  function runScriptOnData(script, data, options = {}) {
21
21
  let parsedData;
22
- if (data instanceof Value) {
22
+ if (isValue(data)) {
23
23
  parsedData = data;
24
24
  } else if (typeof data === "string") {
25
25
  parsedData = parseValue(data, null, null);
package/k.mjs CHANGED
@@ -12,14 +12,23 @@ const prog = argv[1];
12
12
  let kScript, inputStream;
13
13
 
14
14
  function usage() {
15
- console.error(`Usage: ${prog} [ --lib lib-file ]... [ --export spec ]... ( k-expr | -k file ) [ input-file ]`);
15
+ console.error(`Usage: ${prog} [ --lib lib-file ] [ --export spec ]... ( k-expr | file ) [ input-file ]`);
16
16
  console.error(` E.g., echo '["zebara","ela"]' | k-parse --input-type '$x=<{} zebara, {} ela>; $v={x 0, x 1}; $v' | ${prog} '{.1 0}'`);
17
17
  console.error("Options:");
18
- console.error(" --lib file Load a .klib dependency before compiling. May be repeated.");
18
+ console.error(" --lib file Load one .klib dependency before compiling.");
19
19
  console.error(" --export spec Export a library alias into scope. 'name' or 'libname:localname'. May be repeated.");
20
20
  console.error(" -h, --help Show this help.");
21
21
  }
22
22
 
23
+ function isFile(filePath) {
24
+ try {
25
+ return fs.statSync(filePath).isFile();
26
+ } catch (error) {
27
+ if (error?.code === "ENOENT" || error?.code === "ENOTDIR") return false;
28
+ throw error;
29
+ }
30
+ }
31
+
23
32
  function compileFile(filePath, libraries, preamble) {
24
33
  const buffer = fs.readFileSync(filePath);
25
34
  try {
@@ -44,6 +53,7 @@ function compileFile(filePath, libraries, preamble) {
44
53
  args.shift();
45
54
  const libPath = args.shift();
46
55
  if (!libPath) throw new Error("--lib requires a file argument");
56
+ if (libraries.length > 0) throw new Error("--lib may be specified at most once");
47
57
  const libBuffer = fs.readFileSync(libPath);
48
58
  libraries.push(loadLibrary(decodeObject(libBuffer)));
49
59
  } else if (args[0] === "--export") {
@@ -86,10 +96,10 @@ function compileFile(filePath, libraries, preamble) {
86
96
  throw new Error("Missing script argument");
87
97
  }
88
98
  if (arg === "-k") {
89
- return compileFile(args.shift(), libraries, buildExportPreamble());
90
- } else {
91
- return buildExportPreamble() + arg;
99
+ throw new Error("-k is no longer supported; pass the source/object file path directly");
92
100
  }
101
+ if (isFile(arg)) return compileFile(arg, libraries, buildExportPreamble());
102
+ return buildExportPreamble() + arg;
93
103
  })(args.shift());
94
104
  let kScript = typeof kScriptStr === "function" ? kScriptStr : k.compile(kScriptStr, { libraries });
95
105
  inputStream = (function (arg) {
package/kvm.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import fs from "node:fs";
3
3
  import { argv, stdin, exit, stdout } from "node:process";
4
- import { Product, Variant, composePattern, withPattern } from "./Value.mjs";
4
+ import { Value, composePattern, withPattern, isProduct, isVariant } from "./Value.mjs";
5
5
  import { exportPatternGraph } from "./codecs/runtime/codec.mjs";
6
6
  import { patternToPropertyList } from "./codecs/runtime/pattern-json.mjs";
7
7
  import {
@@ -281,7 +281,7 @@ function executeInstruction(inst, registers, context) {
281
281
  }
282
282
  case "project_field": {
283
283
  const val = registers.get(inst.src);
284
- if (!(val instanceof Product)) return undefined;
284
+ if (!isProduct(val)) return undefined;
285
285
  const fieldVal = val.product[inst.label];
286
286
  if (fieldVal === undefined) return undefined;
287
287
 
@@ -295,7 +295,7 @@ function executeInstruction(inst, registers, context) {
295
295
  }
296
296
  case "project_variant": {
297
297
  const val = registers.get(inst.src);
298
- if (!(val instanceof Variant) || val.tag !== inst.tag) return undefined;
298
+ if (!isVariant(val) || val.tag !== inst.tag) return undefined;
299
299
 
300
300
  if (options.envelopeFree) {
301
301
  registers.set(inst.dest, val.value);
@@ -308,11 +308,11 @@ function executeInstruction(inst, registers, context) {
308
308
  case "make_variant": {
309
309
  const val = registers.get(inst.src);
310
310
  if (options.envelopeFree) {
311
- registers.set(inst.dest, new Variant(inst.tag, val));
311
+ registers.set(inst.dest, Value.variant(inst.tag, val));
312
312
  } else {
313
313
  registers.set(
314
314
  inst.dest,
315
- new Variant(inst.tag, val, composePattern("open-union", [[inst.tag, val.pattern]]))
315
+ Value.variant(inst.tag, val, composePattern("open-union", [[inst.tag, val.pattern]]))
316
316
  );
317
317
  }
318
318
  return { type: "continue" };
@@ -375,13 +375,13 @@ function executeInstruction(inst, registers, context) {
375
375
  }
376
376
  let productValue;
377
377
  if (options.envelopeFree) {
378
- productValue = new Product(result);
378
+ productValue = Value.product(result);
379
379
  } else {
380
380
  const staticOutputPattern = inst.pattern;
381
381
  if (staticOutputPattern) {
382
- productValue = new Product(result, staticOutputPattern);
382
+ productValue = Value.product(result, staticOutputPattern);
383
383
  } else {
384
- productValue = new Product(result, composePattern("closed-product", patternEntries));
384
+ productValue = Value.product(result, composePattern("closed-product", patternEntries));
385
385
  }
386
386
  }
387
387
  registers.set(inst.dest, productValue);
@@ -430,7 +430,7 @@ function usage() {
430
430
  const prog = argv[1] || "kvm.mjs";
431
431
  console.error(`Usage: node ${prog} [ options ] ( k-expr | -k file ) [ input-file ]`);
432
432
  console.error("Options:");
433
- console.error(" --lib file Load a .klib dependency before compiling. May be repeated.");
433
+ console.error(" --lib file Load one .klib dependency before compiling.");
434
434
  console.error(" --envelope-free Run the interpreter in envelope-free mode.");
435
435
  console.error(" -h, --help Show this help.");
436
436
  }
@@ -454,6 +454,7 @@ async function main() {
454
454
  args.shift();
455
455
  const libPath = args.shift();
456
456
  if (!libPath) throw new Error("--lib requires a file argument");
457
+ if (libraries.length > 0) throw new Error("--lib may be specified at most once");
457
458
  const libBuffer = fs.readFileSync(libPath);
458
459
  libraries.push(loadLibrary(decodeObject(libBuffer)));
459
460
  } else {
package/objects/README.md CHANGED
@@ -11,7 +11,7 @@ Compiles `.k` source into an executable object file (`.ko`), library file
11
11
  extension, or from `--format`.
12
12
 
13
13
  ```bash
14
- k-compile [--lib lib-file]... [--format ko|klib|kvm] [source-snippet | input-file [output-file]]
14
+ k-compile [--lib lib-file] [--format ko|klib|kvm] [source-snippet | input-file [output-file]]
15
15
  ```
16
16
 
17
17
  Existing input paths are read as files. A non-existing input with `.k`, `.ko`,
@@ -25,7 +25,7 @@ function helpText() {
25
25
  " output-file Output path (.ko, .klib, or .kvm). Writes to stdout when omitted.",
26
26
  "",
27
27
  "Options:",
28
- " --lib file Load a .klib dependency before compiling. May be repeated.",
28
+ " --lib file Load one .klib dependency before compiling.",
29
29
  " --export spec Export a library alias into the source scope. May be repeated.",
30
30
  " spec is 'name' or 'libname:localname'.",
31
31
  " --format fmt Output format: ko, klib, or kvm. Overrides extension detection.",
@@ -168,6 +168,7 @@ try {
168
168
  args.shift();
169
169
  const libPath = args.shift();
170
170
  if (!libPath) throw new Error("--lib requires a file argument");
171
+ if (libraries.length > 0) throw new Error("--lib may be specified at most once");
171
172
  libraries.push(loadLibrary(decodeObject(fs.readFileSync(libPath))));
172
173
  } else if (args[0] === "--export") {
173
174
  args.shift();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fraczak/k",
3
- "version": "6.2.3",
3
+ "version": "6.3.1",
4
4
  "description": "k — a language for composing first-order partial functions over algebraic data types (products and tagged unions); includes runtime, type derivation, REPL, and codec toolchain",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
package/repl.mjs CHANGED
@@ -10,7 +10,7 @@ import { argv, exit, stdin, stdout } from "node:process";
10
10
  import { annotate, parse } from "./index.mjs";
11
11
  import run from "./run.mjs";
12
12
  import codes from "./codes.mjs";
13
- import { Product } from "./Value.mjs";
13
+ import { Value } from "./Value.mjs";
14
14
  import { patterns2filters, prettyCode, prettyRel } from "./pretty.mjs";
15
15
  import {
16
16
  compileObject,
@@ -50,7 +50,7 @@ function cloneJSON(value) {
50
50
  }
51
51
 
52
52
  function emptyValue() {
53
- return new Product({}, [["closed-product", []]]);
53
+ return Value.product({}, [["closed-product", []]]);
54
54
  }
55
55
 
56
56
  function createState() {
package/run.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import assert from "assert";
2
- import { Product, Variant, edgeSubpattern, composePattern, withPattern } from "./Value.mjs"
2
+ import { Value, edgeSubpattern, composePattern, withPattern, isProduct, isVariant } from "./Value.mjs"
3
3
  import { exportPatternGraph, intersectPropertyListPatterns } from "./codecs/runtime/codec.mjs";
4
4
  import { patternToPropertyList } from "./codecs/runtime/pattern-json.mjs";
5
5
 
@@ -238,38 +238,37 @@ function compiledExp(findCode, exp, typePatternGraph) {
238
238
  case "product": {
239
239
  const labels = exp.product.map(({ label }) => label);
240
240
  const fieldFns = exp.product.map(({ exp: e }) => compiledExp(findCode, e, typePatternGraph));
241
- if (staticOutputPattern) {
242
- fn = (value) => {
243
- if (value === undefined) return undefined;
244
- const result = {};
245
- for (let i = 0, len = labels.length; i < len; i++) {
246
- const r = fieldFns[i](value);
247
- if (r === undefined) return undefined;
248
- result[labels[i]] = r;
249
- }
250
- return new Product(result, staticOutputPattern);
251
- };
252
- } else {
253
- fn = (value) => {
254
- if (value === undefined) return undefined;
255
- const result = {};
256
- const patternEntries = [];
257
- for (let i = 0, len = labels.length; i < len; i++) {
258
- const r = fieldFns[i](value);
259
- if (r === undefined) return undefined;
260
- const label = labels[i];
261
- result[label] = r;
262
- patternEntries.push([label, r.pattern]);
263
- }
264
- return new Product(result, composePattern("closed-product", patternEntries));
265
- };
266
- }
241
+ fn = (value) => {
242
+ if (value === undefined) return undefined;
243
+ const result = {};
244
+ const patternEntries = [];
245
+ for (let i = 0, len = labels.length; i < len; i++) {
246
+ const r = fieldFns[i](value);
247
+ if (r === undefined) return undefined;
248
+ const label = labels[i];
249
+ result[label] = r;
250
+ patternEntries.push([label, r.pattern]);
251
+ }
252
+ const dynamicOutputPattern = composePattern("closed-product", patternEntries);
253
+ const pattern = staticOutputPattern && dynamicOutputPattern
254
+ ? intersectPatterns(staticOutputPattern, dynamicOutputPattern)
255
+ : staticOutputPattern || dynamicOutputPattern;
256
+ if (!pattern && staticOutputPattern && dynamicOutputPattern) {
257
+ throw new TypeError(
258
+ `Type Error in '${exp.op}'${expLocation(exp)}\n` +
259
+ ` - Product value envelope does not intersect expression output pattern.\n` +
260
+ ` - output pattern: ${patternPreview(staticOutputPattern)}\n` +
261
+ ` - product envelope: ${patternPreview(dynamicOutputPattern)}`
262
+ );
263
+ }
264
+ return Value.product(result, pattern);
265
+ };
267
266
  break;
268
267
  }
269
268
  case "vid":
270
269
  fn = (value) => {
271
270
  if (value === undefined) return undefined;
272
- return new Variant(exp.vid, value, composePattern("open-union", [[exp.vid, value.pattern]]));
271
+ return Value.variant(exp.vid, value, composePattern("open-union", [[exp.vid, value.pattern]]));
273
272
  };
274
273
  break;
275
274
  default:
@@ -376,13 +375,13 @@ function compiledConvergedExp(findCode, exp, typePatternGraph, options = {}) {
376
375
  break;
377
376
  case "dot":
378
377
  fn = (value) => {
379
- if (value === undefined || !(value instanceof Product)) return undefined;
378
+ if (value === undefined || !isProduct(value)) return undefined;
380
379
  return Object.hasOwn(value.product, exp.dot) ? value.product[exp.dot] : undefined;
381
380
  };
382
381
  break;
383
382
  case "div":
384
383
  fn = (value) => {
385
- if (value === undefined || !(value instanceof Variant) || value.tag !== exp.div) return undefined;
384
+ if (value === undefined || !isVariant(value) || value.tag !== exp.div) return undefined;
386
385
  return value.value;
387
386
  };
388
387
  break;
@@ -420,12 +419,12 @@ function compiledConvergedExp(findCode, exp, typePatternGraph, options = {}) {
420
419
  if (r === undefined) return undefined;
421
420
  result[labels[i]] = r;
422
421
  }
423
- return new Product(result);
422
+ return Value.product(result);
424
423
  };
425
424
  break;
426
425
  }
427
426
  case "vid":
428
- fn = (value) => value === undefined ? undefined : new Variant(exp.vid, value);
427
+ fn = (value) => value === undefined ? undefined : Value.variant(exp.vid, value);
429
428
  break;
430
429
  default:
431
430
  assert(false,`Unknown operation: '${exp.op}'`);
@@ -441,7 +440,7 @@ function verify(findCode, code, value) {
441
440
  code = findCode(code);
442
441
  switch (code.code) {
443
442
  case "product":
444
- if (! (value instanceof Product)) return false;
443
+ if (!isProduct(value)) return false;
445
444
  else {
446
445
  const fields = Object.keys(value.product);
447
446
  if (fields.length !== Object.keys(code.product).length) return false;
@@ -450,7 +449,7 @@ function verify(findCode, code, value) {
450
449
  );
451
450
  }
452
451
  case "union":
453
- if (! (value instanceof Product)) return false;
452
+ if (!isProduct(value)) return false;
454
453
  else {
455
454
  const fields = Object.keys(value.product);
456
455
  if (fields.length !== 1) return false;
@@ -18,6 +18,7 @@ const tests = [
18
18
  ["tests/test-fingerprint.mjs", node, ["tests/test-fingerprint.mjs"]],
19
19
  ["tests/test-hash-fuzz.mjs", node, ["tests/test-hash-fuzz.mjs"]],
20
20
  ["tests/test-hash-normalization.mjs", node, ["tests/test-hash-normalization.mjs"]],
21
+ ["tests/test-structural-values.mjs", node, ["tests/test-structural-values.mjs"]],
21
22
  ["tests/test-deep-wire-value.mjs", node, ["tests/test-deep-wire-value.mjs"]],
22
23
  ["tests/test-k-object.mjs", node, ["tests/test-k-object.mjs"]],
23
24
  ["tests/test-repl.mjs", node, ["tests/test-repl.mjs"]],
@@ -1,7 +1,7 @@
1
1
  import assert from 'assert';
2
2
  import { parseValue } from '../../valueIO.mjs';
3
3
  import { encodeToWire, decodeWire } from '../../codecs/runtime/prefix-codec.mjs';
4
- import { Product, Variant } from '../../Value.mjs';
4
+ import { isProduct, isVariant } from '../../Value.mjs';
5
5
 
6
6
  const value = parseValue('{a:{b:x,c:{}}}');
7
7
  const repeatedClosedValue = parseValue('{a:{m:{},n:{}},b:{m:{},n:{}}}');
@@ -27,9 +27,9 @@ assert.deepEqual(explicitProductWire.pattern, [
27
27
  ]);
28
28
 
29
29
  const decoded = explicitProductWire.value;
30
- assert(decoded instanceof Product);
31
- assert(decoded.product.a instanceof Product);
32
- assert(decoded.product.a.product.b instanceof Variant);
30
+ assert(isProduct(decoded));
31
+ assert(isProduct(decoded.product.a));
32
+ assert(isVariant(decoded.product.a.product.b));
33
33
  assert.equal(decoded.product.a.product.b.tag, "x");
34
34
 
35
35
  const repeatedClosedWire = decodeWire(encodeToWire(repeatedClosedValue, null));