@fraczak/k 6.8.0 → 6.9.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 +10 -0
- package/DOCS/CODECS.md +80 -181
- package/DOCS/CODEC_ARCHITECTURE.md +194 -0
- package/DOCS/REPL.md +41 -39
- package/Examples/arithmetics.k +1 -0
- package/Examples/poly.k +46 -0
- package/browser/repl-browser.mjs +109 -782
- package/browser/shims/process.mjs +7 -0
- package/browser/tree-view.mjs +5 -2
- package/browser/vfs-data.mjs +14 -14
- package/codecs/README.md +7 -0
- package/codecs/ieee.mjs +50 -75
- package/codecs/int.mjs +83 -62
- package/codecs/json-codec.mjs +5 -77
- package/codecs/json.mjs +12 -56
- package/codecs/k-parse.mjs +3 -19
- package/codecs/runtime/codec-sdk.mjs +94 -0
- package/codecs/runtime/pattern-k.mjs +45 -0
- package/codecs/string-codec.mjs +48 -74
- package/codecs/unit.mjs +13 -61
- package/codecs/utf16.mjs +13 -56
- package/codecs/utf8.mjs +11 -55
- package/package.json +1 -1
- package/patterns/from-k.mjs +2 -22
- package/repl-codecs.mjs +69 -196
- package/repl.mjs +63 -187
- package/scripts/build-repl-html.mjs +87 -379
- package/scripts/run-tests.mjs +1 -0
- package/tests/test-codecs.mjs +186 -0
- package/tests/test-poly.mjs +44 -0
- package/tests/test-repl-html.mjs +123 -64
- package/tests/test-repl.mjs +120 -134
- package/tests/test-structural-values.mjs +17 -0
- package/tests/test-tree-view.mjs +3 -0
- package/codecs/example-pipeline.mjs +0 -163
- package/codecs/runtime/ieee-pattern.mjs +0 -30
- package/codecs/runtime/test-codec.mjs +0 -89
- package/codecs/runtime/typeFromValue.mjs +0 -34
package/tests/test-repl.mjs
CHANGED
|
@@ -160,6 +160,9 @@ export function parse(text) {
|
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
export function print(value) {
|
|
163
|
+
if (!value || (value.tag !== "true" && value.tag !== "false")) {
|
|
164
|
+
throw new Error("expected true or false");
|
|
165
|
+
}
|
|
163
166
|
return value.tag;
|
|
164
167
|
}
|
|
165
168
|
`);
|
|
@@ -172,58 +175,52 @@ assert(completions.includes(":codec list"));
|
|
|
172
175
|
completions = completeInput(`:codec load ${tmpDir}/bool`, codecState)[0];
|
|
173
176
|
assert(completions.includes(`:codec load ${codecPath}`));
|
|
174
177
|
output = await evaluateInput(`:codec load ${codecPath}`, codecState);
|
|
175
|
-
assert.equal(output[0], `loaded codec
|
|
178
|
+
assert.equal(output[0], `loaded codec bool-codec.mjs`);
|
|
176
179
|
output = await evaluateInput(":codec list", codecState);
|
|
177
|
-
assert.match(output[0],
|
|
178
|
-
completions = completeInput(":input
|
|
179
|
-
assert(completions.includes(":input
|
|
180
|
-
completions = completeInput(":input
|
|
181
|
-
assert(completions.includes(":input bool
|
|
182
|
-
|
|
183
|
-
assert.
|
|
180
|
+
assert.match(output[0], /^bool-codec\.mjs/);
|
|
181
|
+
completions = completeInput(":input", codecState)[0];
|
|
182
|
+
assert(completions.includes(":input"));
|
|
183
|
+
completions = completeInput(":input ", codecState)[0];
|
|
184
|
+
assert(completions.includes(":input bool-codec.mjs"));
|
|
185
|
+
completions = completeInput(":input b", codecState)[0];
|
|
186
|
+
assert(completions.includes(":input bool-codec.mjs"));
|
|
187
|
+
output = await evaluateInput(":input bool-codec.mjs", codecState);
|
|
188
|
+
assert.equal(promptForState(codecState), "bool-codec.mjs> ");
|
|
184
189
|
output = await evaluateInput("true", codecState);
|
|
185
190
|
assert.match(output[0], /\{\}\|true \?</);
|
|
186
|
-
assert.match(output[0], /
|
|
191
|
+
assert.match(output[0], /bool-codec\.mjs: true/);
|
|
187
192
|
output = await evaluateInput("{} | false", codecState);
|
|
188
|
-
assert.
|
|
193
|
+
assert.match(output[0], /bool-codec\.mjs: false/);
|
|
194
|
+
output = await evaluateInput("{}", codecState);
|
|
195
|
+
assert.doesNotMatch(output[0], /bool-codec\.mjs:/);
|
|
189
196
|
|
|
190
197
|
const utf8State = createState();
|
|
191
198
|
output = await evaluateInput(":load core.k", utf8State);
|
|
192
199
|
assert.equal(output[0], "loaded core.k");
|
|
193
200
|
output = await evaluateInput(":codec load ./codecs/utf8.mjs", utf8State);
|
|
194
|
-
assert.equal(output[0], `loaded codec utf8
|
|
195
|
-
output = await evaluateInput(":input
|
|
196
|
-
assert.
|
|
197
|
-
output = await evaluateInput("hello", utf8State);
|
|
198
|
-
assert.match(output[0], /utf8: hello/);
|
|
201
|
+
assert.equal(output[0], `loaded codec utf8.mjs`);
|
|
202
|
+
output = await evaluateInput(":input utf8.mjs hello", utf8State);
|
|
203
|
+
assert.match(output[0], /utf8\.mjs: hello/);
|
|
199
204
|
|
|
200
205
|
const jsonState = createState();
|
|
201
|
-
output = await evaluateInput("$ bool = < {} true, {} false >;", jsonState);
|
|
202
206
|
output = await evaluateInput(":codec load ./codecs/json.mjs", jsonState);
|
|
203
|
-
assert.match(output[0], /^loaded codec json
|
|
207
|
+
assert.match(output[0], /^loaded codec json\.mjs/);
|
|
204
208
|
output = await evaluateInput(":codec list", jsonState);
|
|
205
|
-
assert.match(output[0], /^json
|
|
206
|
-
completions = completeInput(":input
|
|
207
|
-
assert(completions.includes(":input
|
|
208
|
-
output = await evaluateInput(":input
|
|
209
|
-
assert.equal(
|
|
210
|
-
assert.equal(promptForState(jsonState), "json> ");
|
|
209
|
+
assert.match(output[0], /^json\.mjs/);
|
|
210
|
+
completions = completeInput(":input j", jsonState)[0];
|
|
211
|
+
assert(completions.includes(":input json.mjs"));
|
|
212
|
+
output = await evaluateInput(":input json.mjs", jsonState);
|
|
213
|
+
assert.equal(promptForState(jsonState), "json.mjs> ");
|
|
211
214
|
output = await evaluateInput("true", jsonState);
|
|
212
215
|
assert.match(output[0], /\{\}\|true \?</);
|
|
213
|
-
assert.match(output[0], /json: true/);
|
|
216
|
+
assert.match(output[0], /json\.mjs: true/);
|
|
214
217
|
assert.equal(promptForState(jsonState), "> ");
|
|
215
|
-
output = await evaluateInput(":input
|
|
216
|
-
assert.equal(output[0], `input ${jsonState.typeAliases.bool}: enter value text`);
|
|
217
|
-
assert.equal(promptForState(jsonState), "json> ");
|
|
218
|
-
output = await evaluateInput("false", jsonState);
|
|
218
|
+
output = await evaluateInput(":input json.mjs false", jsonState);
|
|
219
219
|
assert.match(output[0], /\{\}\|false \?</);
|
|
220
|
-
assert.match(output[0], /json: false/);
|
|
220
|
+
assert.match(output[0], /json\.mjs: false/);
|
|
221
221
|
assert.equal(promptForState(jsonState), "> ");
|
|
222
|
-
output = await evaluateInput(
|
|
223
|
-
assert.match(output[0],
|
|
224
|
-
assert.equal(promptForState(jsonState), "json> ");
|
|
225
|
-
output = await evaluateInput('{"left":true,"right":false}', jsonState);
|
|
226
|
-
assert.match(output[0], /json: \{"left":true,"right":false\}/);
|
|
222
|
+
output = await evaluateInput(':input json.mjs {"left":true,"right":false}', jsonState);
|
|
223
|
+
assert.match(output[0], /json\.mjs: \{"left":true,"right":false\}/);
|
|
227
224
|
assert.equal(promptForState(jsonState), "> ");
|
|
228
225
|
|
|
229
226
|
const replPath = fileURLToPath(new URL("../repl.mjs", import.meta.url));
|
|
@@ -302,41 +299,45 @@ assert.match(output[0], /^\{\}\|_\|0\|1\|0\|1/);
|
|
|
302
299
|
output = await evaluateInput("{10 int x, 5 int y} plus", arithState);
|
|
303
300
|
assert.match(output[0], /^\{\}\|_\|1\|1\|1\|1\|\+/);
|
|
304
301
|
|
|
305
|
-
// Verify
|
|
302
|
+
// Verify codecs loading, listing, and unloading
|
|
306
303
|
const codecTestState = createState();
|
|
307
304
|
output = await evaluateInput(":codecs", codecTestState);
|
|
308
305
|
assert.equal(output[0], "(none)");
|
|
309
306
|
|
|
310
|
-
output = await evaluateInput(":codec load int", codecTestState);
|
|
311
|
-
assert.match(output[0], /^loaded codec int
|
|
307
|
+
output = await evaluateInput(":codec load ./codecs/int.mjs", codecTestState);
|
|
308
|
+
assert.match(output[0], /^loaded codec int\.mjs/);
|
|
312
309
|
|
|
313
310
|
output = await evaluateInput(":codecs", codecTestState);
|
|
314
|
-
assert.match(output[0], /^int
|
|
311
|
+
assert.match(output[0], /^int\.mjs/);
|
|
315
312
|
|
|
316
313
|
completions = completeInput(":codec un", codecTestState)[0];
|
|
317
314
|
assert(completions.includes(":codec unload"));
|
|
318
315
|
completions = completeInput(":codec unload ", codecTestState)[0];
|
|
319
|
-
assert(completions.includes(":codec unload int"));
|
|
320
|
-
completions = completeInput(":codec load i", codecTestState)[0];
|
|
321
|
-
assert(completions.includes(":codec load int"));
|
|
316
|
+
assert(completions.includes(":codec unload int.mjs"));
|
|
317
|
+
completions = completeInput(":codec load ./codecs/i", codecTestState)[0];
|
|
318
|
+
assert(completions.includes(":codec load ./codecs/int.mjs"));
|
|
322
319
|
|
|
323
|
-
output = await evaluateInput(":codec unload int", codecTestState);
|
|
324
|
-
assert.equal(output[0], "unloaded codec int");
|
|
320
|
+
output = await evaluateInput(":codec unload int.mjs", codecTestState);
|
|
321
|
+
assert.equal(output[0], "unloaded codec int.mjs");
|
|
325
322
|
output = await evaluateInput(":codecs", codecTestState);
|
|
326
323
|
assert.equal(output[0], "(none)");
|
|
327
324
|
|
|
328
325
|
output = await evaluateInput("$ bool = < {} true, {} false >;", codecTestState);
|
|
329
326
|
registerCodec(codecTestState, {
|
|
330
|
-
name: "yn",
|
|
331
|
-
codes: [codecTestState.typeAliases.bool],
|
|
332
|
-
universal: false,
|
|
327
|
+
name: "yn.mjs",
|
|
333
328
|
parse: (text) => Value.variant(text.trim() === "yes" ? "true" : "false", Value.product({})),
|
|
334
|
-
print: (v) =>
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
329
|
+
print: (v) => {
|
|
330
|
+
if (v.tag !== "true" && v.tag !== "false") throw new Error("not a bool");
|
|
331
|
+
return v.tag === "true" ? "YES" : "NO";
|
|
332
|
+
}
|
|
333
|
+
}, "yn.mjs");
|
|
334
|
+
|
|
335
|
+
output = await evaluateInput(":input yn.mjs", codecTestState);
|
|
336
|
+
assert.equal(promptForState(codecTestState), "yn.mjs> ");
|
|
338
337
|
output = await evaluateInput("yes", codecTestState);
|
|
339
|
-
assert.match(output[0], /yn: YES/);
|
|
338
|
+
assert.match(output[0], /yn\.mjs: YES/);
|
|
339
|
+
output = await evaluateInput(":input yn.mjs no", codecTestState);
|
|
340
|
+
assert.match(output[0], /yn\.mjs: NO/);
|
|
340
341
|
|
|
341
342
|
// Projection on product with variant field (avoids filter variable collisions)
|
|
342
343
|
const projState = createState();
|
|
@@ -351,103 +352,88 @@ assert.match(output[0], /^\{\{\}\|a a, \{\} y\}/);
|
|
|
351
352
|
output = await evaluateInput(".a", projState2);
|
|
352
353
|
assert.match(output[0], /^\{\}\|a/);
|
|
353
354
|
|
|
354
|
-
//
|
|
355
|
-
const
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
assert.
|
|
359
|
-
output = await evaluateInput(":input int",
|
|
360
|
-
output = await evaluateInput("123",
|
|
361
|
-
assert.match(output[0], /int: 123/);
|
|
355
|
+
// Explicit loading of dependencies and codec testing (no auto-loading)
|
|
356
|
+
const intState = createState();
|
|
357
|
+
await evaluateInput(":load Examples/arithmetics.k", intState);
|
|
358
|
+
output = await evaluateInput(":codec load ./codecs/int.mjs", intState);
|
|
359
|
+
assert.match(output[0], /^loaded codec int\.mjs/);
|
|
360
|
+
output = await evaluateInput(":input int.mjs", intState);
|
|
361
|
+
output = await evaluateInput("123", intState);
|
|
362
|
+
assert.match(output[0], /int\.mjs: 123/);
|
|
363
|
+
output = await evaluateInput(":input int.mjs", intState);
|
|
364
|
+
output = await evaluateInput("[0,1,2]", intState);
|
|
365
|
+
assert.match(output[0], /int\.mjs: \[0,1,2\]/);
|
|
362
366
|
|
|
363
367
|
const utf8AutoState = createState();
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
assert.
|
|
367
|
-
|
|
368
|
-
assert.equal(utf8AutoState.typeAliases.utf8, utf8AutoState.typeAliases.string);
|
|
369
|
-
output = await evaluateInput(":input utf8", utf8AutoState);
|
|
368
|
+
await evaluateInput(":load core.k", utf8AutoState);
|
|
369
|
+
output = await evaluateInput(":codec load ./codecs/utf8.mjs", utf8AutoState);
|
|
370
|
+
assert.match(output[0], /^loaded codec utf8\.mjs/);
|
|
371
|
+
output = await evaluateInput(":input utf8.mjs", utf8AutoState);
|
|
370
372
|
output = await evaluateInput("test utf8", utf8AutoState);
|
|
371
|
-
assert.match(output[0], /utf8: test utf8/);
|
|
373
|
+
assert.match(output[0], /utf8\.mjs: test utf8/);
|
|
372
374
|
|
|
373
375
|
const ieeeAutoState = createState();
|
|
374
|
-
|
|
375
|
-
|
|
376
|
+
await evaluateInput(":load Examples/ieee.k", ieeeAutoState);
|
|
377
|
+
output = await evaluateInput(":codec load ./codecs/ieee.mjs", ieeeAutoState);
|
|
378
|
+
assert.match(output[0], /^loaded codec ieee\.mjs/);
|
|
376
379
|
assert.ok(ieeeAutoState.typeAliases.ieee, "ieee type alias should be registered");
|
|
377
|
-
assert.ok(ieeeAutoState.typeAliases.float64, "float64 type alias should be registered");
|
|
378
|
-
assert.equal(ieeeAutoState.typeAliases.ieee, ieeeAutoState.typeAliases.float64);
|
|
379
380
|
|
|
380
381
|
const jsonInputState = createState();
|
|
381
382
|
await evaluateInput(":load core.k", jsonInputState);
|
|
382
|
-
await evaluateInput(":load ieee.k", jsonInputState);
|
|
383
|
-
await evaluateInput(":codec load json", jsonInputState);
|
|
384
|
-
output = await evaluateInput(
|
|
385
|
-
assert.match(output[0], /
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
await evaluateInput(":codec load
|
|
392
|
-
|
|
393
|
-
// 1.
|
|
394
|
-
output = await evaluateInput(
|
|
395
|
-
assert.match(output[0], /
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
output = await evaluateInput(":
|
|
401
|
-
assert.match(output[0], /
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
output
|
|
407
|
-
|
|
408
|
-
output = await evaluateInput(
|
|
409
|
-
assert.match(output[0], /
|
|
410
|
-
|
|
411
|
-
// 4.
|
|
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
|
|
383
|
+
await evaluateInput(":load Examples/ieee.k", jsonInputState);
|
|
384
|
+
await evaluateInput(":codec load ./codecs/json.mjs", jsonInputState);
|
|
385
|
+
output = await evaluateInput(':input json.mjs {"a":"Woj","n":123}', jsonInputState);
|
|
386
|
+
assert.match(output[0], /json\.mjs: \{"a":"Woj","n":123\}/);
|
|
387
|
+
|
|
388
|
+
// Verify standalone codec input, one-line and interactive modes, and multi-codec printing
|
|
389
|
+
const multiCodecState = createState();
|
|
390
|
+
await evaluateInput(":codec load ./codecs/json.mjs", multiCodecState);
|
|
391
|
+
await evaluateInput(":codec load ./codecs/utf8.mjs", multiCodecState);
|
|
392
|
+
await evaluateInput(":codec load ./codecs/int.mjs", multiCodecState);
|
|
393
|
+
|
|
394
|
+
// 1. One-line JSON input: :input json.mjs {"hello":"world"}
|
|
395
|
+
output = await evaluateInput(':input json.mjs {"hello":"world"}', multiCodecState);
|
|
396
|
+
assert.match(output[0], /json\.mjs: \{"hello":"world"\}/);
|
|
397
|
+
|
|
398
|
+
// 2. Interactive JSON input: :input json.mjs then {"anything": [1, 2, 3]}
|
|
399
|
+
output = await evaluateInput(":input json.mjs", multiCodecState);
|
|
400
|
+
assert.equal(promptForState(multiCodecState), "json.mjs> ");
|
|
401
|
+
output = await evaluateInput('{"anything": [1, 2, 3]}', multiCodecState);
|
|
402
|
+
assert.match(output[0], /json\.mjs: \{"anything":\[1,2,3\]\}/);
|
|
403
|
+
assert.equal(promptForState(multiCodecState), "> ");
|
|
404
|
+
|
|
405
|
+
// 3. Integer scalar and list input
|
|
406
|
+
output = await evaluateInput(":input int.mjs 42", multiCodecState);
|
|
407
|
+
assert.match(output[0], /int\.mjs: 42/);
|
|
408
|
+
|
|
409
|
+
output = await evaluateInput(":input int.mjs [0,1,2]", multiCodecState);
|
|
410
|
+
assert.match(output[0], /int\.mjs: \[0,1,2\]/);
|
|
411
|
+
|
|
412
|
+
// 4. Bare :input displays usage and loaded codecs
|
|
419
413
|
const bareInputState = createState();
|
|
420
|
-
assert.equal(promptForState(bareInputState), "> ");
|
|
421
414
|
output = await evaluateInput(":input", bareInputState);
|
|
422
|
-
assert.
|
|
423
|
-
assert.
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
assert.
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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/);
|
|
415
|
+
assert.match(output[0], /^Usage: :input <codec\.mjs> \[text\]/);
|
|
416
|
+
assert.match(output[1], /Loaded codecs:/);
|
|
417
|
+
|
|
418
|
+
// 5. Codec with leading dollar sign is accepted
|
|
419
|
+
output = await evaluateInput(":input $ int.mjs 42", multiCodecState);
|
|
420
|
+
assert.match(output[0], /int\.mjs: 42/);
|
|
421
|
+
output = await evaluateInput(":input $int.mjs 100", multiCodecState);
|
|
422
|
+
assert.match(output[0], /int\.mjs: 100/);
|
|
423
|
+
|
|
424
|
+
// 6. Unknown codec throws descriptive error
|
|
425
|
+
await assert.rejects(
|
|
426
|
+
() => evaluateInput(":input nonexistent 123", multiCodecState),
|
|
427
|
+
/Codec 'nonexistent' is not loaded/
|
|
428
|
+
);
|
|
443
429
|
|
|
444
430
|
const unitState = createState();
|
|
445
|
-
output = await evaluateInput(":codec load unit", unitState);
|
|
446
|
-
assert.match(output[0],
|
|
447
|
-
output = await evaluateInput(":input unit", unitState);
|
|
448
|
-
assert.
|
|
431
|
+
output = await evaluateInput(":codec load ./codecs/unit.mjs", unitState);
|
|
432
|
+
assert.match(output[0], /^loaded codec unit\.mjs/);
|
|
433
|
+
output = await evaluateInput(":input unit.mjs", unitState);
|
|
434
|
+
assert.equal(promptForState(unitState), "unit.mjs> ");
|
|
449
435
|
output = await evaluateInput("{}", unitState);
|
|
450
|
-
assert.match(output[0], /unit: \{\}/);
|
|
436
|
+
assert.match(output[0], /unit\.mjs: \{\}/);
|
|
451
437
|
|
|
452
438
|
const polyAutoState = createState();
|
|
453
439
|
output = await evaluateInput(":load Examples/poly.k", polyAutoState);
|
|
@@ -25,3 +25,20 @@ assert.equal(valueToK(foreignTwo), "{}|_|0|1|+");
|
|
|
25
25
|
|
|
26
26
|
const decoded = decodeWire(encodeToWire(foreignTwo, INT_PATTERN)).value;
|
|
27
27
|
assert.equal(printInt(decoded), "2");
|
|
28
|
+
|
|
29
|
+
const { INT_LIST_PATTERN, parse: parseIntCodec } = await import("../codecs/int.mjs");
|
|
30
|
+
const { valueWithEnvelopeToK } = await import("../codecs/runtime/show-value.mjs");
|
|
31
|
+
|
|
32
|
+
const parsedList = parseIntCodec("[0,1,2]");
|
|
33
|
+
const listWire = encodeToWire(parsedList, INT_LIST_PATTERN);
|
|
34
|
+
const decodedList = decodeWire(listWire).value;
|
|
35
|
+
assert.equal(
|
|
36
|
+
valueWithEnvelopeToK(decodedList),
|
|
37
|
+
"{{}|_|0|+ car, {{}|_|1|+ car, {{}|_|0|1|+ car, {}|nil cdr}|cons cdr}|cons cdr}|cons ?<{<<X1 0, X1 1, {}=X2 _>=X1 +, X1 -> car, X0 cdr} cons, X2 nil>=X0"
|
|
38
|
+
);
|
|
39
|
+
assert.equal(printInt(decodedList), "[0,1,2]");
|
|
40
|
+
|
|
41
|
+
const emptyList = parseIntCodec("[]");
|
|
42
|
+
const emptyWire = encodeToWire(emptyList, INT_LIST_PATTERN);
|
|
43
|
+
const decodedEmpty = decodeWire(emptyWire).value;
|
|
44
|
+
assert.equal(printInt(decodedEmpty), "[]");
|
package/tests/test-tree-view.mjs
CHANGED
|
@@ -172,6 +172,7 @@ assert.strictEqual(patTree.open, true, "Root pattern node must be open");
|
|
|
172
172
|
assert(patTree.textContent.includes("recursive"), "Recursive cycle must be detected and marked 'recursive'");
|
|
173
173
|
|
|
174
174
|
// 5. Test createOutputEntryElement
|
|
175
|
+
variantVal.pattern = recursivePattern;
|
|
175
176
|
const entryEl = createOutputEntryElement({
|
|
176
177
|
value: variantVal,
|
|
177
178
|
rawText: "{}|_|1|0|1|+ ?<<X0 0, X0 1, {} _>=X0 +, X0 ->\nint: 11",
|
|
@@ -180,6 +181,8 @@ const entryEl = createOutputEntryElement({
|
|
|
180
181
|
|
|
181
182
|
assert(entryEl.querySelector(".k-tree-view"), "Tree view container must exist");
|
|
182
183
|
assert(entryEl.querySelector(".k-raw-view"), "Raw view container must exist");
|
|
184
|
+
assert.strictEqual(entryEl.querySelector(".k-tree-value-section")?.open, false, "Value section must be collapsed by default");
|
|
185
|
+
assert.strictEqual(entryEl.querySelector(".k-tree-pat-section")?.open, false, "Pattern section must be collapsed by default");
|
|
183
186
|
assert(entryEl.textContent.includes("int: 11"), "Codec output must be visible in container");
|
|
184
187
|
|
|
185
188
|
console.log("OK - All tree view unit tests passed.");
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Example: Demonstrating the codec pipeline
|
|
4
|
-
*
|
|
5
|
-
* Shows how to:
|
|
6
|
-
* 1. Define types with canonical names
|
|
7
|
-
* 2. Create values
|
|
8
|
-
* 3. Encode to binary
|
|
9
|
-
* 4. Pass through "compiled program" (identity)
|
|
10
|
-
* 5. Decode from binary
|
|
11
|
-
* 6. Print result
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { deriveClosedPattern } from './runtime/codec.mjs';
|
|
15
|
-
import { encodeToWire, decodeWire } from './runtime/prefix-codec.mjs';
|
|
16
|
-
import { patternToPropertyList } from './runtime/pattern-json.mjs';
|
|
17
|
-
import { Value, isVariant } from '../Value.mjs';
|
|
18
|
-
import hash from '../hash.mjs';
|
|
19
|
-
import { argv, exit } from 'node:process';
|
|
20
|
-
|
|
21
|
-
function usage() {
|
|
22
|
-
console.log(`Usage: ${argv[1]}`);
|
|
23
|
-
console.log(" Run a self-contained demonstration of the codec pipeline.");
|
|
24
|
-
console.log("");
|
|
25
|
-
console.log("Options:");
|
|
26
|
-
console.log(" -h, --help Show this help.");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (argv.slice(2).includes("-h") || argv.slice(2).includes("--help")) {
|
|
30
|
-
usage();
|
|
31
|
-
exit(0);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
console.log('=== K Codec Pipeline Example ===\n');
|
|
35
|
-
|
|
36
|
-
// ============================================================================
|
|
37
|
-
// Step 1: Define types (normally from compiler)
|
|
38
|
-
// ============================================================================
|
|
39
|
-
|
|
40
|
-
const types = {};
|
|
41
|
-
|
|
42
|
-
// Unit: {}
|
|
43
|
-
const unitDef = { code: 'product', product: {} };
|
|
44
|
-
const unitName = hash('$C0={};');
|
|
45
|
-
types[unitName] = unitDef;
|
|
46
|
-
|
|
47
|
-
// Bool: <{} false, {} true>
|
|
48
|
-
const boolDef = {
|
|
49
|
-
code: 'union',
|
|
50
|
-
union: { false: unitName, true: unitName }
|
|
51
|
-
};
|
|
52
|
-
const boolName = hash(`$C0=<${unitName}"false",${unitName}"true">;`);
|
|
53
|
-
types[boolName] = boolDef;
|
|
54
|
-
|
|
55
|
-
// Maybe: <{} nothing, Bool something>
|
|
56
|
-
const maybeDef = {
|
|
57
|
-
code: 'union',
|
|
58
|
-
union: { nothing: unitName, something: boolName }
|
|
59
|
-
};
|
|
60
|
-
const maybeName = hash(
|
|
61
|
-
`$C0=<${unitName}"nothing",${boolName}"something">;`
|
|
62
|
-
);
|
|
63
|
-
types[maybeName] = maybeDef;
|
|
64
|
-
|
|
65
|
-
console.log('Types defined:');
|
|
66
|
-
console.log(' unit:', unitName);
|
|
67
|
-
console.log(' bool:', boolName);
|
|
68
|
-
console.log(' maybe:', maybeName);
|
|
69
|
-
console.log();
|
|
70
|
-
|
|
71
|
-
// ============================================================================
|
|
72
|
-
// Step 2: Type resolver
|
|
73
|
-
// ============================================================================
|
|
74
|
-
|
|
75
|
-
function resolveType(typeName) {
|
|
76
|
-
const def = types[typeName];
|
|
77
|
-
if (!def) {
|
|
78
|
-
throw new Error(`Unknown type: ${typeName}`);
|
|
79
|
-
}
|
|
80
|
-
return def;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// ============================================================================
|
|
84
|
-
// Step 3: Create input value: Maybe Bool = something(true)
|
|
85
|
-
// ============================================================================
|
|
86
|
-
|
|
87
|
-
const inputValue = Value.variant(
|
|
88
|
-
'something',
|
|
89
|
-
Value.variant('true', Value.product({}))
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
console.log('Input value:', inputValue.toString());
|
|
93
|
-
console.log();
|
|
94
|
-
|
|
95
|
-
const maybePattern = patternToPropertyList(
|
|
96
|
-
deriveClosedPattern(maybeName, maybeDef, resolveType)
|
|
97
|
-
);
|
|
98
|
-
|
|
99
|
-
// ============================================================================
|
|
100
|
-
// Step 4: Parse (TEXT → BINARY)
|
|
101
|
-
// ============================================================================
|
|
102
|
-
|
|
103
|
-
console.log('--- PARSE (text → binary) ---');
|
|
104
|
-
const binaryInput = encodeToWire(inputValue, maybePattern);
|
|
105
|
-
console.log('Binary size:', binaryInput.length, 'bytes');
|
|
106
|
-
console.log(' Bytes:', binaryInput.toString('hex'));
|
|
107
|
-
console.log();
|
|
108
|
-
|
|
109
|
-
// ============================================================================
|
|
110
|
-
// Step 5: Compiled k-program (BINARY → BINARY)
|
|
111
|
-
// ============================================================================
|
|
112
|
-
|
|
113
|
-
console.log('--- COMPILED PROGRAM (binary → binary) ---');
|
|
114
|
-
|
|
115
|
-
// Simulate a compiled k-program: decode → transform → encode
|
|
116
|
-
const { value: programInput } = decodeWire(binaryInput);
|
|
117
|
-
|
|
118
|
-
console.log('Program sees value:', programInput.toString());
|
|
119
|
-
|
|
120
|
-
// Example transformation: NOT operation (flip bool inside Maybe)
|
|
121
|
-
let programOutput;
|
|
122
|
-
if (isVariant(programInput) && programInput.tag === 'something') {
|
|
123
|
-
const innerBool = programInput.value;
|
|
124
|
-
if (isVariant(innerBool)) {
|
|
125
|
-
const flipped = Value.variant(
|
|
126
|
-
innerBool.tag === 'true' ? 'false' : 'true',
|
|
127
|
-
innerBool.value
|
|
128
|
-
);
|
|
129
|
-
programOutput = Value.variant('something', flipped);
|
|
130
|
-
}
|
|
131
|
-
} else {
|
|
132
|
-
programOutput = programInput; // nothing → nothing
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
console.log('Program output value:', programOutput.toString());
|
|
136
|
-
|
|
137
|
-
// Encode output
|
|
138
|
-
const binaryOutput = encodeToWire(programOutput, maybePattern);
|
|
139
|
-
|
|
140
|
-
console.log('Binary output size:', binaryOutput.length, 'bytes');
|
|
141
|
-
console.log(' Bytes:', binaryOutput.toString('hex'));
|
|
142
|
-
console.log();
|
|
143
|
-
|
|
144
|
-
// ============================================================================
|
|
145
|
-
// Step 6: Print (BINARY → TEXT)
|
|
146
|
-
// ============================================================================
|
|
147
|
-
|
|
148
|
-
console.log('--- PRINT (binary → text) ---');
|
|
149
|
-
const { value: finalValue } = decodeWire(binaryOutput);
|
|
150
|
-
|
|
151
|
-
console.log('Output value:', finalValue.toString());
|
|
152
|
-
console.log();
|
|
153
|
-
|
|
154
|
-
// ============================================================================
|
|
155
|
-
// Summary
|
|
156
|
-
// ============================================================================
|
|
157
|
-
|
|
158
|
-
console.log('=== Pipeline Summary ===');
|
|
159
|
-
console.log('Input: ', inputValue.toString(), '(true inside Maybe)');
|
|
160
|
-
console.log('Transform: NOT operation on inner bool');
|
|
161
|
-
console.log('Output: ', finalValue.toString(), '(false inside Maybe)');
|
|
162
|
-
console.log();
|
|
163
|
-
console.log('Binary representations are canonical and type-safe!');
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import { parse as parseScript } from "../../parser.mjs";
|
|
3
|
-
import codes from "../../codes.mjs";
|
|
4
|
-
import { deriveClosedPattern } from "./codec.mjs";
|
|
5
|
-
import { patternToPropertyList } from "./pattern-json.mjs";
|
|
6
|
-
|
|
7
|
-
const IEEE_SCRIPT = fs.readFileSync(new URL("../../Examples/ieee.k", import.meta.url), "utf8");
|
|
8
|
-
|
|
9
|
-
function loadFloat64Pattern() {
|
|
10
|
-
const { defs } = parseScript(IEEE_SCRIPT);
|
|
11
|
-
const { codes: finalizedCodes, representatives } = codes.finalize(defs.codes);
|
|
12
|
-
const typeName = representatives.float64 || "float64";
|
|
13
|
-
const typeInfo = finalizedCodes[typeName];
|
|
14
|
-
if (!typeInfo) {
|
|
15
|
-
throw new Error("Could not resolve float64 type from Examples/ieee.k");
|
|
16
|
-
}
|
|
17
|
-
const resolveType = (name) => {
|
|
18
|
-
const type = finalizedCodes[name];
|
|
19
|
-
if (!type) {
|
|
20
|
-
throw new Error(`Unknown IEEE helper type '${name}'`);
|
|
21
|
-
}
|
|
22
|
-
return type;
|
|
23
|
-
};
|
|
24
|
-
return patternToPropertyList(deriveClosedPattern(typeName, typeInfo, resolveType));
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const FLOAT64_PATTERN = loadFloat64Pattern();
|
|
28
|
-
|
|
29
|
-
export { FLOAT64_PATTERN, loadFloat64Pattern };
|
|
30
|
-
export default { FLOAT64_PATTERN, loadFloat64Pattern };
|