@amritk/nish-x86_64-linux 0.18.0 → 0.21.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 (104) hide show
  1. package/INSTALL.md +58 -28
  2. package/bin/nish +0 -0
  3. package/docs/AI.md +2759 -0
  4. package/package.json +3 -2
  5. package/runtime/browser.d.ts +14 -0
  6. package/runtime/browser.mjs +88 -0
  7. package/runtime/core/arrays.d.ts +18 -0
  8. package/runtime/core/arrays.mjs +125 -0
  9. package/runtime/core/checks.mjs +20 -0
  10. package/runtime/core/host.d.ts +70 -0
  11. package/runtime/core/host.mjs +311 -0
  12. package/runtime/core/numbers.d.ts +53 -0
  13. package/runtime/core/numbers.mjs +316 -0
  14. package/runtime/core/result.d.ts +41 -0
  15. package/runtime/core/result.mjs +127 -0
  16. package/runtime/core/strings.d.ts +14 -0
  17. package/runtime/core/strings.mjs +169 -0
  18. package/runtime/core.d.ts +9 -0
  19. package/runtime/core.mjs +55 -0
  20. package/runtime/host.d.ts +6 -0
  21. package/runtime/nish.d.ts +99 -5
  22. package/runtime/nish.h +289 -19
  23. package/runtime/nish.mjs +39 -3
  24. package/runtime/node.mjs +383 -0
  25. package/runtime/runtime-aes.c +490 -0
  26. package/runtime/runtime-bytes.c +401 -0
  27. package/runtime/runtime-cross.c +366 -0
  28. package/runtime/runtime-host.c +8 -7
  29. package/runtime/runtime-net.c +93 -34
  30. package/runtime/runtime-os.c +214 -16
  31. package/runtime/runtime-parallel.c +590 -107
  32. package/runtime/runtime-simd.c +235 -11
  33. package/runtime/runtime-term.c +504 -0
  34. package/runtime/runtime-wasm.c +5 -14
  35. package/runtime/runtime.c +257 -17
  36. package/runtime/shim.mjs +6 -915
  37. package/runtime/sqlite/LICENSE.md +85 -0
  38. package/runtime/sqlite/README.md +45 -0
  39. package/runtime/sqlite/nish-sqlite.c +359 -0
  40. package/runtime/sqlite/sqlite3.c +271131 -0
  41. package/runtime/sqlite/sqlite3.h +14447 -0
  42. package/scripts/build.sh +437 -28
  43. package/std/LICENSE-fast-float +23 -0
  44. package/std/LICENSE-fdlibm +8 -0
  45. package/std/README.md +108 -58
  46. package/std/base64.ts +116 -0
  47. package/std/bytes.ts +419 -0
  48. package/std/cli.ts +328 -0
  49. package/std/collections.ts +6 -5
  50. package/std/crypto/LICENSE-crypt_blowfish +26 -0
  51. package/std/crypto/LICENSE-libsecp256k1 +19 -0
  52. package/std/crypto/aes.ts +238 -76
  53. package/std/crypto/base64url.ts +125 -0
  54. package/std/crypto/bcrypt.ts +760 -0
  55. package/std/crypto/chacha20poly1305.ts +43 -9
  56. package/std/crypto/ed25519.ts +840 -0
  57. package/std/crypto/hkdf.ts +304 -12
  58. package/std/crypto/hmac.ts +382 -54
  59. package/std/crypto/p256.ts +932 -61
  60. package/std/crypto/x25519.ts +55 -37
  61. package/std/crypto/x509-random.ts +71 -0
  62. package/std/crypto/x509.ts +20 -131
  63. package/std/json-tokenizer.ts +4237 -0
  64. package/std/json-typed.ts +1014 -0
  65. package/std/json-value.ts +1182 -0
  66. package/std/json.ts +1202 -34
  67. package/std/math.ts +608 -0
  68. package/std/net/buffer-pool.ts +151 -0
  69. package/std/net/hpack.ts +416 -112
  70. package/std/net/http-fields.ts +93 -0
  71. package/std/net/http1-server.ts +501 -62
  72. package/std/net/http1.ts +31 -6
  73. package/std/net/http2-tls.ts +112 -24
  74. package/std/net/http2.ts +333 -75
  75. package/std/net/http3-server.ts +261 -43
  76. package/std/net/http3.ts +187 -28
  77. package/std/net/postgres.ts +1875 -0
  78. package/std/net/prefork.ts +412 -0
  79. package/std/net/quic-listener.ts +108 -11
  80. package/std/net/quic-packet.ts +243 -82
  81. package/std/net/quic-recovery.ts +361 -30
  82. package/std/net/quic-stream.ts +424 -24
  83. package/std/net/quic.ts +519 -167
  84. package/std/net/router.ts +676 -0
  85. package/std/net/tls/codec.ts +426 -27
  86. package/std/net/tls/record-server.ts +478 -132
  87. package/std/net/tls/record.ts +133 -42
  88. package/std/net/tls/schedule.ts +464 -55
  89. package/std/net/tls/ticket.ts +610 -0
  90. package/std/net/tls-tcp.ts +196 -53
  91. package/std/net/tls.ts +1018 -260
  92. package/std/net/url.ts +571 -0
  93. package/std/random.ts +94 -0
  94. package/std/regex.ts +4274 -0
  95. package/std/sqlite.ts +391 -0
  96. package/std/term-io.ts +978 -0
  97. package/std/term-pixels.ts +874 -0
  98. package/std/term-probe.ts +459 -0
  99. package/std/term-rate.ts +993 -0
  100. package/std/term.ts +2453 -0
  101. package/std/text.ts +90 -7
  102. package/std/threads.ts +438 -14
  103. package/std/yaml-lines.ts +141 -0
  104. package/std/yaml.ts +4675 -0
@@ -0,0 +1,53 @@
1
+ /**
2
+ * The widths as the core holds them (docs/RUN_UNDER_NODE.md): `i64` and `u64`
3
+ * are a `bigint`, every other width a `number`. `runtime/nish.d.ts` spells
4
+ * each as `number` for `tsc`'s reading of a Nish program; `tests/run.js`
5
+ * (`runtime-hosts`) holds these signatures to that file's.
6
+ */
7
+ export type i32 = number;
8
+ export type i64 = bigint;
9
+ export type u8 = number;
10
+ export type u16 = number;
11
+ export type u32 = number;
12
+ export type u64 = bigint;
13
+ export type f32 = number;
14
+ export type f64 = number;
15
+
16
+ /** A width as the rewriter names it, for `convert`. */
17
+ export type NumericKind = "i32" | "i64" | "u8" | "u16" | "u32" | "u64" | "f32" | "f64";
18
+
19
+ export declare function toI32(x: number | bigint | boolean): i32;
20
+ export declare function toI64(x: number | bigint | boolean): i64;
21
+ export declare function toF64(x: number | bigint | boolean): f64;
22
+ export declare function f64ToBits(x: f64): i64;
23
+ export declare function f32ToBits(x: f32): i32;
24
+ export declare function bitsToF64(bits: i64): f64;
25
+ export declare function ctSelect<T extends u32 | u64>(mask: T, a: T, b: T): T;
26
+ export declare function ctEq<T extends u32 | u64>(a: T, b: T): T;
27
+ export declare function checkedAdd<T extends i32 | i64>(a: T, b: T): T;
28
+ export declare function checkedSub<T extends i32 | i64>(a: T, b: T): T;
29
+ export declare function checkedMul<T extends i32 | i64>(a: T, b: T): T;
30
+ export declare function checkedNeg<T extends i32 | i64>(a: T): T;
31
+ export declare function wrappingAdd<T extends i32 | i64>(a: T, b: T): T;
32
+ export declare function wrappingSub<T extends i32 | i64>(a: T, b: T): T;
33
+ export declare function wrappingMul<T extends i32 | i64>(a: T, b: T): T;
34
+ export declare function idiv<T extends number | bigint>(a: T, b: T): T;
35
+ export declare function irem<T extends number | bigint>(a: T, b: T): T;
36
+ export declare function wrapI64(x: bigint): i64;
37
+ export declare function shlI64(a: i64, b: i64): i64;
38
+ export declare function ashrI64(a: i64, b: i64): i64;
39
+ export declare function lshrI64(a: i64, b: i64): i64;
40
+ export declare function absI64(x: i64): i64;
41
+ export declare function signI64<T extends i64 | u64>(x: T): T;
42
+ export declare function minI64(a: i64, b: i64): i64;
43
+ export declare function maxI64(a: i64, b: i64): i64;
44
+ export declare function wrapU64(x: bigint): u64;
45
+ export declare function shlU64(a: u64, b: u64): u64;
46
+ export declare function lshrU64(a: u64, b: u64): u64;
47
+ export declare function minU64(a: u64, b: u64): u64;
48
+ export declare function maxU64(a: u64, b: u64): u64;
49
+ export declare function convert(x: number | bigint, from: NumericKind, to: NumericKind): number | bigint;
50
+ export declare function parseInt(s: string): i32;
51
+ export declare function parseFloat(s: string): f64;
52
+ export declare function number(x: string | number | bigint | boolean): f64;
53
+ export declare function offsets<T extends unknown[]>(first: number, args: T): T;
@@ -0,0 +1,316 @@
1
+ /**
2
+ * The numeric half of the core (docs/RUN_UNDER_NODE.md): the integer widths,
3
+ * their wrapping arithmetic and conversions, and the text-to-number readers.
4
+ */
5
+ import { panic } from "./host.mjs";
6
+
7
+ const I32_MIN = -2147483648;
8
+ const I32_MAX = 2147483647;
9
+ const I64_MIN = -(1n << 63n);
10
+ const I64_MAX = (1n << 63n) - 1n;
11
+
12
+ /** `trunc i64 -> i32` (wrap) for BigInt, `llvm.fptosi.sat.i32.f64` for numbers. */
13
+ export function toI32(x) {
14
+ if (typeof x === "bigint") return Number(BigInt.asIntN(32, x));
15
+ if (Number.isNaN(x)) return 0;
16
+ if (x >= I32_MAX) return I32_MAX;
17
+ if (x <= I32_MIN) return I32_MIN;
18
+ return Math.trunc(x) | 0;
19
+ }
20
+
21
+ /** `sext i32 -> i64` for int32 numbers, `llvm.fptosi.sat.i64.f64` for doubles. */
22
+ export function toI64(x) {
23
+ if (typeof x === "bigint") return x;
24
+ if (Number.isNaN(x)) return 0n;
25
+ if (x >= 9223372036854775808) return I64_MAX;
26
+ if (x <= -9223372036854775808) return I64_MIN;
27
+ return BigInt(Math.trunc(x));
28
+ }
29
+
30
+ /** `sitofp` for both integer widths; a double is returned unchanged. */
31
+ export function toF64(x) {
32
+ return typeof x === "bigint" ? Number(x) : x;
33
+ }
34
+
35
+ /**
36
+ * `f64ToBits` / `bitsToF64`: reinterpret the 64 bits, never convert the value.
37
+ * The compiler lowers each to one `bitcast`; here it is a one-element
38
+ * DataView, which is the only way JavaScript lets you see a double's bits.
39
+ * The result is signed, matching the i64 the compiler produces.
40
+ */
41
+ const BITS = new DataView(new ArrayBuffer(8));
42
+
43
+ export function f64ToBits(x) {
44
+ BITS.setFloat64(0, x);
45
+ return BigInt.asIntN(64, BITS.getBigUint64(0));
46
+ }
47
+
48
+ /** `f32ToBits`: the 32 bits of an `f32`, signed like the compiler's i32. */
49
+ export function f32ToBits(x) {
50
+ BITS.setFloat32(0, x);
51
+ return BITS.getInt32(0);
52
+ }
53
+
54
+ export function bitsToF64(b) {
55
+ BITS.setBigInt64(0, BigInt.asIntN(64, b));
56
+ return BITS.getFloat64(0);
57
+ }
58
+
59
+ /**
60
+ * `ctSelect` / `ctEq` (WP34 N6). A `u32` is a `number` here and a `u64` a
61
+ * BigInt, so the operands' kind picks the width, and a mix of the two — which
62
+ * the native checker refuses, and which a `u64` written as a bare literal is
63
+ * under an unrewritten run — throws the `TypeError` BigInt arithmetic throws
64
+ * rather than comparing a number with a BigInt and answering zero. JavaScript's
65
+ * `&` reads a `number` as a signed 32-bit integer, so each answer is put back in
66
+ * range with `>>> 0` or `asUintN(64, ...)`. These branch: only the native
67
+ * lowering promises constant time.
68
+ */
69
+ function ctWide(name, first, second, third) {
70
+ const wide = typeof first === "bigint";
71
+ if ((typeof second === "bigint") !== wide || (typeof third === "bigint") !== wide) {
72
+ throw new TypeError(`${name}: cannot mix a u64 (BigInt) with a u32 (number)`);
73
+ }
74
+ return wide;
75
+ }
76
+
77
+ const U64_ONES = (1n << 64n) - 1n;
78
+
79
+ export function ctSelect(mask, a, b) {
80
+ if (ctWide("ctSelect", mask, a, b)) return wrapU64((a & mask) | (b & ~mask));
81
+ return ((a & mask) | (b & ~mask)) >>> 0;
82
+ }
83
+
84
+ export function ctEq(a, b) {
85
+ // `ctEq` has two operands, so the second one stands in for the third.
86
+ if (ctWide("ctEq", a, b, b)) return wrapU64(a ^ b) === 0n ? U64_ONES : 0n;
87
+ return (a ^ b) === 0 ? 0xffffffff : 0;
88
+ }
89
+
90
+ // ---- Checked arithmetic (wp33 R4) ----------------------------------------------------
91
+ //
92
+ // What `--emit-ts` writes for a signed `+ - *` and unary minus the compiler
93
+ // neither proved in range nor was told to wrap (`--wrapping`): the exact
94
+ // answer, or the panic `nish_panic_overflow` prints, in its words. An i32 is
95
+ // exact in a double until it leaves the range, and `Math.imul` is the
96
+ // wrapped product, so a product that differs from the double one overflowed.
97
+ // A `bigint` operand is an i64.
98
+
99
+ export function checkedAdd(a, b) {
100
+ return typeof a === "bigint" ? checkI64(a + b, "add") : checkI32(a + b, "add");
101
+ }
102
+ export function checkedSub(a, b) {
103
+ return typeof a === "bigint" ? checkI64(a - b, "subtract") : checkI32(a - b, "subtract");
104
+ }
105
+ export function checkedMul(a, b) {
106
+ if (typeof a === "bigint") return checkI64(a * b, "multiply");
107
+ const r = Math.imul(a, b);
108
+ if (r !== a * b) panic("attempt to multiply with overflow");
109
+ return r;
110
+ }
111
+ export function checkedNeg(a) {
112
+ return typeof a === "bigint" ? checkI64(-a, "negate") : checkI32(0 - a, "negate");
113
+ }
114
+ function checkI32(r, op) {
115
+ if (r > I32_MAX || r < I32_MIN) panic(`attempt to ${op} with overflow`);
116
+ return r;
117
+ }
118
+ function checkI64(r, op) {
119
+ if (r > I64_MAX || r < I64_MIN) panic(`attempt to ${op} with overflow`);
120
+ return r;
121
+ }
122
+
123
+ // `wrappingAdd`, `wrappingSub` and `wrappingMul` from `nish:unsafe`: the
124
+ // two's-complement answer at the operands' width, i32 or i64, whatever
125
+ // `--wrapping` says.
126
+ export function wrappingAdd(a, b) {
127
+ return typeof a === "bigint" ? BigInt.asIntN(64, a + b) : (a + b) | 0;
128
+ }
129
+ export function wrappingSub(a, b) {
130
+ return typeof a === "bigint" ? BigInt.asIntN(64, a - b) : (a - b) | 0;
131
+ }
132
+ export function wrappingMul(a, b) {
133
+ return typeof a === "bigint" ? BigInt.asIntN(64, a * b) : Math.imul(a, b);
134
+ }
135
+
136
+ /**
137
+ * Integer `/` and `%` at every width: `sdiv`/`udiv` and `srem`/`urem`, which
138
+ * truncate, and the two panics the compiler guards them with. Only a signed
139
+ * operand can be the minimum, so the overflow test needs no width. A double
140
+ * quotient of two 32-bit integers truncates exactly, and `+ 0` turns the `-0`
141
+ * of `-1 / 2` or `-4 % 2` into the integer zero.
142
+ */
143
+ export function idiv(a, b) {
144
+ divCheck(a, b);
145
+ return typeof a === "bigint" ? a / b : Math.trunc(a / b) + 0;
146
+ }
147
+ export function irem(a, b) {
148
+ divCheck(a, b);
149
+ return typeof a === "bigint" ? a % b : (a % b) + 0;
150
+ }
151
+ function divCheck(a, b) {
152
+ if (b === 0 || b === 0n) panic("attempt to divide by zero");
153
+ if ((a === I32_MIN && b === -1) || (a === I64_MIN && b === -1n)) panic("attempt to divide with overflow");
154
+ }
155
+
156
+ /** Wrap a BigInt to the i64 range: every i64 `+ - * /` and unary minus goes through here. */
157
+ export function wrapI64(x) {
158
+ return BigInt.asIntN(64, x);
159
+ }
160
+
161
+ /**
162
+ * The i64 shifts. BigInt has no `>>>` and neither of its shifts masks the
163
+ * count, so all three do here what `codegen/emit/bitwise.ts` emits: mask the
164
+ * count to 6 bits, then shift. `lshrI64` reads the operand as unsigned before
165
+ * shifting and hands back the signed reading of the result, which is `lshr`.
166
+ */
167
+ export function shlI64(a, b) {
168
+ return BigInt.asIntN(64, a << (b & 63n));
169
+ }
170
+ export function ashrI64(a, b) {
171
+ return a >> (b & 63n);
172
+ }
173
+ export function lshrI64(a, b) {
174
+ return BigInt.asIntN(64, BigInt.asUintN(64, a) >> (b & 63n));
175
+ }
176
+
177
+ /** `llvm.abs.i64(x, false)`: the minimum value wraps to itself. */
178
+ export function absI64(x) {
179
+ return BigInt.asIntN(64, x < 0n ? -x : x);
180
+ }
181
+
182
+ /** `Math.sign` on an i64 or u64, which Math rejects as a BigInt. */
183
+ export function signI64(x) {
184
+ return x > 0n ? 1n : x < 0n ? -1n : 0n;
185
+ }
186
+
187
+ /** `llvm.smin.i64` / `llvm.smax.i64` (Math.min/max reject BigInt). */
188
+ export function minI64(a, b) {
189
+ return a < b ? a : b;
190
+ }
191
+ export function maxI64(a, b) {
192
+ return a > b ? a : b;
193
+ }
194
+
195
+ // ---- Unsigned integers (WP15) -------------------------------------------------------
196
+ //
197
+ // JavaScript has no unsigned integer type, so every unsigned result is masked
198
+ // back into its width right where the compiled code would have relied on the
199
+ // LLVM type. u8/u16/u32 fit a `number` exactly (2^32 - 1 < 2^53); u64 is a
200
+ // BigInt, so it goes through `wrapU64` the way i64 goes through `wrapI64`.
201
+
202
+ /** Wrap into the u64 range: every u64 `+ - * /`, unary minus and shift ends here. */
203
+ export function wrapU64(x) {
204
+ return BigInt.asUintN(64, x);
205
+ }
206
+
207
+ /**
208
+ * The u64 shifts. A u64 is already held as a non-negative BigInt, so its `>>`
209
+ * *is* the logical shift; what these add over the operator is the count mask
210
+ * (BigInt does not mask) and the wrap back into the unsigned range.
211
+ */
212
+ export function shlU64(a, b) {
213
+ return BigInt.asUintN(64, a << (b & 63n));
214
+ }
215
+ export function lshrU64(a, b) {
216
+ return BigInt.asUintN(64, a) >> (b & 63n);
217
+ }
218
+
219
+ /**
220
+ * The widths, as the rewriter names them. `bits` drives every mask and
221
+ * `BigInt.asIntN`/`asUintN` call; `big` says whether the value is a BigInt
222
+ * (i64/u64) or a `number` in JavaScript.
223
+ */
224
+ const INT_KINDS = {
225
+ i32: { bits: 32, signed: true, big: false },
226
+ i64: { bits: 64, signed: true, big: true },
227
+ u8: { bits: 8, signed: false, big: false },
228
+ u16: { bits: 16, signed: false, big: false },
229
+ u32: { bits: 32, signed: false, big: false },
230
+ u64: { bits: 64, signed: false, big: true },
231
+ };
232
+
233
+ /** `llvm.umin`/`umax` on u64 (`Math.min`/`max` reject BigInt); the u32-and-below widths use Math. */
234
+ export function minU64(a, b) {
235
+ return a < b ? a : b;
236
+ }
237
+ export function maxU64(a, b) {
238
+ return a > b ? a : b;
239
+ }
240
+
241
+ /**
242
+ * Every numeric conversion whose source or target is unsigned (`toU8`,
243
+ * `toU32(i)`, `toI32(u)`, ...), as one function taking the kind names the
244
+ * checker recorded. Doing it through BigInt is what makes the whole matrix
245
+ * exact in one place: an integer source is turned into its true mathematical
246
+ * value, then `asIntN`/`asUintN` performs the sign-extend, zero-extend or
247
+ * truncate that the target's width and signedness call for — which is exactly
248
+ * what `sext`/`zext`/`trunc` do natively.
249
+ */
250
+ export function convert(x, from, to) {
251
+ // A zext of an unsigned 32-bit-or-narrower value to u64 keeps the value as it
252
+ // is, and skips the BigInt wrap below: a hot path in u64 arithmetic.
253
+ if (to === "u64" && (from === "u32" || from === "u16" || from === "u8")) return BigInt(x);
254
+ const num = typeof x === "bigint" ? Number(x) : x;
255
+ if (to === "f64") return num; // sitofp / uitofp / fpext
256
+ if (to === "f32") return Math.fround(num); // ... / fptrunc, then rounded to a float
257
+ const target = INT_KINDS[to];
258
+ let exact;
259
+ if (INT_KINDS[from] === undefined) {
260
+ // A float source (f32 or f64) goes through the saturating intrinsics: NaN
261
+ // is 0 and out-of-range values clamp. The bounds are BigInt because
262
+ // 2^64 - 1 has no exact `number`, and are built only here, where they are read.
263
+ const lo = target.signed ? -(1n << BigInt(target.bits - 1)) : 0n;
264
+ const hi = target.signed ? (1n << BigInt(target.bits - 1)) - 1n : (1n << BigInt(target.bits)) - 1n;
265
+ if (Number.isNaN(x)) exact = 0n;
266
+ else if (x <= Number(lo)) exact = lo;
267
+ else if (x >= Number(hi)) exact = hi;
268
+ else exact = BigInt(Math.trunc(x));
269
+ } else {
270
+ exact = BigInt(x); // sext/zext/trunc, below
271
+ }
272
+ const wrapped = target.signed ? BigInt.asIntN(target.bits, exact) : BigInt.asUintN(target.bits, exact);
273
+ return target.big ? wrapped : Number(wrapped);
274
+ }
275
+
276
+ const SPACES = "[ \\t\\n\\v\\f\\r]*";
277
+ /** What `nish_parse_number` recognises: strtod's decimal and hex-integer forms, or an exact `Infinity`. */
278
+ const LITERAL = new RegExp(`^${SPACES}([+-]?)(Infinity|0[xX][0-9a-fA-F]+|(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][+-]?\\d+)?)`);
279
+ const BLANK = new RegExp(`^${SPACES}$`);
280
+ const WHOLE = new RegExp(`${LITERAL.source}${SPACES}$`);
281
+
282
+ /** The value of a `LITERAL` match: hex goes through parseInt(16), and `-` applies afterwards as in strtod. */
283
+ function literalValue(m) {
284
+ const magnitude = /^0[xX]/.test(m[2]) ? Number.parseInt(m[2], 16) : Number(m[2]);
285
+ return m[1] === "-" ? -magnitude : magnitude;
286
+ }
287
+
288
+ /** `parseInt(s)`: strtoll base 10 (ASCII whitespace, sign, digits; 0 without digits) saturated into i32. */
289
+ export function parseInt(s) {
290
+ const m = new RegExp(`^${SPACES}([+-]?\\d+)`).exec(s);
291
+ return m ? toI32(Number(m[1])) : 0;
292
+ }
293
+
294
+ /** `parseFloat(s)`: the longest literal after ASCII whitespace, else NaN (`0x1A` is 26, as strtod reads it). */
295
+ export function parseFloat(s) {
296
+ const m = LITERAL.exec(s);
297
+ return m ? literalValue(m) : NaN;
298
+ }
299
+
300
+ /** `Number(x)`: a string must be one literal bar surrounding ASCII whitespace (blank is 0); others convert numerically. */
301
+ export function number(x) {
302
+ if (typeof x === "bigint") return Number(x);
303
+ if (typeof x === "boolean") return x ? 1 : 0;
304
+ if (typeof x !== "string") return x;
305
+ const m = WHOLE.exec(x);
306
+ if (m) return literalValue(m);
307
+ return BLANK.test(x) ? 0 : NaN;
308
+ }
309
+
310
+ /** A method's arguments with each `bigint` from the `first` on made a number: the offsets and indices `--emit-ts` cannot wrap one by one. */
311
+ export function offsets(first, args) {
312
+ for (let i = first; i < args.length; i++) {
313
+ if (typeof args[i] === "bigint") args[i] = Number(args[i]);
314
+ }
315
+ return args;
316
+ }
@@ -0,0 +1,41 @@
1
+ /** `Result` (docs/LANGUAGE.md -> Result and error handling) and `nish:secret`, as `runtime/nish.d.ts` declares them. */
2
+ import type { u8 } from "./numbers.js";
3
+
4
+ /** The success arm of a `Result`, as the discriminant proves it. */
5
+ export type ResultOk<T> = { readonly ok: true; readonly value: T };
6
+ /** The failure arm. */
7
+ export type ResultErr<E> = { readonly ok: false; readonly error: E };
8
+
9
+ export interface ResultMethods<T, E> {
10
+ isOk(): this is ResultOk<T> & ResultMethods<T, E>;
11
+ isErr(): this is ResultErr<E> & ResultMethods<T, E>;
12
+ /** The success payload, or a throw that `caught` turns into the enclosing function's `Err`. */
13
+ orReturn(): T;
14
+ unwrapOr(fallback: T): T;
15
+ /** The success payload, or `message` through `panic`. */
16
+ expect(message: string): T;
17
+ }
18
+
19
+ /** The outcome of an operation that can fail. */
20
+ export type Result<T, E> = (ResultOk<T> | ResultErr<E>) & ResultMethods<T, E>;
21
+
22
+ /** The class every `Result` is an instance of; `--emit-ts` imports it under the type's name. */
23
+ export declare const Result: { prototype: ResultMethods<unknown, unknown> };
24
+
25
+ export declare function Ok<T, E>(value: T): Result<T, E>;
26
+ export declare function Ok<E>(): Result<void, E>;
27
+ export declare function Err<T, E>(error: E): Result<T, E>;
28
+ /** The `catch` of a body that calls `orReturn`: the `Err` to return, or `thrown` thrown again. */
29
+ export declare function caught<T, E>(thrown: unknown): Result<T, E>;
30
+
31
+ /** Key material, held as a plain wrapper: under JavaScript a wipe promises nothing about copies. */
32
+ export declare class Secret<T> {
33
+ constructor(value: T);
34
+ readonly value: T;
35
+ }
36
+ export declare function secret<T>(value: T): Secret<T>;
37
+ export declare function expose<T, R>(s: Secret<T>, f: (value: T) => R): R;
38
+ export declare function exposeWith<T, A, R>(s: Secret<T>, arg: A, f: (value: T, arg: A) => R): R;
39
+ export declare function wipe<T>(target: Secret<T>): void;
40
+ export declare function wipe(target: object): void;
41
+ export declare function secureZero(bytes: u8[]): void;
@@ -0,0 +1,127 @@
1
+ import { panic } from "./host.mjs";
2
+
3
+ /**
4
+ * `nish:secret` (docs/LANGUAGE.md, "Secrets"). Natively the compiler holds a
5
+ * `Secret` to its rules and `wipe` is a volatile store of zeros; here the rules
6
+ * have already been checked by the compiler or by nobody, so a `Secret` is a
7
+ * plain wrapper and `wipe` zero-fills what it holds. `runtime/nish.mjs`
8
+ * resolves the `nish:secret` specifier to `runtime/shim.mjs`, which re-exports
9
+ * this module, so these are its exports by name. A zero-fill under Node promises nothing about copies the
10
+ * engine made, which is the native wipe's whole point and is not claimed here.
11
+ */
12
+ export class Secret {
13
+ constructor(value) {
14
+ this.value = value;
15
+ }
16
+ }
17
+
18
+ export function secret(value) {
19
+ return new Secret(value);
20
+ }
21
+
22
+ export function expose(s, f) {
23
+ return f(s.value);
24
+ }
25
+
26
+ export function exposeWith(s, arg, f) {
27
+ return f(s.value, arg);
28
+ }
29
+
30
+ /** Zero an array of integers, or every integer field of a record: `0` for a number, `0n` for an `i64` or `u64`. */
31
+ function zeroFill(target) {
32
+ if (Array.isArray(target) || ArrayBuffer.isView(target)) {
33
+ for (let i = 0; i < target.length; i++) {
34
+ target[i] = typeof target[i] === "bigint" ? 0n : 0;
35
+ }
36
+ return;
37
+ }
38
+ for (const key of Object.keys(target)) {
39
+ const field = target[key];
40
+ if (typeof field === "bigint") target[key] = 0n;
41
+ else if (typeof field === "number") target[key] = 0;
42
+ }
43
+ }
44
+
45
+ export function wipe(target) {
46
+ zeroFill(target instanceof Secret ? target.value : target);
47
+ }
48
+
49
+ /**
50
+ * `secureZero(bytes)` (#385): every element set to zero, which is what the
51
+ * native `nish_wipe` leaves. Nothing here can drop a store to an array the
52
+ * caller still holds, so a loop is the whole of it. What it cannot promise is
53
+ * what the native build does: a collector that moved the array may have left a
54
+ * copy of the old bytes behind, and JavaScript has no way to reach it.
55
+ */
56
+ export function secureZero(bytes) {
57
+ for (let i = 0; i < bytes.length; i++) {
58
+ bytes[i] = 0;
59
+ }
60
+ }
61
+
62
+ // ---- Result (WP16) ---------------------------------------------------------
63
+ //
64
+ // Natively a `Result` is a two-arm struct in the arena; here it is an ordinary
65
+ // object with the same three names, so `r.ok`, `r.value` and `r.error` in the
66
+ // rewritten program mean what they mean in the compiled one. Only `orReturn`
67
+ // needs help: it returns from the *enclosing* function, which no expression in
68
+ // JavaScript can do, so it throws a sentinel that `rewrite.js` catches in a
69
+ // wrapper around every body that contains one.
70
+
71
+ class Propagate {
72
+ constructor(error) {
73
+ this.error = error;
74
+ }
75
+ }
76
+
77
+ class NishResult {
78
+ constructor(ok, value, error) {
79
+ this.ok = ok;
80
+ if (ok) this.value = value;
81
+ else this.error = error;
82
+ }
83
+ isOk() {
84
+ return this.ok;
85
+ }
86
+ isErr() {
87
+ return !this.ok;
88
+ }
89
+ unwrapOr(fallback) {
90
+ return this.ok ? this.value : fallback;
91
+ }
92
+ expect(message) {
93
+ if (this.ok) return this.value;
94
+ panic(message);
95
+ }
96
+ orReturn() {
97
+ if (this.ok) return this.value;
98
+ throw new Propagate(this.error);
99
+ }
100
+ }
101
+
102
+ /**
103
+ * The class behind every `Result`, under the type's name, so a module
104
+ * `--emit-ts` writes can import `Result` for its annotations from here.
105
+ */
106
+ export { NishResult as Result };
107
+
108
+ /** `Ok(v)`; `Ok()` on a `Result<void, E>` carries nothing. */
109
+ export function Ok(value) {
110
+ return new NishResult(true, value, undefined);
111
+ }
112
+
113
+ /** `Err(e)`. */
114
+ export function Err(error) {
115
+ return new NishResult(false, undefined, error);
116
+ }
117
+
118
+ /**
119
+ * The `catch` half of `orReturn`: re-raise anything that is not a propagation,
120
+ * and answer the `Err` the enclosing function should return otherwise. The
121
+ * rewriter emits `return __nish.caught(e)` and nothing else, so a genuine
122
+ * runtime error still reaches Node unchanged.
123
+ */
124
+ export function caught(thrown) {
125
+ if (thrown instanceof Propagate) return new NishResult(false, undefined, thrown.error);
126
+ throw thrown;
127
+ }
@@ -0,0 +1,14 @@
1
+ /** The string half of the core: every length and offset counts UTF-8 bytes. */
2
+ import type { i32, u8 } from "./numbers.js";
3
+
4
+ export declare function strLen(x: string | readonly unknown[]): i32;
5
+ export declare function strLenOpt(x: string | null | undefined): i32 | undefined;
6
+ export declare function charCodeAt(s: string, i: number | bigint): u8;
7
+ export declare function substring(s: string, a: number | bigint, b?: number | bigint): string;
8
+ export declare function slice(s: string, a: number | bigint, b?: number | bigint): string;
9
+ export declare function indexOf(s: string, sub: string, from?: number | bigint): i32;
10
+ export declare function startsWith(s: string, sub: string): boolean;
11
+ export declare function endsWith(s: string, sub: string): boolean;
12
+ export declare function fromCharCode(code: number | bigint): string;
13
+ export declare function fromBytes(bytes: readonly u8[], start: number, end: number): string;
14
+ export declare function utf8FromBytes(bytes: readonly u8[], start: number, end: number): string;