@fraczak/k 6.7.0 → 6.8.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.
@@ -16,18 +16,21 @@ import {
16
16
  isMainEntrypoint,
17
17
  lineHasExplicitContinuation,
18
18
  lineTerminatesSnippet,
19
- promptForState
19
+ promptForState,
20
+ registerCodec
20
21
  } from "../repl.mjs";
21
22
  import { decodeObject, objectToFunction } from "../object.mjs";
22
23
  import { Value } from "../Value.mjs";
23
24
 
24
25
  const state = createState();
25
26
 
26
- let output = await evaluateInput(":type nat = <{} zero, nat succ>", state);
27
- assert.match(output[0], /^\$ nat = @/);
27
+ let output = await evaluateInput("$ nat = < {} zero, nat succ >;", state);
28
+ output = await evaluateInput(":type nat", state);
29
+ assert.match(output[0], /^\$ nat = /);
28
30
 
29
- output = await evaluateInput(":rel succ = |succ", state);
30
- assert.match(output[0], /^succ = @/);
31
+ output = await evaluateInput("succ = | succ;", state);
32
+ output = await evaluateInput(":d succ", state);
33
+ assert.match(output[0], /^succ = /);
31
34
 
32
35
  output = await evaluateInput(":codes", state);
33
36
  assert.match(output[0], /^nat = @/m);
@@ -82,8 +85,8 @@ assert.equal(analyzeRawSnippet("a =").kind, "incomplete");
82
85
  assert.equal(analyzeRawSnippet("{} | succ").kind, "withMain");
83
86
 
84
87
  const offsetState = createState();
85
- await evaluateInput(":type ab = <{} 1, {} 2>", offsetState);
86
- await evaluateInput(":type bool = <{} true, {} false>", offsetState);
88
+ await evaluateInput("$ ab = < {} 1, {} 2 >;", offsetState);
89
+ await evaluateInput("$ bool = < {} true, {} false >;", offsetState);
87
90
  await assert.rejects(
88
91
  () => evaluateInput("$ab", offsetState),
89
92
  /Type Error in 'filter' \(lines 1:1\.\.\.1:4\)/
@@ -100,10 +103,10 @@ output = await evaluateInput(`:klib ${libPath}`, state);
100
103
  assert.equal(output[0], `saved ${libPath}`);
101
104
 
102
105
  const recursiveState = createState();
103
- await evaluateInput(":type $ nat = < {}_, nat 0, nat 1 >;", recursiveState);
104
- await evaluateInput(":rel 0? = $ nat < / _ {}|0, / 0 0? >;", recursiveState);
106
+ await evaluateInput("$ nat = < {} _, nat 0, nat 1 >;", recursiveState);
107
+ await evaluateInput("0? = $ nat < / _ {} | 0, / 0 0? >;", recursiveState);
105
108
  const staleZeroHash = recursiveState.relAliases["0?"];
106
- await evaluateInput(":rel 0? = $ nat < / _ {}|_, / 0 0? >;", recursiveState);
109
+ await evaluateInput("0? = $ nat < / _ {} | _, / 0 0? >;", recursiveState);
107
110
  const zeroHash = recursiveState.relAliases["0?"];
108
111
  assert.notEqual(zeroHash, staleZeroHash);
109
112
  await evaluateInput("{}|_|0|0 $nat", recursiveState);
@@ -141,8 +144,7 @@ output = await evaluateInput(":C nat", loadedSource);
141
144
  assert.match(output[0], /^\$ nat = < nat succ, @[^ ]+ zero >; -- @/);
142
145
 
143
146
  const codecState = createState();
144
- output = await evaluateInput(":type bool = <{} true, {} false>", codecState);
145
- assert.match(output[0], /^\$ bool = @/);
147
+ output = await evaluateInput("$ bool = < {} true, {} false >;", codecState);
146
148
  const boolHash = codecState.typeAliases.bool;
147
149
  const valueModuleUrl = pathToFileURL(path.resolve("Value.mjs")).href;
148
150
  fs.writeFileSync(codecPath, `
@@ -196,8 +198,7 @@ output = await evaluateInput("hello", utf8State);
196
198
  assert.match(output[0], /utf8: hello/);
197
199
 
198
200
  const jsonState = createState();
199
- output = await evaluateInput(":type bool = <{} true, {} false>", jsonState);
200
- assert.match(output[0], /^\$ bool = @/);
201
+ output = await evaluateInput("$ bool = < {} true, {} false >;", jsonState);
201
202
  output = await evaluateInput(":codec load ./codecs/json.mjs", jsonState);
202
203
  assert.match(output[0], /^loaded codec json for all types/);
203
204
  output = await evaluateInput(":codec list", jsonState);
@@ -256,7 +257,7 @@ assert.equal(output[0], "(none)");
256
257
 
257
258
  const shorthand = createState();
258
259
  output = await evaluateInput("$ nat = <{} zero, nat succ>\n; succ = |succ\n;", shorthand);
259
- assert.deepEqual(output, []);
260
+ assert.match(output[0], /\/\* comp: .* \*\//);
260
261
  output = await evaluateInput(":codes", shorthand);
261
262
  assert.match(output[0], /^nat = @/m);
262
263
  output = await evaluateInput(":rels", shorthand);
@@ -266,7 +267,7 @@ assert.match(output[0], /^\{\}\|false \?</);
266
267
  assert.match(output[0], / false/);
267
268
  assert.match(output[0], / true/);
268
269
  output = await evaluateInput("$ maybe = <{} none, {} some>;", shorthand);
269
- assert.deepEqual(output, []);
270
+ assert.match(output[0], /\/\* comp: .* \*\//);
270
271
  output = await evaluateInput(":codes", shorthand);
271
272
  assert.match(output[0], /^maybe = @/m);
272
273
  output = await evaluateInput("{} | true not", shorthand);
@@ -279,8 +280,8 @@ await assert.rejects(
279
280
 
280
281
  // Verify WebAssembly in-process backend supports TCO / stack safety on deep recursion
281
282
  const tcoState = createState();
282
- await evaluateInput(":type nat = <{} zero, nat succ>", tcoState);
283
- await evaluateInput(":rel countdown = $nat < /zero {}|zero, /succ countdown >", tcoState);
283
+ await evaluateInput("$ nat = < {} zero, nat succ >;", tcoState);
284
+ await evaluateInput("countdown = $ nat < / zero {} | zero, / succ countdown >;", tcoState);
284
285
 
285
286
  let deepNat = Value.variant("zero", Value.product({}, [["closed-product", []]]), [["open-union", [["zero", 1]]], ["closed-product", []]]);
286
287
  for (let i = 0; i < 5000; i++) {
@@ -301,7 +302,7 @@ assert.match(output[0], /^\{\}\|_\|0\|1\|0\|1/);
301
302
  output = await evaluateInput("{10 int x, 5 int y} plus", arithState);
302
303
  assert.match(output[0], /^\{\}\|_\|1\|1\|1\|1\|\+/);
303
304
 
304
- // Verify built-in codecs, :codecs, :codec define, and :codec unload
305
+ // Verify built-in codecs, :codecs, and :codec unload
305
306
  const codecTestState = createState();
306
307
  output = await evaluateInput(":codecs", codecTestState);
307
308
  assert.equal(output[0], "(none)");
@@ -324,12 +325,14 @@ assert.equal(output[0], "unloaded codec int");
324
325
  output = await evaluateInput(":codecs", codecTestState);
325
326
  assert.equal(output[0], "(none)");
326
327
 
327
- output = await evaluateInput(":type bool = <{} true, {} false>", codecTestState);
328
- output = await evaluateInput(
329
- `:codec define yn bool ({ parse: (text) => Value.variant(text.trim() === "yes" ? "true" : "false", Value.product({})), print: (v) => v.tag === "true" ? "YES" : "NO" })`,
330
- codecTestState
331
- );
332
- assert.match(output[0], /^defined codec yn for @/);
328
+ output = await evaluateInput("$ bool = < {} true, {} false >;", codecTestState);
329
+ registerCodec(codecTestState, {
330
+ name: "yn",
331
+ codes: [codecTestState.typeAliases.bool],
332
+ universal: false,
333
+ parse: (text) => Value.variant(text.trim() === "yes" ? "true" : "false", Value.product({})),
334
+ print: (v) => v.tag === "true" ? "YES" : "NO"
335
+ }, "<test>");
333
336
 
334
337
  output = await evaluateInput(":input bool yn", codecTestState);
335
338
  output = await evaluateInput("yes", codecTestState);
@@ -383,6 +386,61 @@ assert.match(output[0], /enter value text/);
383
386
  output = await evaluateInput('{"a":"Woj","n":123}', jsonInputState);
384
387
  assert.match(output[0], /json: \{"a":"Woj","n":123\}/);
385
388
 
389
+ // Verify pattern expressions and standalone codec input
390
+ const patternInputState = createState();
391
+ await evaluateInput(":codec load json", patternInputState);
392
+
393
+ // 1. Explicit pattern expression: ? {string a, float64 n} json
394
+ output = await evaluateInput(":input ? {string a, float64 n} json", patternInputState);
395
+ assert.match(output[0], /input \? \{string a, float64 n\} using json: enter value text/);
396
+ output = await evaluateInput('{"a":"Woj","n":123}', patternInputState);
397
+ assert.match(output[0], /json: \{"a":"Woj","n":123\}/);
398
+
399
+ // 2. Wildcard pattern expression: ? (...) json
400
+ output = await evaluateInput(":input ? (...) json", patternInputState);
401
+ assert.match(output[0], /enter value text/);
402
+ output = await evaluateInput('{"anything": [1, 2, 3]}', patternInputState);
403
+ assert.match(output[0], /json: \{"anything":\[1,2,3\]\}/);
404
+
405
+ // 3. Standalone codec input: :input json (no predefined type or pattern required)
406
+ output = await evaluateInput(":input json", patternInputState);
407
+ assert.match(output[0], /input json: enter value text/);
408
+ output = await evaluateInput('{"hello":"world"}', patternInputState);
409
+ assert.match(output[0], /json: \{"hello":"world"\}/);
410
+
411
+ // 4. Pattern mismatch detection
412
+ output = await evaluateInput(":input ? {string a, float64 n} json", patternInputState);
413
+ await assert.rejects(
414
+ () => evaluateInput('{"wrong_key": 999}', patternInputState),
415
+ /Closed product pattern does not match value fields/
416
+ );
417
+
418
+ // 5. Bare :input defaults to :input (...) with auto-loaded json codec
419
+ const bareInputState = createState();
420
+ assert.equal(promptForState(bareInputState), "> ");
421
+ output = await evaluateInput(":input", bareInputState);
422
+ assert.deepEqual(output, ["input (...): enter value text"]);
423
+ assert.equal(promptForState(bareInputState), "json> ");
424
+ output = await evaluateInput('{"test": 123}', bareInputState);
425
+ assert.match(output[0], /json: \{"test":123\}/);
426
+ assert.equal(promptForState(bareInputState), "> ");
427
+
428
+ // 6. Pattern as type prefixed by dollar
429
+ const dollarPatternState = createState();
430
+ await evaluateInput(":load arithmetics.k", dollarPatternState);
431
+ output = await evaluateInput(":input $ int", dollarPatternState);
432
+ assert.deepEqual(output, ["input $ int: enter value text"]);
433
+ assert.equal(promptForState(dollarPatternState), "int> ");
434
+ output = await evaluateInput("42", dollarPatternState);
435
+ assert.match(output[0], /int: 42/);
436
+
437
+ await evaluateInput("$ bool = <{} true, {} false>;", dollarPatternState);
438
+ output = await evaluateInput(":input $ bool json", dollarPatternState);
439
+ assert.deepEqual(output, ["input $ bool using json: enter value text"]);
440
+ assert.equal(promptForState(dollarPatternState), "json> ");
441
+ output = await evaluateInput("true", dollarPatternState);
442
+ assert.match(output[0], /json: true/);
443
+
386
444
  const unitState = createState();
387
445
  output = await evaluateInput(":codec load unit", unitState);
388
446
  assert.match(output[0], /loaded codec unit/);
@@ -397,28 +455,20 @@ assert.equal(output[0], "loaded Examples/poly.k");
397
455
  assert.ok(polyAutoState.relAliases.reverse, "poly relations should be loaded");
398
456
  assert.ok(polyAutoState.typeAliases.int, "arithmetics int should be auto-loaded");
399
457
 
400
- // Verify :timing and :time commands
458
+ // Verify timing reporting is always on and :time command
401
459
  const timingState = createState();
402
- output = await evaluateInput(":time ()", timingState);
403
- assert.equal(output[0], "{} ?{}");
404
- assert.match(output[1], /\/\* comp: .*, exec: .* \*\//);
405
- assert.ok(timingState.lastTiming);
406
- assert.ok(typeof timingState.lastTiming.compileMs === "number");
407
- assert.ok(typeof timingState.lastTiming.executeMs === "number");
408
-
409
- output = await evaluateInput(":timing on", timingState);
410
- assert.equal(output[0], "timing reporting enabled");
411
460
  assert.equal(timingState.showTiming, true);
461
+
412
462
  output = await evaluateInput("()", timingState);
413
463
  assert.equal(output[0], "{} ?{}");
414
464
  assert.match(output[1], /\/\* comp: .*, exec: .* \*\//);
415
465
 
416
- output = await evaluateInput(":timing off", timingState);
417
- assert.equal(output[0], "timing reporting disabled");
418
- assert.equal(timingState.showTiming, false);
419
- output = await evaluateInput("()", timingState);
420
- assert.equal(output.length, 1);
466
+ output = await evaluateInput(":time ()", timingState);
421
467
  assert.equal(output[0], "{} ?{}");
468
+ assert.match(output[1], /\/\* comp: .*, exec: .* \*\//);
469
+ assert.ok(timingState.lastTiming);
470
+ assert.ok(typeof timingState.lastTiming.compileMs === "number");
471
+ assert.ok(typeof timingState.lastTiming.executeMs === "number");
422
472
 
423
473
  fs.rmSync(tmpDir, { recursive: true, force: true });
424
474
  fs.rmSync(symlinkPath, { force: true });