@amritk/nish-aarch64-linux 0.10.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 +468 -0
- package/LICENSE +21 -0
- package/bin/nish +0 -0
- package/package.json +31 -0
- package/runtime/nish.d.ts +290 -0
- package/runtime/nish.h +340 -0
- package/runtime/nish.mjs +143 -0
- package/runtime/runtime.c +1184 -0
- package/runtime/runtime_os.c +351 -0
- package/runtime/runtime_parallel.c +156 -0
- package/runtime/runtime_wasm.c +99 -0
- package/runtime/shim.mjs +672 -0
- package/scripts/build.sh +279 -0
- package/std/README.md +185 -0
- package/std/json.ts +402 -0
- package/std/pair.ts +28 -0
- package/std/testing.ts +347 -0
- package/std/text.ts +193 -0
package/runtime/nish.mjs
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run an Nish program under Node, unmodified.
|
|
3
|
+
*
|
|
4
|
+
* ```
|
|
5
|
+
* node --experimental-strip-types --import ./runtime/nish.mjs prog.ts
|
|
6
|
+
* ```
|
|
7
|
+
*
|
|
8
|
+
* This is a *different* claim from the one WP13 tests, and a much smaller one.
|
|
9
|
+
* The differential harness rewrites a program from the checker's own type table
|
|
10
|
+
* before Node sees it (docs/wp13-differential.md), which is what lets it
|
|
11
|
+
* reproduce wrapping arithmetic, byte-length strings and bounds checks exactly.
|
|
12
|
+
* Nothing is rewritten here: the source runs as the TypeScript it is, with the
|
|
13
|
+
* type annotations stripped. All this module can do is supply the globals
|
|
14
|
+
* Nish has and Node does not, and fix `console.log`'s formatting.
|
|
15
|
+
*
|
|
16
|
+
* That is enough for a real and useful subset — **f64 mode**, where JavaScript's
|
|
17
|
+
* `+ - * / %` on doubles *are* `fadd/fsub/fmul/fdiv/frem` and `Math.*` are the
|
|
18
|
+
* same IEEE operations, so the arithmetic needs no help. It is not enough for
|
|
19
|
+
* i32 mode, and it never will be: `number` is a wrapping 32-bit integer there
|
|
20
|
+
* and every operator would have to change.
|
|
21
|
+
*
|
|
22
|
+
* `docs/RUN_UNDER_NODE.md` states the overlap and the whole list of what stays
|
|
23
|
+
* divergent. The short version, because it belongs next to the code too:
|
|
24
|
+
*
|
|
25
|
+
* - **i32 mode is out.** Wrapping, truncating `/`, and the divide-by-zero
|
|
26
|
+
* panic are all operator-level and cannot be reached from here.
|
|
27
|
+
* - **`s.length` is UTF-16 units under Node** and UTF-8 bytes natively, and
|
|
28
|
+
* so is every string offset. ASCII agrees; nothing else does.
|
|
29
|
+
* - **`a[i]` is unchecked**: out of range is `undefined` here and an exit-1
|
|
30
|
+
* panic natively. Only a program that indexes out of range can tell.
|
|
31
|
+
* - **Method dispatch is virtual under Node** and static natively, so an
|
|
32
|
+
* override reached through a base-typed value differs (LANGUAGE.md,
|
|
33
|
+
* "Method dispatch is static").
|
|
34
|
+
* - **`orReturn()` does not propagate.** It throws a marker the rewriter's
|
|
35
|
+
* `try`/`catch` turns into an early `return`; unmodified there is no
|
|
36
|
+
* `catch`, so it escapes. `Ok`/`Err`/`isOk`/`isErr`/`value`/`error`/
|
|
37
|
+
* `unwrapOr`/`expect` all work.
|
|
38
|
+
* - **`Number(s)` keeps JavaScript's parsing.** `Number` is a constructor
|
|
39
|
+
* carrying statics (`Number.isNaN` among them) that this module and Node
|
|
40
|
+
* both need, so it is left alone; `parseInt` and `parseFloat` are plain
|
|
41
|
+
* functions and do get Nish's semantics.
|
|
42
|
+
* - **`Arena.*` reports zero.** There is no arena, and a program that prints
|
|
43
|
+
* `Arena.used()` is measuring the native allocator by definition.
|
|
44
|
+
* - **`i64` and `u64` are out**, for the same reason i32 mode is. The shim
|
|
45
|
+
* represents them as BigInt, because that is the only JavaScript type that
|
|
46
|
+
* holds 64 bits and wraps where the native ones wrap. Unrewritten source
|
|
47
|
+
* says `n + 1`, and JavaScript refuses to mix a BigInt with a number, so
|
|
48
|
+
* `toI64`/`toU64`/`f64ToBits` throw at the first arithmetic instead of
|
|
49
|
+
* answering something that is quietly wrong. That is the intended failure:
|
|
50
|
+
* a `TypeError` naming the line beats a number that silently stopped
|
|
51
|
+
* wrapping at 2^53.
|
|
52
|
+
*
|
|
53
|
+
* Everything here delegates to `runtime/shim.mjs`, the module the differential
|
|
54
|
+
* harness already uses, so the two cannot drift apart: a semantic fixed there
|
|
55
|
+
* is fixed here in the same commit.
|
|
56
|
+
*/
|
|
57
|
+
import * as shim from "./shim.mjs";
|
|
58
|
+
|
|
59
|
+
/** Install `value` as a global unless the program declared its own. */
|
|
60
|
+
const provide = (name, value) => {
|
|
61
|
+
if (!(name in globalThis)) {
|
|
62
|
+
globalThis[name] = value;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// `console.log(x)` is `String(x)` plus a newline on a synchronous write, which
|
|
67
|
+
// is not what Node's console does: it inspects, so `-0` prints `-0` where
|
|
68
|
+
// `String(-0)` is `0`, and a BigInt prints with an `n`. Overwritten rather than
|
|
69
|
+
// `provide`d, because Node always has one.
|
|
70
|
+
globalThis.console = {
|
|
71
|
+
...globalThis.console,
|
|
72
|
+
log: shim.log,
|
|
73
|
+
error: shim.error,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// Streams and files. These are globals in Nish rather than imports from
|
|
77
|
+
// `node:fs`, which is why they have to be installed at all. `readdirSync` is
|
|
78
|
+
// the one whose answer is not simply Node's: the language sorts the listing by
|
|
79
|
+
// UTF-8 bytes, so the shim sorts on the encoded bytes rather than leaving
|
|
80
|
+
// `Array#sort`'s UTF-16 order — the two agree on ASCII names only.
|
|
81
|
+
provide("write", shim.write);
|
|
82
|
+
provide("writeError", shim.writeError);
|
|
83
|
+
provide("panic", shim.panic);
|
|
84
|
+
provide("readFileSync", shim.readFileSync);
|
|
85
|
+
provide("readFileSyncOrNull", shim.readFileSyncOrNull);
|
|
86
|
+
provide("writeFileSync", shim.writeFileSync);
|
|
87
|
+
provide("appendFileSync", shim.appendFileSync);
|
|
88
|
+
provide("mkdirSync", shim.mkdirSync);
|
|
89
|
+
provide("isDirectorySync", shim.isDirectorySync);
|
|
90
|
+
provide("readdirSync", shim.readdirSync);
|
|
91
|
+
provide("realpathSync", shim.realpathSync);
|
|
92
|
+
provide("spawnSync", shim.spawnSync);
|
|
93
|
+
provide("spawnSyncTo", shim.spawnSyncTo);
|
|
94
|
+
provide("getenv", shim.getenv);
|
|
95
|
+
|
|
96
|
+
// The clock. `monotonicNanos()` answers an `i64`, so the value is a BigInt here
|
|
97
|
+
// as it is in the rewritten runner — and unusually for the i64 surface that is
|
|
98
|
+
// enough on its own: `t1 - t0` on two BigInts is the `sub i64` the native build
|
|
99
|
+
// performs, and an elapsed time is nowhere near the width where BigInt's
|
|
100
|
+
// arbitrary precision and the native wrap would part. It is only mixing a
|
|
101
|
+
// reading with a plain `number` that throws, which is the failure the header
|
|
102
|
+
// describes. A printed reading can never match a native run: the two origins are
|
|
103
|
+
// both arbitrary, and only the difference between two reads means anything.
|
|
104
|
+
provide("monotonicNanos", shim.monotonicNanos);
|
|
105
|
+
|
|
106
|
+
// Conversions. In f64 mode `toF64` is the identity and `toI32` is the one that
|
|
107
|
+
// matters (it saturates, where a JavaScript cast would not).
|
|
108
|
+
provide("toI32", shim.toI32);
|
|
109
|
+
provide("toI64", shim.toI64);
|
|
110
|
+
provide("toF64", shim.toF64);
|
|
111
|
+
provide("toF32", (x) => Math.fround(x));
|
|
112
|
+
provide("toU8", (x) => shim.convert(x, "f64", "u8"));
|
|
113
|
+
provide("toU16", (x) => shim.convert(x, "f64", "u16"));
|
|
114
|
+
provide("toU32", (x) => shim.convert(x, "f64", "u32"));
|
|
115
|
+
provide("toU64", (x) => shim.convert(x, "f64", "u64"));
|
|
116
|
+
provide("f64ToBits", shim.f64ToBits);
|
|
117
|
+
provide("bitsToF64", shim.bitsToF64);
|
|
118
|
+
|
|
119
|
+
// `Result`. Everything works but `orReturn`, which needs the caller's control
|
|
120
|
+
// flow and therefore the rewriter; see the header.
|
|
121
|
+
provide("Ok", shim.Ok);
|
|
122
|
+
provide("Err", shim.Err);
|
|
123
|
+
|
|
124
|
+
// The string parsers, whose deviations from JavaScript are documented rules
|
|
125
|
+
// (base-10 `parseInt` that saturates, `parseFloat` that reads a `0x` prefix).
|
|
126
|
+
globalThis.parseInt = shim.parseInt;
|
|
127
|
+
globalThis.parseFloat = shim.parseFloat;
|
|
128
|
+
|
|
129
|
+
// `process.argv[0]` is the program on both sides: the executable natively, this
|
|
130
|
+
// script under Node, which is one index later than Node's own `argv`.
|
|
131
|
+
process.argv = shim.argv();
|
|
132
|
+
|
|
133
|
+
// There is no arena. `mark`/`release`/`reset` are no-ops rather than errors so
|
|
134
|
+
// that a program which manages memory explicitly still runs; `used()` answers
|
|
135
|
+
// zero, which is the honest number for a host that is not bump-allocating.
|
|
136
|
+
// Delegated like everything else here rather than written inline, so that the
|
|
137
|
+
// answers cannot drift from the ones the rewritten runner gives.
|
|
138
|
+
provide("Arena", {
|
|
139
|
+
mark: shim.arenaMark,
|
|
140
|
+
release: shim.arenaRelease,
|
|
141
|
+
reset: shim.arenaReset,
|
|
142
|
+
used: shim.arenaUsed,
|
|
143
|
+
});
|