functionalscript 0.8.2 → 0.9.2

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.
Files changed (91) hide show
  1. package/README.md +5 -5
  2. package/bnf/data/module.f.d.ts +10 -1
  3. package/bnf/data/module.f.js +58 -19
  4. package/bnf/data/test.f.d.ts +2 -0
  5. package/bnf/data/test.f.js +244 -3
  6. package/bnf/module.f.d.ts +6 -2
  7. package/bnf/module.f.js +8 -9
  8. package/cas/module.f.d.ts +18 -0
  9. package/cas/module.f.js +95 -0
  10. package/cas/test.f.d.ts +2 -0
  11. package/cas/test.f.js +1 -0
  12. package/ci/module.f.d.ts +3 -2
  13. package/ci/module.f.js +11 -9
  14. package/ci/module.js +3 -3
  15. package/crypto/sha2/module.f.js +0 -1
  16. package/dev/module.f.d.ts +1 -1
  17. package/dev/module.f.js +14 -6
  18. package/dev/version/module.f.d.ts +2 -11
  19. package/dev/version/module.f.js +17 -14
  20. package/dev/version/test.f.d.ts +3 -1
  21. package/dev/version/test.f.js +26 -10
  22. package/djs/module.f.d.ts +1 -1
  23. package/djs/module.f.js +4 -4
  24. package/djs/parser-new/module.f.d.ts +3 -0
  25. package/djs/parser-new/module.f.js +150 -0
  26. package/djs/parser-new/test.f.d.ts +5 -0
  27. package/djs/parser-new/test.f.js +201 -0
  28. package/djs/serializer/module.f.js +6 -6
  29. package/djs/transpiler/module.f.js +3 -2
  30. package/djs/transpiler/test.f.js +12 -11
  31. package/fjs/module.f.d.ts +2 -0
  32. package/fjs/module.f.js +25 -0
  33. package/{dev/tf → fjs}/module.js +1 -1
  34. package/fsc/module.f.js +1 -1
  35. package/io/module.d.ts +4 -0
  36. package/io/module.f.d.ts +14 -13
  37. package/io/module.f.js +21 -0
  38. package/io/module.js +7 -1
  39. package/io/virtual/module.f.d.ts +1 -1
  40. package/io/virtual/module.f.js +3 -3
  41. package/js/tokenizer/module.f.d.ts +1 -1
  42. package/js/tokenizer/module.f.js +0 -1
  43. package/json/module.f.js +3 -3
  44. package/nanvm-lib/tests/test.f.d.ts +1 -1
  45. package/nanvm-lib/tests/test.f.js +114 -104
  46. package/package.json +6 -7
  47. package/path/module.f.d.ts +1 -0
  48. package/path/module.f.js +6 -3
  49. package/text/utf16/module.f.js +1 -1
  50. package/types/bit_vec/module.f.d.ts +1 -0
  51. package/types/bit_vec/module.f.js +1 -0
  52. package/types/btree/find/module.f.d.ts +7 -8
  53. package/types/btree/set/module.f.js +21 -0
  54. package/types/cbase32/module.f.d.ts +6 -0
  55. package/types/cbase32/module.f.js +71 -0
  56. package/types/cbase32/test.f.d.ts +7 -0
  57. package/types/cbase32/test.f.js +74 -0
  58. package/types/effect/mock/module.f.d.ts +5 -0
  59. package/types/effect/mock/module.f.js +14 -0
  60. package/types/effect/module.d.ts +2 -0
  61. package/types/effect/module.f.d.ts +23 -0
  62. package/types/effect/module.f.js +14 -0
  63. package/types/effect/module.js +11 -0
  64. package/types/effect/node/module.f.d.ts +52 -0
  65. package/types/effect/node/module.f.js +7 -0
  66. package/types/effect/node/test.f.d.ts +27 -0
  67. package/types/effect/node/test.f.js +259 -0
  68. package/types/effect/node/virtual/module.f.d.ts +13 -0
  69. package/types/effect/node/virtual/module.f.js +98 -0
  70. package/types/function/module.f.d.ts +1 -1
  71. package/types/function/module.f.js +1 -1
  72. package/types/function/test.f.js +1 -1
  73. package/types/list/module.f.d.ts +1 -0
  74. package/types/list/module.f.js +6 -6
  75. package/types/nullable/module.f.d.ts +2 -0
  76. package/types/nullable/module.f.js +1 -0
  77. package/types/nullable/test.f.d.ts +1 -1
  78. package/types/nullable/test.f.js +23 -11
  79. package/types/option/module.f.d.ts +9 -0
  80. package/types/option/module.f.js +6 -0
  81. package/types/uint8array/module.f.d.ts +11 -0
  82. package/types/uint8array/module.f.js +21 -0
  83. package/types/uint8array/test.f.d.ts +12 -0
  84. package/types/uint8array/test.f.js +58 -0
  85. package/website/module.d.ts +1 -0
  86. package/website/module.f.d.ts +3 -0
  87. package/website/module.f.js +9 -0
  88. package/website/module.js +3 -0
  89. package/fsc/module.d.ts +0 -2
  90. package/fsc/module.js +0 -4
  91. /package/{dev/tf → fjs}/module.d.ts +0 -0
package/README.md CHANGED
@@ -26,22 +26,22 @@ This repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) and dist
26
26
  Install FunctionalScript via npm:
27
27
 
28
28
  ```bash
29
- npm install functionalscript
29
+ npm install -g functionalscript
30
30
  ```
31
31
 
32
- The FunctionalScript compiler (`fsc`) currently supports:
32
+ The FunctionalScript compiler command (`fjs compile`) currently supports:
33
33
 
34
34
  * `import` statements
35
35
  * `const` declarations
36
36
 
37
37
  It does **not** yet support functions or complex expressions.
38
38
 
39
- Example usage with `fsc`:
39
+ Example usage with `fjs`:
40
40
 
41
41
  ```bash
42
- npx fsc example.f.js output.json
42
+ fjs compile example.f.js output.json
43
43
  # or
44
- npx fsc example.f.js output.f.js
44
+ fjs compile example.f.js output.f.js
45
45
  ```
46
46
 
47
47
  FunctionalScript code can be compiled directly into either JSON or JavaScript without imports.
@@ -29,7 +29,15 @@ type DispatchMap = {
29
29
  type EmptyTagMap = {
30
30
  readonly [id in string]: EmptyTagEntry;
31
31
  };
32
- export type DescentMatchRule = (r: Rule, s: readonly CodePoint[], idx: number) => MatchResult;
32
+ export type DescentMatchRule<T> = (name: string, tag: AstTag, s: readonly CodePointMeta<T>[], idx: number) => DescentMatchResult<T>;
33
+ export type DescentMatchResult<T> = readonly [AstRuleMeta<T>, boolean, number];
34
+ export type DescentMatch<T> = (name: string, s: readonly CodePointMeta<T>[]) => DescentMatchResult<T>;
35
+ export type CodePointMeta<T> = readonly [CodePoint, T];
36
+ export type AstSequenceMeta<T> = readonly (AstRuleMeta<T> | CodePointMeta<T>)[];
37
+ export type AstRuleMeta<T> = {
38
+ readonly tag: AstTag;
39
+ readonly sequence: AstSequenceMeta<T>;
40
+ };
33
41
  /**
34
42
  * Represents a parsed Abstract Syntax Tree (AST) sequence.
35
43
  */
@@ -58,6 +66,7 @@ export type MatchRule = (dr: DispatchRule, s: readonly CodePoint[]) => MatchResu
58
66
  export declare const toData: (fr: FRule) => readonly [RuleSet, string];
59
67
  export declare const dispatchMap: (ruleSet: RuleSet) => DispatchMap;
60
68
  export declare const createEmptyTagMap: (data: readonly [RuleSet, string]) => EmptyTagMap;
69
+ export declare const descentParser: <T>(fr: FRule) => DescentMatch<T>;
61
70
  export declare const parser: (fr: FRule) => Match;
62
71
  export declare const parserRuleSet: (ruleSet: RuleSet) => Match;
63
72
  export {};
@@ -3,6 +3,7 @@ import { strictEqual } from "../../types/function/operator/module.f.js";
3
3
  import { map, toArray } from "../../types/list/module.f.js";
4
4
  import { rangeMap } from "../../types/range_map/module.f.js";
5
5
  import { contains, set } from "../../types/string_set/module.f.js";
6
+ import { contains as rangeContains } from "../../types/range/module.f.js";
6
7
  import { oneEncode, rangeDecode, } from "../module.f.js";
7
8
  const { entries } = Object;
8
9
  const find = (map) => (fr) => {
@@ -198,25 +199,63 @@ const emptyTagMapAdd = (ruleSet) => (map) => (name) => {
198
199
  export const createEmptyTagMap = (data) => {
199
200
  return emptyTagMapAdd(data[0])({})(data[1])[1];
200
201
  };
201
- // export const parserDescent = (fr: FRule): Match => {
202
- // const data = toData(fr)
203
- // const getEmptyTag = (rule: Rule): EmptyTag => {
204
- // return todo()
205
- // }
206
- // const f: DescentMatchRule = (r, cp, idx): MatchResult => {
207
- // const mrSuccess = (tag: AstTag, sequence: AstSequence, r: Remainder): MatchResult => [{tag, sequence}, true, r]
208
- // const mrFail = (tag: AstTag, sequence: AstSequence, r: Remainder): MatchResult => [{tag, sequence}, false, r]
209
- // if (idx >= cp.length) {
210
- // const emptyTag = getEmptyTag(r)
211
- // return mrSuccess(emptyTag, [], emptyTag === undefined ? null : cp)
212
- // }
213
- // return todo()
214
- // }
215
- // const match: Match = (name, cp): MatchResult => {
216
- // return f(data[0][name], cp, 0)
217
- // }
218
- // return match
219
- // }
202
+ export const descentParser = (fr) => {
203
+ const data = toData(fr);
204
+ const emptyTagMap = createEmptyTagMap(data);
205
+ const getEmptyTag = (name) => {
206
+ const res = emptyTagMap[name];
207
+ return res === false ? undefined : res;
208
+ };
209
+ const f = (name, tag, cp, idx) => {
210
+ const mrSuccess = (tag, sequence, idx) => [{ tag, sequence }, true, idx];
211
+ const mrFail = (tag, sequence, idx) => [{ tag, sequence }, false, idx];
212
+ const rule = data[0][name];
213
+ if (typeof rule === 'number') {
214
+ const emptyTag = getEmptyTag(name);
215
+ if (idx >= cp.length) {
216
+ return emptyTag === undefined ? mrFail(emptyTag, [], idx) : mrSuccess(emptyTag, [], idx);
217
+ }
218
+ const cpi = cp[idx];
219
+ const range = rangeDecode(rule);
220
+ if (rangeContains(range)(cpi[0])) {
221
+ return mrSuccess(tag, [cpi], idx + 1);
222
+ }
223
+ return mrFail(emptyTag, [], idx);
224
+ }
225
+ else if (rule instanceof Array) {
226
+ let seq = [];
227
+ let tidx = idx;
228
+ for (const item of rule) {
229
+ const m = f(item, undefined, cp, tidx);
230
+ const [astRule, success, nidx] = m;
231
+ tidx = nidx;
232
+ if (success === false) {
233
+ return mrFail(tag, [], idx);
234
+ }
235
+ seq = [...seq, astRule];
236
+ }
237
+ return mrSuccess(tag, seq, tidx);
238
+ }
239
+ else {
240
+ const entries = Object.entries(rule);
241
+ const emptyTag = getEmptyTag(name);
242
+ let emptyResult = mrFail(emptyTag, [], idx);
243
+ for (const [tag, item] of entries) {
244
+ const m = f(item, tag, cp, idx);
245
+ if (m[1]) {
246
+ if (idx !== m[2])
247
+ return m;
248
+ emptyResult = m;
249
+ }
250
+ }
251
+ return emptyResult;
252
+ }
253
+ };
254
+ const match = (name, cp) => {
255
+ return f(name, undefined, cp, 0);
256
+ };
257
+ return match;
258
+ };
220
259
  export const parser = (fr) => {
221
260
  const data = toData(fr);
222
261
  return parserRuleSet(data[0]);
@@ -4,6 +4,8 @@ declare const _default: {
4
4
  variantTest: () => void;
5
5
  dispatch: (() => void)[];
6
6
  parser: (() => void)[];
7
+ descentParser: (() => void)[];
8
+ descentParserWithMeta: (() => void)[];
7
9
  repeat: (() => void)[];
8
10
  repeatParser: (() => void)[];
9
11
  example: () => void;
@@ -1,11 +1,16 @@
1
1
  import { stringify } from "../../json/module.f.js";
2
2
  import { stringToCodePointList } from "../../text/utf16/module.f.js";
3
3
  import { identity } from "../../types/function/module.f.js";
4
- import { toArray } from "../../types/list/module.f.js";
4
+ import { map, toArray } from "../../types/list/module.f.js";
5
5
  import { sort } from "../../types/object/module.f.js";
6
- import { join0Plus, max, option, range, remove, repeat, repeat0Plus, set } from "../module.f.js";
6
+ import { join0Plus, option, range, repeat0Plus, set } from "../module.f.js";
7
7
  import { classic, deterministic } from "../testlib.f.js";
8
- import { dispatchMap, parser, parserRuleSet, toData, createEmptyTagMap } from "./module.f.js";
8
+ import { dispatchMap, parser, parserRuleSet, toData, createEmptyTagMap, descentParser } from "./module.f.js";
9
+ const mapCodePoint = (cp) => [cp, undefined];
10
+ const descentParserCpOnly = (m, name, cp) => {
11
+ const cpm = toArray(map(mapCodePoint)(cp));
12
+ return m(name, cpm);
13
+ };
9
14
  export default {
10
15
  toData: [
11
16
  () => {
@@ -366,6 +371,19 @@ export default {
366
371
  throw result;
367
372
  }
368
373
  },
374
+ () => {
375
+ const emptyRule = '';
376
+ const minusRule = range('--');
377
+ const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
378
+ const digitRule = range('09');
379
+ const numberRule = [optionalMinusRule, digitRule];
380
+ const m = parser(numberRule);
381
+ const mr = m("", []);
382
+ const result = JSON.stringify(mr);
383
+ if (result !== '[{"sequence":[]},true,null]') {
384
+ throw result;
385
+ } //if remainder is null it means failed
386
+ },
369
387
  () => {
370
388
  const m = parser(option('a'));
371
389
  const isSuccess = (mr) => mr[1] && mr[2]?.length === 0;
@@ -401,6 +419,7 @@ export default {
401
419
  throw mr;
402
420
  }
403
421
  };
422
+ expect('', false);
404
423
  expect('[]', true);
405
424
  expect('[a]', true);
406
425
  expect('[a, a]', true);
@@ -437,6 +456,228 @@ export default {
437
456
  expect(' [{ "q": [ 12, false, [}], "a"] }] ', false);
438
457
  }
439
458
  ],
459
+ descentParser: [
460
+ () => {
461
+ const emptyRule = '';
462
+ const m = descentParser(emptyRule);
463
+ const mr = m("", []);
464
+ const result = JSON.stringify(mr);
465
+ if (result !== '[{"sequence":[]},true,0]') {
466
+ throw result;
467
+ }
468
+ },
469
+ () => {
470
+ const emptyRule = '';
471
+ const m = descentParser(emptyRule);
472
+ const mr = descentParserCpOnly(m, "", [65, 70]);
473
+ const result = JSON.stringify(mr);
474
+ if (result !== '[{"sequence":[]},true,0]') {
475
+ throw result;
476
+ }
477
+ },
478
+ () => {
479
+ const terminalRangeRule = range('AF');
480
+ const m = descentParser(terminalRangeRule);
481
+ const mr = descentParserCpOnly(m, "", [65]);
482
+ const result = JSON.stringify(mr);
483
+ if (result !== '[{"sequence":[[65,null]]},true,1]') {
484
+ throw result;
485
+ }
486
+ },
487
+ () => {
488
+ const terminalRangeRule = range('AF');
489
+ const m = descentParser(terminalRangeRule);
490
+ const mr = descentParserCpOnly(m, "", [64]);
491
+ const result = JSON.stringify(mr);
492
+ if (result !== '[{"sequence":[]},false,0]') {
493
+ throw result;
494
+ }
495
+ },
496
+ () => {
497
+ const variantRule = { 'a': range('AA'), 'b': range('BB') };
498
+ const m = descentParser(variantRule);
499
+ const mr = descentParserCpOnly(m, "", [65]);
500
+ const result = JSON.stringify(mr);
501
+ if (result !== '[{"tag":"a","sequence":[[65,null]]},true,1]') {
502
+ throw result;
503
+ }
504
+ },
505
+ () => {
506
+ const variantRule = { 'a': range('AA'), 'b': range('BB') };
507
+ const m = descentParser(variantRule);
508
+ const mr = descentParserCpOnly(m, "", [64]);
509
+ const result = JSON.stringify(mr);
510
+ if (result !== '[{"sequence":[]},false,0]') {
511
+ throw result;
512
+ }
513
+ },
514
+ () => {
515
+ const emptyRule = '';
516
+ const variantRule = { 'e': emptyRule, 'a': range('AA') };
517
+ const m = descentParser(variantRule);
518
+ const mr = m("", []);
519
+ const result = JSON.stringify(mr);
520
+ if (result !== '[{"tag":"e","sequence":[]},true,0]') {
521
+ throw result;
522
+ }
523
+ },
524
+ () => {
525
+ const emptyRule = '';
526
+ const variantRule = { 'e': emptyRule, 'a': range('AA') };
527
+ const m = descentParser(variantRule);
528
+ const mr = descentParserCpOnly(m, "", [64]);
529
+ const result = JSON.stringify(mr);
530
+ if (result !== '[{"tag":"e","sequence":[]},true,0]') {
531
+ throw result;
532
+ }
533
+ },
534
+ () => {
535
+ const stringRule = 'AB';
536
+ const m = descentParser(stringRule);
537
+ const mr = descentParserCpOnly(m, "", [65, 66]);
538
+ const result = JSON.stringify(mr);
539
+ if (result !== '[{"sequence":[{"sequence":[[65,null]]},{"sequence":[[66,null]]}]},true,2]') {
540
+ throw result;
541
+ }
542
+ },
543
+ () => {
544
+ const stringRule = 'AB';
545
+ const m = descentParser(stringRule);
546
+ const mr = descentParserCpOnly(m, "", [65, 67]);
547
+ const result = JSON.stringify(mr);
548
+ if (result !== '[{"sequence":[]},false,0]') {
549
+ throw result;
550
+ }
551
+ },
552
+ () => {
553
+ const emptyRule = '';
554
+ const minursRule = range('--');
555
+ const optionalMinusRule = { 'none': emptyRule, 'minus': minursRule };
556
+ const digitRule = range('09');
557
+ const numberRule = [optionalMinusRule, digitRule];
558
+ const m = descentParser(numberRule);
559
+ const mr = descentParserCpOnly(m, "", [50]);
560
+ const result = JSON.stringify(mr);
561
+ if (result !== '[{"sequence":[{"tag":"none","sequence":[]},{"sequence":[[50,null]]}]},true,1]') {
562
+ throw result;
563
+ }
564
+ },
565
+ () => {
566
+ const emptyRule = '';
567
+ const minusRule = range('--');
568
+ const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
569
+ const digitRule = range('09');
570
+ const numberRule = [optionalMinusRule, digitRule];
571
+ const m = descentParser(numberRule);
572
+ const mr = descentParserCpOnly(m, "", [45, 50]);
573
+ const result = JSON.stringify(mr);
574
+ if (result !== '[{"sequence":[{"tag":"minus","sequence":[[45,null]]},{"sequence":[[50,null]]}]},true,2]') {
575
+ throw result;
576
+ }
577
+ },
578
+ () => {
579
+ const emptyRule = '';
580
+ const minursRule = range('--');
581
+ const optionalMinusRule = { 'none': emptyRule, 'minus': minursRule };
582
+ const digitRule = range('09');
583
+ const numberRule = [optionalMinusRule, digitRule];
584
+ const m = descentParser(numberRule);
585
+ const mr = m("", []);
586
+ const result = JSON.stringify(mr);
587
+ if (result !== '[{"sequence":[]},false,0]') {
588
+ throw result;
589
+ }
590
+ },
591
+ () => {
592
+ const m = descentParser(option('a'));
593
+ const expect = (s, expected) => {
594
+ const cp = toArray(stringToCodePointList(s));
595
+ const mr = descentParserCpOnly(m, '', cp);
596
+ const success = mr[1] && mr[2] === cp.length;
597
+ if (success !== expected) {
598
+ throw mr;
599
+ }
600
+ };
601
+ expect('a', true);
602
+ expect('', true);
603
+ expect('aa', false);
604
+ expect('b', false);
605
+ },
606
+ () => {
607
+ const ws = repeat0Plus(set(' \n\r\t'));
608
+ const commaJoin0Plus = ([open, close], a) => [
609
+ open,
610
+ ws,
611
+ join0Plus([a, ws], [',', ws]),
612
+ close,
613
+ ];
614
+ const value = () => ({
615
+ object: commaJoin0Plus('{}', 'a'),
616
+ array: commaJoin0Plus('[]', 'a')
617
+ });
618
+ value.name; //bun will fail if no usage of name found
619
+ const m = descentParser(value);
620
+ const expect = (s, expected) => {
621
+ const cp = toArray(stringToCodePointList(s));
622
+ const mr = descentParserCpOnly(m, 'value', cp);
623
+ const success = mr[1] && mr[2] === cp.length;
624
+ if (success !== expected) {
625
+ throw mr;
626
+ }
627
+ };
628
+ expect('', false);
629
+ expect('[]', true);
630
+ expect('[a]', true);
631
+ expect('[a, a]', true);
632
+ expect('{a}', true);
633
+ },
634
+ () => {
635
+ const m = descentParser(deterministic());
636
+ const expect = (s, expected) => {
637
+ const cp = toArray(stringToCodePointList(s));
638
+ const mr = descentParserCpOnly(m, '', cp);
639
+ const success = mr[1] && mr[2] === cp.length;
640
+ if (success !== expected) {
641
+ throw mr;
642
+ }
643
+ };
644
+ expect(' true ', true);
645
+ expect(' tr2ue ', false);
646
+ expect(' true" ', false);
647
+ expect(' "Hello" ', true);
648
+ expect(' "Hello ', false);
649
+ expect(' "Hello\\n\\r\\"" ', true);
650
+ expect(' -56.7e+5 ', true);
651
+ expect(' h-56.7e+5 ', false);
652
+ expect(' -56.7e+5 3', false);
653
+ expect(' [] ', true);
654
+ expect(' {} ', true);
655
+ expect(' [[[]]] ', true);
656
+ expect(' [1] ', true);
657
+ expect(' [ 12, false, "a"] ', true);
658
+ expect(' [ 12, false2, "a"] ', false);
659
+ expect(' { "q": [ 12, false, [{"b" : "c"}], "a"] } ', true);
660
+ expect(' { "q": [ 12, false, [{}], "a"] } ', true);
661
+ expect(' { "q": [ 12, false, [}], "a"] } ', false);
662
+ expect(' [{ "q": [ 12, false, [{}], "a"] }] ', true);
663
+ expect(' [{ "q": [ 12, false, [}], "a"] }] ', false);
664
+ }
665
+ ],
666
+ descentParserWithMeta: [
667
+ () => {
668
+ const emptyRule = '';
669
+ const minusRule = range('--');
670
+ const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
671
+ const digitRule = range('09');
672
+ const numberRule = [optionalMinusRule, digitRule];
673
+ const m = descentParser(numberRule);
674
+ const mr = m("", [[45, 'minus'], [50, 'two']]);
675
+ const result = JSON.stringify(mr);
676
+ if (result !== '[{"sequence":[{"tag":"minus","sequence":[[45,"minus"]]},{"sequence":[[50,"two"]]}]},true,2]') {
677
+ throw result;
678
+ }
679
+ },
680
+ ],
440
681
  repeat: [
441
682
  () => {
442
683
  const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
package/bnf/module.f.d.ts CHANGED
@@ -7,6 +7,9 @@ import { type Array2 } from '../types/array/module.f.ts';
7
7
  * - 0xEEEEEE is the last symbol (24 bits)
8
8
  */
9
9
  export type TerminalRange = number;
10
+ export declare const fullRange: TerminalRange;
11
+ export declare const unicodeRange: TerminalRange;
12
+ export declare const eof = 1114112;
10
13
  /** A sequence of rules. */
11
14
  export type Sequence = readonly Rule[];
12
15
  /** A variant */
@@ -30,8 +33,9 @@ export declare const range: (ab: string) => TerminalRange;
30
33
  export type RangeVariant = {
31
34
  readonly [k in string]: TerminalRange;
32
35
  };
33
- export declare const rangeToId: (r: TerminalRange) => string;
34
- export declare const remove: (range: TerminalRange, removeSet: RangeVariant) => RangeVariant;
36
+ export declare const remove: (range: TerminalRange, v: RangeVariant) => RangeVariant;
37
+ export declare const not: (v: RangeVariant) => RangeVariant;
38
+ export declare const notSet: (s: string) => RangeVariant;
35
39
  export type None = readonly [];
36
40
  export declare const none: None;
37
41
  export type Option<S> = {
package/bnf/module.f.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import { codePointListToString, stringToCodePointList } from "../text/utf16/module.f.js";
2
2
  import { isArray2 } from "../types/array/module.f.js";
3
3
  import { map, toArray, repeat as listRepeat } from "../types/list/module.f.js";
4
+ export const fullRange = 0x000000_FFFFFF;
5
+ export const unicodeRange = 0x000000_10FFFF;
6
+ export const eof = 0x110000;
4
7
  // Internals:
5
8
  const { fromEntries, values } = Object;
6
9
  const { fromCodePoint } = String;
@@ -34,13 +37,7 @@ export const range = (ab) => {
34
37
  }
35
38
  return rangeEncode(...a);
36
39
  };
37
- export const rangeToId = (r) => {
38
- const ab = rangeDecode(r);
39
- const [a, b] = ab;
40
- const cp = a === b ? [a] : ab;
41
- return fromCodePoint(...cp);
42
- };
43
- const rangeToEntry = (r) => [rangeToId(r), r];
40
+ const rangeToEntry = (r) => ['0x' + r.toString(16), r];
44
41
  const toVariantRangeSet = (r) => fromEntries(r.map(rangeToEntry));
45
42
  const removeOne = (list, ab) => {
46
43
  const [a, b] = rangeDecode(ab);
@@ -60,13 +57,15 @@ const removeOne = (list, ab) => {
60
57
  }
61
58
  return result;
62
59
  };
63
- export const remove = (range, removeSet) => {
60
+ export const remove = (range, v) => {
64
61
  let result = [range];
65
- for (const r of values(removeSet)) {
62
+ for (const r of values(v)) {
66
63
  result = removeOne(result, r);
67
64
  }
68
65
  return toVariantRangeSet(result);
69
66
  };
67
+ export const not = (v) => remove(fullRange, v);
68
+ export const notSet = (s) => not(set(s));
70
69
  export const none = [];
71
70
  export const option = (some) => ({
72
71
  some,
@@ -0,0 +1,18 @@
1
+ import { type Sha2 } from "../crypto/sha2/module.f.ts";
2
+ import type { Vec } from "../types/bit_vec/module.f.ts";
3
+ import { type Effect, type Operations } from "../types/effect/module.f.ts";
4
+ import { type Fs, type NodeOperations } from "../types/effect/node/module.f.ts";
5
+ export type KvStore<O extends Operations> = {
6
+ readonly read: (key: Vec) => Effect<O, Vec | undefined>;
7
+ readonly write: (key: Vec, value: Vec) => Effect<O, void>;
8
+ readonly list: () => Effect<O, readonly Vec[]>;
9
+ };
10
+ export type Kv = readonly [Vec, Vec];
11
+ export declare const fileKvStore: (path: string) => KvStore<Fs>;
12
+ export type Cas<O extends Operations> = {
13
+ readonly read: (key: Vec) => Effect<O, Vec | undefined>;
14
+ readonly write: (value: Vec) => Effect<O, Vec>;
15
+ readonly list: () => Effect<O, readonly Vec[]>;
16
+ };
17
+ export declare const cas: (sha2: Sha2) => <O extends Operations>(_: KvStore<O>) => Cas<O>;
18
+ export declare const main: (args: readonly string[]) => Effect<NodeOperations, number>;
@@ -0,0 +1,95 @@
1
+ import { computeSync, sha256 } from "../crypto/sha2/module.f.js";
2
+ import { parse } from "../path/module.f.js";
3
+ import { cBase32ToVec, vecToCBase32 } from "../types/cbase32/module.f.js";
4
+ import { pure } from "../types/effect/module.f.js";
5
+ import { error, log, mkdir, readdir, readFile, writeFile } from "../types/effect/node/module.f.js";
6
+ import { toOption } from "../types/nullable/module.f.js";
7
+ import { unwrap } from "../types/result/module.f.js";
8
+ const o = { withFileTypes: true };
9
+ const split = (s) => [s.substring(0, 2), s.substring(2)];
10
+ const prefix = '.cas';
11
+ const toPath = (key) => {
12
+ const s = vecToCBase32(key);
13
+ const [a, bc] = split(s);
14
+ const [b, c] = split(bc);
15
+ return `${prefix}/${a}/${b}/${c}`;
16
+ };
17
+ export const fileKvStore = (path) => ({
18
+ read: (key) => readFile(toPath(key))
19
+ .map(([status, data]) => status === 'error' ? undefined : data),
20
+ write: (key, value) => {
21
+ const p = toPath(key);
22
+ const parts = parse(p);
23
+ const dir = `${path}/${parts.slice(0, -1).join('/')}`;
24
+ // TODO: error handling
25
+ return mkdir(dir, { recursive: true })
26
+ .pipe(() => writeFile(`${path}/${p}`, value))
27
+ .map(() => undefined);
28
+ },
29
+ list: () => readdir('.cas', { recursive: true })
30
+ // TODO: remove unwrap
31
+ .map(r => unwrap(r).flatMap(({ name, parentPath, isFile }) => toOption(isFile ? cBase32ToVec(parentPath.substring(prefix.length).replaceAll('/', '') + name) : null))),
32
+ });
33
+ export const cas = (sha2) => {
34
+ const compute = computeSync(sha2);
35
+ return ({ read, write, list }) => ({
36
+ read,
37
+ write: (value) => {
38
+ const hash = compute([value]);
39
+ return write(hash, value)
40
+ .map(() => hash);
41
+ },
42
+ list,
43
+ });
44
+ };
45
+ const e = (s) => error(s).map(() => 1);
46
+ export const main = (args) => {
47
+ const c = cas(sha256)(fileKvStore('.'));
48
+ const [cmd, ...options] = args;
49
+ switch (cmd) {
50
+ case 'add': {
51
+ if (options.length !== 1) {
52
+ return e("'cas add' expects one parameter");
53
+ }
54
+ const [path] = options;
55
+ return readFile(path)
56
+ .pipe(v => c.write(unwrap(v)))
57
+ .pipe(hash => log(vecToCBase32(hash)))
58
+ .map(() => 0);
59
+ }
60
+ case 'get': {
61
+ if (options.length !== 2) {
62
+ return e("'cas get' expects two parameters");
63
+ }
64
+ const [hashCBase32, path] = options;
65
+ const hash = cBase32ToVec(hashCBase32);
66
+ if (hash === null) {
67
+ return e(`invalid hash format: ${hashCBase32}`);
68
+ }
69
+ return c.read(hash)
70
+ .pipe(v => {
71
+ const result = v === undefined
72
+ ? e(`no such hash: ${hashCBase32}`)
73
+ : writeFile(path, v).map(() => 0);
74
+ return result;
75
+ });
76
+ }
77
+ case 'list': {
78
+ return c.list()
79
+ .pipe(v => {
80
+ // TODO: make it lazy.
81
+ let i = pure(undefined);
82
+ for (const j of v) {
83
+ i = i.pipe(() => log(vecToCBase32(j)));
84
+ }
85
+ return i;
86
+ })
87
+ .map(() => 0);
88
+ }
89
+ case undefined: {
90
+ return e('Error: CAS command requires subcommand');
91
+ }
92
+ default:
93
+ return e(`Error: Unknown CAS subcommand "${args[0]}"`);
94
+ }
95
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: () => void;
2
+ export default _default;
package/cas/test.f.js ADDED
@@ -0,0 +1 @@
1
+ export default () => { };
package/ci/module.f.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- import type { Io } from '../io/module.f.ts';
2
- declare const _default: (io: Io) => Promise<number>;
1
+ import { type NodeEffect } from '../types/effect/node/module.f.ts';
2
+ export declare const effect: NodeEffect<number>;
3
+ declare const _default: () => NodeEffect<number>;
3
4
  export default _default;