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.
Files changed (181) hide show
  1. package/fs/asn.1/module.f.js +18 -22
  2. package/fs/asn.1/proof.f.d.ts +5 -0
  3. package/fs/asn.1/proof.f.js +38 -2
  4. package/fs/base64/module.f.d.ts +9 -0
  5. package/fs/base64/module.f.js +60 -0
  6. package/fs/base64/proof.f.d.ts +11 -0
  7. package/fs/base64/proof.f.js +117 -0
  8. package/fs/base_n/module.f.d.ts +44 -0
  9. package/fs/base_n/module.f.js +54 -0
  10. package/fs/base_n/proof.f.d.ts +10 -0
  11. package/fs/base_n/proof.f.js +86 -0
  12. package/fs/bnf/data/module.f.d.ts +4 -9
  13. package/fs/bnf/data/module.f.js +4 -3
  14. package/fs/bnf/module.f.d.ts +3 -4
  15. package/fs/bnf/module.f.js +3 -2
  16. package/fs/bnf/proof.f.d.ts +9 -0
  17. package/fs/bnf/proof.f.js +98 -1
  18. package/fs/cas/mcp/module.f.d.ts +40 -0
  19. package/fs/cas/mcp/module.f.js +223 -0
  20. package/fs/cas/mcp/proof.f.d.ts +30 -0
  21. package/fs/cas/mcp/proof.f.js +310 -0
  22. package/fs/cas/module.f.d.ts +9 -3
  23. package/fs/cas/module.f.js +104 -69
  24. package/fs/cas/proof.f.d.ts +2 -0
  25. package/fs/cas/proof.f.js +30 -1
  26. package/fs/cbase32/module.f.d.ts +1 -1
  27. package/fs/cbase32/module.f.js +19 -40
  28. package/fs/cbase32/proof.f.d.ts +1 -0
  29. package/fs/cbase32/proof.f.js +15 -0
  30. package/fs/ci/config/module.f.d.ts +6 -6
  31. package/fs/ci/config/module.f.js +6 -6
  32. package/fs/ci/deno/module.f.js +2 -2
  33. package/fs/ci/module.f.d.ts +5 -0
  34. package/fs/ci/module.f.js +2 -3
  35. package/fs/ci/proof.f.d.ts +1 -0
  36. package/fs/ci/proof.f.js +9 -3
  37. package/fs/cli/module.f.d.ts +3 -1
  38. package/fs/cli/module.f.js +22 -12
  39. package/fs/cli/proof.f.d.ts +5 -0
  40. package/fs/cli/proof.f.js +76 -0
  41. package/fs/crypto/hmac/proof.f.d.ts +1 -0
  42. package/fs/crypto/hmac/proof.f.js +8 -0
  43. package/fs/crypto/secp/proof.f.d.ts +1 -0
  44. package/fs/crypto/secp/proof.f.js +10 -0
  45. package/fs/crypto/sign/module.f.js +1 -4
  46. package/fs/dev/module.f.d.ts +5 -3
  47. package/fs/dev/module.f.js +13 -2
  48. package/fs/dev/package_json/proof.f.d.ts +1 -0
  49. package/fs/dev/package_json/proof.f.js +5 -0
  50. package/fs/dev/proof.f.d.ts +1 -0
  51. package/fs/dev/proof.f.js +12 -1
  52. package/fs/djs/ast/module.f.d.ts +1 -1
  53. package/fs/djs/ast/proof.f.d.ts +5 -0
  54. package/fs/djs/ast/proof.f.js +17 -0
  55. package/fs/djs/module.f.d.ts +1 -1
  56. package/fs/djs/module.f.js +2 -3
  57. package/fs/djs/serializer/module.f.js +24 -11
  58. package/fs/djs/transpiler/module.f.js +3 -4
  59. package/fs/effects/memory/module.f.d.ts +37 -0
  60. package/fs/effects/memory/module.f.js +24 -0
  61. package/fs/effects/memory/proof.f.d.ts +6 -0
  62. package/fs/effects/memory/proof.f.js +64 -0
  63. package/fs/effects/mock/module.f.d.ts +7 -2
  64. package/fs/effects/mock/module.f.js +12 -8
  65. package/fs/effects/module.d.ts +1 -1
  66. package/fs/effects/module.f.d.ts +41 -0
  67. package/fs/effects/module.f.js +25 -0
  68. package/fs/effects/module.js +6 -7
  69. package/fs/effects/node/memory/module.d.ts +20 -0
  70. package/fs/effects/node/memory/module.js +44 -0
  71. package/fs/effects/node/memory/proof.d.ts +10 -0
  72. package/fs/effects/node/memory/proof.js +35 -0
  73. package/fs/effects/node/module.d.ts +1 -1
  74. package/fs/effects/node/module.f.d.ts +54 -8
  75. package/fs/effects/node/module.f.js +55 -4
  76. package/fs/effects/node/module.js +166 -135
  77. package/fs/effects/node/proof.f.d.ts +10 -0
  78. package/fs/effects/node/proof.f.js +88 -21
  79. package/fs/effects/node/virtual/module.f.d.ts +6 -0
  80. package/fs/effects/node/virtual/module.f.js +48 -16
  81. package/fs/effects/node/virtual/proof.f.d.ts +17 -0
  82. package/fs/effects/node/virtual/proof.f.js +79 -0
  83. package/fs/effects/proof.f.d.ts +5 -0
  84. package/fs/effects/proof.f.js +54 -34
  85. package/fs/emergent_testing/module.f.d.ts +6 -1
  86. package/fs/emergent_testing/module.f.js +8 -3
  87. package/fs/emergent_testing/proof.f.d.ts +11 -0
  88. package/fs/emergent_testing/proof.f.js +52 -16
  89. package/fs/fjs/module.f.js +2 -2
  90. package/fs/fjs/proof.f.d.ts +8 -0
  91. package/fs/fjs/proof.f.js +39 -0
  92. package/fs/fsc/module.f.d.ts +5 -0
  93. package/fs/fsc/module.f.js +17 -27
  94. package/fs/fsc/proof.f.d.ts +8 -0
  95. package/fs/fsc/proof.f.js +48 -2
  96. package/fs/fsm/module.f.d.ts +2 -3
  97. package/fs/fsm/module.f.js +1 -1
  98. package/fs/html/module.f.d.ts +2 -3
  99. package/fs/html/module.f.js +7 -6
  100. package/fs/html/proof.f.d.ts +1 -0
  101. package/fs/html/proof.f.js +7 -0
  102. package/fs/js/tokenizer/module.f.js +1 -1
  103. package/fs/js/tokenizer/proof.f.js +7 -0
  104. package/fs/json/module.f.d.ts +9 -2
  105. package/fs/json/module.f.js +9 -7
  106. package/fs/json/parser/module.f.js +4 -6
  107. package/fs/json/parser/proof.f.js +19 -10
  108. package/fs/json/proof.f.d.ts +2 -1
  109. package/fs/json/proof.f.js +33 -6
  110. package/fs/json/rpc/module.f.d.ts +5 -0
  111. package/fs/json/rpc/module.f.js +16 -11
  112. package/fs/json/schema/module.f.d.ts +15 -14
  113. package/fs/json/schema/proof.f.d.ts +3 -0
  114. package/fs/json/schema/proof.f.js +16 -1
  115. package/fs/mcp/module.f.d.ts +103 -5
  116. package/fs/mcp/module.f.js +139 -2
  117. package/fs/mcp/proof.f.d.ts +34 -0
  118. package/fs/mcp/proof.f.js +207 -0
  119. package/fs/mcp/stdio/module.f.d.ts +39 -0
  120. package/fs/mcp/stdio/module.f.js +54 -0
  121. package/fs/mcp/stdio/proof.f.d.ts +10 -0
  122. package/fs/mcp/stdio/proof.f.js +92 -0
  123. package/fs/mime/module.f.d.ts +39 -0
  124. package/fs/mime/module.f.js +78 -0
  125. package/fs/mime/proof.f.d.ts +15 -0
  126. package/fs/mime/proof.f.js +30 -0
  127. package/fs/path/module.f.d.ts +8 -0
  128. package/fs/path/module.f.js +10 -3
  129. package/fs/path/proof.f.d.ts +1 -0
  130. package/fs/path/proof.f.js +40 -2
  131. package/fs/text/sgr/proof.f.js +30 -2
  132. package/fs/text/utf8/module.f.d.ts +7 -0
  133. package/fs/text/utf8/module.f.js +85 -31
  134. package/fs/text/utf8/proof.f.d.ts +1 -0
  135. package/fs/text/utf8/proof.f.js +60 -1
  136. package/fs/types/bigfloat/module.f.d.ts +3 -0
  137. package/fs/types/bigfloat/module.f.js +30 -31
  138. package/fs/types/bigint/module.f.d.ts +24 -2
  139. package/fs/types/bigint/module.f.js +30 -2
  140. package/fs/types/bigint/proof.f.d.ts +7 -0
  141. package/fs/types/bigint/proof.f.js +47 -16
  142. package/fs/types/bit_vec/module.f.d.ts +18 -0
  143. package/fs/types/bit_vec/module.f.js +18 -0
  144. package/fs/types/bit_vec/proof.f.d.ts +1 -0
  145. package/fs/types/bit_vec/proof.f.js +13 -1
  146. package/fs/types/function/operator/proof.f.d.ts +2 -0
  147. package/fs/types/function/operator/proof.f.js +20 -2
  148. package/fs/types/list/module.f.js +1 -4
  149. package/fs/types/list/proof.f.d.ts +1 -1
  150. package/fs/types/list/proof.f.js +14 -6
  151. package/fs/types/map/proof.f.d.ts +1 -0
  152. package/fs/types/map/proof.f.js +10 -1
  153. package/fs/types/nibble_set/module.f.d.ts +13 -0
  154. package/fs/types/nibble_set/module.f.js +16 -0
  155. package/fs/types/object/module.f.d.ts +12 -8
  156. package/fs/types/object/module.f.js +9 -2
  157. package/fs/types/object/proof.f.d.ts +14 -0
  158. package/fs/types/object/proof.f.js +4 -0
  159. package/fs/types/ordered_map/proof.f.d.ts +1 -0
  160. package/fs/types/ordered_map/proof.f.js +39 -79
  161. package/fs/types/phantom/module.f.d.ts +22 -0
  162. package/fs/types/phantom/module.f.js +11 -0
  163. package/fs/types/prime_field/proof.f.d.ts +7 -0
  164. package/fs/types/prime_field/proof.f.js +63 -122
  165. package/fs/types/rtti/common/module.f.d.ts +4 -4
  166. package/fs/types/rtti/common/module.f.js +1 -1
  167. package/fs/types/rtti/module.f.d.ts +2 -3
  168. package/fs/types/rtti/parse/module.f.js +0 -1
  169. package/fs/types/rtti/ts/module.f.d.ts +26 -32
  170. package/fs/types/rtti/ts/module.f.js +2 -2
  171. package/fs/types/rtti/ts/proof.f.js +3 -3
  172. package/fs/types/rtti/validate/module.f.js +0 -1
  173. package/fs/types/sorted_list/module.f.d.ts +6 -0
  174. package/fs/types/sorted_list/module.f.js +11 -0
  175. package/fs/types/sorted_set/module.f.js +2 -8
  176. package/fs/types/ts/module.f.d.ts +1 -1
  177. package/fs/types/ts/module.f.js +3 -1
  178. package/fs/types/ts/proof.f.js +3 -2
  179. package/fs/website/proof.f.d.ts +1 -0
  180. package/fs/website/proof.f.js +8 -1
  181. package/package.json +3 -3
@@ -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 | 0b1100_0000, input & 0b0011_1111 | 0b1000_0000];
54
+ return [input >> 6 | lead2Tag, contByte(input)];
24
55
  }
25
56
  if (input >= 0x0800 && input <= 0xffff) {
26
57
  return [
27
- input >> 12 | 0b1110_0000,
28
- input >> 6 & 0b0011_1111 | 0b1000_0000,
29
- input & 0b0011_1111 | 0b1000_0000,
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 | 0b1111_0000,
35
- input >> 12 & 0b0011_1111 | 0b1000_0000,
36
- input >> 6 & 0b0011_1111 | 0b1000_0000,
37
- input & 0b0011_1111 | 0b1000_0000,
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 & 0b0000_0111 | 0b1111_0000,
44
- input >> 6 & 0b0011_1111 | 0b1000_0000,
45
- input & 0b0011_1111 | 0b1000_0000,
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 & 0b0000_1111 | 0b1110_0000,
51
- input & 0b0011_1111 | 0b1000_0000,
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 & 0b0000_0111 | 0b1111_0000,
57
- input & 0b0011_1111 | 0b1000_0000,
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 < 0b1111_0000
88
- ? ((s0 & 0b0000_1111) << 6) + (s1 & 0b0011_1111) + 0b0000_0100_0000_0000
89
- : ((s0 & 0b0000_0111) << 6) + (s1 & 0b0011_1111) +
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 & 0b0000_0111) << 12) + ((s1 & 0b0011_1111) << 6) +
96
- (s2 & 0b0011_1111) + 0b1000_0000_0000_0000;
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 < 0b1000_0000)
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 >= 0b1000_0000 && byte < 0b1100_0000) {
155
+ if (byte >= contTag && byte < lead2Tag) {
125
156
  switch (state.length) {
126
157
  case 1: {
127
158
  const [s0] = state;
128
- if (s0 < 0b1110_0000) {
129
- return [[((s0 & 0b0001_1111) << 6) + (byte & 0b0011_1111)], null];
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 < 0b1111_0000) {
168
+ if (s0 < lead4Tag) {
138
169
  return [[
139
- ((s0 & 0b0000_1111) << 12) + ((s1 & 0b0011_1111) << 6) +
140
- (byte & 0b0011_1111),
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 & 0b0000_0111) << 18) + ((s1 & 0b0011_1111) << 12) +
151
- ((s2 & 0b0011_1111) << 6) + (byte & 0b0011_1111),
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 < 0b1000_0000)
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
+ };
@@ -2,4 +2,5 @@ export declare const proof: {
2
2
  toCodePoint: (() => void)[];
3
3
  fromCodePointList: (() => void)[];
4
4
  toFrom: (() => void)[];
5
+ fromVec: (() => void)[];
5
6
  };
@@ -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
  };
@@ -1,3 +1,6 @@
1
1
  export type BigFloat = readonly [bigint, number];
2
2
  export declare const multiply: ([m, e]: BigFloat) => (mul: bigint) => BigFloat;
3
3
  export declare const decToBin: (dec: BigFloat) => BigFloat;
4
+ export declare const proof: {
5
+ normalizeMantissaZero: () => void;
6
+ };
@@ -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
- const increaseMantissa = ([m, e]) => (min) => {
10
- if (m === 0n) {
11
- return [m, e];
12
- }
13
- const s = sign(m);
14
- m = abs(m);
15
- while (true) {
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 < max) {
22
+ if (done(m, bound)) {
31
23
  return [BigInt(s) * m, e];
32
24
  }
33
- m = m >> 1n;
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
- const round53 = ([[m, e], r]) => {
42
- const mabs = abs(m);
43
- const s = BigInt(sign(m));
44
- const [m54, e54] = decreaseMantissa([mabs, e])(twoPow54);
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 && mabs === m54 >> BigInt(e - e54)) {
45
+ if (o54 === 1n && r === 0n && mAbs === m54 >> BigInt(e - e54)) {
49
46
  const odd = m53 & 1n;
50
- return multiply([m53 + odd, e53])(s);
47
+ return [m53 + odd, e53];
51
48
  }
52
- return multiply([m53 + o54, e53])(s);
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
- const mAbs = abs(m);
66
- const s = BigInt(sign(m));
67
- const qr = divide([mAbs, e])(p);
68
- const r53 = round53(qr);
69
- return multiply(r53)(s);
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: Reduce;
155
- export declare const roundUp: Reduce;
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
- if (divUp(8n)(8n) !== 1n) {
458
- throw new Error("fail");
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
- if (roundUp(8n)(8n) !== 8n) {
466
- throw new Error("fail");
467
- }
468
- if (roundUp(8n)(15n) !== 16n) {
469
- throw new Error("fail");
470
- }
471
- if (roundUp(8n)(3n) !== 8n) {
472
- throw new Error("fail");
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,4 +1,5 @@
1
1
  export declare const proof: {
2
+ fromSentinel: () => void;
2
3
  examples: {
3
4
  vec: () => void;
4
5
  uint: () => void;
@@ -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);
@@ -5,6 +5,8 @@ export declare const proof: {
5
5
  strictEqualTest: () => void;
6
6
  additionTest: () => void;
7
7
  incrementTest: () => void;
8
+ counterTest: () => void;
9
+ stateScanToScanTest: () => void;
8
10
  foldToScanTest: () => void;
9
11
  reduceToScanTest: () => void;
10
12
  };
@@ -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
- export const proof = { joinTest, concatTest, logicalNotTest, strictEqualTest, additionTest, incrementTest, foldToScanTest, reduceToScanTest };
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 };