functionalscript 0.3.11 → 0.3.13

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.
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Types for defining language grammar using Backus-Naur Form (BNF).
3
+ *
4
+ * @module
5
+ *
6
+ * @description
7
+ *
8
+ * Utilities for serializing and deserializing BNF grammar
9
+ * and creating a simple LL(1) parser.
10
+ *
11
+ * See [Backus-Naur form](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form).
12
+ *
13
+ * @example
14
+ *
15
+ * ```ts
16
+ * import type { Rule } from './module.f.ts'
17
+ *
18
+ * // Matches 'A-Z', 'a-z', and '0-9'
19
+ * const grammar: Rule = () => [
20
+ * [[65, 90]],
21
+ * [[97, 122]],
22
+ * [[48, 57]],
23
+ * ]
24
+ * ```
25
+ */
26
+ import { type CodePoint } from '../../text/utf16/module.f.ts';
27
+ /**
28
+ * Represents a terminal range as a pair of Unicode code points.
29
+ * Typically used to define character ranges.
30
+ *
31
+ * @example
32
+ *
33
+ * ```ts
34
+ * const alpha: TerminalRange = [65, 90] // Matches 'A-Z'
35
+ * ```
36
+ */
37
+ export type TerminalRange = readonly [CodePoint, CodePoint];
38
+ /**
39
+ * Represents a sequence of rules that must match in order.
40
+ *
41
+ * @example
42
+ *
43
+ * ```ts
44
+ * const alpha: TerminalRange = [65, 90] // Matches 'A-Z'
45
+ * const id2: Sequence = [alpha, alpha] // Matches two uppercase letters
46
+ * ```
47
+ */
48
+ export type Sequence = readonly (TerminalRange | Rule)[];
49
+ /**
50
+ * Represents a logical "or" operation between multiple sequences.
51
+ * Allows defining alternatives within the grammar.
52
+ *
53
+ * @example
54
+ *
55
+ * ```ts
56
+ * const alpha: TerminalRange = [65, 90] // Matches 'A-Z'
57
+ * const id2: Sequence = [alpha, alpha] // Matches two uppercase letters
58
+ * const digit: TerminalRange = [48, 57] // Matches '0-9'
59
+ * // Matches two uppercase letters or one digit
60
+ * const id2OrDigit: Or = [
61
+ * id2,
62
+ * [digit],
63
+ * ]
64
+ * ```
65
+ */
66
+ export type Or = readonly Sequence[];
67
+ /**
68
+ * Represents a lazy grammar rule for recursive definitions.
69
+ *
70
+ * @example
71
+ *
72
+ * ```ts
73
+ * const alpha: TerminalRange = [65, 90] // Matches 'A-Z'
74
+ * // zero or more alpha symbols
75
+ * const alpha0x: Rule = () => [
76
+ * [], // Empty
77
+ * [alpha, alpha0x] // Recursive
78
+ * ]
79
+ * const id: Sequence = [alpha, alpha0x]
80
+ * ```
81
+ */
82
+ export type Rule = () => Or;
83
+ /**
84
+ * Converts a string to an array of terminal ranges where each character is a separate range.
85
+ *
86
+ * @param s - The input string.
87
+ * @returns An array of terminal ranges representing each character in the string.
88
+ *
89
+ * @example
90
+ *
91
+ * ```ts
92
+ * const ranges = str('abc') // [[97, 97], [98, 98], [99, 99]]
93
+ * ```
94
+ */
95
+ export declare const str: (s: string) => readonly TerminalRange[];
96
+ /**
97
+ * Converts a single character string to a terminal range.
98
+ *
99
+ * @param a - The input character string.
100
+ * @returns A terminal range representing the character.
101
+ *
102
+ * @example
103
+ * ```ts
104
+ * const range = cp('A'); // [65, 65]
105
+ * ```
106
+ */
107
+ export declare const cp: (a: string) => TerminalRange;
108
+ /**
109
+ * Converts a two-character string into a terminal range.
110
+ *
111
+ * @param ab - The input string of two characters.
112
+ * @returns A terminal range representing the two characters.
113
+ *
114
+ * @throws {number} Throws an error if the input string does not have exactly two code points.
115
+ *
116
+ * @example
117
+ * ```ts
118
+ * const result = range('AZ'); // [65, 90]
119
+ * ```
120
+ */
121
+ export declare const range: (ab: string) => TerminalRange;
122
+ type RangeSet = readonly TerminalRange[];
123
+ /**
124
+ * A set of terminal ranges compatible with the `Or` rule.
125
+ */
126
+ export type OrRangeSet = readonly (readonly [TerminalRange])[];
127
+ /**
128
+ * Removes a terminal range from a set of ranges.
129
+ *
130
+ * @param range the original range.
131
+ * @param removeSet the set of ranges to be removed.
132
+ * @returns The resulting set of ranges after removal.
133
+ *
134
+ * @example
135
+ *
136
+ * ```ts
137
+ * const result = remove([65, 90], [cp('C'), cp('W')]) // [A..Z] w/o C and W
138
+ * ```
139
+ */
140
+ export declare const remove: (range: TerminalRange, removeSet: RangeSet) => OrRangeSet;
141
+ export {};
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Types for defining language grammar using Backus-Naur Form (BNF).
3
+ *
4
+ * @module
5
+ *
6
+ * @description
7
+ *
8
+ * Utilities for serializing and deserializing BNF grammar
9
+ * and creating a simple LL(1) parser.
10
+ *
11
+ * See [Backus-Naur form](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form).
12
+ *
13
+ * @example
14
+ *
15
+ * ```ts
16
+ * import type { Rule } from './module.f.ts'
17
+ *
18
+ * // Matches 'A-Z', 'a-z', and '0-9'
19
+ * const grammar: Rule = () => [
20
+ * [[65, 90]],
21
+ * [[97, 122]],
22
+ * [[48, 57]],
23
+ * ]
24
+ * ```
25
+ */
26
+ import { stringToCodePointList } from "../../text/utf16/module.f.js";
27
+ import { map, toArray } from "../../types/list/module.f.js";
28
+ import { one } from "../../types/range/module.f.js";
29
+ const toTerminalRangeMap = map(one);
30
+ /**
31
+ * Converts a string to an array of terminal ranges where each character is a separate range.
32
+ *
33
+ * @param s - The input string.
34
+ * @returns An array of terminal ranges representing each character in the string.
35
+ *
36
+ * @example
37
+ *
38
+ * ```ts
39
+ * const ranges = str('abc') // [[97, 97], [98, 98], [99, 99]]
40
+ * ```
41
+ */
42
+ export const str = (s) => toArray(toTerminalRangeMap(stringToCodePointList(s)));
43
+ /**
44
+ * Converts a single character string to a terminal range.
45
+ *
46
+ * @param a - The input character string.
47
+ * @returns A terminal range representing the character.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const range = cp('A'); // [65, 65]
52
+ * ```
53
+ */
54
+ export const cp = (a) => one(a.codePointAt(0));
55
+ /**
56
+ * Converts a two-character string into a terminal range.
57
+ *
58
+ * @param ab - The input string of two characters.
59
+ * @returns A terminal range representing the two characters.
60
+ *
61
+ * @throws {number} Throws an error if the input string does not have exactly two code points.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const result = range('AZ'); // [65, 90]
66
+ * ```
67
+ */
68
+ export const range = (ab) => {
69
+ const a = toArray(stringToCodePointList(ab));
70
+ if (a.length !== 2) {
71
+ throw a.length;
72
+ }
73
+ // deno-lint-ignore no-explicit-any
74
+ return a;
75
+ };
76
+ const removeOne = (set, [a, b]) => {
77
+ let result = [];
78
+ for (const [a0, b0] of set) {
79
+ if (a0 < a) {
80
+ // [a0
81
+ // ]a
82
+ result = [...result, [a0, Math.min(b0, a - 1)]];
83
+ }
84
+ if (b < b0) {
85
+ // b0]
86
+ // b[
87
+ result = [...result, [Math.max(b + 1, a0), b0]];
88
+ }
89
+ }
90
+ return result;
91
+ };
92
+ /**
93
+ * Removes a terminal range from a set of ranges.
94
+ *
95
+ * @param range the original range.
96
+ * @param removeSet the set of ranges to be removed.
97
+ * @returns The resulting set of ranges after removal.
98
+ *
99
+ * @example
100
+ *
101
+ * ```ts
102
+ * const result = remove([65, 90], [cp('C'), cp('W')]) // [A..Z] w/o C and W
103
+ * ```
104
+ */
105
+ export const remove = (range, removeSet) => {
106
+ let result = [range];
107
+ for (const r of removeSet) {
108
+ result = removeOne(result, r);
109
+ }
110
+ return result.map(v => [v]);
111
+ };
@@ -0,0 +1,12 @@
1
+ declare const _default: {
2
+ example: {
3
+ module: () => void;
4
+ types: () => void;
5
+ str: () => void;
6
+ cp: () => void;
7
+ range: () => void;
8
+ remove: () => void;
9
+ };
10
+ remove: () => void;
11
+ };
12
+ export default _default;
@@ -0,0 +1,230 @@
1
+ import { stringify } from "../../json/module.f.js";
2
+ import { sort } from "../../types/object/module.f.js";
3
+ import { cp, str, range, remove, } from "./module.f.js";
4
+ const deterministic = () => {
5
+ // {"empty":true,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32]]}
6
+ const ws = () => [
7
+ [],
8
+ [cp('\t'), ws], // 9
9
+ [cp('\n'), ws], // 10
10
+ [cp('\r'), ws], // 13
11
+ [cp(' '), ws], // 32
12
+ ];
13
+ // {"empty":true,"map":[[false,42],[true,43],[false,44],[true,45]]}
14
+ const sign = () => [
15
+ [],
16
+ str('+'), // 43
17
+ str('-'), // 45
18
+ ];
19
+ // {"empty":false,"map":[[false,48],[true,57]]}
20
+ const onenine = () => [
21
+ [range('19')]
22
+ ];
23
+ // {"empty":false,"map":[[false,47],[true,57]]}
24
+ const digit = () => [
25
+ str('0'),
26
+ [onenine],
27
+ ];
28
+ // {"empty":true,"map":[[false,47],[true,57]]}
29
+ const digits1 = () => [
30
+ [],
31
+ [digit, digits1]
32
+ ];
33
+ // {"empty":false,"map":[[false,47],[true,57]]}
34
+ const digits = () => [
35
+ [digit, digits1]
36
+ ];
37
+ // {"empty":true,"map":[[false,68],[true,69],[false,100],[true,101]]}
38
+ const exponent = () => [
39
+ [],
40
+ [cp('E'), sign, digits], // 69
41
+ [cp('e'), sign, digits], // 101
42
+ ];
43
+ // {"empty":true,"map":[[false,45],[true,46]]}
44
+ const fraction = () => [
45
+ [],
46
+ [cp('.'), digits] // 46
47
+ ];
48
+ // {"empty":false,"map":[[false,47],[true,57]]}
49
+ const integer1 = () => [
50
+ str('0'), // 48
51
+ [onenine, digits1], // 49-57
52
+ ];
53
+ // {"empty":false,"map":[[false,44],[true,45],[false,47],[true,57]]}
54
+ const integer = () => [
55
+ [integer1], // 48-57
56
+ [cp('-'), integer1], // 45
57
+ ];
58
+ // {"empty":false,"map":[[false,44],[true,45],[false,47],[true,57]]}
59
+ const number = () => [
60
+ [integer, fraction, exponent]
61
+ ];
62
+ // {"empty":false,"map":[[false,47],[true,57],[false,64],[true,70],[false,96],[true,102]]}
63
+ const hex = () => [
64
+ [digit], // 48-57
65
+ [range('AF')], // A..F
66
+ [range('af')], // a..f
67
+ ];
68
+ // {"empty":false,"map":[[false,33],[true,34],[false,46],[true,47],[false,91],[true,92],[false,97],[true,98],[false,101],[true,102],[false,109],[true,110],[false,113],[true,114],[false,115],[true,117]]}
69
+ const escape = () => [
70
+ str('"'), // 34
71
+ str('/'), // 47
72
+ str('\\'), // 92
73
+ str('b'), // 98
74
+ str('f'), // 102
75
+ str('n'), // 110
76
+ str('r'), // 114
77
+ str('t'), // 116
78
+ [cp('u'), hex, hex, hex, hex] // 117
79
+ ];
80
+ // {"empty":false,"map":[[false,31],[true,33],[false,34],[true,1114111]]}
81
+ const character = () => [
82
+ ...remove([0x20, 0x10FFFF], [cp('"'), cp('\\')]),
83
+ [cp('\\'), escape], // 92
84
+ ];
85
+ // {"empty":true,"map":[[false,31],[true,33],[false,34],[true,1114111]]}
86
+ const characters = () => [
87
+ [],
88
+ [character, characters]
89
+ ];
90
+ // {"empty":false,"map":[[false,33],[true,34]]}
91
+ const string = () => [
92
+ [cp('"'), characters, cp('"')]
93
+ ];
94
+ // {"empty":false,"map":[[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
95
+ const element1 = () => [
96
+ [value, ws]
97
+ ];
98
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
99
+ const element = () => [
100
+ [ws, element1]
101
+ ];
102
+ // {"empty":true,"map":[[false,43],[true,44]]}
103
+ const elements2 = () => [
104
+ [],
105
+ [cp(','), elements] // 44
106
+ ];
107
+ // {"empty":false,"map":[[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
108
+ const elements1 = () => [
109
+ [element1, elements2]
110
+ ];
111
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
112
+ const elements = () => [
113
+ [ws, elements1]
114
+ ];
115
+ // {"empty":false,"map":[[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,92],[true,93],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
116
+ const array1 = () => [
117
+ str(']'), // 93
118
+ [elements1, cp(']')],
119
+ ];
120
+ // {"empty":false,"map":[[false,90],[true,91]]}
121
+ const array = () => [
122
+ [cp('['), ws, array1]
123
+ ];
124
+ // {"empty":false,"map":[[false,33],[true,34]]}
125
+ const member1 = () => [
126
+ [string, ws, cp(':'), element]
127
+ ];
128
+ // {"empty":true,"map":[[false,43],[true,44]]}
129
+ const members2 = () => [
130
+ [],
131
+ [cp(','), members], // 44
132
+ ];
133
+ // {"empty":false,"map":[[false,33],[true,34]]}
134
+ const members1 = () => [
135
+ [member1, members2]
136
+ ];
137
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34]]}
138
+ const members = () => [
139
+ [ws, members1]
140
+ ];
141
+ // {"empty":false,"map":[[false,33],[true,34],[false,124],[true,125]]}
142
+ const object1 = () => [
143
+ str('}'), // 125
144
+ [members1, cp('}')],
145
+ ];
146
+ // {"empty":false,"map":[[false,122],[true,123]]}
147
+ const object = () => [
148
+ [cp('{'), ws, object1]
149
+ ];
150
+ // {"empty":false,"map":[[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
151
+ const value = () => [
152
+ [object], // 123
153
+ [array], // 91
154
+ [string], // 34
155
+ [number], // 45, 48-57
156
+ str('true'), // 116
157
+ str('false'), // 102
158
+ str('null'), // 110
159
+ ];
160
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
161
+ const json = element;
162
+ const _ = json;
163
+ };
164
+ //
165
+ const s = stringify(sort);
166
+ export default {
167
+ example: {
168
+ module: () => {
169
+ // Matches 'A-Z', 'a-z', and '0-9'
170
+ const grammar = () => [
171
+ [range('AZ')],
172
+ [range('az')],
173
+ [range('09')],
174
+ ];
175
+ const _ = grammar;
176
+ },
177
+ types: () => {
178
+ const alpha = range('AZ'); // Matches 'A-Z'
179
+ const id2 = [alpha, alpha]; // Matches two uppercase letters
180
+ const digit = range('09'); // Matches '0-9'
181
+ // Matches two uppercase letters or one digit
182
+ const id2OrDigit = [
183
+ id2,
184
+ [digit],
185
+ ];
186
+ // Matches 'true', 'false'
187
+ const bool = () => [
188
+ str('true'),
189
+ str('false'),
190
+ ];
191
+ // zero or more alpha symbols
192
+ const alpha0x = () => [
193
+ [], // Empty
194
+ [alpha, alpha0x] // Recursive
195
+ ];
196
+ const id = [alpha, alpha0x];
197
+ const _ = [id2OrDigit, bool, id];
198
+ },
199
+ str: () => {
200
+ const ranges = str('abc'); // [[97, 97], [98, 98], [99, 99]]
201
+ const result = s(ranges);
202
+ if (result !== '[[97,97],[98,98],[99,99]]') {
203
+ throw result;
204
+ }
205
+ },
206
+ cp: () => {
207
+ const range = cp('A'); // [65, 65]
208
+ const result = s(range);
209
+ if (result !== '[65,65]') {
210
+ throw result;
211
+ }
212
+ },
213
+ range: () => {
214
+ const r = range('AZ'); // [65, 90]
215
+ const result = s(r);
216
+ if (result !== '[65,90]') {
217
+ throw result;
218
+ }
219
+ },
220
+ remove: () => {
221
+ const result = s(remove([65, 90], [cp('C'), cp('W')])); // [A..Z] w/o C and W
222
+ if (result !== '[[[65,66]],[[68,86]],[[88,90]]]') {
223
+ throw result;
224
+ }
225
+ }
226
+ },
227
+ remove: () => {
228
+ const _x = remove([0x20, 0x10FFFF], [cp('"'), cp('\\')]);
229
+ }
230
+ };
@@ -0,0 +1,25 @@
1
+ import { type Rule } from './module.f.ts';
2
+ export declare const classic: () => {
3
+ readonly ws: Rule;
4
+ readonly sign: Rule;
5
+ readonly digits: Rule;
6
+ readonly exponent: Rule;
7
+ readonly fraction: Rule;
8
+ readonly onenine: Rule;
9
+ readonly digit: Rule;
10
+ readonly string: Rule;
11
+ readonly member: Rule;
12
+ readonly members: Rule;
13
+ readonly object: Rule;
14
+ readonly array: Rule;
15
+ readonly integer: Rule;
16
+ readonly number: Rule;
17
+ readonly value: Rule;
18
+ readonly element: Rule;
19
+ readonly elements: Rule;
20
+ readonly json: Rule;
21
+ readonly hex: Rule;
22
+ readonly escape: Rule;
23
+ readonly character: Rule;
24
+ readonly characters: Rule;
25
+ };
@@ -0,0 +1,150 @@
1
+ import { cp, range, remove, str } from "./module.f.js";
2
+ // https://www.json.org/json-en.html
3
+ export const classic = () => {
4
+ // {"empty":true,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32]]}
5
+ const ws = () => [
6
+ [],
7
+ [cp(' '), ws], // 32
8
+ [cp('\n'), ws], // 10
9
+ [cp('\r'), ws], // 13
10
+ [cp('\t'), ws], // 9
11
+ ];
12
+ // {"empty":true,"map":[[false,42],[true,43],[false,44],[true,45]]}
13
+ const sign = () => [
14
+ [],
15
+ str('+'), // 43
16
+ str('-'), // 45
17
+ ];
18
+ // {"empty":false,"map":[[false,48],[true,57]]}
19
+ const onenine = () => [[[0x31, 0x39]]];
20
+ // {"empty":false,"map":[[false,47],[true,57]]}
21
+ const digit = () => [
22
+ str('0'),
23
+ [onenine],
24
+ ];
25
+ // {"empty":false,"map":[[false,47],[true,57]]}
26
+ const digits = () => [
27
+ [digit],
28
+ [digit, digits]
29
+ ];
30
+ // {"empty":true,"map":[[false,68],[true,69],[false,100],[true,101]]}
31
+ const exponent = () => [
32
+ [],
33
+ [cp('E'), sign, digits], // 69
34
+ [cp('e'), sign, digits], // 101
35
+ ];
36
+ // {"empty":true,"map":[[false,45],[true,46]]}
37
+ const fraction = () => [
38
+ [],
39
+ [cp('.'), digits] // 46
40
+ ];
41
+ // {"empty":false,"map":[[false,44],[true,45],[false,47],[true,57]]}
42
+ const integer = () => [
43
+ [digit], // 48-57
44
+ [onenine, digits],
45
+ [cp('-'), digit], // 45
46
+ [cp('-'), onenine, digits],
47
+ ];
48
+ // {"empty":false,"map":[[false,44],[true,45],[false,47],[true,57]]}
49
+ const number = () => [
50
+ [integer, fraction, exponent]
51
+ ];
52
+ // {"empty":false,"map":[[false,47],[true,57],[false,64],[true,70],[false,96],[true,102]]}
53
+ const hex = () => [
54
+ [digit], // 48-57
55
+ [range('AF')], // A..F
56
+ [range('af')], // a..f
57
+ ];
58
+ // {"empty":false,"map":[[false,33],[true,34],[false,46],[true,47],[false,91],[true,92],[false,97],[true,98],[false,101],[true,102],[false,109],[true,110],[false,113],[true,114],[false,115],[true,117]]}
59
+ const escape = () => [
60
+ str('"'), // 34
61
+ str('\\'), // 92
62
+ str('/'), // 47
63
+ str('b'), // 98
64
+ str('f'), // 102
65
+ str('n'), // 110
66
+ str('r'), // 114
67
+ str('t'), // 116
68
+ [cp('u'), hex, hex, hex, hex] // 117
69
+ ];
70
+ // {"empty":false,"map":[[false,31],[true,33],[false,34],[true,1114111]]}
71
+ const character = () => [
72
+ ...remove([0x20, 0x10FFFF], [cp('"'), cp('\\')]),
73
+ [cp('\\'), escape],
74
+ ];
75
+ // {"empty":true,"map":[[false,31],[true,33],[false,34],[true,1114111]]}
76
+ const characters = () => [
77
+ [],
78
+ [character, characters]
79
+ ];
80
+ // {"empty":false,"map":[[false,33],[true,34]]}
81
+ const string = () => [
82
+ [cp('"'), characters, cp('"')]
83
+ ];
84
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
85
+ const element = () => [
86
+ [ws, value, ws]
87
+ ];
88
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
89
+ const elements = () => [
90
+ [element],
91
+ [element, cp(','), elements]
92
+ ];
93
+ // {"empty":false,"map":[[false,90],[true,91]]}
94
+ const array = () => [
95
+ [cp('['), ws, cp(']')], // 91
96
+ [cp('['), elements, cp(']')],
97
+ ];
98
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34]]}
99
+ const member = () => [
100
+ [ws, string, ws, cp(':'), element]
101
+ ];
102
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34]]}
103
+ const members = () => [
104
+ [member],
105
+ [member, cp(','), members],
106
+ ];
107
+ // {"empty":false,"map":[[false,122],[true,123]]}
108
+ const object = () => [
109
+ [cp('{'), ws, cp('}')], // 123
110
+ [cp('{'), members, cp('}')],
111
+ ];
112
+ // {"empty":false,"map":[[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
113
+ const value = () => [
114
+ [object], // 123
115
+ [array], // 91
116
+ [string], // 34
117
+ [number], // 45, 48-57
118
+ str('true'), // 116
119
+ str('false'), // 102
120
+ str('null'), // 110
121
+ ];
122
+ // {"empty":false,"map":[[false,8],[true,10],[false,12],[true,13],[false,31],[true,32],[false,33],[true,34],[false,44],[true,45],[false,47],[true,57],[false,90],[true,91],[false,101],[true,102],[false,109],[true,110],[false,115],[true,116],[false,122],[true,123]]}
123
+ const json = () => [
124
+ [element]
125
+ ];
126
+ return {
127
+ ws,
128
+ sign,
129
+ digits,
130
+ exponent,
131
+ fraction,
132
+ onenine,
133
+ digit,
134
+ string,
135
+ member,
136
+ members,
137
+ object,
138
+ array,
139
+ integer,
140
+ number,
141
+ value,
142
+ element,
143
+ elements,
144
+ json,
145
+ hex,
146
+ escape,
147
+ character,
148
+ characters,
149
+ };
150
+ };
@@ -23,7 +23,8 @@ export default (input) => {
23
23
  if (v.length === 0) {
24
24
  const [[s, r], delta, state0] = measure(() => tryCatch(v))(state);
25
25
  state = state0;
26
- if (s === 'error') {
26
+ // Usual tests throw on error, but if the function name is 'throw', then the test passes if it throws.
27
+ if ((s === 'error') === (v.name !== 'throw')) {
27
28
  ts = addFail(delta)(ts);
28
29
  if (isGitHub) {
29
30
  // https://docs.github.com/en/actions/learn-github-actions/workflow-commands-for-github-actions
package/fsc/module.f.js CHANGED
@@ -21,6 +21,7 @@ const reduce = (a) => {
21
21
  const merge = rangeMapMerge({
22
22
  union,
23
23
  equal: strictEqual,
24
+ def,
24
25
  });
25
26
  return toArray(listReduce(merge)(empty)(a));
26
27
  };