functionalscript 0.30.0 → 0.31.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/fs/asn.1/module.f.js +18 -22
- package/fs/asn.1/proof.f.d.ts +5 -0
- package/fs/asn.1/proof.f.js +38 -2
- package/fs/base64/module.f.d.ts +9 -0
- package/fs/base64/module.f.js +60 -0
- package/fs/base64/proof.f.d.ts +11 -0
- package/fs/base64/proof.f.js +117 -0
- package/fs/base_n/module.f.d.ts +44 -0
- package/fs/base_n/module.f.js +54 -0
- package/fs/base_n/proof.f.d.ts +10 -0
- package/fs/base_n/proof.f.js +86 -0
- package/fs/bnf/data/module.f.d.ts +4 -9
- package/fs/bnf/data/module.f.js +4 -3
- package/fs/bnf/module.f.d.ts +3 -4
- package/fs/bnf/module.f.js +3 -2
- package/fs/bnf/proof.f.d.ts +9 -0
- package/fs/bnf/proof.f.js +98 -1
- package/fs/cas/mcp/module.f.d.ts +40 -0
- package/fs/cas/mcp/module.f.js +223 -0
- package/fs/cas/mcp/proof.f.d.ts +30 -0
- package/fs/cas/mcp/proof.f.js +310 -0
- package/fs/cas/module.f.d.ts +9 -3
- package/fs/cas/module.f.js +104 -69
- package/fs/cas/proof.f.d.ts +2 -0
- package/fs/cas/proof.f.js +30 -1
- package/fs/cbase32/module.f.d.ts +1 -1
- package/fs/cbase32/module.f.js +19 -40
- package/fs/cbase32/proof.f.d.ts +1 -0
- package/fs/cbase32/proof.f.js +15 -0
- package/fs/ci/config/module.f.d.ts +6 -6
- package/fs/ci/config/module.f.js +6 -6
- package/fs/ci/deno/module.f.js +2 -2
- package/fs/ci/module.f.d.ts +5 -0
- package/fs/ci/module.f.js +2 -3
- package/fs/ci/proof.f.d.ts +1 -0
- package/fs/ci/proof.f.js +9 -3
- package/fs/cli/module.f.d.ts +3 -1
- package/fs/cli/module.f.js +22 -12
- package/fs/cli/proof.f.d.ts +5 -0
- package/fs/cli/proof.f.js +76 -0
- package/fs/crypto/hmac/proof.f.d.ts +1 -0
- package/fs/crypto/hmac/proof.f.js +8 -0
- package/fs/crypto/secp/proof.f.d.ts +1 -0
- package/fs/crypto/secp/proof.f.js +10 -0
- package/fs/crypto/sign/module.f.js +1 -4
- package/fs/dev/module.f.d.ts +5 -3
- package/fs/dev/module.f.js +13 -2
- package/fs/dev/package_json/proof.f.d.ts +1 -0
- package/fs/dev/package_json/proof.f.js +5 -0
- package/fs/dev/proof.f.d.ts +1 -0
- package/fs/dev/proof.f.js +12 -1
- package/fs/djs/ast/module.f.d.ts +1 -1
- package/fs/djs/ast/proof.f.d.ts +5 -0
- package/fs/djs/ast/proof.f.js +17 -0
- package/fs/djs/module.f.d.ts +1 -1
- package/fs/djs/module.f.js +2 -3
- package/fs/djs/serializer/module.f.js +24 -11
- package/fs/djs/transpiler/module.f.js +3 -4
- package/fs/effects/memory/module.f.d.ts +37 -0
- package/fs/effects/memory/module.f.js +24 -0
- package/fs/effects/memory/proof.f.d.ts +6 -0
- package/fs/effects/memory/proof.f.js +64 -0
- package/fs/effects/mock/module.f.d.ts +7 -2
- package/fs/effects/mock/module.f.js +12 -8
- package/fs/effects/module.d.ts +1 -1
- package/fs/effects/module.f.d.ts +41 -0
- package/fs/effects/module.f.js +25 -0
- package/fs/effects/module.js +6 -7
- package/fs/effects/node/memory/module.d.ts +20 -0
- package/fs/effects/node/memory/module.js +44 -0
- package/fs/effects/node/memory/proof.d.ts +10 -0
- package/fs/effects/node/memory/proof.js +35 -0
- package/fs/effects/node/module.d.ts +1 -1
- package/fs/effects/node/module.f.d.ts +54 -8
- package/fs/effects/node/module.f.js +55 -4
- package/fs/effects/node/module.js +166 -135
- package/fs/effects/node/proof.f.d.ts +10 -0
- package/fs/effects/node/proof.f.js +88 -21
- package/fs/effects/node/virtual/module.f.d.ts +6 -0
- package/fs/effects/node/virtual/module.f.js +48 -16
- package/fs/effects/node/virtual/proof.f.d.ts +17 -0
- package/fs/effects/node/virtual/proof.f.js +79 -0
- package/fs/effects/proof.f.d.ts +5 -0
- package/fs/effects/proof.f.js +54 -34
- package/fs/emergent_testing/module.f.d.ts +6 -1
- package/fs/emergent_testing/module.f.js +8 -3
- package/fs/emergent_testing/proof.f.d.ts +11 -0
- package/fs/emergent_testing/proof.f.js +52 -16
- package/fs/fjs/module.f.js +2 -2
- package/fs/fjs/proof.f.d.ts +8 -0
- package/fs/fjs/proof.f.js +39 -0
- package/fs/fsc/module.f.d.ts +5 -0
- package/fs/fsc/module.f.js +17 -27
- package/fs/fsc/proof.f.d.ts +8 -0
- package/fs/fsc/proof.f.js +48 -2
- package/fs/fsm/module.f.d.ts +2 -3
- package/fs/fsm/module.f.js +1 -1
- package/fs/html/module.f.d.ts +2 -3
- package/fs/html/module.f.js +7 -6
- package/fs/html/proof.f.d.ts +1 -0
- package/fs/html/proof.f.js +7 -0
- package/fs/js/tokenizer/module.f.js +1 -1
- package/fs/js/tokenizer/proof.f.js +7 -0
- package/fs/json/module.f.d.ts +9 -2
- package/fs/json/module.f.js +9 -7
- package/fs/json/parser/module.f.js +4 -6
- package/fs/json/parser/proof.f.js +19 -10
- package/fs/json/proof.f.d.ts +2 -1
- package/fs/json/proof.f.js +33 -6
- package/fs/json/rpc/module.f.d.ts +5 -0
- package/fs/json/rpc/module.f.js +16 -11
- package/fs/json/schema/module.f.d.ts +15 -14
- package/fs/json/schema/proof.f.d.ts +3 -0
- package/fs/json/schema/proof.f.js +16 -1
- package/fs/mcp/module.f.d.ts +103 -5
- package/fs/mcp/module.f.js +139 -2
- package/fs/mcp/proof.f.d.ts +34 -0
- package/fs/mcp/proof.f.js +207 -0
- package/fs/mcp/stdio/module.f.d.ts +39 -0
- package/fs/mcp/stdio/module.f.js +54 -0
- package/fs/mcp/stdio/proof.f.d.ts +10 -0
- package/fs/mcp/stdio/proof.f.js +92 -0
- package/fs/mime/module.f.d.ts +39 -0
- package/fs/mime/module.f.js +78 -0
- package/fs/mime/proof.f.d.ts +15 -0
- package/fs/mime/proof.f.js +30 -0
- package/fs/path/module.f.d.ts +8 -0
- package/fs/path/module.f.js +10 -3
- package/fs/path/proof.f.d.ts +1 -0
- package/fs/path/proof.f.js +40 -2
- package/fs/text/sgr/proof.f.js +30 -2
- package/fs/text/utf8/module.f.d.ts +7 -0
- package/fs/text/utf8/module.f.js +85 -31
- package/fs/text/utf8/proof.f.d.ts +1 -0
- package/fs/text/utf8/proof.f.js +60 -1
- package/fs/types/bigfloat/module.f.d.ts +3 -0
- package/fs/types/bigfloat/module.f.js +30 -31
- package/fs/types/bigint/module.f.d.ts +24 -2
- package/fs/types/bigint/module.f.js +30 -2
- package/fs/types/bigint/proof.f.d.ts +7 -0
- package/fs/types/bigint/proof.f.js +47 -16
- package/fs/types/bit_vec/module.f.d.ts +18 -0
- package/fs/types/bit_vec/module.f.js +18 -0
- package/fs/types/bit_vec/proof.f.d.ts +1 -0
- package/fs/types/bit_vec/proof.f.js +13 -1
- package/fs/types/function/operator/proof.f.d.ts +2 -0
- package/fs/types/function/operator/proof.f.js +20 -2
- package/fs/types/list/module.f.js +1 -4
- package/fs/types/list/proof.f.d.ts +1 -1
- package/fs/types/list/proof.f.js +14 -6
- package/fs/types/map/proof.f.d.ts +1 -0
- package/fs/types/map/proof.f.js +10 -1
- package/fs/types/nibble_set/module.f.d.ts +13 -0
- package/fs/types/nibble_set/module.f.js +16 -0
- package/fs/types/object/module.f.d.ts +12 -8
- package/fs/types/object/module.f.js +9 -2
- package/fs/types/object/proof.f.d.ts +14 -0
- package/fs/types/object/proof.f.js +4 -0
- package/fs/types/ordered_map/proof.f.d.ts +1 -0
- package/fs/types/ordered_map/proof.f.js +39 -79
- package/fs/types/phantom/module.f.d.ts +22 -0
- package/fs/types/phantom/module.f.js +11 -0
- package/fs/types/prime_field/proof.f.d.ts +7 -0
- package/fs/types/prime_field/proof.f.js +63 -122
- package/fs/types/rtti/common/module.f.d.ts +4 -4
- package/fs/types/rtti/common/module.f.js +1 -1
- package/fs/types/rtti/module.f.d.ts +2 -3
- package/fs/types/rtti/parse/module.f.js +0 -1
- package/fs/types/rtti/ts/module.f.d.ts +26 -32
- package/fs/types/rtti/ts/module.f.js +2 -2
- package/fs/types/rtti/ts/proof.f.js +3 -3
- package/fs/types/rtti/validate/module.f.js +0 -1
- package/fs/types/sorted_list/module.f.d.ts +6 -0
- package/fs/types/sorted_list/module.f.js +11 -0
- package/fs/types/sorted_set/module.f.js +2 -8
- package/fs/types/ts/module.f.d.ts +1 -1
- package/fs/types/ts/module.f.js +3 -1
- package/fs/types/ts/proof.f.js +3 -2
- package/fs/website/proof.f.d.ts +1 -0
- package/fs/website/proof.f.js +8 -1
- package/package.json +3 -3
package/fs/text/utf8/module.f.js
CHANGED
|
@@ -3,8 +3,39 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
|
-
import { flatMap } from "../../types/list/module.f.js";
|
|
6
|
+
import { flatMap, toArray } from "../../types/list/module.f.js";
|
|
7
7
|
import { decoder, errorMask } from "../code_point/module.f.js";
|
|
8
|
+
import { msb, u8List, length } from "../../types/bit_vec/module.f.js";
|
|
9
|
+
import { codePointListToString } from "../utf16/module.f.js";
|
|
10
|
+
/**
|
|
11
|
+
* UTF-8 byte-format constants. Each byte kind is defined by a tag — the fixed
|
|
12
|
+
* high bits identifying the kind — and a payload mask selecting the code-point
|
|
13
|
+
* bits the byte carries. The encoder and the decoder are exact inverses, so
|
|
14
|
+
* both read their bit patterns from this single set of definitions:
|
|
15
|
+
*
|
|
16
|
+
* | byte kind | pattern | tag | payload mask |
|
|
17
|
+
* |-------------|--------------|-----------|--------------|
|
|
18
|
+
* | continuation| `10xx_xxxx` | `contTag` | `contMask` |
|
|
19
|
+
* | 2-byte lead | `110x_xxxx` | `lead2Tag`| `lead2Mask` |
|
|
20
|
+
* | 3-byte lead | `1110_xxxx` | `lead3Tag`| `lead3Mask` |
|
|
21
|
+
* | 4-byte lead | `1111_0xxx` | `lead4Tag`| `lead4Mask` |
|
|
22
|
+
*/
|
|
23
|
+
const contTag = 0b1000_0000;
|
|
24
|
+
const contMask = 0b0011_1111;
|
|
25
|
+
const lead2Tag = 0b1100_0000;
|
|
26
|
+
const lead2Mask = 0b0001_1111;
|
|
27
|
+
const lead3Tag = 0b1110_0000;
|
|
28
|
+
const lead3Mask = 0b0000_1111;
|
|
29
|
+
const lead4Tag = 0b1111_0000;
|
|
30
|
+
const lead4Mask = 0b0000_0111;
|
|
31
|
+
/**
|
|
32
|
+
* Encodes the low six bits of `x` as a UTF-8 continuation byte.
|
|
33
|
+
*/
|
|
34
|
+
const contByte = (x) => x & contMask | contTag;
|
|
35
|
+
/**
|
|
36
|
+
* Reads the six payload bits of a continuation byte.
|
|
37
|
+
*/
|
|
38
|
+
const contPayload = (b) => b & contMask;
|
|
8
39
|
/**
|
|
9
40
|
* Converts a Unicode code point to a sequence of UTF-8 bytes.
|
|
10
41
|
* @param input The Unicode code point to be converted. Valid range:
|
|
@@ -20,41 +51,41 @@ const codePointToUtf8 = (input) => {
|
|
|
20
51
|
return [input & 0b01111_1111];
|
|
21
52
|
}
|
|
22
53
|
if (input >= 0x0080 && input <= 0x07ff) {
|
|
23
|
-
return [input >> 6 |
|
|
54
|
+
return [input >> 6 | lead2Tag, contByte(input)];
|
|
24
55
|
}
|
|
25
56
|
if (input >= 0x0800 && input <= 0xffff) {
|
|
26
57
|
return [
|
|
27
|
-
input >> 12 |
|
|
28
|
-
input >> 6
|
|
29
|
-
input
|
|
58
|
+
input >> 12 | lead3Tag,
|
|
59
|
+
contByte(input >> 6),
|
|
60
|
+
contByte(input),
|
|
30
61
|
];
|
|
31
62
|
}
|
|
32
63
|
if (input >= 0x10000 && input <= 0x10ffff) {
|
|
33
64
|
return [
|
|
34
|
-
input >> 18 |
|
|
35
|
-
input >> 12
|
|
36
|
-
input >> 6
|
|
37
|
-
input
|
|
65
|
+
input >> 18 | lead4Tag,
|
|
66
|
+
contByte(input >> 12),
|
|
67
|
+
contByte(input >> 6),
|
|
68
|
+
contByte(input),
|
|
38
69
|
];
|
|
39
70
|
}
|
|
40
71
|
if ((input & errorMask) !== 0) {
|
|
41
72
|
if ((input & 0b1000_0000_0000_0000) !== 0) {
|
|
42
73
|
return [
|
|
43
|
-
input >> 12 &
|
|
44
|
-
input >> 6
|
|
45
|
-
input
|
|
74
|
+
input >> 12 & lead4Mask | lead4Tag,
|
|
75
|
+
contByte(input >> 6),
|
|
76
|
+
contByte(input),
|
|
46
77
|
];
|
|
47
78
|
}
|
|
48
79
|
if ((input & 0b0000_0100_0000_0000) !== 0) {
|
|
49
80
|
return [
|
|
50
|
-
input >> 6 &
|
|
51
|
-
input
|
|
81
|
+
input >> 6 & lead3Mask | lead3Tag,
|
|
82
|
+
contByte(input),
|
|
52
83
|
];
|
|
53
84
|
}
|
|
54
85
|
if ((input & 0b0000_0010_0000_0000) !== 0) {
|
|
55
86
|
return [
|
|
56
|
-
input >> 6 &
|
|
57
|
-
input
|
|
87
|
+
input >> 6 & lead4Mask | lead4Tag,
|
|
88
|
+
contByte(input),
|
|
58
89
|
];
|
|
59
90
|
}
|
|
60
91
|
if ((input & 0b0000_0000_1000_0000) !== 0)
|
|
@@ -84,16 +115,16 @@ const utf8StateToError = (state) => {
|
|
|
84
115
|
}
|
|
85
116
|
case 2: {
|
|
86
117
|
const [s0, s1] = state;
|
|
87
|
-
x = s0 <
|
|
88
|
-
? ((s0 &
|
|
89
|
-
: ((s0 &
|
|
118
|
+
x = s0 < lead4Tag
|
|
119
|
+
? ((s0 & lead3Mask) << 6) + contPayload(s1) + 0b0000_0100_0000_0000
|
|
120
|
+
: ((s0 & lead4Mask) << 6) + contPayload(s1) +
|
|
90
121
|
0b0000_0010_0000_0000;
|
|
91
122
|
break;
|
|
92
123
|
}
|
|
93
124
|
case 3: {
|
|
94
125
|
const [s0, s1, s2] = state;
|
|
95
|
-
x = ((s0 &
|
|
96
|
-
(s2
|
|
126
|
+
x = ((s0 & lead4Mask) << 12) + (contPayload(s1) << 6) +
|
|
127
|
+
contPayload(s2) + 0b1000_0000_0000_0000;
|
|
97
128
|
break;
|
|
98
129
|
}
|
|
99
130
|
default:
|
|
@@ -115,18 +146,18 @@ const utf8ByteToCodePointOp = (byte, state) => {
|
|
|
115
146
|
return [[errorMask], state];
|
|
116
147
|
}
|
|
117
148
|
if (state === null) {
|
|
118
|
-
if (byte <
|
|
149
|
+
if (byte < contTag)
|
|
119
150
|
return [[byte], null];
|
|
120
151
|
if (byte >= 0b1100_0010 && byte <= 0b1111_0100)
|
|
121
152
|
return [[], [byte]];
|
|
122
153
|
return [[byte | errorMask], null];
|
|
123
154
|
}
|
|
124
|
-
if (byte >=
|
|
155
|
+
if (byte >= contTag && byte < lead2Tag) {
|
|
125
156
|
switch (state.length) {
|
|
126
157
|
case 1: {
|
|
127
158
|
const [s0] = state;
|
|
128
|
-
if (s0 <
|
|
129
|
-
return [[((s0 &
|
|
159
|
+
if (s0 < lead3Tag) {
|
|
160
|
+
return [[((s0 & lead2Mask) << 6) + contPayload(byte)], null];
|
|
130
161
|
}
|
|
131
162
|
if (s0 < 0b1111_1000)
|
|
132
163
|
return [[], [s0, byte]];
|
|
@@ -134,10 +165,10 @@ const utf8ByteToCodePointOp = (byte, state) => {
|
|
|
134
165
|
}
|
|
135
166
|
case 2: {
|
|
136
167
|
const [s0, s1] = state;
|
|
137
|
-
if (s0 <
|
|
168
|
+
if (s0 < lead4Tag) {
|
|
138
169
|
return [[
|
|
139
|
-
((s0 &
|
|
140
|
-
(byte
|
|
170
|
+
((s0 & lead3Mask) << 12) + (contPayload(s1) << 6) +
|
|
171
|
+
contPayload(byte),
|
|
141
172
|
], null];
|
|
142
173
|
}
|
|
143
174
|
if (s0 < 0b1111_1000)
|
|
@@ -147,14 +178,14 @@ const utf8ByteToCodePointOp = (byte, state) => {
|
|
|
147
178
|
case 3: {
|
|
148
179
|
const [s0, s1, s2] = state;
|
|
149
180
|
return [[
|
|
150
|
-
((s0 &
|
|
151
|
-
((s2
|
|
181
|
+
((s0 & lead4Mask) << 18) + (contPayload(s1) << 12) +
|
|
182
|
+
(contPayload(s2) << 6) + contPayload(byte),
|
|
152
183
|
], null];
|
|
153
184
|
}
|
|
154
185
|
}
|
|
155
186
|
}
|
|
156
187
|
const error = utf8StateToError(state);
|
|
157
|
-
if (byte <
|
|
188
|
+
if (byte < contTag)
|
|
158
189
|
return [[error, byte], null];
|
|
159
190
|
if (byte >= 0b1100_0010 && byte <= 0b1111_0100)
|
|
160
191
|
return [[error], [byte]];
|
|
@@ -179,3 +210,26 @@ const utf8EofToCodePointOp = (state) => [
|
|
|
179
210
|
* @returns A list of Unicode code points or error codes.
|
|
180
211
|
*/
|
|
181
212
|
export const toCodePointList = decoder(utf8ByteToCodePointOp, utf8EofToCodePointOp);
|
|
213
|
+
/**
|
|
214
|
+
* Returns the decoded string if `v` is valid UTF-8, or `null` otherwise.
|
|
215
|
+
* Rejects non-octet Vecs, invalid byte sequences, surrogates, and out-of-range
|
|
216
|
+
* code points.
|
|
217
|
+
*/
|
|
218
|
+
export const fromVec = (v) => {
|
|
219
|
+
if (length(v) % 8n !== 0n) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
const arr = toArray(toCodePointList(u8List(msb)(v)));
|
|
223
|
+
for (const cp of arr) {
|
|
224
|
+
if (cp < 0) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
if (cp > 0x10FFFF) {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
if (cp >= 0xD800 && cp <= 0xDFFF) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return codePointListToString(arr);
|
|
235
|
+
};
|
package/fs/text/utf8/proof.f.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { toCodePointList, fromCodePointList } from "./module.f.js";
|
|
1
|
+
import { toCodePointList, fromCodePointList, fromVec } from "./module.f.js";
|
|
2
2
|
import { stringify as jsonStringify } from "../../json/module.f.js";
|
|
3
3
|
import { sort } from "../../types/object/module.f.js";
|
|
4
4
|
import { toArray } from "../../types/list/module.f.js";
|
|
5
|
+
import { msb, u8ListToVec } from "../../types/bit_vec/module.f.js";
|
|
5
6
|
const stringify = jsonStringify(sort);
|
|
6
7
|
export const proof = {
|
|
7
8
|
toCodePoint: [
|
|
@@ -170,5 +171,63 @@ export const proof = {
|
|
|
170
171
|
throw result;
|
|
171
172
|
}
|
|
172
173
|
}
|
|
174
|
+
],
|
|
175
|
+
fromVec: [
|
|
176
|
+
// Valid ASCII → decoded string
|
|
177
|
+
() => {
|
|
178
|
+
const v = u8ListToVec(msb)([0x68, 0x65, 0x6c, 0x6c, 0x6f]); // "hello"
|
|
179
|
+
if (fromVec(v) !== 'hello') {
|
|
180
|
+
throw 'expected "hello"';
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
// Valid multi-byte UTF-8 → decoded string (U+00A9 COPYRIGHT SIGN, 2-byte)
|
|
184
|
+
() => {
|
|
185
|
+
const v = u8ListToVec(msb)([0xc2, 0xa9]); // "©"
|
|
186
|
+
if (fromVec(v) !== '©') {
|
|
187
|
+
throw 'expected copyright sign';
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
// Valid 3-byte UTF-8 (U+4E2D CJK)
|
|
191
|
+
() => {
|
|
192
|
+
const v = u8ListToVec(msb)([0xe4, 0xb8, 0xad]); // "中"
|
|
193
|
+
if (fromVec(v) !== '中') {
|
|
194
|
+
throw 'expected CJK character';
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
// Valid 4-byte UTF-8 (U+1F600 GRINNING FACE)
|
|
198
|
+
() => {
|
|
199
|
+
const v = u8ListToVec(msb)([0xf0, 0x9f, 0x98, 0x80]);
|
|
200
|
+
if (fromVec(v) !== '\u{1f600}') {
|
|
201
|
+
throw 'expected emoji';
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
// Invalid byte sequence → null
|
|
205
|
+
() => {
|
|
206
|
+
const v = u8ListToVec(msb)([0xff, 0xfe]); // not valid UTF-8
|
|
207
|
+
if (fromVec(v) !== null) {
|
|
208
|
+
throw 'expected null for invalid UTF-8';
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
// Lone continuation byte → null
|
|
212
|
+
() => {
|
|
213
|
+
const v = u8ListToVec(msb)([0x80]);
|
|
214
|
+
if (fromVec(v) !== null) {
|
|
215
|
+
throw 'expected null for lone continuation byte';
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
// Surrogate half (U+D800, encoded as CESU-8 0xED 0xA0 0x80) → null
|
|
219
|
+
() => {
|
|
220
|
+
const v = u8ListToVec(msb)([0xed, 0xa0, 0x80]);
|
|
221
|
+
if (fromVec(v) !== null) {
|
|
222
|
+
throw 'expected null for surrogate';
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
// Empty Vec → empty string
|
|
226
|
+
() => {
|
|
227
|
+
const v = u8ListToVec(msb)([]);
|
|
228
|
+
if (fromVec(v) !== '') {
|
|
229
|
+
throw 'expected empty string';
|
|
230
|
+
}
|
|
231
|
+
},
|
|
173
232
|
]
|
|
174
233
|
};
|
|
@@ -6,51 +6,48 @@
|
|
|
6
6
|
import { abs, sign } from "../bigint/module.f.js";
|
|
7
7
|
const twoPow53 = 9007199254740992n;
|
|
8
8
|
const twoPow54 = 18014398509481984n;
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (m >= min) {
|
|
17
|
-
return [BigInt(s) * m, e];
|
|
18
|
-
}
|
|
19
|
-
m = m << 1n;
|
|
20
|
-
e--;
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
const decreaseMantissa = ([m, e]) => (max) => {
|
|
9
|
+
/**
|
|
10
|
+
* Shifts the mantissa magnitude one bit at a time, compensating the exponent,
|
|
11
|
+
* until `done(magnitude, bound)` holds; the sign is restored on return.
|
|
12
|
+
* A zero mantissa is returned unchanged: it can never satisfy a lower bound,
|
|
13
|
+
* so shifting it would not terminate.
|
|
14
|
+
*/
|
|
15
|
+
const normalizeMantissa = (shift, de, done) => ([m, e]) => (bound) => {
|
|
24
16
|
if (m === 0n) {
|
|
25
17
|
return [m, e];
|
|
26
18
|
}
|
|
27
19
|
const s = sign(m);
|
|
28
20
|
m = abs(m);
|
|
29
21
|
while (true) {
|
|
30
|
-
if (m
|
|
22
|
+
if (done(m, bound)) {
|
|
31
23
|
return [BigInt(s) * m, e];
|
|
32
24
|
}
|
|
33
|
-
m = m
|
|
34
|
-
e
|
|
25
|
+
m = shift(m);
|
|
26
|
+
e += de;
|
|
35
27
|
}
|
|
36
28
|
};
|
|
29
|
+
const increaseMantissa = normalizeMantissa(m => m << 1n, -1, (m, min) => m >= min);
|
|
30
|
+
const decreaseMantissa = normalizeMantissa(m => m >> 1n, +1, (m, max) => m < max);
|
|
37
31
|
const pow = (base) => (exp) => base ** BigInt(exp);
|
|
38
32
|
const pow5 = pow(5n);
|
|
39
33
|
export const multiply = ([m, e]) => (mul) => [m * mul, e];
|
|
40
34
|
const divide = ([m, e]) => (div) => [[m / div, e], m % div];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Runs `f` on the magnitude `[abs(m), e]` and restores the sign of `m` on the
|
|
37
|
+
* result: operations on signed mantissas factor through the magnitude.
|
|
38
|
+
*/
|
|
39
|
+
const withSign = (m, e) => (f) => multiply(f([abs(m), e]))(BigInt(sign(m)));
|
|
40
|
+
const round53 = ([[m, e], r]) => withSign(m, e)(([mAbs]) => {
|
|
41
|
+
const [m54, e54] = decreaseMantissa([mAbs, e])(twoPow54);
|
|
45
42
|
const o54 = m54 & 1n;
|
|
46
43
|
const m53 = m54 >> 1n;
|
|
47
44
|
const e53 = e54 + 1;
|
|
48
|
-
if (o54 === 1n && r === 0n &&
|
|
45
|
+
if (o54 === 1n && r === 0n && mAbs === m54 >> BigInt(e - e54)) {
|
|
49
46
|
const odd = m53 & 1n;
|
|
50
|
-
return
|
|
47
|
+
return [m53 + odd, e53];
|
|
51
48
|
}
|
|
52
|
-
return
|
|
53
|
-
};
|
|
49
|
+
return [m53 + o54, e53];
|
|
50
|
+
});
|
|
54
51
|
export const decToBin = (dec) => {
|
|
55
52
|
if (dec[0] === 0n) {
|
|
56
53
|
return [0n, 0];
|
|
@@ -62,9 +59,11 @@ export const decToBin = (dec) => {
|
|
|
62
59
|
}
|
|
63
60
|
const p = pow5(-dec[1]);
|
|
64
61
|
const [m, e] = increaseMantissa(dec)(p * twoPow53);
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
return withSign(m, e)(magnitude => round53(divide(magnitude)(p)));
|
|
63
|
+
};
|
|
64
|
+
export const proof = {
|
|
65
|
+
// normalizeMantissa guards against zero mantissa to prevent an infinite loop;
|
|
66
|
+
// this path is unreachable through decToBin (which returns early for 0n),
|
|
67
|
+
// so we exercise it here where the private helper is in scope.
|
|
68
|
+
normalizeMantissaZero: () => { increaseMantissa([0n, 5])(1n); }
|
|
70
69
|
};
|
|
@@ -151,5 +151,27 @@ export declare const factorial: (b: bigint) => bigint;
|
|
|
151
151
|
*/
|
|
152
152
|
export declare const combination: (...k: readonly bigint[]) => bigint;
|
|
153
153
|
export declare const xor: Reduce;
|
|
154
|
-
export declare const divUp:
|
|
155
|
-
export declare const roundUp:
|
|
154
|
+
export declare const divUp: (b: bigint) => Unary;
|
|
155
|
+
export declare const roundUp: (b: bigint) => Unary;
|
|
156
|
+
/**
|
|
157
|
+
* Divides a bigint value up to the nearest multiple of 2^e (shift-based, power-of-two only).
|
|
158
|
+
*
|
|
159
|
+
* @param e - The exponent (divisor = 2^e).
|
|
160
|
+
* @returns A function that rounds a value up by the given power of two.
|
|
161
|
+
*/
|
|
162
|
+
export declare const divUpE2: (e: bigint) => Unary;
|
|
163
|
+
/**
|
|
164
|
+
* Rounds a bigint value up to the nearest multiple of 2^e (shift-based, power-of-two only).
|
|
165
|
+
*
|
|
166
|
+
* @param e - The exponent (multiple = 2^e).
|
|
167
|
+
* @returns A function that rounds a value up to the nearest multiple of the given power of two.
|
|
168
|
+
*/
|
|
169
|
+
export declare const roundUpE2: (e: bigint) => Unary;
|
|
170
|
+
/**
|
|
171
|
+
* Converts a bit count to a byte count, rounding up — divides by `8` (`2^3` bits per byte).
|
|
172
|
+
*/
|
|
173
|
+
export declare const divUp8: Unary;
|
|
174
|
+
/**
|
|
175
|
+
* Rounds a bit count up to the nearest whole byte — the nearest multiple of `8` (`2^3` bits per byte).
|
|
176
|
+
*/
|
|
177
|
+
export declare const roundUp8: Unary;
|
|
@@ -216,11 +216,39 @@ export const combination = (...k) => {
|
|
|
216
216
|
return partialFactorial(m)(s) / p;
|
|
217
217
|
};
|
|
218
218
|
export const xor = a => b => a ^ b;
|
|
219
|
-
export const divUp = b => {
|
|
219
|
+
export const divUp = (b) => {
|
|
220
220
|
const m = b - 1n;
|
|
221
221
|
return v => (v + m) / b;
|
|
222
222
|
};
|
|
223
|
-
export const roundUp = b => {
|
|
223
|
+
export const roundUp = (b) => {
|
|
224
224
|
const d = divUp(b);
|
|
225
225
|
return v => d(v) * b;
|
|
226
226
|
};
|
|
227
|
+
/**
|
|
228
|
+
* Divides a bigint value up to the nearest multiple of 2^e (shift-based, power-of-two only).
|
|
229
|
+
*
|
|
230
|
+
* @param e - The exponent (divisor = 2^e).
|
|
231
|
+
* @returns A function that rounds a value up by the given power of two.
|
|
232
|
+
*/
|
|
233
|
+
export const divUpE2 = (e) => {
|
|
234
|
+
const m = mask(e);
|
|
235
|
+
return v => (v + m) >> e;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Rounds a bigint value up to the nearest multiple of 2^e (shift-based, power-of-two only).
|
|
239
|
+
*
|
|
240
|
+
* @param e - The exponent (multiple = 2^e).
|
|
241
|
+
* @returns A function that rounds a value up to the nearest multiple of the given power of two.
|
|
242
|
+
*/
|
|
243
|
+
export const roundUpE2 = (e) => {
|
|
244
|
+
const d = divUpE2(e);
|
|
245
|
+
return v => d(v) << e;
|
|
246
|
+
};
|
|
247
|
+
/**
|
|
248
|
+
* Converts a bit count to a byte count, rounding up — divides by `8` (`2^3` bits per byte).
|
|
249
|
+
*/
|
|
250
|
+
export const divUp8 = divUpE2(3n);
|
|
251
|
+
/**
|
|
252
|
+
* Rounds a bit count up to the nearest whole byte — the nearest multiple of `8` (`2^3` bits per byte).
|
|
253
|
+
*/
|
|
254
|
+
export const roundUp8 = roundUpE2(3n);
|
|
@@ -29,4 +29,11 @@ export declare const proof: {
|
|
|
29
29
|
combination3: () => void;
|
|
30
30
|
divUp: () => void;
|
|
31
31
|
roundUp: () => void;
|
|
32
|
+
divUpE2: () => void;
|
|
33
|
+
roundUpE2: () => void;
|
|
34
|
+
divUp8: () => void;
|
|
35
|
+
roundUp8: () => void;
|
|
36
|
+
xor: () => void;
|
|
37
|
+
multiple: () => void;
|
|
38
|
+
product: () => void;
|
|
32
39
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { sum, abs, serialize, log2, bitLength, mask, combination, factorial, divUp, roundUp } from "./module.f.js";
|
|
1
|
+
import { sum, abs, serialize, log2, bitLength, mask, combination, factorial, xor, multiple, product, divUp, roundUp, divUpE2, roundUpE2, divUp8, roundUp8 } from "./module.f.js";
|
|
2
|
+
import { assertEq } from "../../asserts/module.f.js";
|
|
2
3
|
import { min } from "../function/compare/module.f.js";
|
|
3
4
|
const oldLog2 = (v) => {
|
|
4
5
|
if (v <= 0n) {
|
|
@@ -454,22 +455,52 @@ export const proof = {
|
|
|
454
455
|
}
|
|
455
456
|
},
|
|
456
457
|
divUp: () => {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
if (divUp(8n)(15n) !== 2n) {
|
|
461
|
-
throw new Error("fail");
|
|
462
|
-
}
|
|
458
|
+
assertEq(divUp(8n)(8n), 1n);
|
|
459
|
+
assertEq(divUp(8n)(15n), 2n);
|
|
463
460
|
},
|
|
464
461
|
roundUp: () => {
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
462
|
+
assertEq(roundUp(8n)(8n), 8n);
|
|
463
|
+
assertEq(roundUp(8n)(15n), 16n);
|
|
464
|
+
assertEq(roundUp(8n)(3n), 8n);
|
|
465
|
+
},
|
|
466
|
+
divUpE2: () => {
|
|
467
|
+
assertEq(divUpE2(3n)(8n), 1n);
|
|
468
|
+
assertEq(divUpE2(3n)(15n), 2n);
|
|
469
|
+
assertEq(divUpE2(3n)(0n), 0n);
|
|
470
|
+
assertEq(divUpE2(3n)(8n), 1n);
|
|
471
|
+
assertEq(divUpE2(3n)(9n), 2n);
|
|
472
|
+
},
|
|
473
|
+
roundUpE2: () => {
|
|
474
|
+
assertEq(roundUpE2(3n)(8n), 8n);
|
|
475
|
+
assertEq(roundUpE2(3n)(15n), 16n);
|
|
476
|
+
assertEq(roundUpE2(3n)(3n), 8n);
|
|
477
|
+
assertEq(roundUpE2(3n)(0n), 0n);
|
|
478
|
+
assertEq(roundUpE2(3n)(8n), 8n);
|
|
479
|
+
assertEq(roundUpE2(3n)(9n), 16n);
|
|
480
|
+
},
|
|
481
|
+
divUp8: () => {
|
|
482
|
+
assertEq(divUp8(0n), 0n);
|
|
483
|
+
assertEq(divUp8(1n), 1n);
|
|
484
|
+
assertEq(divUp8(8n), 1n);
|
|
485
|
+
assertEq(divUp8(9n), 2n);
|
|
486
|
+
},
|
|
487
|
+
roundUp8: () => {
|
|
488
|
+
assertEq(roundUp8(0n), 0n);
|
|
489
|
+
assertEq(roundUp8(1n), 8n);
|
|
490
|
+
assertEq(roundUp8(8n), 8n);
|
|
491
|
+
assertEq(roundUp8(9n), 16n);
|
|
492
|
+
},
|
|
493
|
+
xor: () => {
|
|
494
|
+
assertEq(xor(5n)(3n), 6n);
|
|
495
|
+
assertEq(xor(0n)(15n), 15n);
|
|
496
|
+
assertEq(xor(0xffn)(0xf0n), 0x0fn);
|
|
497
|
+
},
|
|
498
|
+
multiple: () => {
|
|
499
|
+
assertEq(multiple(3n)(4n), 12n);
|
|
500
|
+
assertEq(multiple(0n)(100n), 0n);
|
|
501
|
+
},
|
|
502
|
+
product: () => {
|
|
503
|
+
assertEq(product([1n, 2n, 3n, 4n]), 24n);
|
|
504
|
+
assertEq(product([5n, 6n]), 30n);
|
|
474
505
|
},
|
|
475
506
|
};
|
|
@@ -30,6 +30,24 @@ export declare const vec: (len: bigint) => (ui: bigint) => Vec;
|
|
|
30
30
|
* Creates an 8-bit vector from an unsigned integer.
|
|
31
31
|
*/
|
|
32
32
|
export declare const vec8: (ui: bigint) => Vec;
|
|
33
|
+
/**
|
|
34
|
+
* Builds a vector from a bigint whose most-significant set bit is a sentinel
|
|
35
|
+
* marking the start of the data.
|
|
36
|
+
*
|
|
37
|
+
* The sentinel does double duty: it fixes the length (`bitLength - 1`) and is
|
|
38
|
+
* stripped from the result. This lets a plain hex literal carry leading zero
|
|
39
|
+
* bits that would otherwise be lost — write `0x1` ahead of the data and the
|
|
40
|
+
* `1` both delimits and disappears.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
*
|
|
44
|
+
* ```js
|
|
45
|
+
* uint(fromSentinel(0x1_89_50n)) // 0x8950n
|
|
46
|
+
* length(fromSentinel(0x1_89_50n)) // 16n — the two data bytes, sentinel gone
|
|
47
|
+
* fromSentinel(0x1_00_05n) // a 16-bit vector holding 0x0005
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare const fromSentinel: (raw: bigint) => Vec;
|
|
33
51
|
/**
|
|
34
52
|
* Returns the unsigned integer representation of the vector by clearing the stop bit.
|
|
35
53
|
*
|
|
@@ -67,6 +67,24 @@ export const vec = (len) => {
|
|
|
67
67
|
* Creates an 8-bit vector from an unsigned integer.
|
|
68
68
|
*/
|
|
69
69
|
export const vec8 = vec(8n);
|
|
70
|
+
/**
|
|
71
|
+
* Builds a vector from a bigint whose most-significant set bit is a sentinel
|
|
72
|
+
* marking the start of the data.
|
|
73
|
+
*
|
|
74
|
+
* The sentinel does double duty: it fixes the length (`bitLength - 1`) and is
|
|
75
|
+
* stripped from the result. This lets a plain hex literal carry leading zero
|
|
76
|
+
* bits that would otherwise be lost — write `0x1` ahead of the data and the
|
|
77
|
+
* `1` both delimits and disappears.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
*
|
|
81
|
+
* ```js
|
|
82
|
+
* uint(fromSentinel(0x1_89_50n)) // 0x8950n
|
|
83
|
+
* length(fromSentinel(0x1_89_50n)) // 16n — the two data bytes, sentinel gone
|
|
84
|
+
* fromSentinel(0x1_00_05n) // a 16-bit vector holding 0x0005
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export const fromSentinel = (raw) => vec(bitLength(raw) - 1n)(raw);
|
|
70
88
|
/**
|
|
71
89
|
* Returns the unsigned integer representation of the vector by clearing the stop bit.
|
|
72
90
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mask } from "../bigint/module.f.js";
|
|
2
2
|
import { asBase, asNominal } from "../nominal/module.f.js";
|
|
3
|
-
import { length, empty, uint, vec, lsb, msb, repeat, vec8, u8ListToVec, u8List, chunkList } from "./module.f.js";
|
|
3
|
+
import { length, empty, uint, vec, lsb, msb, repeat, vec8, u8ListToVec, u8List, chunkList, fromSentinel } from "./module.f.js";
|
|
4
4
|
import { repeat as listRepeat, toArray } from "../list/module.f.js";
|
|
5
5
|
const unsafeVec = (a) => asNominal(a);
|
|
6
6
|
// 0x8 = 0b1000 = 0 + 8
|
|
@@ -81,6 +81,18 @@ const concat = (e) => (r) => () => {
|
|
|
81
81
|
}
|
|
82
82
|
};
|
|
83
83
|
export const proof = {
|
|
84
|
+
fromSentinel: () => {
|
|
85
|
+
// Two data bytes; the leading 0x1 nibble is the sentinel, stripped out.
|
|
86
|
+
const v = fromSentinel(0x18950n);
|
|
87
|
+
assertEq(length(v), 16n);
|
|
88
|
+
assertEq(uint(v), 0x8950n);
|
|
89
|
+
// Leading zero bytes survive because the sentinel pins the length.
|
|
90
|
+
const z = fromSentinel(0x10005n);
|
|
91
|
+
assertEq(length(z), 16n);
|
|
92
|
+
assertEq(uint(z), 0x0005n);
|
|
93
|
+
// A bare sentinel yields the empty vector.
|
|
94
|
+
assertEq(fromSentinel(0x1n), empty);
|
|
95
|
+
},
|
|
84
96
|
examples: {
|
|
85
97
|
vec: () => {
|
|
86
98
|
const vec4 = vec(4n);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join, concat, logicalNot, strictEqual, addition, increment, foldToScan, reduceToScan, } from "./module.f.js";
|
|
1
|
+
import { join, concat, logicalNot, strictEqual, addition, increment, counter, stateScanToScan, foldToScan, reduceToScan, } from "./module.f.js";
|
|
2
2
|
const joinTest = () => {
|
|
3
3
|
const result = join(', ')('world')('hello');
|
|
4
4
|
if (result !== 'hello, world') {
|
|
@@ -63,4 +63,22 @@ const reduceToScanTest = () => {
|
|
|
63
63
|
throw v1;
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
|
-
|
|
66
|
+
const counterTest = () => {
|
|
67
|
+
const fn = counter();
|
|
68
|
+
if (fn(4) !== 5) {
|
|
69
|
+
throw 'counter() returned wrong function';
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
const stateScanToScanTest = () => {
|
|
73
|
+
const op = (input, state) => [input + state, input + state];
|
|
74
|
+
const scan = stateScanToScan(op)(0);
|
|
75
|
+
const [v1, scan2] = scan(3);
|
|
76
|
+
if (v1 !== 3) {
|
|
77
|
+
throw v1;
|
|
78
|
+
}
|
|
79
|
+
const [v2] = scan2(4);
|
|
80
|
+
if (v2 !== 7) {
|
|
81
|
+
throw v2;
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
export const proof = { joinTest, concatTest, logicalNotTest, strictEqualTest, additionTest, incrementTest, counterTest, stateScanToScanTest, foldToScanTest, reduceToScanTest };
|