functionalscript 0.4.0 → 0.4.1
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/bnf/djs/test.f.js +36 -41
- package/bnf/func/module.f.d.ts +12 -5
- package/bnf/func/module.f.js +27 -6
- package/bnf/func/test.f.js +25 -84
- package/bnf/tag/module.f.d.ts +30 -0
- package/bnf/tag/module.f.js +37 -0
- package/bnf/tag/test.f.d.ts +1 -0
- package/bnf/tag/test.f.js +138 -0
- package/fsc/bnf.f.d.ts +2 -0
- package/fsc/bnf.f.js +54 -0
- package/fsc/json.f.d.ts +7 -0
- package/fsc/json.f.js +89 -0
- package/package.json +1 -1
- package/types/array/module.f.d.ts +1 -0
- package/types/array/module.f.js +1 -0
- package/types/bigint/module.f.d.ts +6 -0
- package/types/bigint/module.f.js +27 -5
- package/types/bigint/test.f.d.ts +8 -5
- package/types/bigint/test.f.js +91 -19
package/bnf/djs/test.f.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { cp, range, remove, str } from "../func/module.f.js";
|
|
1
|
+
import { cp, range, remove, set, str } from "../func/module.f.js";
|
|
2
2
|
import { parser, toRuleMap } from "./module.f.js";
|
|
3
3
|
import { classic } from "../func/testlib.f.js";
|
|
4
4
|
import * as j from "../../json/module.f.js";
|
|
@@ -114,14 +114,24 @@ const classicTest = () => {
|
|
|
114
114
|
const result = map;
|
|
115
115
|
return result;
|
|
116
116
|
};
|
|
117
|
+
const repeat0Name = (v) => `${v}Repeat0`;
|
|
118
|
+
const repeat0Body = (v) => [
|
|
119
|
+
[],
|
|
120
|
+
[v, repeat0Name(v)]
|
|
121
|
+
];
|
|
122
|
+
const repeat0 = (v) => {
|
|
123
|
+
const name = repeat0Name(v);
|
|
124
|
+
const body = repeat0Body(v);
|
|
125
|
+
return { [name]: body };
|
|
126
|
+
};
|
|
117
127
|
const deterministic = () => {
|
|
118
128
|
const map = {
|
|
119
129
|
json: [
|
|
120
|
-
['
|
|
130
|
+
['wsRepeat0', 'element']
|
|
121
131
|
],
|
|
122
132
|
value: [
|
|
123
|
-
[cp('{'), '
|
|
124
|
-
[cp('['), '
|
|
133
|
+
[cp('{'), 'wsRepeat0', 'object', cp('}')],
|
|
134
|
+
[cp('['), 'wsRepeat0', 'array', cp(']')],
|
|
125
135
|
['string'],
|
|
126
136
|
['number'],
|
|
127
137
|
str('true'),
|
|
@@ -130,14 +140,14 @@ const deterministic = () => {
|
|
|
130
140
|
],
|
|
131
141
|
object: [
|
|
132
142
|
[],
|
|
133
|
-
['member', '
|
|
143
|
+
['member', 'memberTailRepeat0'],
|
|
134
144
|
],
|
|
135
|
-
|
|
136
|
-
[]
|
|
137
|
-
[cp(','), 'ws', 'member', 'members'],
|
|
145
|
+
memberTail: [
|
|
146
|
+
[cp(','), 'wsRepeat0', 'member']
|
|
138
147
|
],
|
|
148
|
+
...repeat0('memberTail'),
|
|
139
149
|
member: [
|
|
140
|
-
['string', '
|
|
150
|
+
['string', 'wsRepeat0', cp(':'), 'wsRepeat0', 'element'],
|
|
141
151
|
],
|
|
142
152
|
array: [
|
|
143
153
|
[],
|
|
@@ -145,31 +155,21 @@ const deterministic = () => {
|
|
|
145
155
|
],
|
|
146
156
|
elements: [
|
|
147
157
|
[],
|
|
148
|
-
[cp(','), '
|
|
158
|
+
[cp(','), 'wsRepeat0', 'element', 'elements'],
|
|
149
159
|
],
|
|
150
160
|
element: [
|
|
151
|
-
['value', '
|
|
161
|
+
['value', 'wsRepeat0'],
|
|
152
162
|
],
|
|
153
163
|
string: [
|
|
154
|
-
[cp('"'), '
|
|
155
|
-
],
|
|
156
|
-
characters: [
|
|
157
|
-
[],
|
|
158
|
-
['character', 'characters'],
|
|
164
|
+
[cp('"'), 'characterRepeat0', cp('"')],
|
|
159
165
|
],
|
|
166
|
+
...repeat0('character'),
|
|
160
167
|
character: [
|
|
161
168
|
...remove([0x20, 0x10FFFF], [cp('"'), cp('\\')]),
|
|
162
169
|
[cp('\\'), 'escape'], // 92
|
|
163
170
|
],
|
|
164
171
|
escape: [
|
|
165
|
-
|
|
166
|
-
[cp('\\')],
|
|
167
|
-
[cp('/')],
|
|
168
|
-
[cp('b')],
|
|
169
|
-
[cp('f')],
|
|
170
|
-
[cp('n')],
|
|
171
|
-
[cp('r')],
|
|
172
|
-
[cp('t')],
|
|
172
|
+
...set('"\\/bfnrt'),
|
|
173
173
|
[cp('u'), 'hex', 'hex', 'hex', 'hex'],
|
|
174
174
|
],
|
|
175
175
|
hex: [
|
|
@@ -177,18 +177,18 @@ const deterministic = () => {
|
|
|
177
177
|
[range('AF')],
|
|
178
178
|
[range('af')],
|
|
179
179
|
],
|
|
180
|
+
numberSign: [
|
|
181
|
+
[],
|
|
182
|
+
[cp('-')]
|
|
183
|
+
],
|
|
180
184
|
number: [
|
|
181
|
-
['integer', 'fraction', 'exponent'],
|
|
182
|
-
[cp('-'), 'integer', 'fraction', 'exponent'],
|
|
185
|
+
['numberSign', 'integer', 'fraction', 'exponent'],
|
|
183
186
|
],
|
|
184
187
|
integer: [
|
|
185
188
|
[cp('0')],
|
|
186
|
-
['onenine', '
|
|
187
|
-
],
|
|
188
|
-
digits: [
|
|
189
|
-
[],
|
|
190
|
-
['digit', 'digits'],
|
|
189
|
+
['onenine', 'digitRepeat0'],
|
|
191
190
|
],
|
|
191
|
+
...repeat0('digit'),
|
|
192
192
|
digit: [
|
|
193
193
|
[cp('0')],
|
|
194
194
|
['onenine'],
|
|
@@ -198,25 +198,20 @@ const deterministic = () => {
|
|
|
198
198
|
],
|
|
199
199
|
fraction: [
|
|
200
200
|
[],
|
|
201
|
-
[cp('.'), 'digit', '
|
|
201
|
+
[cp('.'), 'digit', 'digitRepeat0'],
|
|
202
202
|
],
|
|
203
|
+
e: set('Ee'),
|
|
203
204
|
exponent: [
|
|
204
205
|
[],
|
|
205
|
-
[
|
|
206
|
-
[cp('e'), 'sign', 'digit', 'digits'],
|
|
206
|
+
['e', 'sign', 'digit', 'digitRepeat0'],
|
|
207
207
|
],
|
|
208
208
|
sign: [
|
|
209
209
|
[],
|
|
210
210
|
[cp('+')],
|
|
211
211
|
[cp('-')],
|
|
212
212
|
],
|
|
213
|
-
ws:
|
|
214
|
-
|
|
215
|
-
[cp(' '), 'ws'],
|
|
216
|
-
[cp('\n'), 'ws'],
|
|
217
|
-
[cp('\r'), 'ws'],
|
|
218
|
-
[cp('\t'), 'ws'],
|
|
219
|
-
],
|
|
213
|
+
ws: set(' \n\r\t'),
|
|
214
|
+
...repeat0('ws'),
|
|
220
215
|
};
|
|
221
216
|
const _map = map;
|
|
222
217
|
return _map;
|
package/bnf/func/module.f.d.ts
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*
|
|
6
|
-
* @description
|
|
2
|
+
* Types for defining language grammar using Backus-Naur Form (BNF).
|
|
7
3
|
*
|
|
8
4
|
* Utilities for serializing and deserializing BNF grammar
|
|
9
5
|
* and creating a simple LL(1) parser.
|
|
10
6
|
*
|
|
11
7
|
* See [Backus-Naur form](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form).
|
|
12
8
|
*
|
|
9
|
+
* @module
|
|
10
|
+
*
|
|
13
11
|
* @example
|
|
14
12
|
*
|
|
15
13
|
* ```ts
|
|
@@ -124,6 +122,13 @@ type RangeSet = readonly TerminalRange[];
|
|
|
124
122
|
* A set of terminal ranges compatible with the `Or` rule.
|
|
125
123
|
*/
|
|
126
124
|
export type OrRangeSet = readonly (readonly [TerminalRange])[];
|
|
125
|
+
/**
|
|
126
|
+
* Convert a sequence of character into `OrRangeSet`
|
|
127
|
+
*
|
|
128
|
+
* @param s a set of code points
|
|
129
|
+
* @returns A set compatible with `Or`
|
|
130
|
+
*/
|
|
131
|
+
export declare const set: (s: string) => OrRangeSet;
|
|
127
132
|
/**
|
|
128
133
|
* Removes a terminal range from a set of ranges.
|
|
129
134
|
*
|
|
@@ -138,4 +143,6 @@ export type OrRangeSet = readonly (readonly [TerminalRange])[];
|
|
|
138
143
|
* ```
|
|
139
144
|
*/
|
|
140
145
|
export declare const remove: (range: TerminalRange, removeSet: RangeSet) => OrRangeSet;
|
|
146
|
+
export declare const repeat0: (rule: Rule) => Rule;
|
|
147
|
+
export declare const join0: (rule: Rule, separator: Rule) => Rule;
|
|
141
148
|
export {};
|
package/bnf/func/module.f.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*
|
|
6
|
-
* @description
|
|
2
|
+
* Types for defining language grammar using Backus-Naur Form (BNF).
|
|
7
3
|
*
|
|
8
4
|
* Utilities for serializing and deserializing BNF grammar
|
|
9
5
|
* and creating a simple LL(1) parser.
|
|
10
6
|
*
|
|
11
7
|
* See [Backus-Naur form](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form).
|
|
12
8
|
*
|
|
9
|
+
* @module
|
|
10
|
+
*
|
|
13
11
|
* @example
|
|
14
12
|
*
|
|
15
13
|
* ```ts
|
|
@@ -73,6 +71,14 @@ export const range = (ab) => {
|
|
|
73
71
|
// deno-lint-ignore no-explicit-any
|
|
74
72
|
return a;
|
|
75
73
|
};
|
|
74
|
+
const toOr = (r) => r.map(v => [v]);
|
|
75
|
+
/**
|
|
76
|
+
* Convert a sequence of character into `OrRangeSet`
|
|
77
|
+
*
|
|
78
|
+
* @param s a set of code points
|
|
79
|
+
* @returns A set compatible with `Or`
|
|
80
|
+
*/
|
|
81
|
+
export const set = (s) => toOr(str(s));
|
|
76
82
|
const removeOne = (set, [a, b]) => {
|
|
77
83
|
let result = [];
|
|
78
84
|
for (const [a0, b0] of set) {
|
|
@@ -107,5 +113,20 @@ export const remove = (range, removeSet) => {
|
|
|
107
113
|
for (const r of removeSet) {
|
|
108
114
|
result = removeOne(result, r);
|
|
109
115
|
}
|
|
110
|
-
return result
|
|
116
|
+
return toOr(result);
|
|
117
|
+
};
|
|
118
|
+
export const repeat0 = (rule) => {
|
|
119
|
+
const result = () => [
|
|
120
|
+
[],
|
|
121
|
+
[rule, result],
|
|
122
|
+
];
|
|
123
|
+
return result;
|
|
124
|
+
};
|
|
125
|
+
export const join0 = (rule, separator) => {
|
|
126
|
+
const tail = repeat0(() => [[separator, rule]]);
|
|
127
|
+
const result = () => [
|
|
128
|
+
[],
|
|
129
|
+
[rule, tail],
|
|
130
|
+
];
|
|
131
|
+
return result;
|
|
111
132
|
};
|
package/bnf/func/test.f.js
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
import { stringify } from "../../json/module.f.js";
|
|
2
2
|
import { sort } from "../../types/object/module.f.js";
|
|
3
|
-
import { cp, str, range, remove, } from "./module.f.js";
|
|
3
|
+
import { cp, str, range, remove, set, repeat0, join0, } from "./module.f.js";
|
|
4
4
|
const deterministic = () => {
|
|
5
|
+
const wsSet = () => set('\t\n\r '); // 9,10,13,32
|
|
5
6
|
// {"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
|
-
];
|
|
7
|
+
const ws = repeat0(wsSet);
|
|
13
8
|
// {"empty":true,"map":[[false,42],[true,43],[false,44],[true,45]]}
|
|
14
9
|
const sign = () => [
|
|
15
10
|
[],
|
|
16
|
-
|
|
17
|
-
str('-'), // 45
|
|
11
|
+
...set('+-'), // 43
|
|
18
12
|
];
|
|
19
13
|
// {"empty":false,"map":[[false,48],[true,57]]}
|
|
20
14
|
const onenine = () => [
|
|
@@ -26,34 +20,31 @@ const deterministic = () => {
|
|
|
26
20
|
[onenine],
|
|
27
21
|
];
|
|
28
22
|
// {"empty":true,"map":[[false,47],[true,57]]}
|
|
29
|
-
const
|
|
30
|
-
[],
|
|
31
|
-
[digit, digits1]
|
|
32
|
-
];
|
|
23
|
+
const digits0 = repeat0(digit);
|
|
33
24
|
// {"empty":false,"map":[[false,47],[true,57]]}
|
|
34
|
-
const
|
|
35
|
-
[digit,
|
|
25
|
+
const digits1 = () => [
|
|
26
|
+
[digit, digits0]
|
|
36
27
|
];
|
|
28
|
+
const e = () => set('Ee'); // 69, 101
|
|
37
29
|
// {"empty":true,"map":[[false,68],[true,69],[false,100],[true,101]]}
|
|
38
30
|
const exponent = () => [
|
|
39
31
|
[],
|
|
40
|
-
[
|
|
41
|
-
[cp('e'), sign, digits], // 101
|
|
32
|
+
[e, sign, digits1], // 69 | 101
|
|
42
33
|
];
|
|
43
34
|
// {"empty":true,"map":[[false,45],[true,46]]}
|
|
44
35
|
const fraction = () => [
|
|
45
36
|
[],
|
|
46
|
-
[cp('.'),
|
|
37
|
+
[cp('.'), digits1] // 46
|
|
47
38
|
];
|
|
48
39
|
// {"empty":false,"map":[[false,47],[true,57]]}
|
|
49
|
-
const
|
|
40
|
+
const unsignedInteger = () => [
|
|
50
41
|
str('0'), // 48
|
|
51
|
-
[onenine,
|
|
42
|
+
[onenine, digits0], // 49-57
|
|
52
43
|
];
|
|
53
44
|
// {"empty":false,"map":[[false,44],[true,45],[false,47],[true,57]]}
|
|
54
45
|
const integer = () => [
|
|
55
|
-
[
|
|
56
|
-
[cp('-'),
|
|
46
|
+
[unsignedInteger], // 48-57
|
|
47
|
+
[cp('-'), unsignedInteger], // 45
|
|
57
48
|
];
|
|
58
49
|
// {"empty":false,"map":[[false,44],[true,45],[false,47],[true,57]]}
|
|
59
50
|
const number = () => [
|
|
@@ -67,14 +58,7 @@ const deterministic = () => {
|
|
|
67
58
|
];
|
|
68
59
|
// {"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
60
|
const escape = () => [
|
|
70
|
-
|
|
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
|
|
61
|
+
...set('"\\/bfnrt'),
|
|
78
62
|
[cp('u'), hex, hex, hex, hex] // 117
|
|
79
63
|
];
|
|
80
64
|
// {"empty":false,"map":[[false,31],[true,33],[false,34],[true,1114111]]}
|
|
@@ -83,70 +67,27 @@ const deterministic = () => {
|
|
|
83
67
|
[cp('\\'), escape], // 92
|
|
84
68
|
];
|
|
85
69
|
// {"empty":true,"map":[[false,31],[true,33],[false,34],[true,1114111]]}
|
|
86
|
-
const characters = ()
|
|
87
|
-
[],
|
|
88
|
-
[character, characters]
|
|
89
|
-
];
|
|
70
|
+
const characters = repeat0(character);
|
|
90
71
|
// {"empty":false,"map":[[false,33],[true,34]]}
|
|
91
72
|
const string = () => [
|
|
92
73
|
[cp('"'), characters, cp('"')]
|
|
93
74
|
];
|
|
75
|
+
const comma = () => [[cp(','), ws]];
|
|
94
76
|
// {"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
77
|
const element = () => [
|
|
100
|
-
[
|
|
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]
|
|
78
|
+
[value, ws]
|
|
114
79
|
];
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
str(']'), // 93
|
|
118
|
-
[elements1, cp(']')],
|
|
80
|
+
const list = (open, rule, close) => () => [
|
|
81
|
+
[cp(open), ws, join0(rule, comma), cp(close)]
|
|
119
82
|
];
|
|
120
83
|
// {"empty":false,"map":[[false,90],[true,91]]}
|
|
121
|
-
const array = (
|
|
122
|
-
[cp('['), ws, array1]
|
|
123
|
-
];
|
|
84
|
+
const array = list('[', element, ']');
|
|
124
85
|
// {"empty":false,"map":[[false,33],[true,34]]}
|
|
125
|
-
const
|
|
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('}')],
|
|
86
|
+
const member = () => [
|
|
87
|
+
[string, ws, cp(':'), ws, element]
|
|
145
88
|
];
|
|
146
89
|
// {"empty":false,"map":[[false,122],[true,123]]}
|
|
147
|
-
const object = (
|
|
148
|
-
[cp('{'), ws, object1]
|
|
149
|
-
];
|
|
90
|
+
const object = list('{', member, '}');
|
|
150
91
|
// {"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
92
|
const value = () => [
|
|
152
93
|
[object], // 123
|
|
@@ -158,7 +99,7 @@ const deterministic = () => {
|
|
|
158
99
|
str('null'), // 110
|
|
159
100
|
];
|
|
160
101
|
// {"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;
|
|
102
|
+
const json = [ws, element];
|
|
162
103
|
const _ = json;
|
|
163
104
|
};
|
|
164
105
|
//
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Array2 } from '../../types/array/module.f.ts';
|
|
2
|
+
export type Range = bigint;
|
|
3
|
+
export type Sequence = readonly Rule[];
|
|
4
|
+
export type Or = {
|
|
5
|
+
readonly [k in string]: Rule;
|
|
6
|
+
};
|
|
7
|
+
export type DataRule = Or | Sequence | Range | string;
|
|
8
|
+
export type LazyRule = () => DataRule;
|
|
9
|
+
export type Rule = DataRule | LazyRule;
|
|
10
|
+
export declare const rangeEncode: (a: number, b: number) => Range;
|
|
11
|
+
export declare const oneEncode: (a: number) => Range;
|
|
12
|
+
export declare const rangeDecode: (r: bigint) => Array2<number>;
|
|
13
|
+
export declare const str: (s: string) => readonly Range[] | Range;
|
|
14
|
+
export declare const set: (s: string) => Or;
|
|
15
|
+
export declare const range: (ab: string) => Range;
|
|
16
|
+
export type None = readonly [];
|
|
17
|
+
export declare const none: None;
|
|
18
|
+
export type Option<S> = {
|
|
19
|
+
none: None;
|
|
20
|
+
some: S;
|
|
21
|
+
};
|
|
22
|
+
export declare const option: <S extends Rule>(some: S) => Option<S>;
|
|
23
|
+
export type Repeat0<T> = () => Option<readonly [T, Repeat0<T>]>;
|
|
24
|
+
export declare const repeat0: <T extends Rule>(some: T) => Repeat0<T>;
|
|
25
|
+
export type Repeat1<T> = readonly [T, Repeat0<T>];
|
|
26
|
+
export declare const repeat1: <T extends Rule>(some: T) => Repeat1<T>;
|
|
27
|
+
export type Join1<T, S> = readonly [T, Repeat0<readonly [S, T]>];
|
|
28
|
+
export declare const join1: <T extends Rule, S extends Rule>(some: T, separator: S) => Join1<T, S>;
|
|
29
|
+
export type Join0<T, S> = Option<readonly [T, Repeat0<readonly [S, T]>]>;
|
|
30
|
+
export declare const join0: <T extends Rule, S extends Rule>(some: T, separator: S) => Rule;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { stringToCodePointList } from "../../text/utf16/module.f.js";
|
|
2
|
+
import { isArray2 } from "../../types/array/module.f.js";
|
|
3
|
+
import { map, toArray } from "../../types/list/module.f.js";
|
|
4
|
+
//
|
|
5
|
+
const { fromEntries } = Object;
|
|
6
|
+
const { fromCodePoint } = String;
|
|
7
|
+
const offset = 24n;
|
|
8
|
+
const mask = (1n << offset) - 1n;
|
|
9
|
+
export const rangeEncode = (a, b) => (BigInt(a) << offset) | BigInt(b);
|
|
10
|
+
export const oneEncode = (a) => rangeEncode(a, a);
|
|
11
|
+
export const rangeDecode = (r) => [Number(r >> offset), Number(r & mask)];
|
|
12
|
+
const mapOneEncode = map(oneEncode);
|
|
13
|
+
export const str = (s) => {
|
|
14
|
+
const x = toArray(mapOneEncode(stringToCodePointList(s)));
|
|
15
|
+
return x.length === 1 ? x[0] : x;
|
|
16
|
+
};
|
|
17
|
+
const mapEntry = map((v) => [fromCodePoint(v), oneEncode(v)]);
|
|
18
|
+
export const set = (s) => fromEntries(toArray(mapEntry(stringToCodePointList(s))));
|
|
19
|
+
export const range = (ab) => {
|
|
20
|
+
const a = toArray(stringToCodePointList(ab));
|
|
21
|
+
if (!isArray2(a)) {
|
|
22
|
+
throw `Invalid range ${ab}.`;
|
|
23
|
+
}
|
|
24
|
+
return rangeEncode(...a);
|
|
25
|
+
};
|
|
26
|
+
export const none = [];
|
|
27
|
+
export const option = (some) => ({
|
|
28
|
+
none,
|
|
29
|
+
some,
|
|
30
|
+
});
|
|
31
|
+
export const repeat0 = (some) => {
|
|
32
|
+
const f = () => option([some, f]);
|
|
33
|
+
return f;
|
|
34
|
+
};
|
|
35
|
+
export const repeat1 = (some) => [some, repeat0(some)];
|
|
36
|
+
export const join1 = (some, separator) => [some, repeat0([separator, some])];
|
|
37
|
+
export const join0 = (some, separator) => option(join1(some, separator));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { join0, none, option, range, repeat0, set } from "./module.f.js";
|
|
2
|
+
const _classic = () => {
|
|
3
|
+
const json = () => [element];
|
|
4
|
+
const value = () => ({
|
|
5
|
+
object,
|
|
6
|
+
array,
|
|
7
|
+
string,
|
|
8
|
+
number,
|
|
9
|
+
true: 'true',
|
|
10
|
+
false: 'false',
|
|
11
|
+
null: 'null'
|
|
12
|
+
});
|
|
13
|
+
const object = () => ({
|
|
14
|
+
ws: ['{', ws, '}'],
|
|
15
|
+
members: ['{', members, '}'],
|
|
16
|
+
});
|
|
17
|
+
const members = () => ({
|
|
18
|
+
member,
|
|
19
|
+
members: [member, ',', members],
|
|
20
|
+
});
|
|
21
|
+
const member = () => [ws, string, ws, ':', element];
|
|
22
|
+
const array = () => ({
|
|
23
|
+
ws: ['[', ws, ']'],
|
|
24
|
+
elements: ['[', elements, ']'],
|
|
25
|
+
});
|
|
26
|
+
const elements = () => ({
|
|
27
|
+
element,
|
|
28
|
+
elements: [element, ',', elements],
|
|
29
|
+
});
|
|
30
|
+
const element = () => [ws, value, ws];
|
|
31
|
+
const string = () => ['"', characters, '"'];
|
|
32
|
+
const characters = () => ({
|
|
33
|
+
none,
|
|
34
|
+
characters: [character, characters],
|
|
35
|
+
});
|
|
36
|
+
const character = () => ({
|
|
37
|
+
0: 0x20000021n,
|
|
38
|
+
1: 0x2300005bn,
|
|
39
|
+
2: 0x5d10ffffn,
|
|
40
|
+
escape: ['\\', escape],
|
|
41
|
+
});
|
|
42
|
+
const escape = () => ({
|
|
43
|
+
...set('"\\/bfnrt'),
|
|
44
|
+
u: ['u', hex, hex, hex, hex],
|
|
45
|
+
});
|
|
46
|
+
const hex = () => ({
|
|
47
|
+
digit,
|
|
48
|
+
AF: range('AF'),
|
|
49
|
+
af: range('af'),
|
|
50
|
+
});
|
|
51
|
+
const number = () => [integer, fraction, exponent];
|
|
52
|
+
const integer = () => ({
|
|
53
|
+
digit,
|
|
54
|
+
onenine: [onenine, digits],
|
|
55
|
+
negDigit: ['-', digit],
|
|
56
|
+
negOnenine: ['-', onenine, digits],
|
|
57
|
+
});
|
|
58
|
+
const digits = () => ({
|
|
59
|
+
digit,
|
|
60
|
+
digits: [digit, digits],
|
|
61
|
+
});
|
|
62
|
+
const digit = () => ({
|
|
63
|
+
'0': '0',
|
|
64
|
+
onenine,
|
|
65
|
+
});
|
|
66
|
+
const onenine = range('12');
|
|
67
|
+
const fraction = () => ({
|
|
68
|
+
none,
|
|
69
|
+
digits: ['.', digits],
|
|
70
|
+
});
|
|
71
|
+
const exponent = () => ({
|
|
72
|
+
none,
|
|
73
|
+
E: ['E', sign, digits],
|
|
74
|
+
e: ['e', sign, digits],
|
|
75
|
+
});
|
|
76
|
+
const sign = {
|
|
77
|
+
none,
|
|
78
|
+
...set('+-'),
|
|
79
|
+
};
|
|
80
|
+
const ws = () => ({
|
|
81
|
+
none,
|
|
82
|
+
' ': [' ', ws],
|
|
83
|
+
'\n': ['\n', ws],
|
|
84
|
+
'\r': ['\r', ws],
|
|
85
|
+
'\t': ['\t', ws],
|
|
86
|
+
});
|
|
87
|
+
return json;
|
|
88
|
+
};
|
|
89
|
+
const _deterministic = () => {
|
|
90
|
+
const onenine = range('12');
|
|
91
|
+
const digit = {
|
|
92
|
+
'0': '0',
|
|
93
|
+
onenine,
|
|
94
|
+
};
|
|
95
|
+
const hex = {
|
|
96
|
+
digit,
|
|
97
|
+
AF: range('AF'),
|
|
98
|
+
af: range('af'),
|
|
99
|
+
};
|
|
100
|
+
const escape = {
|
|
101
|
+
...set('"\\/bfnrt'),
|
|
102
|
+
u: ['u', hex, hex, hex, hex],
|
|
103
|
+
};
|
|
104
|
+
const character = {
|
|
105
|
+
0: 0x20000021n,
|
|
106
|
+
1: 0x2300005bn,
|
|
107
|
+
2: 0x5d10ffffn,
|
|
108
|
+
escape: ['\\', escape],
|
|
109
|
+
};
|
|
110
|
+
const characters = repeat0(character);
|
|
111
|
+
const string = ['"', characters, '"'];
|
|
112
|
+
const digits0 = repeat0(digit);
|
|
113
|
+
const digits = [digit, digits0];
|
|
114
|
+
const integer = [option('-'), {
|
|
115
|
+
'0': '0',
|
|
116
|
+
onenine: [onenine, digits0],
|
|
117
|
+
}];
|
|
118
|
+
const fraction = option(['.', digits]);
|
|
119
|
+
const sign = option(set('+-'));
|
|
120
|
+
const exponent = option([set('Ee'), sign, digits]);
|
|
121
|
+
const number = [integer, fraction, exponent];
|
|
122
|
+
const ws = repeat0(set(' \n\r\t'));
|
|
123
|
+
const value = () => ({
|
|
124
|
+
object,
|
|
125
|
+
array,
|
|
126
|
+
string,
|
|
127
|
+
number,
|
|
128
|
+
true: 'true',
|
|
129
|
+
false: 'false',
|
|
130
|
+
null: 'null'
|
|
131
|
+
});
|
|
132
|
+
const commaJoin0 = ([open, close], a) => [open, ws, join0([a, ws], [',', ws]), close];
|
|
133
|
+
const array = commaJoin0('[]', value);
|
|
134
|
+
const member = [string, ws, ':', ws, value];
|
|
135
|
+
const object = commaJoin0('{}', member);
|
|
136
|
+
const json = [ws, value, ws];
|
|
137
|
+
return json;
|
|
138
|
+
};
|
package/fsc/bnf.f.d.ts
ADDED
package/fsc/bnf.f.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { cp, range, remove, set, str } from "../bnf/func/module.f.js";
|
|
2
|
+
import { digit, json, unicode, ws0, ws1, wsNoNewLine0 } from "./json.f.js";
|
|
3
|
+
export const wsModule = () => [[ws0, module]];
|
|
4
|
+
const module = () => [
|
|
5
|
+
[json, ws0],
|
|
6
|
+
[fjs],
|
|
7
|
+
];
|
|
8
|
+
const fjs = () => [
|
|
9
|
+
[],
|
|
10
|
+
[...str('const'), ws1, id, ws0, cp('='), ws0, json, wsNoNewLine0, fjsTail],
|
|
11
|
+
[...str('export'), ws1, ...str('default'), ws1, json],
|
|
12
|
+
];
|
|
13
|
+
const fjsTail = () => [
|
|
14
|
+
[],
|
|
15
|
+
[cp('\n'), ws0, fjs],
|
|
16
|
+
];
|
|
17
|
+
// line comment
|
|
18
|
+
const lineItem = () => remove(unicode, [cp('\n')]);
|
|
19
|
+
const line = () => [
|
|
20
|
+
[],
|
|
21
|
+
[lineItem, line]
|
|
22
|
+
];
|
|
23
|
+
const lineComment = () => [
|
|
24
|
+
[cp('/'), commentTail, cp('\n')]
|
|
25
|
+
];
|
|
26
|
+
const multiLineSkip = () => remove(unicode, [cp('/')]);
|
|
27
|
+
const multiLineItem = () => remove(unicode, [cp('*')]);
|
|
28
|
+
const multiLine = () => [
|
|
29
|
+
[cp('*'), multiLineTail],
|
|
30
|
+
[multiLineItem, multiLine]
|
|
31
|
+
];
|
|
32
|
+
const multiLineTail = () => [
|
|
33
|
+
[cp('/')],
|
|
34
|
+
[multiLineSkip, multiLine]
|
|
35
|
+
];
|
|
36
|
+
const commentTail = () => [
|
|
37
|
+
[cp('/'), lineComment],
|
|
38
|
+
[cp('*'), multiLine],
|
|
39
|
+
];
|
|
40
|
+
// id
|
|
41
|
+
const id = () => [[alpha, idTail0]];
|
|
42
|
+
const alpha = () => [
|
|
43
|
+
[range('AZ')],
|
|
44
|
+
[range('az')],
|
|
45
|
+
...set('_$'),
|
|
46
|
+
];
|
|
47
|
+
const idTail0 = () => [
|
|
48
|
+
[],
|
|
49
|
+
[alphaDigit, idTail0],
|
|
50
|
+
];
|
|
51
|
+
const alphaDigit = () => [
|
|
52
|
+
[alpha],
|
|
53
|
+
[digit],
|
|
54
|
+
];
|
package/fsc/json.f.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Rule, type TerminalRange } from '../bnf/func/module.f.ts';
|
|
2
|
+
export declare const wsNoNewLine0: Rule;
|
|
3
|
+
export declare const ws0: Rule;
|
|
4
|
+
export declare const ws1: Rule;
|
|
5
|
+
export declare const json: Rule;
|
|
6
|
+
export declare const unicode: TerminalRange;
|
|
7
|
+
export declare const digit: Rule;
|
package/fsc/json.f.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { cp, join0, range, remove, repeat0, set, str } from "../bnf/func/module.f.js";
|
|
2
|
+
// space
|
|
3
|
+
const wsNoNewLineItem = () => set(' \t\r');
|
|
4
|
+
export const wsNoNewLine0 = () => [
|
|
5
|
+
[],
|
|
6
|
+
[wsNoNewLineItem, wsNoNewLine0],
|
|
7
|
+
];
|
|
8
|
+
const wsItem = () => [
|
|
9
|
+
[wsNoNewLineItem],
|
|
10
|
+
str('\n'),
|
|
11
|
+
];
|
|
12
|
+
export const ws0 = () => [
|
|
13
|
+
[],
|
|
14
|
+
[ws1],
|
|
15
|
+
];
|
|
16
|
+
export const ws1 = () => [
|
|
17
|
+
[wsItem, ws0]
|
|
18
|
+
];
|
|
19
|
+
//
|
|
20
|
+
export const json = () => [
|
|
21
|
+
[object],
|
|
22
|
+
[array],
|
|
23
|
+
[number],
|
|
24
|
+
[string],
|
|
25
|
+
str('true'),
|
|
26
|
+
str('false'),
|
|
27
|
+
str('null'),
|
|
28
|
+
];
|
|
29
|
+
//
|
|
30
|
+
const separator = () => [[cp(','), ws0]];
|
|
31
|
+
// object
|
|
32
|
+
const member = () => [[string, ws0, cp(':'), ws0, json, ws0]];
|
|
33
|
+
const object = () => [
|
|
34
|
+
[cp('{'), ws0, join0(member, separator), cp('}')]
|
|
35
|
+
];
|
|
36
|
+
// array
|
|
37
|
+
const element = () => [
|
|
38
|
+
[json, ws0]
|
|
39
|
+
];
|
|
40
|
+
const array = () => [
|
|
41
|
+
[cp('['), ws0, join0(element, separator), cp(']')]
|
|
42
|
+
];
|
|
43
|
+
// string
|
|
44
|
+
const character = () => [
|
|
45
|
+
...remove(unicode, [cp('"'), cp('\\')]),
|
|
46
|
+
[cp('\\'), escape],
|
|
47
|
+
];
|
|
48
|
+
const string = () => [[cp('"'), repeat0(character), cp('"')]];
|
|
49
|
+
export const unicode = [0x20, 0x10FFFF];
|
|
50
|
+
const escape = () => [
|
|
51
|
+
...set('"\\/bfnrt'),
|
|
52
|
+
[cp('u'), hex, hex, hex, hex] // 117
|
|
53
|
+
];
|
|
54
|
+
const hex = () => [
|
|
55
|
+
[digit],
|
|
56
|
+
[range('AF')],
|
|
57
|
+
[range('af')],
|
|
58
|
+
];
|
|
59
|
+
// number
|
|
60
|
+
const number = () => [
|
|
61
|
+
[uNumber],
|
|
62
|
+
[cp('-'), uNumber],
|
|
63
|
+
];
|
|
64
|
+
const uNumber = () => [
|
|
65
|
+
[uint, fraction0, exponent0],
|
|
66
|
+
];
|
|
67
|
+
const uint = () => [
|
|
68
|
+
str('0'),
|
|
69
|
+
[range('19'), digits0]
|
|
70
|
+
];
|
|
71
|
+
export const digit = () => [[range('09')]];
|
|
72
|
+
const digits0 = repeat0(digit);
|
|
73
|
+
const digits1 = () => [
|
|
74
|
+
[digit, digits0]
|
|
75
|
+
];
|
|
76
|
+
const fraction0 = () => [
|
|
77
|
+
[],
|
|
78
|
+
[cp('.'), digits1]
|
|
79
|
+
];
|
|
80
|
+
const exponent0 = () => [
|
|
81
|
+
[],
|
|
82
|
+
[e, sign, digits1],
|
|
83
|
+
];
|
|
84
|
+
const e = () => set('eE');
|
|
85
|
+
const sign = () => [
|
|
86
|
+
[],
|
|
87
|
+
[cp('+')],
|
|
88
|
+
[cp('-')],
|
|
89
|
+
];
|
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
export type Array1<T> = readonly [T];
|
|
7
7
|
export type Index1 = 0;
|
|
8
8
|
export type Array2<T> = readonly [T, T];
|
|
9
|
+
export declare const isArray2: <T>(a: readonly T[]) => a is Array2<T>;
|
|
9
10
|
export type Tuple2<T0, T1> = readonly [T0, T1];
|
|
10
11
|
export type Index2 = 0 | 1;
|
|
11
12
|
export type Array3<T> = readonly [T, T, T];
|
package/types/array/module.f.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* const logValue = log2(8n) // 3n
|
|
14
14
|
* const bitCount = bitLength(255n) // 8n
|
|
15
15
|
* const bitmask = mask(5n) // 31n
|
|
16
|
+
* const m = min(3n)(13n) // 3n
|
|
16
17
|
* ```
|
|
17
18
|
*/
|
|
18
19
|
import { type Sign } from '../function/compare/module.f.ts';
|
|
@@ -42,6 +43,7 @@ export declare const serialize: (a: bigint) => string;
|
|
|
42
43
|
* of the most significant bit.
|
|
43
44
|
* 2. **Binary Search Phase:** Refines the result by halving the step size and incrementally
|
|
44
45
|
* determining the exact value of the logarithm.
|
|
46
|
+
* 3. **Remainder Phase:** Using `Math.log2`.
|
|
45
47
|
*/
|
|
46
48
|
export declare const log2: (v: bigint) => bigint;
|
|
47
49
|
/**
|
|
@@ -78,3 +80,7 @@ export declare const bitLength: (v: bigint) => bigint;
|
|
|
78
80
|
* ```
|
|
79
81
|
*/
|
|
80
82
|
export declare const mask: (len: bigint) => bigint;
|
|
83
|
+
/**
|
|
84
|
+
* A minimal value.
|
|
85
|
+
*/
|
|
86
|
+
export declare const min: (a: bigint) => (b: bigint) => bigint;
|
package/types/bigint/module.f.js
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
* const logValue = log2(8n) // 3n
|
|
14
14
|
* const bitCount = bitLength(255n) // 8n
|
|
15
15
|
* const bitmask = mask(5n) // 31n
|
|
16
|
+
* const m = min(3n)(13n) // 3n
|
|
16
17
|
* ```
|
|
17
18
|
*/
|
|
18
19
|
import { unsafeCmp } from "../function/compare/module.f.js";
|
|
@@ -39,13 +40,19 @@ export const serialize = (a) => `${a}n`;
|
|
|
39
40
|
* of the most significant bit.
|
|
40
41
|
* 2. **Binary Search Phase:** Refines the result by halving the step size and incrementally
|
|
41
42
|
* determining the exact value of the logarithm.
|
|
43
|
+
* 3. **Remainder Phase:** Using `Math.log2`.
|
|
42
44
|
*/
|
|
43
45
|
export const log2 = (v) => {
|
|
44
46
|
if (v <= 0n) {
|
|
45
47
|
return -1n;
|
|
46
48
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
//
|
|
50
|
+
// 1. Fast Doubling.
|
|
51
|
+
//
|
|
52
|
+
let result = -1n;
|
|
53
|
+
// `bigints` higher than 2**1023 may lead to `Inf` during conversion to `number`.
|
|
54
|
+
// For example: `Number((1n << 1024n) - (1n << 970n)) === Inf`.
|
|
55
|
+
let i = 1023n;
|
|
49
56
|
while (true) {
|
|
50
57
|
const n = v >> i;
|
|
51
58
|
if (n === 0n) {
|
|
@@ -56,9 +63,12 @@ export const log2 = (v) => {
|
|
|
56
63
|
result += i;
|
|
57
64
|
i <<= 1n;
|
|
58
65
|
}
|
|
66
|
+
//
|
|
67
|
+
// 2. Binary Search.
|
|
68
|
+
//
|
|
59
69
|
// We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0.
|
|
60
|
-
// Because of this, We check if `i` is greater than
|
|
61
|
-
while (i !==
|
|
70
|
+
// Because of this, We check if `i` is greater than 1023 before we divide it by 2.
|
|
71
|
+
while (i !== 1023n) {
|
|
62
72
|
i >>= 1n;
|
|
63
73
|
const n = v >> i;
|
|
64
74
|
if (n !== 0n) {
|
|
@@ -66,7 +76,15 @@ export const log2 = (v) => {
|
|
|
66
76
|
v = n;
|
|
67
77
|
}
|
|
68
78
|
}
|
|
69
|
-
|
|
79
|
+
//
|
|
80
|
+
// 3. Remainder Phase.
|
|
81
|
+
//
|
|
82
|
+
// We know that `v` is less than `1n << 1023` so we can calculate a remainder using
|
|
83
|
+
// `Math.log2`.
|
|
84
|
+
const rem = BigInt(Math.log2(Number(v)) | 0);
|
|
85
|
+
// (v >> rem) is either `0` or `1`, and it's used as a correction for
|
|
86
|
+
// Math.log2 rounding.
|
|
87
|
+
return result + rem + (v >> rem);
|
|
70
88
|
};
|
|
71
89
|
/**
|
|
72
90
|
* Calculates the bit length of a given BigInt.
|
|
@@ -110,3 +128,7 @@ export const bitLength = (v) => {
|
|
|
110
128
|
* ```
|
|
111
129
|
*/
|
|
112
130
|
export const mask = (len) => (1n << len) - 1n;
|
|
131
|
+
/**
|
|
132
|
+
* A minimal value.
|
|
133
|
+
*/
|
|
134
|
+
export const min = (a) => (b) => a < b ? a : b;
|
package/types/bigint/test.f.d.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
export declare const clz32Log2: (v: bigint) => bigint;
|
|
1
2
|
declare const _default: {
|
|
2
3
|
example: () => void;
|
|
3
|
-
benchmark: {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
benchmark: () => {
|
|
5
|
+
big: {
|
|
6
|
+
[k: string]: () => void;
|
|
7
|
+
};
|
|
8
|
+
small: {
|
|
9
|
+
[k: string]: () => void;
|
|
10
|
+
};
|
|
8
11
|
};
|
|
9
12
|
mask: () => void;
|
|
10
13
|
sum: () => void;
|
package/types/bigint/test.f.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sum, abs, serialize, log2, bitLength, mask } from "./module.f.js";
|
|
1
|
+
import { sum, abs, serialize, log2, bitLength, mask, min } from "./module.f.js";
|
|
2
2
|
const oldLog2 = (v) => {
|
|
3
3
|
if (v <= 0n) {
|
|
4
4
|
return -1n;
|
|
@@ -27,24 +27,83 @@ const oldLog2 = (v) => {
|
|
|
27
27
|
}
|
|
28
28
|
return result;
|
|
29
29
|
};
|
|
30
|
-
const
|
|
31
|
-
const
|
|
30
|
+
const strBinLog2 = (v) => BigInt(v.toString(2).length) - 1n;
|
|
31
|
+
const strHexLog2 = (v) => {
|
|
32
32
|
const len = (BigInt(v.toString(16).length) - 1n) << 2n;
|
|
33
|
-
|
|
34
|
-
return len + 31n - BigInt(Math.clz32(Number(x)));
|
|
33
|
+
return len + 31n - BigInt(Math.clz32(Number(v >> len)));
|
|
35
34
|
};
|
|
36
|
-
const
|
|
35
|
+
const str32Log2 = (v) => {
|
|
36
|
+
const len = (BigInt(v.toString(32).length) - 1n) * 5n;
|
|
37
|
+
return len + 31n - BigInt(Math.clz32(Number(v >> len)));
|
|
38
|
+
};
|
|
39
|
+
export const clz32Log2 = (v) => {
|
|
40
|
+
if (v <= 0n) {
|
|
41
|
+
return -1n;
|
|
42
|
+
}
|
|
43
|
+
let result = 31n;
|
|
44
|
+
let i = 32n;
|
|
45
|
+
while (true) {
|
|
46
|
+
const n = v >> i;
|
|
47
|
+
if (n === 0n) {
|
|
48
|
+
// overshot
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
v = n;
|
|
52
|
+
result += i;
|
|
53
|
+
i <<= 1n;
|
|
54
|
+
}
|
|
55
|
+
// We know that `v` is not 0 so it doesn't make sense to check `n` when `i` is 0.
|
|
56
|
+
// Because of this, We check if `i` is greater than 32 before we divide it by 2.
|
|
57
|
+
while (i !== 32n) {
|
|
58
|
+
i >>= 1n;
|
|
59
|
+
const n = v >> i;
|
|
60
|
+
if (n !== 0n) {
|
|
61
|
+
result += i;
|
|
62
|
+
v = n;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result - BigInt(Math.clz32(Number(v)));
|
|
66
|
+
};
|
|
67
|
+
const benchmark = f => () => {
|
|
37
68
|
let e = 1048575n;
|
|
38
69
|
let c = 1n << e;
|
|
39
|
-
for (let i = 0n; i <
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
70
|
+
for (let i = 0n; i < 1_100; ++i) {
|
|
71
|
+
{
|
|
72
|
+
const x = f(c);
|
|
73
|
+
if (x !== e) {
|
|
74
|
+
throw x;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
{
|
|
78
|
+
const x = f(c - 1n);
|
|
79
|
+
if (x !== e - 1n) {
|
|
80
|
+
throw [e, x];
|
|
81
|
+
}
|
|
43
82
|
}
|
|
44
83
|
c >>= 1n;
|
|
45
84
|
--e;
|
|
46
85
|
}
|
|
47
86
|
};
|
|
87
|
+
const benchmarkSmall = f => () => {
|
|
88
|
+
let e = 2000n;
|
|
89
|
+
let c = 1n << e;
|
|
90
|
+
do {
|
|
91
|
+
{
|
|
92
|
+
const x = f(c);
|
|
93
|
+
if (x !== e) {
|
|
94
|
+
throw [e, x];
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (let j = 1n; j < min(c >> 1n)(1000n); ++j) {
|
|
98
|
+
const x = f(c - j);
|
|
99
|
+
if (x !== e - 1n) {
|
|
100
|
+
throw [j, e, x];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
c >>= 1n;
|
|
104
|
+
--e;
|
|
105
|
+
} while (c !== 0n);
|
|
106
|
+
};
|
|
48
107
|
export default {
|
|
49
108
|
example: () => {
|
|
50
109
|
const total = sum([1n, 2n, 3n]); // 6n
|
|
@@ -53,26 +112,39 @@ export default {
|
|
|
53
112
|
}
|
|
54
113
|
const absoluteValue = abs(-42n); // 42n
|
|
55
114
|
if (absoluteValue !== 42n) {
|
|
56
|
-
throw
|
|
115
|
+
throw absoluteValue;
|
|
57
116
|
}
|
|
58
117
|
const logValue = log2(8n); // 3n
|
|
59
118
|
if (logValue !== 3n) {
|
|
60
|
-
throw
|
|
119
|
+
throw logValue;
|
|
61
120
|
}
|
|
62
121
|
const bitCount = bitLength(255n); // 8n
|
|
63
122
|
if (bitCount !== 8n) {
|
|
64
|
-
throw
|
|
123
|
+
throw bitCount;
|
|
65
124
|
}
|
|
66
125
|
const bitmask = mask(5n); // 31n
|
|
67
126
|
if (bitmask !== 31n) {
|
|
68
|
-
throw
|
|
127
|
+
throw benchmark;
|
|
128
|
+
}
|
|
129
|
+
const m = min(3n)(13n); // 3n
|
|
130
|
+
if (m !== 3n) {
|
|
131
|
+
throw m;
|
|
69
132
|
}
|
|
70
133
|
},
|
|
71
|
-
benchmark: {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
134
|
+
benchmark: () => {
|
|
135
|
+
const list = {
|
|
136
|
+
strBinLog2,
|
|
137
|
+
strHexLog2,
|
|
138
|
+
str32Log2,
|
|
139
|
+
oldLog2,
|
|
140
|
+
clz32Log2,
|
|
141
|
+
log2,
|
|
142
|
+
};
|
|
143
|
+
const transform = (b) => Object.fromEntries(Object.entries(list).map(([k, f]) => [k, b(f)]));
|
|
144
|
+
return {
|
|
145
|
+
big: transform(benchmark),
|
|
146
|
+
small: transform(benchmarkSmall),
|
|
147
|
+
};
|
|
76
148
|
},
|
|
77
149
|
mask: () => {
|
|
78
150
|
const result = mask(3n); // 7n
|