@fraczak/k 6.10.5 → 7.0.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.
- package/CHANGELOG.md +70 -0
- package/CLAUDE.md +1 -1
- package/DOCS/BIG_PICTURE.md +156 -172
- package/DOCS/BINARY_CODEC_STATUS_AND_TODO.md +3 -3
- package/DOCS/CODEC_ARCHITECTURE.md +2 -2
- package/DOCS/DICTIONARY.md +243 -250
- package/DOCS/DIVERGENCE_DETECTION.md +0 -1
- package/DOCS/FILE_FORMATS.md +5 -5
- package/DOCS/KIR_SPECIALIZATION_DESIGN.md +1 -1
- package/DOCS/OBJECT_FILE_AND_PATTERN.md +12 -12
- package/DOCS/PATTERNS.md +17 -17
- package/DOCS/PATTERNS_AND_TYPED_VALUES.md +1 -1
- package/DOCS/REPL.md +9 -19
- package/DOCS/TYPE_DERIVATION.md +2 -8
- package/DOCS/WEB_REPL_REQUIREMENTS.md +8 -8
- package/DOCS/book/01-introduction.md +8 -11
- package/DOCS/book/02-syntax-and-values.md +19 -20
- package/DOCS/book/03-types-as-finite-automata.md +42 -43
- package/DOCS/book/04-partial-functions-and-composition.md +2 -3
- package/DOCS/book/05-typing-filters-and-normalization.md +44 -46
- package/DOCS/book/06-values-in-memory.md +10 -10
- package/DOCS/book/08-operational-semantics-and-execution.md +21 -26
- package/DOCS/book/09-compiler-architecture.md +11 -11
- package/DOCS/book/10-from-ast-to-intermediate-representation.md +6 -7
- package/DOCS/book/14-canonical-serialization.md +2 -2
- package/DOCS/book/appendix-b-incorporating-external-predefined-types-and-functions.md +17 -17
- package/DOCS/book.md +5 -5
- package/Examples/arithmetics.k +49 -153
- package/Examples/bnat.k +13 -13
- package/Examples/byte.k +2 -50
- package/Examples/ieee.k +408 -423
- package/Examples/karatsuba-mult.k +30 -34
- package/Examples/nat.k +5 -6
- package/README.md +54 -49
- package/TODO.md +13 -18
- package/browser/repl-browser.mjs +40 -22
- package/browser/shims/fs.mjs +7 -10
- package/browser/vfs-data.mjs +12 -12
- package/codecs/BINARY_FORMAT.md +4 -4
- package/codecs/POLYMORPHIC_BINARY_FORMAT.md +4 -4
- package/codecs/README.md +6 -6
- package/codecs/ieee.mjs +15 -11
- package/codecs/int.mjs +9 -5
- package/codecs/string-codec.mjs +46 -47
- package/core.k +124 -175
- package/object.mjs +0 -7
- package/package.json +5 -2
- package/parser.jison +2 -41
- package/parser.mjs +55 -95
- package/pretty.mjs +11 -4
- package/repl.mjs +8 -63
- package/scripts/build-repl-html.mjs +18 -49
- package/tests/code-derivation/blowup.mjs +2 -4
- package/tests/code-derivation/bnat.mjs +2 -3
- package/tests/code-derivation/dot.mjs +5 -11
- package/tests/code-derivation/nat.mjs +2 -2
- package/tests/code-derivation/not-not.mjs +6 -6
- package/tests/code-derivation/pattern-envelope.mjs +4 -6
- package/tests/code-derivation/product.mjs +3 -6
- package/tests/code-derivation/rlz.mjs +4 -5
- package/tests/test-codecs.mjs +1 -1
- package/tests/test-fingerprint.mjs +36 -41
- package/tests/test-hash-normalization.mjs +4 -6
- package/tests/test-ieee-arithmetic.mjs +6 -7
- package/tests/test-k-object.mjs +11 -15
- package/tests/test-kir.mjs +0 -1
- package/tests/test-kvm-polymorphic.mjs +1 -2
- package/tests/test-kvm.mjs +8 -11
- package/tests/test-repl-html.mjs +86 -9
- package/tests/test-repl.mjs +38 -53
- package/tests/test.mjs +2 -3
package/tests/test-repl-html.mjs
CHANGED
|
@@ -139,15 +139,15 @@ if (chromiumBin) {
|
|
|
139
139
|
const vfsList = await evaluateAsync(`window.kRepl.getAllVfsFiles().sort()`);
|
|
140
140
|
const expectedFiles = [
|
|
141
141
|
"arithmetics.k",
|
|
142
|
-
"codecs/ieee.mjs",
|
|
143
|
-
"codecs/int.mjs",
|
|
144
|
-
"codecs/json.mjs",
|
|
145
|
-
"codecs/unit.mjs",
|
|
146
|
-
"codecs/utf8.mjs",
|
|
147
142
|
"core.k",
|
|
148
143
|
"ieee.k",
|
|
144
|
+
"ieee.mjs",
|
|
145
|
+
"int.mjs",
|
|
146
|
+
"json.mjs",
|
|
149
147
|
"karatsuba-mult.k",
|
|
150
|
-
"poly.k"
|
|
148
|
+
"poly.k",
|
|
149
|
+
"unit.mjs",
|
|
150
|
+
"utf8.mjs"
|
|
151
151
|
].sort();
|
|
152
152
|
assert.deepStrictEqual(vfsList, expectedFiles, `getAllVfsFiles() must match curated files list, got: ${JSON.stringify(vfsList)}`);
|
|
153
153
|
|
|
@@ -581,6 +581,7 @@ if (chromiumBin) {
|
|
|
581
581
|
const hasTime = modalText.includes(":time");
|
|
582
582
|
const hasT = modalText.includes(":t <name>");
|
|
583
583
|
const hasCodecDefine = modalText.includes(":codec define");
|
|
584
|
+
const hasRels = modalText.includes(":rels");
|
|
584
585
|
const hasType = modalText.includes(":type <name>");
|
|
585
586
|
const hasTypes = modalText.includes(":types");
|
|
586
587
|
const hasCodes = modalText.includes(":codes");
|
|
@@ -592,6 +593,7 @@ if (chromiumBin) {
|
|
|
592
593
|
rect: { left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom },
|
|
593
594
|
helpModalOpen,
|
|
594
595
|
hasRel,
|
|
596
|
+
hasRels,
|
|
595
597
|
hasVal,
|
|
596
598
|
hasTiming,
|
|
597
599
|
hasTime,
|
|
@@ -608,8 +610,9 @@ if (chromiumBin) {
|
|
|
608
610
|
assert.strictEqual(narrowNavbarCheck.isVisible, true, "#btn-help should be visible within narrow viewport");
|
|
609
611
|
assert.strictEqual(narrowNavbarCheck.helpModalOpen, true, "Clicking #btn-help in narrow viewport should open help modal");
|
|
610
612
|
assert.strictEqual(narrowNavbarCheck.hasRel, true, "Help modal should contain :rel <name>");
|
|
611
|
-
assert.strictEqual(narrowNavbarCheck.
|
|
612
|
-
assert.strictEqual(narrowNavbarCheck.
|
|
613
|
+
assert.strictEqual(narrowNavbarCheck.hasRels, true, "Help modal should contain :rels");
|
|
614
|
+
assert.strictEqual(narrowNavbarCheck.hasType, false, "Help modal should not contain :type <name>");
|
|
615
|
+
assert.strictEqual(narrowNavbarCheck.hasTypes, false, "Help modal should not contain :types");
|
|
613
616
|
assert.strictEqual(narrowNavbarCheck.hasEngine, true, "Help modal should contain :engine");
|
|
614
617
|
assert.strictEqual(narrowNavbarCheck.hasCodes, false, "Help modal should not contain :codes");
|
|
615
618
|
assert.strictEqual(narrowNavbarCheck.hasTime, false, "Help modal should not contain :time");
|
|
@@ -635,7 +638,81 @@ if (chromiumBin) {
|
|
|
635
638
|
assert.strictEqual(engineCheck.jsEngine, "js");
|
|
636
639
|
assert.strictEqual(engineCheck.badgeJsText, "js-in-process");
|
|
637
640
|
assert.strictEqual(engineCheck.wasmEngine, "wasm");
|
|
638
|
-
|
|
641
|
+
// 7. Test uploading a file (adds to VFS without auto-loading)
|
|
642
|
+
const uploadCheck = await evaluateAsync(`(async () => {
|
|
643
|
+
const codecCode = \`export default {
|
|
644
|
+
name: "custom.mjs",
|
|
645
|
+
target: "(...)",
|
|
646
|
+
format: "custom",
|
|
647
|
+
parse: (raw) => raw,
|
|
648
|
+
print: (v) => "CUSTOM_VAL"
|
|
649
|
+
};\`;
|
|
650
|
+
const file = new File(
|
|
651
|
+
[codecCode],
|
|
652
|
+
"custom.mjs",
|
|
653
|
+
{ type: "text/javascript" }
|
|
654
|
+
);
|
|
655
|
+
await window.kRepl.handleFileUpload(file);
|
|
656
|
+
|
|
657
|
+
const vfsContent = window.kRepl.getVfsFile("custom.mjs");
|
|
658
|
+
const inVfsList = window.kRepl.getAllVfsFiles().includes("custom.mjs");
|
|
659
|
+
|
|
660
|
+
// Verify system message showed upload confirmation
|
|
661
|
+
const systemMessages = Array.from(
|
|
662
|
+
document.querySelectorAll(".system-msg")
|
|
663
|
+
).map(el => el.textContent);
|
|
664
|
+
const hasUploadedMsg = systemMessages.some(
|
|
665
|
+
m => m.includes("Uploaded custom.mjs into VFS")
|
|
666
|
+
);
|
|
667
|
+
|
|
668
|
+
// Verify it was NOT auto-loaded (:codecs does not list it)
|
|
669
|
+
await window.kRepl.executeCommand(":codecs");
|
|
670
|
+
const linesBefore = Array.from(
|
|
671
|
+
document.querySelectorAll(".entry-line")
|
|
672
|
+
).map(el => el.textContent);
|
|
673
|
+
const codecsBefore = linesBefore[linesBefore.length - 1];
|
|
674
|
+
|
|
675
|
+
// Explicitly load it to prove it can be loaded as a codec
|
|
676
|
+
await window.kRepl.executeCommand(":codec load custom.mjs");
|
|
677
|
+
const linesAfter = Array.from(
|
|
678
|
+
document.querySelectorAll(".entry-line")
|
|
679
|
+
).map(el => el.textContent);
|
|
680
|
+
const codecsAfter = linesAfter[linesAfter.length - 1];
|
|
681
|
+
|
|
682
|
+
return {
|
|
683
|
+
hasVfsContent: typeof vfsContent === "string" &&
|
|
684
|
+
vfsContent.includes("custom.mjs"),
|
|
685
|
+
inVfsList,
|
|
686
|
+
hasUploadedMsg,
|
|
687
|
+
codecsBefore,
|
|
688
|
+
codecsAfter
|
|
689
|
+
};
|
|
690
|
+
})()`);
|
|
691
|
+
assert.strictEqual(
|
|
692
|
+
uploadCheck.hasVfsContent,
|
|
693
|
+
true,
|
|
694
|
+
"Uploaded file must be present in VFS"
|
|
695
|
+
);
|
|
696
|
+
assert.strictEqual(
|
|
697
|
+
uploadCheck.inVfsList,
|
|
698
|
+
true,
|
|
699
|
+
"Uploaded file must be in getAllVfsFiles()"
|
|
700
|
+
);
|
|
701
|
+
assert.strictEqual(
|
|
702
|
+
uploadCheck.hasUploadedMsg,
|
|
703
|
+
true,
|
|
704
|
+
"Upload confirmation message must be displayed"
|
|
705
|
+
);
|
|
706
|
+
assert.strictEqual(
|
|
707
|
+
uploadCheck.codecsBefore.includes("custom.mjs"),
|
|
708
|
+
false,
|
|
709
|
+
"Upload must NOT auto-load the file"
|
|
710
|
+
);
|
|
711
|
+
assert.strictEqual(
|
|
712
|
+
uploadCheck.codecsAfter.includes("custom.mjs"),
|
|
713
|
+
true,
|
|
714
|
+
"Explicit :codec load of uploaded file must succeed"
|
|
715
|
+
);
|
|
639
716
|
|
|
640
717
|
ws.close();
|
|
641
718
|
console.log(" Browser execution verified successfully!");
|
package/tests/test-repl.mjs
CHANGED
|
@@ -24,18 +24,16 @@ import { Value } from "../Value.mjs";
|
|
|
24
24
|
|
|
25
25
|
const state = createState();
|
|
26
26
|
|
|
27
|
-
let output = await evaluateInput("
|
|
28
|
-
output = await evaluateInput(":
|
|
29
|
-
assert.match(output[0],
|
|
27
|
+
let output = await evaluateInput("zero = {} | zero;", state);
|
|
28
|
+
output = await evaluateInput(":rel zero", state);
|
|
29
|
+
assert.match(output[0], /^zero = /);
|
|
30
30
|
|
|
31
31
|
output = await evaluateInput("succ = | succ;", state);
|
|
32
32
|
output = await evaluateInput(":rel succ", state);
|
|
33
33
|
assert.match(output[0], /^succ = /);
|
|
34
34
|
|
|
35
|
-
output = await evaluateInput(":types", state);
|
|
36
|
-
assert.match(output[0], /^nat = @/m);
|
|
37
|
-
|
|
38
35
|
output = await evaluateInput(":rels", state);
|
|
36
|
+
assert.match(output[0], /^zero = @/m);
|
|
39
37
|
assert.match(output[0], /^succ = @/m);
|
|
40
38
|
|
|
41
39
|
output = await evaluateInput("succ", state);
|
|
@@ -54,18 +52,18 @@ assert.match(output[0], /^succ = /);
|
|
|
54
52
|
let completions = completeInput(":he", state)[0];
|
|
55
53
|
assert.deepEqual(completions, [":help"]);
|
|
56
54
|
|
|
57
|
-
const canonicalPartial = state.
|
|
55
|
+
const canonicalPartial = state.relAliases.zero.slice(0, 8);
|
|
58
56
|
completions = completeInput(`:rel ${canonicalPartial}`, state)[0];
|
|
59
|
-
assert(completions.some((line) => line.endsWith(state.
|
|
57
|
+
assert(completions.some((line) => line.endsWith(state.relAliases.zero)));
|
|
60
58
|
|
|
61
59
|
completions = completeInput(`(${canonicalPartial}`, state)[0];
|
|
62
|
-
assert(completions.includes(`(${state.
|
|
60
|
+
assert(completions.includes(`(${state.relAliases.zero}`));
|
|
63
61
|
|
|
64
62
|
completions = completeInput(":rel su", state)[0];
|
|
65
63
|
assert(completions.includes(":rel succ"));
|
|
66
|
-
completions = completeInput(":
|
|
67
|
-
assert(completions.includes(":
|
|
68
|
-
assert(completions.includes(":
|
|
64
|
+
completions = completeInput(":re", state)[0];
|
|
65
|
+
assert(completions.includes(":rels"));
|
|
66
|
+
assert(completions.includes(":rel"));
|
|
69
67
|
|
|
70
68
|
await assert.rejects(
|
|
71
69
|
() => evaluateInput(":run succ", state),
|
|
@@ -83,27 +81,26 @@ await assert.rejects(
|
|
|
83
81
|
completions = completeInput(":co", state)[0];
|
|
84
82
|
assert(completions.includes(":codec"));
|
|
85
83
|
|
|
86
|
-
completions = completeInput("
|
|
87
|
-
assert(completions.includes("
|
|
84
|
+
completions = completeInput("ze", state)[0];
|
|
85
|
+
assert(completions.includes("zero"));
|
|
88
86
|
|
|
89
|
-
assert.deepEqual(aliasNames(state), ["
|
|
87
|
+
assert.deepEqual(aliasNames(state), ["succ", "zero"]);
|
|
90
88
|
assert.equal(lineTerminatesSnippet(";"), true);
|
|
91
89
|
assert.equal(lineTerminatesSnippet(" ; "), true);
|
|
92
90
|
assert.equal(lineTerminatesSnippet(" ; -- comment"), false);
|
|
93
91
|
assert.equal(lineTerminatesSnippet("succ"), false);
|
|
94
|
-
assert.equal(explicitSnippetTerminated("
|
|
92
|
+
assert.equal(explicitSnippetTerminated("bool = <{} true, {} false>;"), true);
|
|
95
93
|
assert.equal(lineHasExplicitContinuation("succ \\"), true);
|
|
96
|
-
assert.equal(analyzeRawSnippet("
|
|
97
|
-
assert.equal(analyzeAcceptedSnippet("
|
|
94
|
+
assert.equal(analyzeRawSnippet("bool = <{} true, {} false>").kind, "incomplete");
|
|
95
|
+
assert.equal(analyzeAcceptedSnippet("bool = <{} true, {} false>;", true).kind, "definitionsOnly");
|
|
98
96
|
assert.equal(analyzeRawSnippet("a =").kind, "incomplete");
|
|
99
97
|
assert.equal(analyzeRawSnippet("{} | succ").kind, "withMain");
|
|
100
98
|
|
|
101
99
|
const offsetState = createState();
|
|
102
|
-
await evaluateInput("
|
|
103
|
-
await evaluateInput("$ bool = < {} true, {} false >;", offsetState);
|
|
100
|
+
await evaluateInput("zero = {} | zero;\nsucc = | succ;", offsetState);
|
|
104
101
|
await assert.rejects(
|
|
105
|
-
() => evaluateInput("
|
|
106
|
-
/Type Error in '
|
|
102
|
+
() => evaluateInput("{} .x", offsetState),
|
|
103
|
+
/Type Error in 'comp' \(lines 1:1\.\.\.1:6\)/
|
|
107
104
|
);
|
|
108
105
|
|
|
109
106
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "k-repl-"));
|
|
@@ -117,13 +114,12 @@ output = await evaluateInput(`:klib ${libPath}`, state);
|
|
|
117
114
|
assert.equal(output[0], `saved ${libPath}`);
|
|
118
115
|
|
|
119
116
|
const recursiveState = createState();
|
|
120
|
-
await evaluateInput("
|
|
121
|
-
await evaluateInput("0? = $ nat < / _ {} | 0, / 0 0? >;", recursiveState);
|
|
117
|
+
await evaluateInput("0? = ?< {} _, X 0, X 1 > = X < / _ {} | 0, / 0 0? >;", recursiveState);
|
|
122
118
|
const staleZeroHash = recursiveState.relAliases["0?"];
|
|
123
|
-
await evaluateInput("0? =
|
|
119
|
+
await evaluateInput("0? = ?< {} _, X 0, X 1 > = X < / _ {} | _, / 0 0? >;", recursiveState);
|
|
124
120
|
const zeroHash = recursiveState.relAliases["0?"];
|
|
125
121
|
assert.notEqual(zeroHash, staleZeroHash);
|
|
126
|
-
await evaluateInput("{}|_|0|0
|
|
122
|
+
await evaluateInput("{}|_|0|0 0?", recursiveState);
|
|
127
123
|
assert.deepEqual(
|
|
128
124
|
Object.keys(recursiveState.rels).sort(),
|
|
129
125
|
[staleZeroHash, zeroHash].sort()
|
|
@@ -144,28 +140,21 @@ const objectFn = objectToFunction(decodeObject(fs.readFileSync(koPath)));
|
|
|
144
140
|
const objectResult = objectFn(Value.product({}, [["closed-product", []]]));
|
|
145
141
|
assert.equal(objectResult.toJSON(), "succ");
|
|
146
142
|
|
|
147
|
-
fs.writeFileSync(sourcePath, "
|
|
143
|
+
fs.writeFileSync(sourcePath, "succ = |succ;\ntwice = succ succ;\n");
|
|
148
144
|
const loadedSource = createState();
|
|
149
145
|
output = await evaluateInput(`:load ${sourcePath}`, loadedSource);
|
|
150
146
|
assert.equal(output[0], `loaded ${sourcePath}`);
|
|
151
|
-
output = await evaluateInput(":types", loadedSource);
|
|
152
|
-
assert.match(output[0], /^nat = @/m);
|
|
153
147
|
output = await evaluateInput(":rels", loadedSource);
|
|
154
148
|
assert.match(output[0], /^succ = @/m);
|
|
155
149
|
output = await evaluateInput(":rel twice", loadedSource);
|
|
156
|
-
assert.match(output[0], /^twice =
|
|
157
|
-
output = await evaluateInput(":C nat", loadedSource);
|
|
158
|
-
assert.match(output[0], /^\$ nat = < nat succ, @[^ ]+ zero >; -- @/);
|
|
150
|
+
assert.match(output[0], /^twice = .*succ succ.*; -- @/);
|
|
159
151
|
|
|
160
152
|
const codecState = createState();
|
|
161
|
-
output = await evaluateInput("$ bool = < {} true, {} false >;", codecState);
|
|
162
|
-
const boolHash = codecState.typeAliases.bool;
|
|
163
153
|
const valueModuleUrl = pathToFileURL(path.resolve("Value.mjs")).href;
|
|
164
154
|
fs.writeFileSync(codecPath, `
|
|
165
155
|
import { Value } from ${JSON.stringify(valueModuleUrl)};
|
|
166
156
|
|
|
167
157
|
export const name = "yn";
|
|
168
|
-
export const codes = [${JSON.stringify(boolHash)}];
|
|
169
158
|
|
|
170
159
|
export function parse(text) {
|
|
171
160
|
const tag = text.trim();
|
|
@@ -249,11 +238,9 @@ const reloaded = createState();
|
|
|
249
238
|
output = await evaluateInput(`:load ${libPath}`, reloaded);
|
|
250
239
|
assert.equal(output[0], `loaded ${libPath}`);
|
|
251
240
|
|
|
252
|
-
output = await evaluateInput(":types", reloaded);
|
|
253
|
-
assert.match(output[0], /^nat = @/m);
|
|
254
|
-
|
|
255
241
|
output = await evaluateInput(":rels", reloaded);
|
|
256
242
|
assert.match(output[0], /^succ = @/m);
|
|
243
|
+
assert.match(output[0], /^zero = @/m);
|
|
257
244
|
|
|
258
245
|
output = await evaluateInput("succ", reloaded);
|
|
259
246
|
assert.equal(output[0], "{}|succ ?<{} succ, ...>");
|
|
@@ -261,25 +248,22 @@ assert.equal(output[0], "{}|succ ?<{} succ, ...>");
|
|
|
261
248
|
const noAliasReloaded = createState();
|
|
262
249
|
output = await evaluateInput(`:load --no-alias ${libPath}`, noAliasReloaded);
|
|
263
250
|
assert.equal(output[0], `loaded ${libPath}`);
|
|
264
|
-
output = await evaluateInput(":types", noAliasReloaded);
|
|
265
|
-
assert.equal(output[0], "(none)");
|
|
266
251
|
output = await evaluateInput(":rels", noAliasReloaded);
|
|
267
252
|
assert.equal(output[0], "(none)");
|
|
268
253
|
|
|
269
254
|
const shorthand = createState();
|
|
270
|
-
output = await evaluateInput("
|
|
255
|
+
output = await evaluateInput("zero = {} | zero\n; succ = |succ\n;", shorthand);
|
|
271
256
|
assert.match(output[0], /\/\* comp: .* \*\//);
|
|
272
|
-
output = await evaluateInput(":types", shorthand);
|
|
273
|
-
assert.match(output[0], /^nat = @/m);
|
|
274
257
|
output = await evaluateInput(":rels", shorthand);
|
|
258
|
+
assert.match(output[0], /^zero = @/m);
|
|
275
259
|
assert.match(output[0], /^succ = @/m);
|
|
276
|
-
output = await evaluateInput("
|
|
260
|
+
output = await evaluateInput("not = </true | false, /false | true >\n; {} | true not", shorthand);
|
|
277
261
|
assert.match(output[0], /^\{\}\|false \?</);
|
|
278
262
|
assert.match(output[0], / false/);
|
|
279
263
|
assert.match(output[0], / true/);
|
|
280
|
-
output = await evaluateInput("
|
|
264
|
+
output = await evaluateInput("maybe = < /none {} | none, /some | some >;", shorthand);
|
|
281
265
|
assert.match(output[0], /\/\* comp: .* \*\//);
|
|
282
|
-
output = await evaluateInput(":
|
|
266
|
+
output = await evaluateInput(":rels", shorthand);
|
|
283
267
|
assert.match(output[0], /^maybe = @/m);
|
|
284
268
|
output = await evaluateInput("{} | true not", shorthand);
|
|
285
269
|
assert.match(output[0], /^\{\}\|false \?</);
|
|
@@ -291,8 +275,7 @@ await assert.rejects(
|
|
|
291
275
|
|
|
292
276
|
// Verify WebAssembly in-process backend supports TCO / stack safety on deep recursion
|
|
293
277
|
const tcoState = createState();
|
|
294
|
-
await evaluateInput("
|
|
295
|
-
await evaluateInput("countdown = $ nat < / zero {} | zero, / succ countdown >;", tcoState);
|
|
278
|
+
await evaluateInput("countdown = ?< {} zero, X succ > = X < / zero {} | zero, / succ countdown >;", tcoState);
|
|
296
279
|
|
|
297
280
|
let deepNat = Value.variant("zero", Value.product({}, [["closed-product", []]]), [["open-union", [["zero", 1]]], ["closed-product", []]]);
|
|
298
281
|
for (let i = 0; i < 5000; i++) {
|
|
@@ -336,7 +319,7 @@ assert.equal(output[0], "unloaded codec int.mjs");
|
|
|
336
319
|
output = await evaluateInput(":codecs", codecTestState);
|
|
337
320
|
assert.equal(output[0], "(none)");
|
|
338
321
|
|
|
339
|
-
output = await evaluateInput("
|
|
322
|
+
output = await evaluateInput("bool = < /true {} | true, /false {} | false >;", codecTestState);
|
|
340
323
|
registerCodec(codecTestState, {
|
|
341
324
|
name: "yn.mjs",
|
|
342
325
|
parse: (text) => Value.variant(text.trim() === "yes" ? "true" : "false", Value.product({})),
|
|
@@ -390,7 +373,9 @@ const ieeeAutoState = createState();
|
|
|
390
373
|
await evaluateInput(":load Examples/ieee.k", ieeeAutoState);
|
|
391
374
|
output = await evaluateInput(":codec load ./codecs/ieee.mjs", ieeeAutoState);
|
|
392
375
|
assert.match(output[0], /^loaded codec ieee\.mjs/);
|
|
393
|
-
assert.ok(ieeeAutoState.
|
|
376
|
+
assert.ok(ieeeAutoState.codecs["ieee.mjs"], "ieee codec should be registered");
|
|
377
|
+
output = await evaluateInput(":input ieee.mjs 1.5", ieeeAutoState);
|
|
378
|
+
assert.match(output[0], /ieee\.mjs: 1\.5/);
|
|
394
379
|
|
|
395
380
|
const jsonInputState = createState();
|
|
396
381
|
await evaluateInput(":load core.k", jsonInputState);
|
|
@@ -453,7 +438,7 @@ const polyAutoState = createState();
|
|
|
453
438
|
output = await evaluateInput(":load Examples/poly.k", polyAutoState);
|
|
454
439
|
assert.equal(output[0], "loaded Examples/poly.k");
|
|
455
440
|
assert.ok(polyAutoState.relAliases.reverse, "poly relations should be loaded");
|
|
456
|
-
assert.ok(polyAutoState.
|
|
441
|
+
assert.ok(polyAutoState.relAliases.int, "arithmetics int should be auto-loaded");
|
|
457
442
|
|
|
458
443
|
// Verify timing reporting is always on and reflects active engine
|
|
459
444
|
const timingState = createState();
|
|
@@ -510,11 +495,11 @@ assert(completions.includes(":engine js"));
|
|
|
510
495
|
const jsState = createState({ engine: "js" });
|
|
511
496
|
assert.equal(jsState.engine, "js");
|
|
512
497
|
|
|
513
|
-
output = await evaluateInput("
|
|
498
|
+
output = await evaluateInput("succ = | succ;\n{} | zero succ succ", jsState);
|
|
514
499
|
assert.match(output[0], /^\{\}\|zero\|succ\|succ/);
|
|
515
500
|
assert.match(output[1], /\(js\)/);
|
|
516
501
|
|
|
517
|
-
output = await evaluateInput("
|
|
502
|
+
output = await evaluateInput("not = </true | false, /false | true >;\n{} | true not", jsState);
|
|
518
503
|
assert.match(output[0], /^\{\}\|false/);
|
|
519
504
|
assert.match(output[1], /\(js\)/);
|
|
520
505
|
|
package/tests/test.mjs
CHANGED
|
@@ -22,9 +22,8 @@ import k from "../index.mjs";
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
let k_expression = `
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
false = {} | false $bool;
|
|
25
|
+
true = {} | true;
|
|
26
|
+
false = {} | false;
|
|
28
27
|
|
|
29
28
|
list? = ?< {} nil, {X car, Y cdr} cons > = Y;
|
|
30
29
|
nil = {}|nil list?;
|