functionalscript 0.33.0 → 0.35.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/README.md +27 -14
- package/fs/asserts/module.f.d.ts +1 -1
- package/fs/asserts/module.f.js +4 -1
- package/fs/base64/proof.f.d.ts +1 -0
- package/fs/base64/proof.f.js +25 -56
- package/fs/base_n/module.f.js +11 -5
- package/fs/base_n/proof.f.d.ts +1 -0
- package/fs/base_n/proof.f.js +12 -1
- package/fs/bnf/data/module.f.d.ts +0 -103
- package/fs/bnf/data/module.f.js +10 -246
- package/fs/bnf/data/proof.f.d.ts +0 -10
- package/fs/bnf/data/proof.f.js +2 -642
- package/fs/bnf/descent/module.f.d.ts +56 -0
- package/fs/bnf/descent/module.f.js +119 -0
- package/fs/bnf/descent/proof.f.d.ts +5 -0
- package/fs/bnf/descent/proof.f.js +296 -0
- package/fs/bnf/ll1/module.f.d.ts +72 -0
- package/fs/bnf/ll1/module.f.js +153 -0
- package/fs/bnf/ll1/proof.f.d.ts +9 -0
- package/fs/bnf/ll1/proof.f.js +358 -0
- package/fs/cas/cli/module.f.d.ts +6 -0
- package/fs/cas/cli/module.f.js +56 -0
- package/fs/cas/cli/proof.f.d.ts +14 -0
- package/fs/cas/cli/proof.f.js +149 -0
- package/fs/cas/mcp/module.f.d.ts +9 -17
- package/fs/cas/mcp/module.f.js +123 -96
- package/fs/cas/mcp/proof.f.d.ts +12 -1
- package/fs/cas/mcp/proof.f.js +199 -32
- package/fs/cas/module.f.d.ts +35 -15
- package/fs/cas/module.f.js +168 -131
- package/fs/cas/proof.f.d.ts +16 -13
- package/fs/cas/proof.f.js +255 -121
- package/fs/ci/config/module.f.d.ts +14 -14
- package/fs/ci/config/module.f.js +14 -14
- package/fs/djs/tokenizer-new/module.f.js +1 -1
- package/fs/djs/tokenizer-new/proof.f.d.ts +2 -0
- package/fs/djs/tokenizer-new/proof.f.js +357 -229
- package/fs/effects/list/module.f.d.ts +31 -0
- package/fs/effects/list/module.f.js +16 -0
- package/fs/effects/module.f.d.ts +11 -5
- package/fs/effects/module.f.js +16 -6
- package/fs/effects/node/module.f.d.ts +29 -3
- package/fs/effects/node/module.f.js +35 -1
- package/fs/effects/node/module.js +32 -18
- package/fs/effects/node/virtual/module.f.js +57 -0
- package/fs/effects/proof.f.d.ts +4 -0
- package/fs/effects/proof.f.js +18 -1
- package/fs/fjs/module.f.js +2 -8
- package/fs/html/module.f.js +6 -8
- package/fs/mcp/module.f.d.ts +1 -1
- package/fs/mcp/stdio/module.f.d.ts +8 -0
- package/fs/mcp/stdio/module.f.js +33 -6
- package/fs/mcp/stdio/proof.f.d.ts +3 -0
- package/fs/mcp/stdio/proof.f.js +52 -1
- package/fs/mime/module.f.d.ts +101 -5
- package/fs/mime/module.f.js +159 -6
- package/fs/mime/proof.f.d.ts +25 -0
- package/fs/mime/proof.f.js +193 -3
- package/fs/text/code_point/module.f.d.ts +39 -2
- package/fs/text/code_point/module.f.js +74 -2
- package/fs/text/code_point/proof.f.d.ts +8 -0
- package/fs/text/code_point/proof.f.js +72 -0
- package/fs/text/module.f.d.ts +11 -1
- package/fs/text/module.f.js +13 -3
- package/fs/text/proof.f.d.ts +6 -0
- package/fs/text/proof.f.js +25 -2
- package/fs/text/utf16/module.f.js +4 -26
- package/fs/text/utf8/module.f.d.ts +27 -0
- package/fs/text/utf8/module.f.js +8 -14
- package/fs/types/bit_vec/module.f.d.ts +20 -2
- package/fs/types/bit_vec/module.f.js +77 -27
- package/fs/types/bit_vec/proof.f.d.ts +8 -0
- package/fs/types/bit_vec/proof.f.js +24 -6
- package/fs/types/function/operator/module.f.d.ts +26 -0
- package/fs/types/list/module.f.d.ts +3 -0
- package/fs/types/nullable/module.f.d.ts +9 -5
- package/fs/types/nullable/module.f.js +19 -0
- package/fs/types/result/module.d.ts +2 -4
- package/fs/types/result/module.js +9 -3
- package/package.json +3 -3
- package/issues/demo/data/data.f.js +0 -12
- package/issues/demo/data/shared.f.js +0 -3
- package/issues/demo/fs/app.js +0 -4
- package/issues/demo/fs/math.f.js +0 -4
- package/issues/demo/sample/proof.f.js +0 -13
- /package/{issues → todo}/031-json.f.d.ts +0 -0
- /package/{issues → todo}/031-json.f.js +0 -0
- /package/{issues → todo}/proof.f.d.ts +0 -0
- /package/{issues → todo}/proof.f.js +0 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LL(1) dispatch/matcher backend over the BNF data {@link RuleSet}.
|
|
3
|
+
*
|
|
4
|
+
* Built from the serializable IR in `fs/bnf/data`, this is one member of the
|
|
5
|
+
* family of automaton builders that consume a {@link RuleSet}: it compiles the
|
|
6
|
+
* grammar into a predictive {@link dispatchMap} and matches input into an AST
|
|
7
|
+
* ({@link MatchResult}). It throws at build time (`can not merge …`) when the
|
|
8
|
+
* grammar is not LL(1) — a first/first conflict.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import {} from "../../text/utf16/module.f.js";
|
|
13
|
+
import { strictEqual } from "../../types/function/operator/module.f.js";
|
|
14
|
+
import { toArray } from "../../types/list/module.f.js";
|
|
15
|
+
import { rangeMap } from "../../types/range_map/module.f.js";
|
|
16
|
+
import { contains, set } from "../../types/string_set/module.f.js";
|
|
17
|
+
import { rangeDecode } from "../module.f.js";
|
|
18
|
+
import { definedEntries } from "../../types/object/module.f.js";
|
|
19
|
+
import { toData } from "../data/module.f.js";
|
|
20
|
+
import {} from "../module.f.js";
|
|
21
|
+
const dispatchOp = rangeMap({
|
|
22
|
+
union: a => b => {
|
|
23
|
+
if (a === null) {
|
|
24
|
+
return b;
|
|
25
|
+
}
|
|
26
|
+
if (b === null) {
|
|
27
|
+
return a;
|
|
28
|
+
}
|
|
29
|
+
throw ['can not merge [', a, '][', b, ']'];
|
|
30
|
+
},
|
|
31
|
+
equal: strictEqual,
|
|
32
|
+
def: null,
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Builds a dispatch map for a {@link RuleSet} to enable predictive parsing.
|
|
36
|
+
*/
|
|
37
|
+
export const dispatchMap = (ruleSet) => {
|
|
38
|
+
const addRuleToDispatch = (dr, name) => {
|
|
39
|
+
if (dr === null)
|
|
40
|
+
return null;
|
|
41
|
+
return { tag: dr.tag, rules: [...dr.rules, name] };
|
|
42
|
+
};
|
|
43
|
+
const addTagToDispatch = (dr, tag) => {
|
|
44
|
+
if (dr === null)
|
|
45
|
+
return null;
|
|
46
|
+
return { tag, rules: dr.rules };
|
|
47
|
+
};
|
|
48
|
+
const dispatchRule = (dm, name, current) => {
|
|
49
|
+
if (name in dm) {
|
|
50
|
+
return dm;
|
|
51
|
+
}
|
|
52
|
+
const newCurrent = set(name)(current);
|
|
53
|
+
const rule = ruleSet[name];
|
|
54
|
+
if (typeof rule === 'number') {
|
|
55
|
+
const range = rangeDecode(rule);
|
|
56
|
+
const dispatch = dispatchOp.fromRange(range)({ tag: undefined, rules: [] });
|
|
57
|
+
const dr = { emptyTag: undefined, rangeMap: dispatch };
|
|
58
|
+
return { ...dm, [name]: dr };
|
|
59
|
+
}
|
|
60
|
+
else if (rule instanceof Array) {
|
|
61
|
+
let emptyTag = true;
|
|
62
|
+
let result = [];
|
|
63
|
+
for (const item of rule) {
|
|
64
|
+
if (contains(item)(newCurrent)) {
|
|
65
|
+
result = result.map(x => [addRuleToDispatch(x[0], item), x[1]]);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
dm = dispatchRule(dm, item, newCurrent);
|
|
69
|
+
const dr = dm[item];
|
|
70
|
+
if (emptyTag === true) {
|
|
71
|
+
result = result.map(x => [addRuleToDispatch(x[0], item), x[1]]);
|
|
72
|
+
result = toArray(dispatchOp.merge(result)(dr.rangeMap));
|
|
73
|
+
emptyTag = dr.emptyTag !== undefined ? true : undefined;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
result = result.map(x => [addRuleToDispatch(x[0], item), x[1]]);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
const dr = { emptyTag, rangeMap: result };
|
|
81
|
+
return { ...dm, [name]: dr };
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const entries = definedEntries(rule);
|
|
85
|
+
let result = [];
|
|
86
|
+
let emptyTag = undefined;
|
|
87
|
+
for (const [tag, item] of entries) {
|
|
88
|
+
dm = dispatchRule(dm, item, newCurrent);
|
|
89
|
+
const dr = dm[item];
|
|
90
|
+
if (dr.emptyTag !== undefined) {
|
|
91
|
+
emptyTag = tag;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const d = dr.rangeMap.map(x => [addTagToDispatch(x[0], tag), x[1]]);
|
|
95
|
+
result = toArray(dispatchOp.merge(result)(d));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const dr = { emptyTag, rangeMap: result };
|
|
99
|
+
return { ...dm, [name]: dr };
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
let result = {};
|
|
103
|
+
for (const k in ruleSet) {
|
|
104
|
+
result = dispatchRule(result, k, null);
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* Creates an LL(1) parser from a functional grammar rule.
|
|
110
|
+
*/
|
|
111
|
+
export const parser = (fr) => {
|
|
112
|
+
const data = toData(fr);
|
|
113
|
+
return parserRuleSet(data[0]);
|
|
114
|
+
};
|
|
115
|
+
const mrSuccess = (tag, sequence, r) => [{ tag, sequence }, true, r];
|
|
116
|
+
const mrFail = (tag, sequence, r) => [{ tag, sequence }, false, r];
|
|
117
|
+
/**
|
|
118
|
+
* Creates an LL(1) parser from an already materialized {@link RuleSet}.
|
|
119
|
+
*/
|
|
120
|
+
export const parserRuleSet = (ruleSet) => {
|
|
121
|
+
const map = dispatchMap(ruleSet);
|
|
122
|
+
const f = ({ emptyTag, rangeMap }, cp) => {
|
|
123
|
+
if (cp.length === 0) {
|
|
124
|
+
return mrSuccess(emptyTag, [], emptyTag === undefined ? null : cp);
|
|
125
|
+
}
|
|
126
|
+
const [cp0] = cp;
|
|
127
|
+
const dr = dispatchOp.get(cp0)(rangeMap);
|
|
128
|
+
if (dr === null) {
|
|
129
|
+
return emptyTag === undefined
|
|
130
|
+
? mrFail(emptyTag, [], cp)
|
|
131
|
+
: mrSuccess(emptyTag, [], cp);
|
|
132
|
+
}
|
|
133
|
+
let seq = [cp0];
|
|
134
|
+
const [, ...restCp] = cp;
|
|
135
|
+
let r = restCp;
|
|
136
|
+
const { tag, rules } = dr;
|
|
137
|
+
for (const i of rules) {
|
|
138
|
+
const rule = typeof i === 'string' ? map[i] : i;
|
|
139
|
+
const res = f(rule, r);
|
|
140
|
+
const [astRule, success, newR] = res;
|
|
141
|
+
if (success === false) {
|
|
142
|
+
return res;
|
|
143
|
+
}
|
|
144
|
+
seq = [...seq, astRule];
|
|
145
|
+
if (newR === null) {
|
|
146
|
+
return mrSuccess(tag, seq, null);
|
|
147
|
+
}
|
|
148
|
+
r = newR;
|
|
149
|
+
}
|
|
150
|
+
return mrSuccess(tag, seq, r);
|
|
151
|
+
};
|
|
152
|
+
return (name, cp) => f(map[name], cp);
|
|
153
|
+
};
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
import { stringToCodePointList } from "../../text/utf16/module.f.js";
|
|
2
|
+
import { toArray } from "../../types/list/module.f.js";
|
|
3
|
+
import { commaJoin0Plus, option, range, repeat0Plus, set } from "../module.f.js";
|
|
4
|
+
import { deterministic } from "../testlib.f.js";
|
|
5
|
+
import { toData } from "../data/module.f.js";
|
|
6
|
+
import { dispatchMap, parser, parserRuleSet } from "./module.f.js";
|
|
7
|
+
export const proof = {
|
|
8
|
+
dispatch: [
|
|
9
|
+
() => {
|
|
10
|
+
const terminalRangeRule = range('AF');
|
|
11
|
+
const data = toData(terminalRangeRule);
|
|
12
|
+
const dm = dispatchMap(data[0]);
|
|
13
|
+
const result = JSON.stringify(dm);
|
|
14
|
+
if (result !== '{"":{"rangeMap":[[null,64],[{"rules":[]},70]]}}') {
|
|
15
|
+
throw result;
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
() => {
|
|
19
|
+
const stringRule = 'AB';
|
|
20
|
+
const data = toData(stringRule);
|
|
21
|
+
const dm = dispatchMap(data[0]);
|
|
22
|
+
const result = JSON.stringify(dm);
|
|
23
|
+
if (result !== '{"0":{"rangeMap":[[null,64],[{"rules":[]},65]]},"1":{"rangeMap":[[null,65],[{"rules":[]},66]]},"":{"rangeMap":[[null,64],[{"rules":["1"]},65]]}}') {
|
|
24
|
+
throw result;
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
() => {
|
|
28
|
+
const a = range('AA');
|
|
29
|
+
const b = range('BB');
|
|
30
|
+
const ab = [a, b];
|
|
31
|
+
const data = toData(ab);
|
|
32
|
+
const dm = dispatchMap(data[0]);
|
|
33
|
+
const result = JSON.stringify(dm);
|
|
34
|
+
if (result !== '{"0":{"rangeMap":[[null,64],[{"rules":[]},65]]},"1":{"rangeMap":[[null,65],[{"rules":[]},66]]},"":{"rangeMap":[[null,64],[{"rules":["1"]},65]]}}') {
|
|
35
|
+
throw result;
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
() => {
|
|
39
|
+
const emptyRule = '';
|
|
40
|
+
const data = toData(emptyRule);
|
|
41
|
+
const dm = dispatchMap(data[0]);
|
|
42
|
+
const result = JSON.stringify(dm);
|
|
43
|
+
if (result !== '{"":{"emptyTag":true,"rangeMap":[]}}') {
|
|
44
|
+
throw result;
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
() => {
|
|
48
|
+
const variantRule = { 'a': range('AA'), 'b': range('BB') };
|
|
49
|
+
const data = toData(variantRule);
|
|
50
|
+
const dm = dispatchMap(data[0]);
|
|
51
|
+
const result = JSON.stringify(dm);
|
|
52
|
+
if (result !== '{"0":{"rangeMap":[[null,64],[{"rules":[]},65]]},"1":{"rangeMap":[[null,65],[{"rules":[]},66]]},"":{"rangeMap":[[null,64],[{"tag":"a","rules":[]},65],[{"tag":"b","rules":[]},66]]}}') {
|
|
53
|
+
throw result;
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
() => {
|
|
57
|
+
const emptyRule = '';
|
|
58
|
+
const variantRule = { 'e': emptyRule, 'a': range('AA') };
|
|
59
|
+
const data = toData(variantRule);
|
|
60
|
+
const dm = dispatchMap(data[0]);
|
|
61
|
+
const result = JSON.stringify(dm);
|
|
62
|
+
if (result !== '{"0":{"emptyTag":true,"rangeMap":[]},"1":{"rangeMap":[[null,64],[{"rules":[]},65]]},"":{"emptyTag":"e","rangeMap":[[null,64],[{"tag":"a","rules":[]},65]]}}') {
|
|
63
|
+
throw result;
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
() => {
|
|
67
|
+
const emptyRule = '';
|
|
68
|
+
const minursRule = range('--');
|
|
69
|
+
const optionalMinusRule = { 'none': emptyRule, 'minus': minursRule };
|
|
70
|
+
const digitRule = range('09');
|
|
71
|
+
const numberRule = [optionalMinusRule, digitRule];
|
|
72
|
+
const data = toData(numberRule);
|
|
73
|
+
const dm = dispatchMap(data[0]);
|
|
74
|
+
const result = JSON.stringify(dm);
|
|
75
|
+
if (result !== '{"0":{"emptyTag":"none","rangeMap":[[null,44],[{"tag":"minus","rules":[]},45]]},"1":{"emptyTag":true,"rangeMap":[]},"2":{"rangeMap":[[null,44],[{"rules":[]},45]]},"3":{"rangeMap":[[null,47],[{"rules":[]},57]]},"":{"rangeMap":[[null,44],[{"tag":"minus","rules":["3"]},45],[null,47],[{"rules":[]},57]]}}') {
|
|
76
|
+
throw result;
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
() => {
|
|
80
|
+
const emptyRule = '';
|
|
81
|
+
const spaceRule = range(' ');
|
|
82
|
+
const optionalSpaceRule = { 'none': emptyRule, 'space': spaceRule };
|
|
83
|
+
const minusRule = range('--');
|
|
84
|
+
const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
|
|
85
|
+
const digitRule = range('09');
|
|
86
|
+
const numberRule = [optionalSpaceRule, optionalMinusRule, digitRule];
|
|
87
|
+
const data = toData(numberRule);
|
|
88
|
+
const dm = dispatchMap(data[0]);
|
|
89
|
+
const result = JSON.stringify(dm);
|
|
90
|
+
if (result !== '{"0":{"emptyTag":"none","rangeMap":[[null,31],[{"tag":"space","rules":[]},32]]},"1":{"emptyTag":true,"rangeMap":[]},"2":{"rangeMap":[[null,31],[{"rules":[]},32]]},"3":{"emptyTag":"none","rangeMap":[[null,44],[{"tag":"minus","rules":[]},45]]},"4":{"rangeMap":[[null,44],[{"rules":[]},45]]},"5":{"rangeMap":[[null,47],[{"rules":[]},57]]},"":{"rangeMap":[[null,31],[{"tag":"space","rules":["3","5"]},32],[null,44],[{"tag":"minus","rules":["5"]},45],[null,47],[{"rules":[]},57]]}}') {
|
|
91
|
+
throw result;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
parser: [
|
|
96
|
+
() => {
|
|
97
|
+
const emptyRule = '';
|
|
98
|
+
const m = parser(emptyRule);
|
|
99
|
+
const mr = m("", []);
|
|
100
|
+
const result = JSON.stringify(mr);
|
|
101
|
+
if (result !== '[{"tag":true,"sequence":[]},true,[]]') {
|
|
102
|
+
throw result;
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
() => {
|
|
106
|
+
const emptyRule = '';
|
|
107
|
+
const m = parser(emptyRule);
|
|
108
|
+
const mr = m("", [65, 70]);
|
|
109
|
+
const result = JSON.stringify(mr);
|
|
110
|
+
if (result !== '[{"tag":true,"sequence":[]},true,[65,70]]') {
|
|
111
|
+
throw result;
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
() => {
|
|
115
|
+
const terminalRangeRule = range('AF');
|
|
116
|
+
const m = parser(terminalRangeRule);
|
|
117
|
+
const mr = m("", [65]);
|
|
118
|
+
const result = JSON.stringify(mr);
|
|
119
|
+
if (result !== '[{"sequence":[65]},true,[]]') {
|
|
120
|
+
throw result;
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
() => {
|
|
124
|
+
const terminalRangeRule = 0x000079_000087;
|
|
125
|
+
const m = parser(terminalRangeRule);
|
|
126
|
+
const mr = m("", [64]);
|
|
127
|
+
const result = JSON.stringify(mr);
|
|
128
|
+
if (result !== '[{"sequence":[]},false,[64]]') {
|
|
129
|
+
throw result;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
() => {
|
|
133
|
+
const terminalRangeRule = 0x000080_000087; //broken range
|
|
134
|
+
const m = parser(terminalRangeRule);
|
|
135
|
+
const mr = m("", [64]);
|
|
136
|
+
const result = JSON.stringify(mr);
|
|
137
|
+
if (result !== '[{"sequence":[]},false,[64]]') {
|
|
138
|
+
throw result;
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
() => {
|
|
142
|
+
const variantRule = { 'a': range('AA'), 'b': range('BB') };
|
|
143
|
+
const m = parser(variantRule);
|
|
144
|
+
const mr = m("", [65]);
|
|
145
|
+
const result = JSON.stringify(mr);
|
|
146
|
+
if (result !== '[{"tag":"a","sequence":[65]},true,[]]') {
|
|
147
|
+
throw result;
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
() => {
|
|
151
|
+
const variantRule = { 'a': range('AA'), 'b': range('BB') };
|
|
152
|
+
const m = parser(variantRule);
|
|
153
|
+
const mr = m("", [64]);
|
|
154
|
+
const result = JSON.stringify(mr);
|
|
155
|
+
if (result !== '[{"sequence":[]},false,[64]]') {
|
|
156
|
+
throw result;
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
() => {
|
|
160
|
+
const emptyRule = '';
|
|
161
|
+
const variantRule = { 'e': emptyRule, 'a': range('AA') };
|
|
162
|
+
const m = parser(variantRule);
|
|
163
|
+
const mr = m("", []);
|
|
164
|
+
const result = JSON.stringify(mr);
|
|
165
|
+
if (result !== '[{"tag":"e","sequence":[]},true,[]]') {
|
|
166
|
+
throw result;
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
() => {
|
|
170
|
+
const emptyRule = '';
|
|
171
|
+
const variantRule = { 'e': emptyRule, 'a': range('AA') };
|
|
172
|
+
const m = parser(variantRule);
|
|
173
|
+
const mr = m("", [64]);
|
|
174
|
+
const result = JSON.stringify(mr);
|
|
175
|
+
if (result !== '[{"tag":"e","sequence":[]},true,[64]]') {
|
|
176
|
+
throw result;
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
() => {
|
|
180
|
+
const stringRule = 'AB';
|
|
181
|
+
const m = parser(stringRule);
|
|
182
|
+
const mr = m("", [65, 66]);
|
|
183
|
+
const result = JSON.stringify(mr);
|
|
184
|
+
if (result !== '[{"sequence":[65,{"sequence":[66]}]},true,[]]') {
|
|
185
|
+
throw result;
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
() => {
|
|
189
|
+
const stringRule = 'AB';
|
|
190
|
+
const m = parser(stringRule);
|
|
191
|
+
const mr = m("", [65, 67]);
|
|
192
|
+
const result = JSON.stringify(mr);
|
|
193
|
+
if (result !== '[{"sequence":[]},false,[67]]') {
|
|
194
|
+
throw result;
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
() => {
|
|
198
|
+
const emptyRule = '';
|
|
199
|
+
const minursRule = range('--');
|
|
200
|
+
const optionalMinusRule = { 'none': emptyRule, 'minus': minursRule };
|
|
201
|
+
const digitRule = range('09');
|
|
202
|
+
const numberRule = [optionalMinusRule, digitRule];
|
|
203
|
+
const m = parser(numberRule);
|
|
204
|
+
const mr = m("", [50]);
|
|
205
|
+
const result = JSON.stringify(mr);
|
|
206
|
+
if (result !== '[{"sequence":[50]},true,[]]') {
|
|
207
|
+
throw result;
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
() => {
|
|
211
|
+
const emptyRule = '';
|
|
212
|
+
const minusRule = range('--');
|
|
213
|
+
const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
|
|
214
|
+
const digitRule = range('09');
|
|
215
|
+
const numberRule = [optionalMinusRule, digitRule];
|
|
216
|
+
const m = parser(numberRule);
|
|
217
|
+
const mr = m("", [45, 50]);
|
|
218
|
+
const result = JSON.stringify(mr);
|
|
219
|
+
if (result !== '[{"tag":"minus","sequence":[45,{"sequence":[50]}]},true,[]]') {
|
|
220
|
+
throw result;
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
() => {
|
|
224
|
+
const emptyRule = '';
|
|
225
|
+
const minusRule = range('--');
|
|
226
|
+
const optionalMinusRule = { 'none': emptyRule, 'minus': minusRule };
|
|
227
|
+
const digitRule = range('09');
|
|
228
|
+
const numberRule = [optionalMinusRule, digitRule];
|
|
229
|
+
const m = parser(numberRule);
|
|
230
|
+
const mr = m("", []);
|
|
231
|
+
const result = JSON.stringify(mr);
|
|
232
|
+
if (result !== '[{"sequence":[]},true,null]') {
|
|
233
|
+
throw result;
|
|
234
|
+
} //if remainder is null it means failed
|
|
235
|
+
},
|
|
236
|
+
() => {
|
|
237
|
+
const m = parser(option('a'));
|
|
238
|
+
const isSuccess = (mr) => mr[1] && mr[2]?.length === 0;
|
|
239
|
+
const expect = (s, success) => {
|
|
240
|
+
const mr = m('', toArray(stringToCodePointList(s)));
|
|
241
|
+
if (isSuccess(mr) !== success) {
|
|
242
|
+
throw mr;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
expect('a', true);
|
|
246
|
+
expect('', true);
|
|
247
|
+
expect('aa', false);
|
|
248
|
+
expect('b', false);
|
|
249
|
+
},
|
|
250
|
+
() => {
|
|
251
|
+
const ws = repeat0Plus(set(' \n\r\t'));
|
|
252
|
+
const cj = commaJoin0Plus(ws);
|
|
253
|
+
const value = () => ({
|
|
254
|
+
object: cj('{}', 'a'),
|
|
255
|
+
array: cj('[]', 'a')
|
|
256
|
+
});
|
|
257
|
+
value.name; //bun will fail if no usage of name found
|
|
258
|
+
const m = parser(value);
|
|
259
|
+
const isSuccess = (mr) => mr[1] && mr[2]?.length === 0;
|
|
260
|
+
const expect = (s, success) => {
|
|
261
|
+
const mr = m('value', toArray(stringToCodePointList(s)));
|
|
262
|
+
if (isSuccess(mr) !== success) {
|
|
263
|
+
throw mr;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
expect('', false);
|
|
267
|
+
expect('[]', true);
|
|
268
|
+
expect('[a]', true);
|
|
269
|
+
expect('[a, a]', true);
|
|
270
|
+
expect('{a}', true);
|
|
271
|
+
},
|
|
272
|
+
() => {
|
|
273
|
+
const m = parser(deterministic());
|
|
274
|
+
const isSuccess = (mr) => mr[1] && mr[2]?.length === 0;
|
|
275
|
+
const expect = (s, success) => {
|
|
276
|
+
const mr = m('', toArray(stringToCodePointList(s)));
|
|
277
|
+
if (isSuccess(mr) !== success) {
|
|
278
|
+
throw mr;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
expect(' true ', true);
|
|
282
|
+
expect(' tr2ue ', false);
|
|
283
|
+
expect(' true" ', false);
|
|
284
|
+
expect(' "Hello" ', true);
|
|
285
|
+
expect(' "Hello ', false);
|
|
286
|
+
expect(' "Hello\\n\\r\\"" ', true);
|
|
287
|
+
expect(' -56.7e+5 ', true);
|
|
288
|
+
expect(' h-56.7e+5 ', false);
|
|
289
|
+
expect(' -56.7e+5 3', false);
|
|
290
|
+
expect(' [] ', true);
|
|
291
|
+
expect(' {} ', true);
|
|
292
|
+
expect(' [[[]]] ', true);
|
|
293
|
+
expect(' [1] ', true);
|
|
294
|
+
expect(' [ 12, false, "a"] ', true);
|
|
295
|
+
expect(' [ 12, false2, "a"] ', false);
|
|
296
|
+
expect(' { "q": [ 12, false, [{"b" : "c"}], "a"] } ', true);
|
|
297
|
+
expect(' { "q": [ 12, false, [{}], "a"] } ', true);
|
|
298
|
+
expect(' { "q": [ 12, false, [}], "a"] } ', false);
|
|
299
|
+
expect(' [{ "q": [ 12, false, [{}], "a"] }] ', true);
|
|
300
|
+
expect(' [{ "q": [ 12, false, [}], "a"] }] ', false);
|
|
301
|
+
}
|
|
302
|
+
],
|
|
303
|
+
repeat: [
|
|
304
|
+
() => {
|
|
305
|
+
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
|
|
306
|
+
const dm = dispatchMap(repeatData[0]);
|
|
307
|
+
const result = JSON.stringify(dm);
|
|
308
|
+
if (result !== '{"ws":{"emptyTag":true,"rangeMap":[]},"a":{"rangeMap":[[null,64],[{"rules":[]},65]]},"repa":{"rangeMap":[[null,64],[{"rules":[""]},65]]},"":{"rangeMap":[[null,64],[{"rules":[""]},65]]}}') {
|
|
309
|
+
throw result;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
],
|
|
313
|
+
repeatParser: [
|
|
314
|
+
() => {
|
|
315
|
+
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
|
|
316
|
+
const m = parserRuleSet(repeatData[0]);
|
|
317
|
+
const mr = m("", []);
|
|
318
|
+
const result = JSON.stringify(mr);
|
|
319
|
+
if (result !== '[{"sequence":[]},true,null]') {
|
|
320
|
+
throw result;
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
() => {
|
|
324
|
+
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
|
|
325
|
+
const m = parserRuleSet(repeatData[0]);
|
|
326
|
+
const mr = m("", [65]);
|
|
327
|
+
const result = JSON.stringify(mr);
|
|
328
|
+
if (result !== '[{"sequence":[65,{"sequence":[]}]},true,null]') {
|
|
329
|
+
throw result;
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
() => {
|
|
333
|
+
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
|
|
334
|
+
const m = parserRuleSet(repeatData[0]);
|
|
335
|
+
const mr = m("", [65, 65, 65]);
|
|
336
|
+
const result = JSON.stringify(mr);
|
|
337
|
+
if (result !== '[{"sequence":[65,{"sequence":[65,{"sequence":[65,{"sequence":[]}]}]}]},true,null]') {
|
|
338
|
+
throw result;
|
|
339
|
+
}
|
|
340
|
+
},
|
|
341
|
+
() => {
|
|
342
|
+
const repeatData = [{ "": ["ws", "repa"], "ws": [], "repa": ["a", ""], "a": 1090519105 }, ""];
|
|
343
|
+
const m = parserRuleSet(repeatData[0]);
|
|
344
|
+
const mr = m("", [66]);
|
|
345
|
+
const result = JSON.stringify(mr);
|
|
346
|
+
if (result !== '[{"sequence":[]},false,[66]]') {
|
|
347
|
+
throw result;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
],
|
|
351
|
+
throw: {
|
|
352
|
+
ambiguousVariantDispatch: () => {
|
|
353
|
+
// Two alternatives covering the same code point — dispatch merge throws.
|
|
354
|
+
const conflictRule = { 'a': range('AA'), 'b': range('AA') };
|
|
355
|
+
dispatchMap(toData(conflictRule)[0]);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type All, type Read, type Write, type WriteFile } from '../../effects/node/module.f.ts';
|
|
2
|
+
import { type Commands } from '../../cli/module.f.ts';
|
|
3
|
+
import { type MemOp } from '../../effects/memory/module.f.ts';
|
|
4
|
+
import { type FileCasOperation } from '../module.f.ts';
|
|
5
|
+
export declare const commands: Commands<FileCasOperation | WriteFile | Write | All | MemOp | Read>;
|
|
6
|
+
export declare const main: (options: import("../../effects/node/module.f.ts").NodeProgramOptions) => import("../../effects/module.f.ts").Effect<All | Read | Write | WriteFile | FileCasOperation | MemOp, number>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAS CLI command handlers.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import { sha256 } from "../../crypto/sha2/module.f.js";
|
|
7
|
+
import { cBase32ToVec, vecToCBase32 } from "../../cbase32/module.f.js";
|
|
8
|
+
import { forEachStep, pure } from "../../effects/module.f.js";
|
|
9
|
+
import { errorExit, log, writeFromStream } from "../../effects/node/module.f.js";
|
|
10
|
+
import { dispatch } from "../../cli/module.f.js";
|
|
11
|
+
import {} from "../../effects/memory/module.f.js";
|
|
12
|
+
import { casAddFile, fileCas } from "../module.f.js";
|
|
13
|
+
export const commands = [
|
|
14
|
+
{
|
|
15
|
+
names: ['add'],
|
|
16
|
+
description: 'Store file content and print its hash',
|
|
17
|
+
handler: ({ home, args: [path, ...rest] }) => {
|
|
18
|
+
if (path === undefined || rest.length !== 0) {
|
|
19
|
+
return errorExit("'cas add' expects one parameter");
|
|
20
|
+
}
|
|
21
|
+
const c = fileCas(sha256)(home);
|
|
22
|
+
return casAddFile(c)(path)
|
|
23
|
+
.step(hashResult => hashResult[0] === 'error'
|
|
24
|
+
? pure(1)
|
|
25
|
+
: log(vecToCBase32(hashResult[1])).step(() => pure(0)));
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
names: ['get'],
|
|
30
|
+
description: 'Restore content by hash into a file',
|
|
31
|
+
handler: ({ home, args: [hashCBase32, path, ...rest] }) => {
|
|
32
|
+
if (hashCBase32 === undefined || path === undefined || rest.length !== 0) {
|
|
33
|
+
return errorExit("'cas get' expects two parameters");
|
|
34
|
+
}
|
|
35
|
+
const hash = cBase32ToVec(hashCBase32);
|
|
36
|
+
if (hash === null) {
|
|
37
|
+
return errorExit(`invalid hash format: ${hashCBase32}`);
|
|
38
|
+
}
|
|
39
|
+
const c = fileCas(sha256)(home);
|
|
40
|
+
const x = c.read(hash);
|
|
41
|
+
return writeFromStream(path, x)
|
|
42
|
+
.step(([r, v]) => r === 'error' ? errorExit(`e: ` + String(v)) : pure(0));
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
names: ['list'],
|
|
47
|
+
description: 'List all stored content hashes',
|
|
48
|
+
handler: ({ home }) => {
|
|
49
|
+
const c = fileCas(sha256)(home);
|
|
50
|
+
return c.list()
|
|
51
|
+
.step(forEachStep(j => log(vecToCBase32(j))))
|
|
52
|
+
.step(() => pure(0));
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
export const main = dispatch(commands);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const proof: {
|
|
2
|
+
mainAdd: () => void;
|
|
3
|
+
mainAddGetBig: () => void;
|
|
4
|
+
mainAddWrongArgs: () => void;
|
|
5
|
+
mainGetFound: () => void;
|
|
6
|
+
mainGetNotFound: () => void;
|
|
7
|
+
mainGetWrongArgs: () => void;
|
|
8
|
+
mainGetInvalidHash: () => void;
|
|
9
|
+
mainList: () => void;
|
|
10
|
+
mainListEmptyStore: () => void;
|
|
11
|
+
mainListCorruptStore: () => void;
|
|
12
|
+
mainNoCmd: () => void;
|
|
13
|
+
mainUnknownCmd: () => void;
|
|
14
|
+
};
|