@amritk/nish 0.12.0 → 0.14.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/README.md +27 -23
- package/bin/launcher.js +45 -41
- package/bin/packaging.js +39 -33
- package/docs/AI.md +157 -35
- package/docs/INSTALL.md +13 -13
- package/llms.txt +1 -1
- package/package.json +9 -6
- package/runtime/nish.d.ts +85 -1
- package/runtime/nish.h +62 -11
- package/runtime/nish.mjs +38 -3
- package/runtime/runtime-host.c +178 -0
- package/runtime/{runtime_os.c → runtime-os.c} +16 -1
- package/runtime/{runtime_parallel.c → runtime-parallel.c} +112 -4
- package/runtime/{runtime_wasm.c → runtime-wasm.c} +6 -1
- package/runtime/runtime.c +5 -5
- package/runtime/shim.mjs +128 -6
- package/scripts/bootstrap.sh +29 -29
- package/scripts/build.sh +19 -13
- package/scripts/changelog-gen.mjs +260 -192
- package/scripts/ci-profile.mjs +80 -68
- package/scripts/codes-registry.js +25 -13
- package/scripts/gen-diagnostic-codes.mjs +124 -85
- package/scripts/nish-compiler.sh +2 -0
- package/scripts/platform-package.mjs +26 -26
- package/scripts/postinstall.mjs +46 -36
- package/scripts/size-report.sh +3 -3
- package/scripts/smoke.sh +1 -1
- package/std/README.md +42 -2
- package/std/collections.ts +194 -188
- package/std/crypto/base64url.ts +145 -0
- package/std/crypto/ct.ts +64 -0
- package/std/crypto/hkdf.ts +118 -0
- package/std/crypto/hmac.ts +155 -0
- package/std/crypto/sha256.ts +444 -0
- package/std/crypto/sha512.ts +510 -0
- package/std/crypto/x25519.ts +494 -0
- package/std/json.ts +136 -136
- package/std/map.ts +9 -7
- package/std/pair.ts +2 -2
- package/std/testing.ts +67 -67
- package/std/text.ts +54 -54
- package/std/threads.ts +126 -38
|
@@ -22,41 +22,41 @@
|
|
|
22
22
|
* say so when none was installed; two packages claiming one command name would
|
|
23
23
|
* leave which binary wins up to npm's link order.
|
|
24
24
|
*/
|
|
25
|
-
import fs from "node:fs"
|
|
26
|
-
import path from "node:path"
|
|
27
|
-
import { targetForAsset } from "../bin/packaging.js"
|
|
25
|
+
import fs from "node:fs"
|
|
26
|
+
import path from "node:path"
|
|
27
|
+
import { targetForAsset } from "../bin/packaging.js"
|
|
28
28
|
|
|
29
|
-
const args = process.argv.slice(2)
|
|
29
|
+
const args = process.argv.slice(2)
|
|
30
30
|
const flag = (name) => {
|
|
31
|
-
const i = args.indexOf(name)
|
|
32
|
-
return i < 0 ? null : args[i + 1]
|
|
33
|
-
}
|
|
34
|
-
const positional = args.filter((a, i) => !a.startsWith("--") && !(args[i - 1] ?? "").startsWith("--"))
|
|
35
|
-
const [stageDir, asset] = positional
|
|
31
|
+
const i = args.indexOf(name)
|
|
32
|
+
return i < 0 ? null : args[i + 1]
|
|
33
|
+
}
|
|
34
|
+
const positional = args.filter((a, i) => !a.startsWith("--") && !(args[i - 1] ?? "").startsWith("--"))
|
|
35
|
+
const [stageDir, asset] = positional
|
|
36
36
|
|
|
37
37
|
if (stageDir === undefined || asset === undefined) {
|
|
38
|
-
console.error("usage: platform-package.mjs <stage-dir> <asset> [--version <v>]")
|
|
39
|
-
process.exit(2)
|
|
38
|
+
console.error("usage: platform-package.mjs <stage-dir> <asset> [--version <v>]")
|
|
39
|
+
process.exit(2)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const root = path.resolve(import.meta.dirname, "..")
|
|
43
|
-
const main = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"))
|
|
44
|
-
const version = flag("--version") ?? main.version
|
|
42
|
+
const root = path.resolve(import.meta.dirname, "..")
|
|
43
|
+
const main = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"))
|
|
44
|
+
const version = flag("--version") ?? main.version
|
|
45
45
|
|
|
46
|
-
const target = targetForAsset(asset)
|
|
46
|
+
const target = targetForAsset(asset)
|
|
47
47
|
if (target === null) {
|
|
48
|
-
console.error(`platform-package.mjs: ${asset} is not a platform this project builds for`)
|
|
49
|
-
process.exit(1)
|
|
48
|
+
console.error(`platform-package.mjs: ${asset} is not a platform this project builds for`)
|
|
49
|
+
process.exit(1)
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const binary = path.join(stageDir, "bin", "nish")
|
|
52
|
+
const binary = path.join(stageDir, "bin", "nish")
|
|
53
53
|
if (!fs.existsSync(binary)) {
|
|
54
|
-
console.error(`platform-package.mjs: ${binary} does not exist; stage the binary before packaging it`)
|
|
55
|
-
process.exit(1)
|
|
54
|
+
console.error(`platform-package.mjs: ${binary} does not exist; stage the binary before packaging it`)
|
|
55
|
+
process.exit(1)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
const pretty = { linux: "Linux", darwin: "macOS" }[target.os] ?? target.os
|
|
59
|
-
const chip = { x64: "x86_64", arm64: "ARM64" }[target.cpu] ?? target.cpu
|
|
58
|
+
const pretty = { linux: "Linux", darwin: "macOS" }[target.os] ?? target.os
|
|
59
|
+
const chip = { x64: "x86_64", arm64: "ARM64" }[target.cpu] ?? target.cpu
|
|
60
60
|
|
|
61
61
|
const manifest = {
|
|
62
62
|
name: `${main.name}-${asset}`,
|
|
@@ -84,8 +84,8 @@ const manifest = {
|
|
|
84
84
|
repository: main.repository,
|
|
85
85
|
bugs: main.bugs,
|
|
86
86
|
homepage: main.homepage,
|
|
87
|
-
}
|
|
87
|
+
}
|
|
88
88
|
|
|
89
|
-
const out = path.join(stageDir, "package.json")
|
|
90
|
-
fs.writeFileSync(out, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
91
|
-
console.log(`${manifest.name}@${version} (os ${target.os}, cpu ${target.cpu}) -> ${out}`)
|
|
89
|
+
const out = path.join(stageDir, "package.json")
|
|
90
|
+
fs.writeFileSync(out, `${JSON.stringify(manifest, null, 2)}\n`)
|
|
91
|
+
console.log(`${manifest.name}@${version} (os ${target.os}, cpu ${target.cpu}) -> ${out}`)
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
*
|
|
29
29
|
* **The compiler resolves the link itself as of 0.6.0** -- the real path of
|
|
30
30
|
* whatever `argv[0]` named is a candidate for the package root
|
|
31
|
-
* ([wp19 §5a](../docs/wp19-stage0-retirement.md) item 4, in `
|
|
31
|
+
* ([wp19 §5a](../docs/wp19-stage0-retirement.md) item 4, in `src/`) -- so this
|
|
32
32
|
* `exec` is no longer what makes a copy work, and the reason it is still here is
|
|
33
33
|
* the 91 ms above rather than the defect. It also still carries whoever never
|
|
34
34
|
* ran this script: a shim npm linked and nothing swapped now finds its own
|
|
@@ -45,44 +45,54 @@
|
|
|
45
45
|
* postinstall that can break `npm ci` is a worse bug than the startup cost it
|
|
46
46
|
* exists to remove.
|
|
47
47
|
*/
|
|
48
|
-
import fs from "node:fs"
|
|
49
|
-
import path from "node:path"
|
|
50
|
-
import { createRequire } from "node:module"
|
|
51
|
-
import { pathToFileURL } from "node:url"
|
|
48
|
+
import fs from "node:fs"
|
|
49
|
+
import path from "node:path"
|
|
50
|
+
import { createRequire } from "node:module"
|
|
51
|
+
import { pathToFileURL } from "node:url"
|
|
52
52
|
|
|
53
|
-
const root = path.resolve(import.meta.dirname, "..")
|
|
53
|
+
const root = path.resolve(import.meta.dirname, "..")
|
|
54
54
|
|
|
55
55
|
const swap = async () => {
|
|
56
56
|
// A checkout, not an install. The repository is its own package, so `npm ci`
|
|
57
57
|
// here installs this package's own optionalDependencies -- and without this
|
|
58
58
|
// guard, the first `npm ci` after they are published would overwrite the
|
|
59
59
|
// tracked `bin/nish` with a binary and leave the working tree dirty. The
|
|
60
|
-
// landmark is `
|
|
61
|
-
// makes and is not in `files`; it used to be `src/launcher.ts`, which stopped
|
|
60
|
+
// landmark is `src/compile.ts`, which is the check `scripts/bootstrap.sh`
|
|
61
|
+
// makes and is not in `files`; it used to be stage0's `src/launcher.ts`, which stopped
|
|
62
62
|
// being a landmark when the launcher moved into `bin/` and ships.
|
|
63
|
-
if (fs.existsSync(path.join(root, "
|
|
63
|
+
if (fs.existsSync(path.join(root, "src", "compile.ts"))) {
|
|
64
|
+
return "a checkout, so the shim stays"
|
|
65
|
+
}
|
|
64
66
|
|
|
65
|
-
const shim = path.join(root, "bin", "nish")
|
|
66
|
-
if (!fs.existsSync(shim))
|
|
67
|
+
const shim = path.join(root, "bin", "nish")
|
|
68
|
+
if (!fs.existsSync(shim)) {
|
|
69
|
+
return "no bin/nish to replace"
|
|
70
|
+
}
|
|
67
71
|
|
|
68
|
-
const packaging = path.join(root, "bin", "packaging.js")
|
|
69
|
-
if (!fs.existsSync(packaging))
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
const packaging = path.join(root, "bin", "packaging.js")
|
|
73
|
+
if (!fs.existsSync(packaging)) {
|
|
74
|
+
return "bin/packaging.js is missing"
|
|
75
|
+
}
|
|
76
|
+
const { assetFor, platformPackageName } = await import(pathToFileURL(packaging).href)
|
|
77
|
+
const asset = assetFor(process.platform, process.arch)
|
|
78
|
+
if (asset === null) {
|
|
79
|
+
return `no prebuilt binary for ${process.platform}/${process.arch}`
|
|
80
|
+
}
|
|
73
81
|
|
|
74
82
|
const name = platformPackageName(
|
|
75
83
|
JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8")).name,
|
|
76
84
|
asset
|
|
77
|
-
)
|
|
78
|
-
let binary
|
|
85
|
+
)
|
|
86
|
+
let binary
|
|
79
87
|
try {
|
|
80
|
-
const manifest = createRequire(import.meta.url).resolve(`${name}/package.json`)
|
|
81
|
-
binary = path.join(path.dirname(manifest), "bin", "nish")
|
|
88
|
+
const manifest = createRequire(import.meta.url).resolve(`${name}/package.json`)
|
|
89
|
+
binary = path.join(path.dirname(manifest), "bin", "nish")
|
|
82
90
|
} catch {
|
|
83
|
-
return `${name} is not installed
|
|
91
|
+
return `${name} is not installed`
|
|
92
|
+
}
|
|
93
|
+
if (!fs.existsSync(binary)) {
|
|
94
|
+
return `${name} carries no bin/nish`
|
|
84
95
|
}
|
|
85
|
-
if (!fs.existsSync(binary)) return `${name} carries no bin/nish`;
|
|
86
96
|
|
|
87
97
|
// The absolute path is baked in at install time, which is the one thing this
|
|
88
98
|
// gives up: a `node_modules` copied to a different path without a reinstall
|
|
@@ -99,35 +109,35 @@ const swap = async () => {
|
|
|
99
109
|
// have ended up in, the shell would expand them. A home directory with a `$`
|
|
100
110
|
// in it is unusual and entirely legal. In POSIX sh nothing is special inside
|
|
101
111
|
// single quotes, so the only thing to handle is a single quote itself.
|
|
102
|
-
const shellQuote = (value) => `'${value.split("'").join(`'\\''`)}'
|
|
103
|
-
const target = shellQuote(binary)
|
|
112
|
+
const shellQuote = (value) => `'${value.split("'").join(`'\\''`)}'`
|
|
113
|
+
const target = shellQuote(binary)
|
|
104
114
|
const script =
|
|
105
115
|
"#!/bin/sh\n" +
|
|
106
116
|
"# Written by scripts/postinstall.mjs. `npm rebuild` regenerates it.\n" +
|
|
107
117
|
`if [ -x ${target} ]; then exec ${target} "$@"; fi\n` +
|
|
108
118
|
// Exit 3 is this project's toolchain code: the compiler could not be run,
|
|
109
119
|
// which is exactly what has happened (docs/wp12-release.md, "Exit codes").
|
|
110
|
-
|
|
111
|
-
"exit 3\n"
|
|
112
|
-
const temp = `${shim}.${process.pid}.tmp
|
|
120
|
+
"echo \"nish: the prebuilt compiler is not where it was installed; run 'npm rebuild' to repoint this\" >&2\n" +
|
|
121
|
+
"exit 3\n"
|
|
122
|
+
const temp = `${shim}.${process.pid}.tmp`
|
|
113
123
|
try {
|
|
114
|
-
fs.writeFileSync(temp, script)
|
|
115
|
-
fs.chmodSync(temp, 0o755)
|
|
116
|
-
fs.renameSync(temp, shim)
|
|
124
|
+
fs.writeFileSync(temp, script)
|
|
125
|
+
fs.chmodSync(temp, 0o755)
|
|
126
|
+
fs.renameSync(temp, shim)
|
|
117
127
|
} catch (err) {
|
|
118
128
|
try {
|
|
119
|
-
fs.rmSync(temp, { force: true })
|
|
129
|
+
fs.rmSync(temp, { force: true })
|
|
120
130
|
} catch {
|
|
121
131
|
// Nothing to do about it, and it is not worth a second message.
|
|
122
132
|
}
|
|
123
|
-
throw err
|
|
133
|
+
throw err
|
|
124
134
|
}
|
|
125
|
-
return `bin/nish now execs the native compiler in ${name}
|
|
126
|
-
}
|
|
135
|
+
return `bin/nish now execs the native compiler in ${name}`
|
|
136
|
+
}
|
|
127
137
|
|
|
128
138
|
try {
|
|
129
|
-
console.log(`nish: ${await swap()}`)
|
|
139
|
+
console.log(`nish: ${await swap()}`)
|
|
130
140
|
} catch (err) {
|
|
131
141
|
// Deliberately not an error: the shim is still there and still works.
|
|
132
|
-
console.log(`nish: keeping the node launcher (${err instanceof Error ? err.message : String(err)})`)
|
|
142
|
+
console.log(`nish: keeping the node launcher (${err instanceof Error ? err.message : String(err)})`)
|
|
133
143
|
}
|
package/scripts/size-report.sh
CHANGED
|
@@ -51,13 +51,13 @@ text_sum() { # text_sum <object>: every .text* secti
|
|
|
51
51
|
}
|
|
52
52
|
sect() { size -A "$2" | awk -v s="$1" '$1 == s { print $2 }'; }
|
|
53
53
|
"${CC:-clang}" -Oz -c runtime/runtime.c -o build/size/runtime.o
|
|
54
|
-
"${CC:-clang}" -Oz -c runtime/
|
|
54
|
+
"${CC:-clang}" -Oz -c runtime/runtime-os.c -o build/size/runtime_os.o
|
|
55
55
|
row runtime "$(text_sum build/size/runtime.o)" \
|
|
56
56
|
"clang -Oz -c runtime/runtime.c && size -A (.text*; budget 3584)"
|
|
57
57
|
row runtime_os "$(text_sum build/size/runtime_os.o)" \
|
|
58
|
-
"clang -Oz -c runtime/
|
|
58
|
+
"clang -Oz -c runtime/runtime-os.c && size -A (.text*; budget 1280)"
|
|
59
59
|
row rodata "$(sect .rodata build/size/runtime.o)" "the core object's .rodata (no budget; the Ryu tables live here)"
|
|
60
|
-
# `scripts/build.sh` compiles
|
|
60
|
+
# `scripts/build.sh` compiles runtime-os.c beside any runtime.c it is handed, so naming the
|
|
61
61
|
# core here builds the whole runtime -- and `--gc-sections` then drops whatever this module
|
|
62
62
|
# never calls, which for `examples/add.ts` is all of it.
|
|
63
63
|
for p in debug speed size; do
|
package/scripts/smoke.sh
CHANGED
package/std/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Nish modules written in Nish, for Nish programs to import. There is no magic
|
|
|
4
4
|
here and — with three exceptions, `threads.ts`, `collections.ts` and `map.ts` —
|
|
5
5
|
nothing the compiler knows about: a module in this directory is an ordinary Nish source file, compiled as part of
|
|
6
6
|
whatever program imports it, and subject to the same rules as `examples/` or
|
|
7
|
-
`
|
|
7
|
+
`src/` ([`docs/LANGUAGE.md`](../docs/LANGUAGE.md) is the style guide).
|
|
8
8
|
|
|
9
9
|
| Module | What it is |
|
|
10
10
|
| --- | --- |
|
|
@@ -16,6 +16,46 @@ whatever program imports it, and subject to the same rules as `examples/` or
|
|
|
16
16
|
| [`map.ts`](./map.ts) | `reserve(m, n)` and `getOrInsert(m, k, v)` for the global `Map`. Their bodies are the meaning, and what runs under Node: `reserve` does nothing, and `getOrInsert` is a `get`, and a `set` of `v` when the key was missing. Natively the compiler lowers every call in place — `reserve` to the table's `reserveSlots`, which grows the buckets once so that `n` entries fit without a rebuild, and `getOrInsert` to one `probe` and a `valueAt` or an `insertAt` through its answer — so, like `collections.ts`, it writes no `.ll` of its own ([`docs/wp32-map.md`](../docs/wp32-map.md) §9.2, [`docs/LANGUAGE.md`](../docs/LANGUAGE.md#map-and-set)) |
|
|
17
17
|
| [`threads.ts`](./threads.ts) | `parallelMapInto(src, dst, f)` and `parallelReduce(src, f, identity)`: a function over every element of an array, on as many threads as the length is worth. Its bodies are the sequential meaning, which is what runs under Node; the compiler recognises the two templates by module and name, lowers the one loop in each onto `nish_parallel_range`, holds the function to the rules that make that safe, and compiles an importing program with `--threads` ([`docs/LANGUAGE.md`](../docs/LANGUAGE.md#data-parallelism-nishthreads)). `tests/link/par_*` are its programs |
|
|
18
18
|
|
|
19
|
+
## `nish/crypto` — the primitives under TLS 1.3
|
|
20
|
+
|
|
21
|
+
The first lanes of [WP34](../docs/wp34-hosting-cs.md) §5: K1's hashes, MACs and
|
|
22
|
+
key derivation, and K4's key exchange, in pure Nish (decision S1), each module
|
|
23
|
+
imported by its own specifier. Every one is written from its specification
|
|
24
|
+
rather than ported, and reproduces that specification's published vectors in
|
|
25
|
+
its `tests/link/crypto_*` programs. The performance gate compiles every module
|
|
26
|
+
with no diagnostics under both `--number-mode i32` and `f64`, and the hashes,
|
|
27
|
+
HMAC, HKDF and X25519 also run their vectors in `f64` (`crypto_*_f64`).
|
|
28
|
+
|
|
29
|
+
| Module | What it is | Reproduces |
|
|
30
|
+
| --- | --- | --- |
|
|
31
|
+
| [`crypto/sha256.ts`](./crypto/sha256.ts) | `sha256(data)`, and `Sha256`, a streaming hasher: `update(buf, off, len)` over a window of a `u8[]`, `copy()` for the hash of a prefix while the original keeps going, and `digest()`, a fresh 32-byte array. `SHA256_SIZE` and `SHA256_BLOCK` | FIPS 180-4 §6.2 |
|
|
32
|
+
| [`crypto/sha512.ts`](./crypto/sha512.ts) | SHA-512 and SHA-384 on one compression function: `sha512` and `sha384`, and the streaming `Sha512` and `Sha384` with `Sha256`'s three methods; digests of 64 and 48 bytes. `SHA512_SIZE`, `SHA384_SIZE` and `SHA512_BLOCK` | FIPS 180-4 §6.4, §6.5 |
|
|
33
|
+
| [`crypto/hmac.ts`](./crypto/hmac.ts) | `hmacSha256` and `hmacSha384`, the streaming `HmacSha256` and `HmacSha384` (keyed in the constructor, then `update` and `digest`), and `hmacSha256Verify` / `hmacSha384Verify`, which compare a received tag with `timingSafeEqual` | RFC 2104, RFC 4231 §4 |
|
|
34
|
+
| [`crypto/hkdf.ts`](./crypto/hkdf.ts) | `hkdfExtractSha256` / `hkdfExtractSha384` (an empty salt is HashLen zeros) and `hkdfExpandSha256` / `hkdfExpandSha384`, which answer `null` for a length below zero or above 255 × HashLen. TLS 1.3's HKDF-Expand-Label is not here; it belongs with TLS | RFC 5869 §2, Appendix A |
|
|
35
|
+
| [`crypto/ct.ts`](./crypto/ct.ts) | `timingSafeEqual(a, b)`, which reads every byte whatever it holds, and `timingSafeEqualAt(a, aOff, b, bOff, len)` over two windows, which answers `false` for a window outside its array. Two lengths that differ answer `false` at once, because a length is public | — |
|
|
36
|
+
| [`crypto/base64url.ts`](./crypto/base64url.ts) | `base64urlEncode(data)` and `base64urlDecode(text)`, unpadded. Decoding is strict, so every byte string has one spelling: a `=`, a character outside the alphabet, a length of 1 mod 4 or nonzero unused low bits answer `null` | RFC 4648 §5, §10 |
|
|
37
|
+
| [`crypto/x25519.ts`](./crypto/x25519.ts) | `x25519(scalar, u)` and `x25519Base(scalar)`, on ten 25.5-bit limbs in `i64`. Either answers `null` unless its arguments are `X25519_SIZE` (32) bytes; the scalar is clamped on a copy | RFC 7748 §5.2, §6.1 |
|
|
38
|
+
|
|
39
|
+
Three rules hold across the modules:
|
|
40
|
+
|
|
41
|
+
- **A digest ends the computation.** After `digest()` on a hasher or an HMAC, a
|
|
42
|
+
further `update` or `digest` panics rather than answering a hash over the
|
|
43
|
+
padding, and so does a window outside its buffer. `Sha256.copy()` on a
|
|
44
|
+
digested hasher panics too; `Sha512.copy()` and `Sha384.copy()` answer a copy
|
|
45
|
+
that is itself spent, so any `update` or `digest` on it panics. Either way,
|
|
46
|
+
copy *before* `digest` when the computation has to go on.
|
|
47
|
+
- **An all-zero X25519 result is returned, not refused.** It is what a
|
|
48
|
+
low-order `u` gives, and RFC 7748 §6.1 leaves the check to the protocol; TLS
|
|
49
|
+
1.3 (WP34 T1) makes it. A key exchange outside TLS has to make it itself.
|
|
50
|
+
- **Constant time by construction, not yet by proof.** No module branches on,
|
|
51
|
+
or indexes by, a secret: comparisons OR the differences into one word and
|
|
52
|
+
test it once, the ladder swaps with a mask and always runs 255 steps, and
|
|
53
|
+
base64url maps characters by arithmetic on range masks rather than a table.
|
|
54
|
+
Every branch is on a length, a loop counter or a bit position. What checks
|
|
55
|
+
that the machine code kept that shape is WP34 N6 — the `ctSelect` / `ctEq`
|
|
56
|
+
builtins behind an optimisation barrier, and a disassembly check — and it is
|
|
57
|
+
not built yet, so this is the discipline and not a verified property.
|
|
58
|
+
|
|
19
59
|
## How a program imports it
|
|
20
60
|
|
|
21
61
|
By its package specifier:
|
|
@@ -130,7 +170,7 @@ that are *not* this package.
|
|
|
130
170
|
stdout. `tests/link/std_text_f64` is the same corpus under
|
|
131
171
|
`--number-mode f64`, which is where a module that spelled its widths and forgot
|
|
132
172
|
a `toI32` is caught.
|
|
133
|
-
- **`std/` is not on the compiler's dependency list.** Nothing in `
|
|
173
|
+
- **`std/` is not on the compiler's dependency list.** Nothing in `src/`
|
|
134
174
|
imports it, and nothing should: the compiler is the thing that has to
|
|
135
175
|
build before the library means anything.
|
|
136
176
|
|