@amritk/nish-x86_64-linux 0.20.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.
- package/INSTALL.md +22 -10
- package/bin/nish +0 -0
- package/docs/AI.md +2759 -0
- package/package.json +2 -1
- package/runtime/browser.d.ts +14 -0
- package/runtime/browser.mjs +88 -0
- package/runtime/core/arrays.d.ts +18 -0
- package/runtime/core/arrays.mjs +125 -0
- package/runtime/core/checks.mjs +20 -0
- package/runtime/core/host.d.ts +70 -0
- package/runtime/core/host.mjs +311 -0
- package/runtime/core/numbers.d.ts +53 -0
- package/runtime/core/numbers.mjs +316 -0
- package/runtime/core/result.d.ts +41 -0
- package/runtime/core/result.mjs +127 -0
- package/runtime/core/strings.d.ts +14 -0
- package/runtime/core/strings.mjs +169 -0
- package/runtime/core.d.ts +9 -0
- package/runtime/core.mjs +55 -0
- package/runtime/host.d.ts +6 -0
- package/runtime/nish.d.ts +44 -0
- package/runtime/nish.h +75 -2
- package/runtime/nish.mjs +23 -3
- package/runtime/node.mjs +383 -0
- package/runtime/runtime-bytes.c +401 -0
- package/runtime/runtime-cross.c +1 -1
- package/runtime/runtime-host.c +1 -1
- package/runtime/runtime-os.c +1 -1
- package/runtime/runtime-parallel.c +1 -1
- package/runtime/runtime-simd.c +231 -7
- package/runtime/runtime-term.c +504 -0
- package/runtime/runtime-wasm.c +0 -11
- package/runtime/runtime.c +190 -6
- package/runtime/shim.mjs +6 -985
- package/runtime/sqlite/LICENSE.md +85 -0
- package/runtime/sqlite/README.md +45 -0
- package/runtime/sqlite/nish-sqlite.c +359 -0
- package/runtime/sqlite/sqlite3.c +271131 -0
- package/runtime/sqlite/sqlite3.h +14447 -0
- package/scripts/build.sh +261 -53
- package/std/LICENSE-fast-float +23 -0
- package/std/LICENSE-fdlibm +8 -0
- package/std/README.md +31 -11
- package/std/base64.ts +116 -0
- package/std/bytes.ts +256 -0
- package/std/cli.ts +328 -0
- package/std/collections.ts +6 -5
- package/std/crypto/LICENSE-crypt_blowfish +26 -0
- package/std/crypto/base64url.ts +125 -0
- package/std/crypto/bcrypt.ts +760 -0
- package/std/crypto/hmac.ts +138 -2
- package/std/crypto/x509.ts +11 -122
- package/std/json-tokenizer.ts +2998 -57
- package/std/json-value.ts +22 -3
- package/std/json.ts +83 -1
- package/std/math.ts +608 -0
- package/std/net/http1-server.ts +85 -8
- package/std/net/http3-server.ts +50 -12
- package/std/net/postgres.ts +1875 -0
- package/std/net/quic-listener.ts +20 -4
- package/std/regex.ts +4274 -0
- package/std/sqlite.ts +391 -0
- package/std/term-io.ts +978 -0
- package/std/term-pixels.ts +874 -0
- package/std/term-probe.ts +459 -0
- package/std/term-rate.ts +993 -0
- package/std/term.ts +2453 -0
- package/std/text.ts +90 -7
- package/std/yaml-lines.ts +141 -0
- package/std/yaml.ts +4675 -0
package/std/text.ts
CHANGED
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The language gives a string `length`, `charCodeAt`, `substring`, `indexOf`,
|
|
5
5
|
* `startsWith`, `endsWith` and `===` by content, and an array `join`. It does
|
|
6
|
-
* **not** give `split`, `trim`, `toLowerCase` or a regular expression
|
|
7
|
-
* is a decision rather than a gap: each
|
|
8
|
-
* need a locale or a character table
|
|
6
|
+
* **not** give `split`, `trim`, `toLowerCase` or a regular expression (that is
|
|
7
|
+
* `std/regex`), and that is a decision rather than a gap: each allocates, and
|
|
8
|
+
* several need a locale or a character table this runtime has no room for
|
|
9
9
|
* (`docs/wp7-runtime.md` keeps the runtime under a measured byte budget).
|
|
10
10
|
*
|
|
11
11
|
* So a program that reads a file and wants its lines writes the loop. This
|
|
12
12
|
* module is that loop, written once. Every offset here is a **byte** offset,
|
|
13
|
-
* like `s.length` itself, and every function is ASCII-only where it
|
|
14
|
-
* characters at all — a UTF-8 string passes through `splitLines` and
|
|
15
|
-
* untouched, because a newline and a space cannot appear inside a
|
|
16
|
-
* sequence.
|
|
13
|
+
* like `s.length` itself, and every function but one is ASCII-only where it
|
|
14
|
+
* inspects characters at all — a UTF-8 string passes through `splitLines` and
|
|
15
|
+
* `split` untouched, because a newline and a space cannot appear inside a
|
|
16
|
+
* multi-byte sequence. The one is `codePointLength`, which counts code points
|
|
17
|
+
* rather than bytes and answers the same natively and under Node; it says how.
|
|
17
18
|
*
|
|
18
19
|
* Every width this module declares is spelled (`i32`, never `number`) *and*
|
|
19
20
|
* every value a builtin hands it is converted at the read: `s.length`,
|
|
@@ -268,3 +269,85 @@ const indexOfAnyFrom = (text: string, bytes: string, from: i32): i32 => {
|
|
|
268
269
|
}
|
|
269
270
|
return -1
|
|
270
271
|
}
|
|
272
|
+
|
|
273
|
+
/** The top two bits of a UTF-8 byte, which say whether it starts a code point. */
|
|
274
|
+
const UTF8_TOP_BITS: i32 = 0xc0
|
|
275
|
+
|
|
276
|
+
/** What those two bits are on a continuation byte: `10xxxxxx`, never a code point's first byte. */
|
|
277
|
+
const UTF8_CONTINUATION: i32 = 0x80
|
|
278
|
+
|
|
279
|
+
/** The first high surrogate, the unit that opens a UTF-16 pair. */
|
|
280
|
+
const HIGH_SURROGATE: i32 = 0xd800
|
|
281
|
+
|
|
282
|
+
/** The first low surrogate, the unit that closes a pair; the high ones end just below it. */
|
|
283
|
+
const LOW_SURROGATE: i32 = 0xdc00
|
|
284
|
+
|
|
285
|
+
/** One past the last low surrogate. */
|
|
286
|
+
const SURROGATE_END: i32 = 0xe000
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Whether a string's units are UTF-8 bytes, as they are natively, rather than
|
|
290
|
+
* UTF-16 units, as they are under Node.
|
|
291
|
+
*
|
|
292
|
+
* `é` is two bytes and one UTF-16 unit, so its length says which host is
|
|
293
|
+
* running. It is written as an escape so that how this file is saved, `é` as
|
|
294
|
+
* one code point or as `e` and a combining accent, cannot change the answer.
|
|
295
|
+
* Natively the length of a literal is a load from a constant, and the
|
|
296
|
+
* optimiser folds this call to `true` and drops the other walk in
|
|
297
|
+
* `codePointLength`. The name is long for the reason `isTextBlankByte`'s is.
|
|
298
|
+
*/
|
|
299
|
+
const textUnitsAreBytes = (): boolean => toI32("\u00e9".length) === 2
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* The number of Unicode code points in `text`: what JSON Schema's
|
|
303
|
+
* `minLength` and `maxLength` count, and not what `text.length` counts.
|
|
304
|
+
* `codePointLength("é")` is 1 where `"é".length` is 2, and
|
|
305
|
+
* `codePointLength("😀")` is 1 where its length is 4.
|
|
306
|
+
*
|
|
307
|
+
* Natively a string is its UTF-8 bytes, and every code point has exactly one
|
|
308
|
+
* byte that is not a continuation byte (`10xxxxxx`), so that is what is
|
|
309
|
+
* counted. Under Node the same `charCodeAt` reads UTF-16 units, where a byte
|
|
310
|
+
* rule would miscount: `"©®±"` is three units in `0x80`–`0xBF`, which are
|
|
311
|
+
* continuation bytes in UTF-8 but whole characters here. So the function asks
|
|
312
|
+
* which host it is on (`textUnitsAreBytes`) and, under Node, counts every unit
|
|
313
|
+
* except the low half of a surrogate pair. Both walks answer the same for any
|
|
314
|
+
* string literal, a lone surrogate escape included: it is three WTF-8 bytes
|
|
315
|
+
* with one leading byte natively, and one unit under Node. They differ for
|
|
316
|
+
* text built from bytes: `String.fromBytes` and `String.fromCharCode` give one
|
|
317
|
+
* unit per byte under Node, so a string decoded that way, as `nish/json`
|
|
318
|
+
* decodes a `\u` escape, counts its UTF-8 bytes there. They also differ for text
|
|
319
|
+
* that is not well-formed — bytes that are not UTF-8 natively, where each
|
|
320
|
+
* stray continuation byte counts nothing, or the two halves of a pair joined
|
|
321
|
+
* at run time, which are one string under Node and two lone surrogates
|
|
322
|
+
* natively.
|
|
323
|
+
*/
|
|
324
|
+
export const codePointLength = (text: string): i32 => {
|
|
325
|
+
const length: i32 = toI32(text.length)
|
|
326
|
+
// `count` never passes `i`, which stays below `length`, so it never wraps.
|
|
327
|
+
// It is a `u32` because unsigned addition carries no overflow check: an
|
|
328
|
+
// `i32` would need a panic branch, or a `count < length` guard to prove it
|
|
329
|
+
// away, and either one keeps the byte walk from vectorizing.
|
|
330
|
+
let count: u32 = 0
|
|
331
|
+
let i: i32 = 0
|
|
332
|
+
if (textUnitsAreBytes()) {
|
|
333
|
+
while (i < length) {
|
|
334
|
+
if ((toI32(text.charCodeAt(i)) & UTF8_TOP_BITS) !== UTF8_CONTINUATION) {
|
|
335
|
+
count += 1
|
|
336
|
+
}
|
|
337
|
+
i += 1
|
|
338
|
+
}
|
|
339
|
+
return toI32(count)
|
|
340
|
+
}
|
|
341
|
+
// A low surrogate right after a high one closes a pair the high one already
|
|
342
|
+
// counted. Any other unit, a lone surrogate included, is a code point.
|
|
343
|
+
let afterHigh: boolean = false
|
|
344
|
+
while (i < length) {
|
|
345
|
+
const unit: i32 = toI32(text.charCodeAt(i))
|
|
346
|
+
if (!(afterHigh && unit >= LOW_SURROGATE && unit < SURROGATE_END)) {
|
|
347
|
+
count += 1
|
|
348
|
+
}
|
|
349
|
+
afterHigh = unit >= HIGH_SURROGATE && unit < LOW_SURROGATE
|
|
350
|
+
i += 1
|
|
351
|
+
}
|
|
352
|
+
return toI32(count)
|
|
353
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `nish/yaml-lines` — byte offsets turned into the `line:column` a person reads.
|
|
3
|
+
*
|
|
4
|
+
* Every range `nish/yaml` reports — a node's `start` and `end`, a diagnostic's
|
|
5
|
+
* — is a byte offset into the text it parsed, because a byte offset is what a
|
|
6
|
+
* program slices with and what costs nothing to keep. A message for a person
|
|
7
|
+
* wants a line and a column instead, and this module turns one into the other:
|
|
8
|
+
*
|
|
9
|
+
* import { YamlLineIndex } from "nish/yaml-lines"
|
|
10
|
+
*
|
|
11
|
+
* const lines = new YamlLineIndex(text)
|
|
12
|
+
* lines.line(offset) // 1-based
|
|
13
|
+
* lines.column(offset) // 1-based, in characters
|
|
14
|
+
*
|
|
15
|
+
* The index scans the text once, with `indexOf`, to record where each line
|
|
16
|
+
* starts; every lookup after that is a binary search. A line break is LF, CR
|
|
17
|
+
* LF or a lone CR (YAML 1.2 §5.4, `b-break`), and CR LF is one break, not two,
|
|
18
|
+
* so a Windows file has as many lines as a Unix one.
|
|
19
|
+
*
|
|
20
|
+
* An offset is clamped to `[0, text.length]` first, so a range's `end`, one
|
|
21
|
+
* past its last byte, has a position too, and a slip below zero reads as the
|
|
22
|
+
* start rather than panicking. `column` counts characters: every byte that is
|
|
23
|
+
* not a UTF-8 continuation byte, so `é` is one column natively. `byteColumn`
|
|
24
|
+
* counts bytes, which is what an editor that indexes lines by byte wants.
|
|
25
|
+
* Under Node a string is UTF-16 and each unit counts, which is the same answer
|
|
26
|
+
* for ASCII and the JavaScript answer otherwise.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const YAML_LINES_LF: i32 = 10
|
|
30
|
+
/** A UTF-8 continuation byte is `10xxxxxx`: at least this and below `0xC0`. */
|
|
31
|
+
const YAML_LINES_CONTINUATION: i32 = 128
|
|
32
|
+
const YAML_LINES_LEAD: i32 = 192
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Where each line of one text starts, for turning byte offsets into lines and
|
|
36
|
+
* columns. Its fields and its "Internal" methods are reachable, as every member
|
|
37
|
+
* in Nish is; use the others, and do not change the fields.
|
|
38
|
+
*/
|
|
39
|
+
export class YamlLineIndex {
|
|
40
|
+
/** The text the index was built from. */
|
|
41
|
+
text: string
|
|
42
|
+
/** Internal: `starts[n]` is the byte at which line `n + 1` begins; line 1 begins at 0. */
|
|
43
|
+
starts: i32[]
|
|
44
|
+
|
|
45
|
+
constructor(text: string) {
|
|
46
|
+
this.text = text
|
|
47
|
+
this.starts = [0]
|
|
48
|
+
const length: i32 = toI32(text.length)
|
|
49
|
+
let nl: i32 = toI32(text.indexOf("\n"))
|
|
50
|
+
let cr: i32 = toI32(text.indexOf("\r"))
|
|
51
|
+
while (nl >= 0 || cr >= 0) {
|
|
52
|
+
if (cr >= 0 && (nl < 0 || cr < nl)) {
|
|
53
|
+
// CR LF is one break: step over both, and move the LF search past it.
|
|
54
|
+
if (cr + 1 < length && toI32(text.charCodeAt(cr + 1)) === YAML_LINES_LF) {
|
|
55
|
+
this.starts.push(cr + 2)
|
|
56
|
+
nl = toI32(text.indexOf("\n", cr + 2))
|
|
57
|
+
} else {
|
|
58
|
+
this.starts.push(cr + 1)
|
|
59
|
+
}
|
|
60
|
+
cr = toI32(text.indexOf("\r", cr + 1))
|
|
61
|
+
} else {
|
|
62
|
+
this.starts.push(nl + 1)
|
|
63
|
+
nl = toI32(text.indexOf("\n", nl + 1))
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** How many lines the text has: one more than its breaks, so `""` has one. */
|
|
69
|
+
lineCount(): i32 {
|
|
70
|
+
return toI32(this.starts.length)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** The byte at which 1-based `line` begins; a line outside the text clamps to the first or last. */
|
|
74
|
+
lineStart(line: i32): i32 {
|
|
75
|
+
const count: i32 = toI32(this.starts.length)
|
|
76
|
+
let index: i32 = line - 1
|
|
77
|
+
if (index >= count) {
|
|
78
|
+
index = count - 1
|
|
79
|
+
}
|
|
80
|
+
if (index < 0) {
|
|
81
|
+
index = 0
|
|
82
|
+
}
|
|
83
|
+
return index < count ? this.starts[index] : 0
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** The 1-based line `offset` is on, after clamping it to `[0, text.length]`. */
|
|
87
|
+
line(offset: i32): i32 {
|
|
88
|
+
return this.lineIndexOf(this.clamp(offset)) + 1
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** The 1-based column of `offset` on its line, counting characters. */
|
|
92
|
+
column(offset: i32): i32 {
|
|
93
|
+
const at: i32 = this.clamp(offset)
|
|
94
|
+
const index: i32 = this.lineIndexOf(at)
|
|
95
|
+
const starts: i32[] = this.starts
|
|
96
|
+
let i: i32 = index >= 0 && index < toI32(starts.length) ? starts[index] : 0
|
|
97
|
+
const text: string = this.text
|
|
98
|
+
const length: i32 = toI32(text.length)
|
|
99
|
+
let column: i32 = 1
|
|
100
|
+
while (i >= 0 && i < at && i < length) {
|
|
101
|
+
const code: i32 = toI32(text.charCodeAt(i))
|
|
102
|
+
if (code < YAML_LINES_CONTINUATION || code >= YAML_LINES_LEAD) {
|
|
103
|
+
column += 1
|
|
104
|
+
}
|
|
105
|
+
i += 1
|
|
106
|
+
}
|
|
107
|
+
return column
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The 1-based column of `offset` on its line, counting bytes. */
|
|
111
|
+
byteColumn(offset: i32): i32 {
|
|
112
|
+
const at: i32 = this.clamp(offset)
|
|
113
|
+
return at - this.lineStart(this.lineIndexOf(at) + 1) + 1
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Internal: `offset` clamped to `[0, text.length]`. */
|
|
117
|
+
clamp(offset: i32): i32 {
|
|
118
|
+
const length: i32 = toI32(this.text.length)
|
|
119
|
+
if (offset < 0) {
|
|
120
|
+
return 0
|
|
121
|
+
}
|
|
122
|
+
return offset > length ? length : offset
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Internal: the 0-based line holding byte `at`, by binary search over `starts`. */
|
|
126
|
+
lineIndexOf(at: i32): i32 {
|
|
127
|
+
const starts: i32[] = this.starts
|
|
128
|
+
let low: i32 = 0
|
|
129
|
+
let high: i32 = toI32(starts.length) - 1
|
|
130
|
+
while (low < high) {
|
|
131
|
+
const mid: i32 = (low + high + 1) >> 1
|
|
132
|
+
const start: i32 = mid >= 0 && mid < toI32(starts.length) ? starts[mid] : 0
|
|
133
|
+
if (start <= at) {
|
|
134
|
+
low = mid
|
|
135
|
+
} else {
|
|
136
|
+
high = mid - 1
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return low
|
|
140
|
+
}
|
|
141
|
+
}
|