@scriptc/compiler 0.3.4 → 0.3.6
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/ambient/scriptc-node-fallback.d.ts +409 -42
- package/dist/backend/llvm/array-search.js +1 -1
- package/dist/backend/llvm/array-search.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.d.ts +6 -0
- package/dist/backend/llvm/call-lifetimes.js +19 -0
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +2 -21
- package/dist/backend/llvm/constant-callbacks.js +36 -219
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +22 -0
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +9 -0
- package/dist/backend/llvm/dense-array-access.js +27 -1
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +6 -0
- package/dist/backend/llvm/dyn.js +71 -7
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +120 -2
- package/dist/backend/llvm/emitter.js +820 -142
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +17 -7
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.js +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +11 -0
- package/dist/backend/llvm/expr-callbacks.js +53 -0
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +88 -2
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +50 -27
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.js +1 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +25 -1
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +20 -1
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +4 -0
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/integer-clones.d.ts +103 -0
- package/dist/backend/llvm/integer-clones.js +1336 -0
- package/dist/backend/llvm/integer-clones.js.map +1 -0
- package/dist/backend/llvm/integer-clones.test.d.ts +1 -0
- package/dist/backend/llvm/integer-clones.test.js +219 -0
- package/dist/backend/llvm/integer-clones.test.js.map +1 -0
- package/dist/backend/llvm/lib-datagram.js +14 -0
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +32 -1
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +61 -1
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +21 -3
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +34 -0
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +77 -2
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-test.js +16 -3
- package/dist/backend/llvm/lib-test.js.map +1 -1
- package/dist/backend/llvm/lib-tls.js +6 -0
- package/dist/backend/llvm/lib-tls.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +1 -1
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/map-entry-fusion.d.ts +28 -0
- package/dist/backend/llvm/map-entry-fusion.js +233 -0
- package/dist/backend/llvm/map-entry-fusion.js.map +1 -0
- package/dist/backend/llvm/map-entry-fusion.test.d.ts +1 -0
- package/dist/backend/llvm/map-entry-fusion.test.js +183 -0
- package/dist/backend/llvm/map-entry-fusion.test.js.map +1 -0
- package/dist/backend/llvm/map-number-lookup.d.ts +2 -0
- package/dist/backend/llvm/map-number-lookup.js +1 -1
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.test.js +10 -11
- package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.d.ts +2 -0
- package/dist/backend/llvm/map-read-lifetimes.js +3 -0
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +2 -2
- package/dist/backend/llvm/nullable-unions.d.ts +6 -3
- package/dist/backend/llvm/nullable-unions.js +2 -0
- package/dist/backend/llvm/nullable-unions.js.map +1 -1
- package/dist/backend/llvm/publish.d.ts +16 -0
- package/dist/backend/llvm/publish.js +81 -10
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/publish.test.d.ts +1 -0
- package/dist/backend/llvm/publish.test.js +94 -0
- package/dist/backend/llvm/publish.test.js.map +1 -0
- package/dist/backend/llvm/record-results.d.ts +1 -1
- package/dist/backend/llvm/record-results.js +78 -4
- package/dist/backend/llvm/record-results.js.map +1 -1
- package/dist/backend/llvm/record-sources.d.ts +7 -0
- package/dist/backend/llvm/record-sources.js +14 -0
- package/dist/backend/llvm/record-sources.js.map +1 -0
- package/dist/backend/llvm/reference-writes.js +1 -0
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +12 -3
- package/dist/backend/llvm/shapes.js +23 -14
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +5 -3
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/speculative-integers.d.ts +74 -0
- package/dist/backend/llvm/speculative-integers.js +571 -0
- package/dist/backend/llvm/speculative-integers.js.map +1 -0
- package/dist/backend/llvm/speculative-integers.test.d.ts +1 -0
- package/dist/backend/llvm/speculative-integers.test.js +148 -0
- package/dist/backend/llvm/speculative-integers.test.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.test.js +75 -1
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +17 -0
- package/dist/backend/llvm/walkers.js +123 -0
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.js +2 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +2 -1
- package/dist/backend/native/executable.js +6 -1
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +1 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.d.ts +7 -3
- package/dist/backend/runtime-pack.js +12 -6
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +16 -7
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/contracts/check.js +1 -0
- package/dist/contracts/check.js.map +1 -1
- package/dist/coverage/surface-manifest.js +3 -3
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +1 -1
- package/dist/diagnostics/diagnostic.js +6 -2
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/builtin-calls.js +13 -0
- package/dist/frontend/lowering/builtin-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/callable-aliases.js +82 -8
- package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-async.d.ts +8 -6
- package/dist/frontend/lowering/builtins/child-process-async.js +45 -29
- package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
- package/dist/frontend/lowering/builtins/compression.d.ts +9 -0
- package/dist/frontend/lowering/builtins/compression.js +145 -30
- package/dist/frontend/lowering/builtins/compression.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.js +12 -1
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +5 -3
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +6 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +16 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.d.ts +8 -0
- package/dist/frontend/lowering/builtins/filesystem.js +199 -2
- package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
- package/dist/frontend/lowering/builtins/fs-streams.d.ts +26 -0
- package/dist/frontend/lowering/builtins/fs-streams.js +131 -0
- package/dist/frontend/lowering/builtins/fs-streams.js.map +1 -0
- package/dist/frontend/lowering/builtins/hash-stream.d.ts +12 -0
- package/dist/frontend/lowering/builtins/hash-stream.js +80 -0
- package/dist/frontend/lowering/builtins/hash-stream.js.map +1 -0
- package/dist/frontend/lowering/builtins/module-calls.js +17 -3
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.js +9 -2
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/readline.d.ts +45 -13
- package/dist/frontend/lowering/builtins/readline.js +812 -47
- package/dist/frontend/lowering/builtins/readline.js.map +1 -1
- package/dist/frontend/lowering/builtins/workers.d.ts +4 -0
- package/dist/frontend/lowering/builtins/workers.js +58 -0
- package/dist/frontend/lowering/builtins/workers.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +150 -8
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.d.ts +55 -0
- package/dist/frontend/lowering/class-protocols.js +735 -0
- package/dist/frontend/lowering/class-protocols.js.map +1 -1
- package/dist/frontend/lowering/containers/array-from-async.d.ts +18 -0
- package/dist/frontend/lowering/containers/array-from-async.js +282 -0
- package/dist/frontend/lowering/containers/array-from-async.js.map +1 -0
- package/dist/frontend/lowering/containers/bytes.js +33 -12
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-grouping.js +2 -1
- package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +27 -23
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/devirtualize.js +20 -7
- package/dist/frontend/lowering/devirtualize.js.map +1 -1
- package/dist/frontend/lowering/divergences.js +188 -15
- package/dist/frontend/lowering/divergences.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +129 -25
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +46 -1
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +55 -15
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.d.ts +9 -1
- package/dist/frontend/lowering/lower-event-emitter.js +88 -1
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +4 -0
- package/dist/frontend/lowering/lower-exprs.js +239 -71
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +49 -3
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-mock.d.ts +11 -1
- package/dist/frontend/lowering/lower-mock.js +377 -61
- package/dist/frontend/lowering/lower-mock.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +1 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +2 -1
- package/dist/frontend/lowering/lower-server.js +234 -21
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +60 -13
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +1 -3
- package/dist/frontend/lowering/lower-stream.js +325 -20
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.js +147 -48
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +13 -1
- package/dist/frontend/lowering/lowerer.js +10 -2
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/null-prototype.d.ts +13 -0
- package/dist/frontend/lowering/null-prototype.js +33 -0
- package/dist/frontend/lowering/null-prototype.js.map +1 -0
- package/dist/frontend/lowering/record-sources.d.ts +15 -0
- package/dist/frontend/lowering/record-sources.js +46 -0
- package/dist/frontend/lowering/record-sources.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +3 -3
- package/dist/frontend/lowering/surfaces.js +59 -5
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/mock-shapes.d.ts +5 -0
- package/dist/frontend/mock-shapes.js +27 -2
- package/dist/frontend/mock-shapes.js.map +1 -1
- package/dist/frontend/program.js +5 -4
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +3 -0
- package/dist/frontend/type-mapper.js +148 -4
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +18 -8
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +10 -0
- package/dist/ir/analysis.js +35 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/analysis.test.js +69 -1
- package/dist/ir/analysis.test.js.map +1 -1
- package/dist/ir/builtin-effects.js +72 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +258 -13
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/capture-values.d.ts +107 -0
- package/dist/ir/capture-values.js +850 -0
- package/dist/ir/capture-values.js.map +1 -0
- package/dist/ir/capture-values.test.d.ts +1 -0
- package/dist/ir/capture-values.test.js +268 -0
- package/dist/ir/capture-values.test.js.map +1 -0
- package/dist/ir/field-values.d.ts +16 -0
- package/dist/ir/field-values.js +128 -0
- package/dist/ir/field-values.js.map +1 -0
- package/dist/ir/field-values.test.d.ts +1 -0
- package/dist/ir/field-values.test.js +160 -0
- package/dist/ir/field-values.test.js.map +1 -0
- package/dist/ir/final-fields.d.ts +4 -1
- package/dist/ir/final-fields.js +11 -3
- package/dist/ir/final-fields.js.map +1 -1
- package/dist/ir/function-references.test.js +2 -1
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/init-only-globals.d.ts +16 -0
- package/dist/ir/init-only-globals.js +121 -0
- package/dist/ir/init-only-globals.js.map +1 -0
- package/dist/ir/init-only-globals.test.d.ts +1 -0
- package/dist/ir/init-only-globals.test.js +115 -0
- package/dist/ir/init-only-globals.test.js.map +1 -0
- package/dist/ir/initializer-bindings.d.ts +18 -1
- package/dist/ir/initializer-bindings.js +91 -1
- package/dist/ir/initializer-bindings.js.map +1 -1
- package/dist/ir/initializer-bindings.test.js +57 -2
- package/dist/ir/initializer-bindings.test.js.map +1 -1
- package/dist/ir/int32-slots.d.ts +22 -0
- package/dist/ir/int32-slots.js +398 -13
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +119 -8
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loop-facts.d.ts +27 -1
- package/dist/ir/integer-loop-facts.js +239 -7
- package/dist/ir/integer-loop-facts.js.map +1 -1
- package/dist/ir/integer-ranges.d.ts +8 -5
- package/dist/ir/integer-ranges.js +147 -59
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +285 -7
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/ir.d.ts +22 -1
- package/dist/ir/ir.js +4 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/property-bags.d.ts +14 -0
- package/dist/ir/property-bags.js +121 -0
- package/dist/ir/property-bags.js.map +1 -0
- package/dist/ir/receiver-readers.d.ts +21 -0
- package/dist/ir/receiver-readers.js +217 -0
- package/dist/ir/receiver-readers.js.map +1 -0
- package/dist/ir/runtime-features.d.ts +3 -1
- package/dist/ir/runtime-features.js +102 -7
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/runtime-features.test.js +62 -0
- package/dist/ir/runtime-features.test.js.map +1 -1
- package/dist/ir/traverse.js +4 -0
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +71 -3
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +59 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/int-infer.js +3 -0
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/ir-policy.js +5 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +57 -19
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import * as ts from "../../ts7/adapter.js";
|
|
2
2
|
import {} from "../lowerer.js";
|
|
3
3
|
import { locOf } from "../../program.js";
|
|
4
|
-
import { DYN, F64, STRING, VOID } from "../../../ir/ir.js";
|
|
5
|
-
import { boolLit, numLit } from "../../../ir/build.js";
|
|
4
|
+
import { BOOL, DYN, F64, STRING, VOID, arrayOf, BYTES_U8, } from "../../../ir/ir.js";
|
|
5
|
+
import { boolLit, dynUndefinedExpr, numLit } from "../../../ir/build.js";
|
|
6
6
|
import { READLINE_DOCUMENTED_OPTIONS, fenceOrDropOptionKey } from "../surfaces.js";
|
|
7
7
|
import { streamSidesOf } from "../lower-stream.js";
|
|
8
|
+
import { voidizedCallback } from "../lower-server.js";
|
|
8
9
|
/** The ambient module declaring `d`, or null. */
|
|
9
10
|
function ambientModuleOf(d) {
|
|
10
11
|
let up = d.parent;
|
|
@@ -39,7 +40,18 @@ export function isReadlineTyped(lowerer, node) {
|
|
|
39
40
|
});
|
|
40
41
|
}
|
|
41
42
|
/** The runtime's listener event numbers (scr_readline.c). */
|
|
42
|
-
const RL_EVENTS = {
|
|
43
|
+
const RL_EVENTS = {
|
|
44
|
+
line: 0,
|
|
45
|
+
close: 1,
|
|
46
|
+
pause: 2,
|
|
47
|
+
resume: 3,
|
|
48
|
+
error: 4,
|
|
49
|
+
history: 5,
|
|
50
|
+
SIGINT: 6,
|
|
51
|
+
SIGTSTP: 7,
|
|
52
|
+
SIGCONT: 8,
|
|
53
|
+
};
|
|
54
|
+
const RL_EVENT_LIST = '"line", "close", "pause", "resume", "error", "history", "SIGINT", "SIGTSTP" and "SIGCONT"';
|
|
43
55
|
/** True when the call's resolved signature answers a Promise — the
|
|
44
56
|
* readline/promises question. */
|
|
45
57
|
function returnsPromise(lowerer, call) {
|
|
@@ -64,19 +76,164 @@ function questionSignal(lowerer, node) {
|
|
|
64
76
|
}
|
|
65
77
|
return signal;
|
|
66
78
|
}
|
|
79
|
+
/** True when `node`'s checker type is readline/promises' Readline. */
|
|
80
|
+
function isReadlineUiTyped(lowerer, node) {
|
|
81
|
+
const t = lowerer.checker.getTypeAtLocation(node);
|
|
82
|
+
const sym = t.getAliasSymbol() ?? t.getSymbol();
|
|
83
|
+
if (sym?.name !== "Readline")
|
|
84
|
+
return false;
|
|
85
|
+
return lowerer.checker.declarationsOf(sym).some((d) => {
|
|
86
|
+
if (!ts.isClassDeclaration(d) && !ts.isInterfaceDeclaration(d))
|
|
87
|
+
return false;
|
|
88
|
+
if (!lowerer.isStdlibFile(d.getSourceFile()))
|
|
89
|
+
return false;
|
|
90
|
+
const spec = ambientModuleOf(d);
|
|
91
|
+
return spec === "readline/promises" || spec === "node:readline/promises";
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** The process.stdout/stderr target (1/2) of `node`, or 0. */
|
|
95
|
+
function processOutputOf(lowerer, node) {
|
|
96
|
+
if (!ts.isPropertyAccessExpression(node))
|
|
97
|
+
return 0;
|
|
98
|
+
const member = lowerer.stdlibGlobalMember(node, "process");
|
|
99
|
+
return member === "stdout" ? 1 : member === "stderr" ? 2 : 0;
|
|
100
|
+
}
|
|
101
|
+
/** new Readline(stream, options?) from readline/promises: the stream is
|
|
102
|
+
* process.stdout, process.stderr or a writable stream (checked with
|
|
103
|
+
* isWritable at runtime), the options an object literal with a boolean
|
|
104
|
+
* autoCommit. Null for other constructors. */
|
|
105
|
+
export function lowerReadlineUiNew(lowerer, expr) {
|
|
106
|
+
if (!isReadlineUiTyped(lowerer, expr))
|
|
107
|
+
return null;
|
|
108
|
+
const loc = locOf(expr);
|
|
109
|
+
const args = expr.arguments ?? [];
|
|
110
|
+
if (args.length < 1 || args.length > 2 || args.some(ts.isSpreadElement)) {
|
|
111
|
+
lowerer.noLowering(`new Readline with ${args.length} arguments`, expr);
|
|
112
|
+
}
|
|
113
|
+
const fd = processOutputOf(lowerer, args[0]);
|
|
114
|
+
let stream = null;
|
|
115
|
+
if (fd === 0) {
|
|
116
|
+
stream = lowerer.lowerExpr(args[0]);
|
|
117
|
+
const info = stream.type.kind === "object" ? lowerer.classes.get(stream.type.className) : undefined;
|
|
118
|
+
const sides = streamSidesOf(lowerer, info);
|
|
119
|
+
if (sides !== "w" && sides !== "rw") {
|
|
120
|
+
lowerer.noLowering("new Readline with this stream", args[0], "process.stdout, process.stderr and writable streams are the supported streams");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
let autoCommit = boolLit(false, loc);
|
|
124
|
+
const opts = args[1];
|
|
125
|
+
if (opts !== undefined && !isNullish(opts)) {
|
|
126
|
+
if (!ts.isObjectLiteralExpression(opts)) {
|
|
127
|
+
lowerer.noLowering("new Readline with options that are not an object literal", opts, "write the options inline: new Readline(stream, { autoCommit: true })");
|
|
128
|
+
}
|
|
129
|
+
for (const p of opts.properties) {
|
|
130
|
+
if (ts.isPropertyAssignment(p) &&
|
|
131
|
+
ts.isIdentifier(p.name) &&
|
|
132
|
+
p.name.text === "autoCommit" &&
|
|
133
|
+
!isNullish(p.initializer)) {
|
|
134
|
+
if (!(lowerer.typeOf(p.initializer).flags & ts.TypeFlags.BooleanLike)) {
|
|
135
|
+
lowerer.noLowering("the Readline option 'autoCommit' with a value that is not a boolean", p.initializer);
|
|
136
|
+
}
|
|
137
|
+
autoCommit = lowerer.lowerExprExpecting(p.initializer, BOOL);
|
|
138
|
+
}
|
|
139
|
+
else if (!(ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) && p.name.text === "autoCommit")) {
|
|
140
|
+
lowerer.noLowering("new Readline with this option", p, "autoCommit is the supported option");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (stream !== null) {
|
|
145
|
+
return { kind: "libCall", fn: "rl.uiOpenStream", args: [stream, autoCommit], type: F64, loc };
|
|
146
|
+
}
|
|
147
|
+
return { kind: "libCall", fn: "rl.uiOpen", args: [numLit(fd, loc), autoCommit], type: F64, loc };
|
|
148
|
+
}
|
|
149
|
+
/** Readline methods: cursorTo(x, y?), moveCursor(dx, dy), clearLine(dir),
|
|
150
|
+
* clearScreenDown() and rollback() answer the receiver; commit() answers
|
|
151
|
+
* a promise. */
|
|
152
|
+
function lowerReadlineUiCall(lowerer, call, access) {
|
|
153
|
+
const name = access.name.text;
|
|
154
|
+
const loc = locOf(call);
|
|
155
|
+
const args = call.arguments;
|
|
156
|
+
const plan = {
|
|
157
|
+
cursorTo: ["rl.uiCursorTo", 1, 2],
|
|
158
|
+
moveCursor: ["rl.uiMoveCursor", 2, 2],
|
|
159
|
+
clearLine: ["rl.uiClearLine", 1, 1],
|
|
160
|
+
clearScreenDown: ["rl.uiClearScreenDown", 0, 0],
|
|
161
|
+
rollback: ["rl.uiRollback", 0, 0],
|
|
162
|
+
commit: ["rl.uiCommit", 0, 0],
|
|
163
|
+
};
|
|
164
|
+
const entry = plan[name];
|
|
165
|
+
if (entry === undefined ||
|
|
166
|
+
args.length < entry[1] ||
|
|
167
|
+
args.length > entry[2] ||
|
|
168
|
+
args.some(ts.isSpreadElement)) {
|
|
169
|
+
lowerer.noLowering(`readlinePromises.Readline.${name}`, call, "cursorTo, moveCursor, clearLine, clearScreenDown, commit and rollback are the supported Readline members", lowerer.checker.getSymbolAtLocation(access.name));
|
|
170
|
+
}
|
|
171
|
+
const l = lowerer.declareHiddenLocal("%rlUi", F64);
|
|
172
|
+
const recv = { kind: "varRef", localId: l.id, type: F64, loc };
|
|
173
|
+
const stmts = [
|
|
174
|
+
{
|
|
175
|
+
kind: "varDecl",
|
|
176
|
+
localId: l.id,
|
|
177
|
+
init: lowerer.lowerExprExpecting(access.expression, F64),
|
|
178
|
+
loc,
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
if (name === "commit") {
|
|
182
|
+
return {
|
|
183
|
+
kind: "seqExpr",
|
|
184
|
+
stmts,
|
|
185
|
+
result: {
|
|
186
|
+
kind: "libCall",
|
|
187
|
+
fn: "rl.uiCommit",
|
|
188
|
+
args: [recv],
|
|
189
|
+
type: { kind: "promise", inner: VOID },
|
|
190
|
+
loc,
|
|
191
|
+
},
|
|
192
|
+
type: { kind: "promise", inner: VOID },
|
|
193
|
+
loc,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
const number = (n) => {
|
|
197
|
+
if (!(lowerer.typeOf(n).flags & ts.TypeFlags.NumberLike)) {
|
|
198
|
+
lowerer.noLowering(`Readline.${name} with an argument that is not a number`, n);
|
|
199
|
+
}
|
|
200
|
+
return lowerer.lowerExprExpecting(n, F64);
|
|
201
|
+
};
|
|
202
|
+
const values = [recv];
|
|
203
|
+
if (name === "cursorTo") {
|
|
204
|
+
// cursorTo(x, y?): [handle, x, whether y is given, y]
|
|
205
|
+
const y = args[1];
|
|
206
|
+
const hasY = y !== undefined && !isNullish(y);
|
|
207
|
+
values.push(number(args[0]), boolLit(hasY, loc), hasY ? number(y) : numLit(0, loc));
|
|
208
|
+
}
|
|
209
|
+
else {
|
|
210
|
+
for (const n of args)
|
|
211
|
+
values.push(number(n));
|
|
212
|
+
}
|
|
213
|
+
stmts.push({
|
|
214
|
+
kind: "exprStmt",
|
|
215
|
+
expr: { kind: "libCall", fn: entry[0], args: values, type: VOID, loc },
|
|
216
|
+
loc,
|
|
217
|
+
});
|
|
218
|
+
return { kind: "seqExpr", stmts, result: recv, type: F64, loc };
|
|
219
|
+
}
|
|
67
220
|
/** Method calls on readline Interface receivers (both modules):
|
|
68
221
|
* - question(query, cb) — the callback form; question(query, { signal }?)
|
|
69
222
|
* — the promise form (readline/promises);
|
|
70
|
-
* - close(), pause(), resume(), prompt(), setPrompt(p),
|
|
71
|
-
* write(data);
|
|
223
|
+
* - close(), pause(), resume(), prompt(preserveCursor?), setPrompt(p),
|
|
224
|
+
* getPrompt(), write(data, key?);
|
|
72
225
|
* - on/once/addListener for 'line' ((input: string) or no parameters),
|
|
73
|
-
* '
|
|
74
|
-
* no parameters),
|
|
226
|
+
* 'error' ((err: Error) or no parameters), 'history' ((history:
|
|
227
|
+
* string[]) or no parameters), and 'close'/'pause'/'resume'/'SIGINT'/
|
|
228
|
+
* 'SIGTSTP'/'SIGCONT' (no parameters), as statements.
|
|
75
229
|
* Everything else the lib declares fences member-qualified. Null for
|
|
76
230
|
* non-Interface receivers. */
|
|
77
231
|
export function lowerReadlineMethodCall(lowerer, call, access) {
|
|
78
232
|
if (call.questionDotToken || access.questionDotToken)
|
|
79
233
|
return null;
|
|
234
|
+
if (isReadlineUiTyped(lowerer, access.expression) && lowerer.isStdlibMember(access)) {
|
|
235
|
+
return lowerReadlineUiCall(lowerer, call, access);
|
|
236
|
+
}
|
|
80
237
|
if (!isReadlineTyped(lowerer, access.expression))
|
|
81
238
|
return null;
|
|
82
239
|
if (!lowerer.isStdlibMember(access))
|
|
@@ -123,13 +280,15 @@ export function lowerReadlineMethodCall(lowerer, call, access) {
|
|
|
123
280
|
if ((name === "pause" || name === "resume") && !ts.isExpressionStatement(call.parent)) {
|
|
124
281
|
lowerer.unsupported("SC1090", call, `using the result of readline ${name}() (call it as its own statement)`);
|
|
125
282
|
}
|
|
126
|
-
// prompt(preserveCursor)
|
|
127
|
-
// interface: a boolean literal is accepted and has no effect here.
|
|
283
|
+
// prompt(preserveCursor) keeps a terminal interface's cursor
|
|
128
284
|
const flag = args[0];
|
|
129
|
-
if (flag !== undefined &&
|
|
130
|
-
flag.
|
|
131
|
-
|
|
132
|
-
|
|
285
|
+
if (flag !== undefined && flag.kind !== ts.SyntaxKind.FalseKeyword) {
|
|
286
|
+
if (!(lowerer.typeOf(flag).flags & ts.TypeFlags.BooleanLike)) {
|
|
287
|
+
lowerer.noLowering("readline prompt() with a preserveCursor that is not a boolean", flag, "pass a boolean or omit it");
|
|
288
|
+
}
|
|
289
|
+
const recv = receiver();
|
|
290
|
+
const keep = lowerer.lowerExprExpecting(flag, BOOL);
|
|
291
|
+
return { kind: "libCall", fn: "rl.promptWith", args: [recv, keep], type: VOID, loc };
|
|
133
292
|
}
|
|
134
293
|
return { kind: "libCall", fn: simpleFn, args: [receiver()], type: VOID, loc };
|
|
135
294
|
}
|
|
@@ -141,29 +300,72 @@ export function lowerReadlineMethodCall(lowerer, call, access) {
|
|
|
141
300
|
if (name === "getPrompt" && args.length === 0) {
|
|
142
301
|
return { kind: "libCall", fn: "rl.getPrompt", args: [receiver()], type: STRING, loc };
|
|
143
302
|
}
|
|
144
|
-
if (name === "
|
|
303
|
+
if (name === "getCursorPos" && args.length === 0) {
|
|
304
|
+
// { rows, cols } of the prompt and the line before the cursor
|
|
305
|
+
const t = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
306
|
+
const shape = t?.kind === "record" ? lowerer.shapes.get(t.shapeId) : undefined;
|
|
307
|
+
if (t?.kind !== "record" ||
|
|
308
|
+
!shape ||
|
|
309
|
+
!shape.fields.every((f) => (f.name === "rows" || f.name === "cols") && f.type.kind === "f64")) {
|
|
310
|
+
lowerer.badType(call, lowerer.typeOf(call));
|
|
311
|
+
}
|
|
312
|
+
const l = lowerer.declareHiddenLocal("%rl", F64);
|
|
313
|
+
const recv = { kind: "varRef", localId: l.id, type: F64, loc };
|
|
314
|
+
return {
|
|
315
|
+
kind: "seqExpr",
|
|
316
|
+
stmts: [{ kind: "varDecl", localId: l.id, init: receiver(), loc }],
|
|
317
|
+
result: {
|
|
318
|
+
kind: "recordLit",
|
|
319
|
+
fields: shape.fields.map((f) => ({
|
|
320
|
+
name: f.name,
|
|
321
|
+
value: {
|
|
322
|
+
kind: "libCall",
|
|
323
|
+
fn: "rl.cursorPos",
|
|
324
|
+
args: [recv, numLit(f.name === "rows" ? 0 : 1, loc)],
|
|
325
|
+
type: F64,
|
|
326
|
+
loc,
|
|
327
|
+
},
|
|
328
|
+
})),
|
|
329
|
+
type: t,
|
|
330
|
+
loc,
|
|
331
|
+
},
|
|
332
|
+
type: t,
|
|
333
|
+
loc,
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
if (name === "write" && args.length === 1 && !isNullish(args[0])) {
|
|
145
337
|
const recv = receiver();
|
|
146
338
|
const data = lowerer.lowerExprExpecting(args[0], STRING);
|
|
147
339
|
return { kind: "libCall", fn: "rl.write", args: [recv, data], type: VOID, loc };
|
|
148
340
|
}
|
|
341
|
+
if (name === "write" && (args.length === 1 || args.length === 2)) {
|
|
342
|
+
return lowerWriteKey(lowerer, receiver(), args[0], args[1], loc);
|
|
343
|
+
}
|
|
149
344
|
if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) {
|
|
150
345
|
const evT = lowerer.typeOf(args[0]);
|
|
151
346
|
const event = evT.isStringLiteralType() ? evT.value : null;
|
|
152
347
|
const ev = event === null ? undefined : RL_EVENTS[event];
|
|
153
348
|
if (ev === undefined) {
|
|
154
|
-
lowerer.noLowering(`readline.Interface.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0],
|
|
349
|
+
lowerer.noLowering(`readline.Interface.${name}(${event === null ? "non-literal event" : `"${event}"`}, ...)`, args[0], `${RL_EVENT_LIST} are the supported readline events`);
|
|
155
350
|
}
|
|
156
351
|
if (!ts.isExpressionStatement(call.parent)) {
|
|
157
352
|
lowerer.unsupported("SC1090", call, "chaining readline listener registration (register each listener as its own statement)");
|
|
158
353
|
}
|
|
159
354
|
const recv = receiver();
|
|
160
355
|
const cb = lowerer.lowerExpr(args[1]);
|
|
161
|
-
const want = event === "line"
|
|
356
|
+
const want = event === "line"
|
|
357
|
+
? "string"
|
|
358
|
+
: event === "error"
|
|
359
|
+
? "error"
|
|
360
|
+
: event === "history"
|
|
361
|
+
? "history"
|
|
362
|
+
: null;
|
|
162
363
|
const param = cb.type.kind === "func" ? cb.type.params[0] : undefined;
|
|
163
364
|
const paramOk = param === undefined ||
|
|
164
365
|
(want !== null && param.kind === "dyn") ||
|
|
165
366
|
(want === "string" && param.kind === "string") ||
|
|
166
|
-
(want === "error" && param.kind === "object" && param.className === "Error")
|
|
367
|
+
(want === "error" && param.kind === "object" && param.className === "Error") ||
|
|
368
|
+
(want === "history" && param.kind === "array" && param.elem.kind === "string");
|
|
167
369
|
if (cb.type.kind !== "func" ||
|
|
168
370
|
cb.type.ret.kind !== "void" ||
|
|
169
371
|
cb.type.params.length > (want === null ? 0 : 1) ||
|
|
@@ -172,7 +374,9 @@ export function lowerReadlineMethodCall(lowerer, call, access) {
|
|
|
172
374
|
? "'line' listeners other than (input: string) => void"
|
|
173
375
|
: want === "error"
|
|
174
376
|
? "'error' listeners other than (err: Error) => void"
|
|
175
|
-
:
|
|
377
|
+
: want === "history"
|
|
378
|
+
? "'history' listeners other than (history: string[]) => void"
|
|
379
|
+
: `'${event}' listeners with parameters or a return value (use ())`);
|
|
176
380
|
}
|
|
177
381
|
return {
|
|
178
382
|
kind: "libCall",
|
|
@@ -182,7 +386,338 @@ export function lowerReadlineMethodCall(lowerer, call, access) {
|
|
|
182
386
|
loc,
|
|
183
387
|
};
|
|
184
388
|
}
|
|
185
|
-
lowerer.noLowering(`readline.Interface.${name}`, call,
|
|
389
|
+
lowerer.noLowering(`readline.Interface.${name}`, call, `question, close, pause, resume, prompt, setPrompt, getPrompt, write, for await, and on/once for ${RL_EVENT_LIST.replace(/"/g, "'")} are the supported Interface members`, lowerer.checker.getSymbolAtLocation(access.name));
|
|
390
|
+
}
|
|
391
|
+
function isNullish(node) {
|
|
392
|
+
return (node.kind === ts.SyntaxKind.NullKeyword || (ts.isIdentifier(node) && node.text === "undefined"));
|
|
393
|
+
}
|
|
394
|
+
/** write(data, key): data a string, null or undefined; key an object
|
|
395
|
+
* literal of name, ctrl, meta and shift. rl.writeKey's arguments: the
|
|
396
|
+
* interface, whether data is present, the data, whether the key is, whether
|
|
397
|
+
* its name is, the name and the three flags. */
|
|
398
|
+
function lowerWriteKey(lowerer, recv, dataNode, keyNode, loc) {
|
|
399
|
+
const empty = { kind: "strLit", value: "", type: STRING, loc };
|
|
400
|
+
const hasData = !isNullish(dataNode);
|
|
401
|
+
const data = hasData ? lowerer.lowerExprExpecting(dataNode, STRING) : empty;
|
|
402
|
+
let hasKey = false;
|
|
403
|
+
let hasName = false;
|
|
404
|
+
let keyName = empty;
|
|
405
|
+
const flags = {
|
|
406
|
+
ctrl: boolLit(false, loc),
|
|
407
|
+
meta: boolLit(false, loc),
|
|
408
|
+
shift: boolLit(false, loc),
|
|
409
|
+
};
|
|
410
|
+
if (keyNode !== undefined && !isNullish(keyNode)) {
|
|
411
|
+
if (!ts.isObjectLiteralExpression(keyNode)) {
|
|
412
|
+
lowerer.noLowering("readline write() with a key that is not an object literal", keyNode, "write the key inline: write(null, { ctrl: true, name: 'u' })");
|
|
413
|
+
}
|
|
414
|
+
hasKey = true;
|
|
415
|
+
for (const p of keyNode.properties) {
|
|
416
|
+
const member = ts.isPropertyAssignment(p) && ts.isIdentifier(p.name) ? p.name.text : null;
|
|
417
|
+
const value = member !== null ? p.initializer : null;
|
|
418
|
+
if (member === "name" && value !== null && !isNullish(value)) {
|
|
419
|
+
hasName = true;
|
|
420
|
+
keyName = lowerer.lowerExprExpecting(value, STRING);
|
|
421
|
+
}
|
|
422
|
+
else if (member === "name") {
|
|
423
|
+
// an undefined name is no name
|
|
424
|
+
}
|
|
425
|
+
else if (member !== null && value !== null && flags[member] !== undefined) {
|
|
426
|
+
if (!(lowerer.typeOf(value).flags & ts.TypeFlags.BooleanLike)) {
|
|
427
|
+
lowerer.noLowering(`a readline write() key '${member}' that is not a boolean`, value);
|
|
428
|
+
}
|
|
429
|
+
flags[member] = lowerer.lowerExprExpecting(value, BOOL);
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
lowerer.noLowering("readline write() with this key member", p, "name, ctrl, meta and shift are the supported key members");
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
kind: "libCall",
|
|
438
|
+
fn: "rl.writeKey",
|
|
439
|
+
args: [
|
|
440
|
+
recv,
|
|
441
|
+
boolLit(hasData, loc),
|
|
442
|
+
data,
|
|
443
|
+
boolLit(hasKey, loc),
|
|
444
|
+
boolLit(hasName, loc),
|
|
445
|
+
keyName,
|
|
446
|
+
flags.ctrl,
|
|
447
|
+
flags.meta,
|
|
448
|
+
flags.shift,
|
|
449
|
+
],
|
|
450
|
+
type: VOID,
|
|
451
|
+
loc,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/** readline.emitKeypressEvents(stream[, interface]): process.stdin or a
|
|
455
|
+
* readable stream; the interface is a readline Interface or an object
|
|
456
|
+
* literal with escapeCodeTimeout. rl.keypressStdin / rl.keypressStream
|
|
457
|
+
* take the interface handle (0 for none) and the timeout (NaN: the
|
|
458
|
+
* interface's, or 500). */
|
|
459
|
+
function lowerEmitKeypressEvents(lowerer, expr, loc) {
|
|
460
|
+
const args = expr.arguments;
|
|
461
|
+
if (args.length < 1 || args.length > 2 || args.some(ts.isSpreadElement)) {
|
|
462
|
+
lowerer.noLowering(`readline.emitKeypressEvents with ${args.length} arguments`, expr);
|
|
463
|
+
}
|
|
464
|
+
const stmts = [];
|
|
465
|
+
const streamNode = args[0];
|
|
466
|
+
let stream = null;
|
|
467
|
+
const stdin = ts.isPropertyAccessExpression(streamNode) &&
|
|
468
|
+
lowerer.stdlibGlobalMember(streamNode, "process") === "stdin";
|
|
469
|
+
if (!stdin) {
|
|
470
|
+
stream = lowerer.lowerExpr(streamNode);
|
|
471
|
+
const info = stream.type.kind === "object" ? lowerer.classes.get(stream.type.className) : undefined;
|
|
472
|
+
const sides = streamSidesOf(lowerer, info);
|
|
473
|
+
if (sides !== "r" && sides !== "rw") {
|
|
474
|
+
lowerer.noLowering("readline.emitKeypressEvents with this stream", streamNode, "process.stdin and readable streams are the supported streams");
|
|
475
|
+
}
|
|
476
|
+
const l = lowerer.declareHiddenLocal("%rlStream", stream.type);
|
|
477
|
+
stmts.push({ kind: "varDecl", localId: l.id, init: stream, loc });
|
|
478
|
+
stream = { kind: "varRef", localId: l.id, type: stream.type, loc };
|
|
479
|
+
}
|
|
480
|
+
let iface = numLit(0, loc);
|
|
481
|
+
let timeout = numLit(NaN, loc);
|
|
482
|
+
const ifaceNode = args[1];
|
|
483
|
+
if (ifaceNode !== undefined && !isNullish(ifaceNode)) {
|
|
484
|
+
if (isReadlineTyped(lowerer, ifaceNode)) {
|
|
485
|
+
iface = lowerer.lowerExprExpecting(ifaceNode, F64);
|
|
486
|
+
}
|
|
487
|
+
else if (ts.isObjectLiteralExpression(ifaceNode)) {
|
|
488
|
+
for (const p of ifaceNode.properties) {
|
|
489
|
+
if (ts.isPropertyAssignment(p) &&
|
|
490
|
+
ts.isIdentifier(p.name) &&
|
|
491
|
+
p.name.text === "escapeCodeTimeout" &&
|
|
492
|
+
lowerer.typeOf(p.initializer).flags & ts.TypeFlags.NumberLike) {
|
|
493
|
+
timeout = lowerer.lowerExprExpecting(p.initializer, F64);
|
|
494
|
+
}
|
|
495
|
+
else {
|
|
496
|
+
lowerer.noLowering("readline.emitKeypressEvents with this interface member", p, "a number escapeCodeTimeout is the supported member");
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
lowerer.noLowering("readline.emitKeypressEvents with this interface", ifaceNode, "pass a readline Interface or { escapeCodeTimeout }");
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const call = stream === null
|
|
505
|
+
? { kind: "libCall", fn: "rl.keypressStdin", args: [iface, timeout], type: VOID, loc }
|
|
506
|
+
: {
|
|
507
|
+
kind: "libCall",
|
|
508
|
+
fn: "rl.keypressStream",
|
|
509
|
+
args: [stream, iface, timeout],
|
|
510
|
+
type: VOID,
|
|
511
|
+
loc,
|
|
512
|
+
};
|
|
513
|
+
return stmts.length === 0 ? call : { kind: "seqExpr", stmts, result: call, type: VOID, loc };
|
|
514
|
+
}
|
|
515
|
+
/** Checks a 'keypress' listener (process.stdin or a readable stream): the
|
|
516
|
+
* first argument is undefined for escape sequences, so a typed first
|
|
517
|
+
* parameter must admit undefined, and the key is readline.Key. */
|
|
518
|
+
export function checkKeypressListener(lowerer, node, cb) {
|
|
519
|
+
if (cb.type.kind === "dyn")
|
|
520
|
+
return;
|
|
521
|
+
if (cb.type.kind !== "func" || cb.type.params.length > 2) {
|
|
522
|
+
lowerer.noLowering("'keypress' listeners with more than two parameters", node, "(str, key) => void listeners are supported");
|
|
523
|
+
}
|
|
524
|
+
const first = cb.type.params[0];
|
|
525
|
+
if (first !== undefined && first.kind !== "dyn") {
|
|
526
|
+
const def = first.kind === "union" ? lowerer.unions.get(first.unionId) : undefined;
|
|
527
|
+
const ok = !!def &&
|
|
528
|
+
def.arms.some((a) => a.kind === "undefinedT") &&
|
|
529
|
+
def.arms.every((a) => a.kind === "undefinedT" || a.kind === "string");
|
|
530
|
+
if (!ok) {
|
|
531
|
+
lowerer.noLowering(`a 'keypress' listener whose first parameter is '${lowerer.fmt(first)}'`, node, "the first argument is undefined for escape sequences — declare it as string | undefined");
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
const second = cb.type.params[1];
|
|
535
|
+
if (second !== undefined && second.kind !== "dyn") {
|
|
536
|
+
lowerer.noLowering(`a 'keypress' listener whose second parameter is '${lowerer.fmt(second)}'`, node, "declare the key as readline.Key");
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
/** process.stdin's 'keypress' listener as the checked-dynamic function the
|
|
540
|
+
* runtime calls with (str, key). */
|
|
541
|
+
export function stdinKeypressListener(lowerer, node) {
|
|
542
|
+
const cb = lowerer.lowerExpr(node);
|
|
543
|
+
checkKeypressListener(lowerer, node, cb);
|
|
544
|
+
return lowerer.coerceToExpected(cb, DYN);
|
|
545
|
+
}
|
|
546
|
+
const CURSOR_HELPERS = {
|
|
547
|
+
cursorTo: 0,
|
|
548
|
+
moveCursor: 1,
|
|
549
|
+
clearLine: 2,
|
|
550
|
+
clearScreenDown: 3,
|
|
551
|
+
};
|
|
552
|
+
/** readline.cursorTo(stream, x[, y][, callback]), moveCursor(stream, dx,
|
|
553
|
+
* dy[, callback]), clearLine(stream, dir[, callback]) and
|
|
554
|
+
* clearScreenDown(stream[, callback]). The stream is process.stdout,
|
|
555
|
+
* process.stderr, a writable stream, or null/undefined (nothing is
|
|
556
|
+
* written and the callback runs on the next tick). The arguments are
|
|
557
|
+
* evaluated in order; rl.seq checks them (NaN coordinates throw
|
|
558
|
+
* ERR_INVALID_ARG_VALUE) and builds the escape sequence, which goes
|
|
559
|
+
* through the stream's own write. The result is write()'s boolean, or
|
|
560
|
+
* true. */
|
|
561
|
+
export function lowerReadlineCursorCall(lowerer, expr, member, loc) {
|
|
562
|
+
if (member === "emitKeypressEvents")
|
|
563
|
+
return lowerEmitKeypressEvents(lowerer, expr, loc);
|
|
564
|
+
const kind = CURSOR_HELPERS[member];
|
|
565
|
+
if (kind === undefined)
|
|
566
|
+
return null;
|
|
567
|
+
const args = [...expr.arguments];
|
|
568
|
+
if (args.some(ts.isSpreadElement)) {
|
|
569
|
+
lowerer.noLowering(`readline.${member} with a spread argument`, expr);
|
|
570
|
+
}
|
|
571
|
+
const numbers = kind === 0 ? 2 : kind === 1 ? 2 : kind === 2 ? 1 : 0;
|
|
572
|
+
const isFunc = (n) => lowerer.mapTypeOf(lowerer.typeOf(n))?.kind === "func";
|
|
573
|
+
// cursorTo(stream, x, callback): the third argument is the callback
|
|
574
|
+
let numberNodes = args.slice(1, 1 + numbers);
|
|
575
|
+
let cbNode = args[1 + numbers];
|
|
576
|
+
if (kind === 0 && args[2] !== undefined && isFunc(args[2])) {
|
|
577
|
+
numberNodes = [args[1]];
|
|
578
|
+
cbNode = args[2];
|
|
579
|
+
}
|
|
580
|
+
if (args.length > 2 + numbers || args.length < 1 + (kind === 0 ? 1 : numbers)) {
|
|
581
|
+
lowerer.noLowering(`readline.${member} with ${args.length} arguments`, expr);
|
|
582
|
+
}
|
|
583
|
+
if (cbNode !== undefined && isNullish(cbNode))
|
|
584
|
+
cbNode = undefined;
|
|
585
|
+
const stmts = [];
|
|
586
|
+
const hold = (name, value) => {
|
|
587
|
+
const l = lowerer.declareHiddenLocal(name, value.type);
|
|
588
|
+
stmts.push({ kind: "varDecl", localId: l.id, init: value, loc });
|
|
589
|
+
return { kind: "varRef", localId: l.id, type: value.type, loc };
|
|
590
|
+
};
|
|
591
|
+
// the stream
|
|
592
|
+
const streamNode = args[0];
|
|
593
|
+
let target;
|
|
594
|
+
const proc = ts.isPropertyAccessExpression(streamNode) && lowerer.stdlibGlobalMember(streamNode, "process");
|
|
595
|
+
if (proc === "stdout" || proc === "stderr") {
|
|
596
|
+
target = proc;
|
|
597
|
+
}
|
|
598
|
+
else if (isNullish(streamNode)) {
|
|
599
|
+
target = "none";
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
const v = lowerer.lowerExpr(streamNode);
|
|
603
|
+
const info = v.type.kind === "object" ? lowerer.classes.get(v.type.className) : undefined;
|
|
604
|
+
const sides = streamSidesOf(lowerer, info);
|
|
605
|
+
if (sides !== "w" && sides !== "rw") {
|
|
606
|
+
lowerer.noLowering(`readline.${member} with this stream`, streamNode, "process.stdout, process.stderr, writable streams, null and undefined are the supported streams");
|
|
607
|
+
}
|
|
608
|
+
target = hold("%rlStream", v);
|
|
609
|
+
}
|
|
610
|
+
// the coordinates (cursorTo's x may be left undefined: then nothing is
|
|
611
|
+
// written, or ERR_INVALID_CURSOR_POS when y is given)
|
|
612
|
+
const values = [];
|
|
613
|
+
let hasB = false;
|
|
614
|
+
let noX = false;
|
|
615
|
+
for (let i = 0; i < numberNodes.length; i++) {
|
|
616
|
+
const n = numberNodes[i];
|
|
617
|
+
if (kind === 0 && isNullish(n)) {
|
|
618
|
+
if (i === 0) {
|
|
619
|
+
noX = true;
|
|
620
|
+
values.push(numLit(0, loc));
|
|
621
|
+
}
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
if (!(lowerer.typeOf(n).flags & ts.TypeFlags.NumberLike)) {
|
|
625
|
+
lowerer.noLowering(`readline.${member} with an argument that is not a number`, n);
|
|
626
|
+
}
|
|
627
|
+
values.push(hold("%rlArg", lowerer.lowerExprExpecting(n, F64)));
|
|
628
|
+
if (i === 1)
|
|
629
|
+
hasB = true;
|
|
630
|
+
}
|
|
631
|
+
// the callback: () => void, as the lib declares it
|
|
632
|
+
let cb = null;
|
|
633
|
+
if (cbNode !== undefined) {
|
|
634
|
+
const c = lowerer.lowerExpr(cbNode);
|
|
635
|
+
if (c.type.kind !== "func" || c.type.params.length > 0 || c.type.ret.kind !== "void") {
|
|
636
|
+
lowerer.noLowering(`readline.${member} callbacks with parameters or a return value`, cbNode, "() => void callbacks are supported");
|
|
637
|
+
}
|
|
638
|
+
cb = hold("%rlCallback", target === "stdout" || target === "stderr" ? voidizedCallback(lowerer, c, loc) : c);
|
|
639
|
+
}
|
|
640
|
+
const seqKind = noX && hasB && target !== "none" ? 4 : kind;
|
|
641
|
+
const seq = hold("%rlSeq", {
|
|
642
|
+
kind: "libCall",
|
|
643
|
+
fn: "rl.seq",
|
|
644
|
+
args: [
|
|
645
|
+
numLit(seqKind, loc),
|
|
646
|
+
values[0] ?? numLit(0, loc),
|
|
647
|
+
values[1] ?? numLit(0, loc),
|
|
648
|
+
boolLit(hasB, loc),
|
|
649
|
+
],
|
|
650
|
+
type: STRING,
|
|
651
|
+
loc,
|
|
652
|
+
});
|
|
653
|
+
const skipped = () => {
|
|
654
|
+
const later = cb
|
|
655
|
+
? [
|
|
656
|
+
{
|
|
657
|
+
kind: "exprStmt",
|
|
658
|
+
expr: { kind: "libCall", fn: "process.nextTick", args: [cb], type: VOID, loc },
|
|
659
|
+
loc,
|
|
660
|
+
},
|
|
661
|
+
]
|
|
662
|
+
: [];
|
|
663
|
+
return { kind: "seqExpr", stmts: later, result: boolLit(true, loc), type: BOOL, loc };
|
|
664
|
+
};
|
|
665
|
+
let result;
|
|
666
|
+
if (target === "none" || (noX && !hasB)) {
|
|
667
|
+
result = skipped();
|
|
668
|
+
}
|
|
669
|
+
else {
|
|
670
|
+
let write;
|
|
671
|
+
if (target === "stdout" || target === "stderr") {
|
|
672
|
+
const utf8 = { kind: "strLit", value: "utf8", type: STRING, loc };
|
|
673
|
+
write = cb
|
|
674
|
+
? {
|
|
675
|
+
kind: "libCall",
|
|
676
|
+
fn: target === "stdout" ? "process.stdoutWriteBytesCb" : "process.stderrWriteBytesCb",
|
|
677
|
+
args: [
|
|
678
|
+
{ kind: "libCall", fn: "buffer.fromStr", args: [seq, utf8], type: BYTES_U8, loc },
|
|
679
|
+
utf8,
|
|
680
|
+
cb,
|
|
681
|
+
],
|
|
682
|
+
type: BOOL,
|
|
683
|
+
loc,
|
|
684
|
+
}
|
|
685
|
+
: {
|
|
686
|
+
kind: "libCall",
|
|
687
|
+
fn: target === "stdout" ? "process.stdoutWrite" : "process.stderrWrite",
|
|
688
|
+
args: [seq],
|
|
689
|
+
type: BOOL,
|
|
690
|
+
loc,
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
else {
|
|
694
|
+
write = {
|
|
695
|
+
kind: "libCall",
|
|
696
|
+
fn: "writable.writeStr",
|
|
697
|
+
args: cb ? [target, seq, cb] : [target, seq],
|
|
698
|
+
type: BOOL,
|
|
699
|
+
loc,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
result =
|
|
703
|
+
kind === 1
|
|
704
|
+
? {
|
|
705
|
+
kind: "ternary",
|
|
706
|
+
cond: {
|
|
707
|
+
kind: "libCall",
|
|
708
|
+
fn: "rl.moves",
|
|
709
|
+
args: [values[0], values[1]],
|
|
710
|
+
type: BOOL,
|
|
711
|
+
loc,
|
|
712
|
+
},
|
|
713
|
+
then: write,
|
|
714
|
+
else_: skipped(),
|
|
715
|
+
type: BOOL,
|
|
716
|
+
loc,
|
|
717
|
+
}
|
|
718
|
+
: write;
|
|
719
|
+
}
|
|
720
|
+
return { kind: "seqExpr", stmts, result, type: BOOL, loc };
|
|
186
721
|
}
|
|
187
722
|
/** The interface's input: process.stdin (null) or a readable stream. */
|
|
188
723
|
function lowerInput(lowerer, node) {
|
|
@@ -217,31 +752,84 @@ function lowerOutput(lowerer, node) {
|
|
|
217
752
|
}
|
|
218
753
|
return v;
|
|
219
754
|
}
|
|
220
|
-
/** createInterface({ input, output?, terminal
|
|
221
|
-
*
|
|
222
|
-
* node:readline or node:readline/promises. The input is process.stdin
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
* the prompt and the signal when present.
|
|
228
|
-
|
|
755
|
+
/** createInterface({ input, output?, terminal?, crlfDelay?, prompt?,
|
|
756
|
+
* signal?, ... }) or createInterface(input, output?, completer?,
|
|
757
|
+
* terminal?), from node:readline or node:readline/promises. The input is process.stdin or a readable
|
|
758
|
+
* stream; the output process.stdout, a writable stream, or absent
|
|
759
|
+
* (prompts are then not written). rl.create's arguments: the mode literal
|
|
760
|
+
* (1 stream input, 2 stream output, 4 stdout output, 8 signal, 16
|
|
761
|
+
* prompt), then the input and output streams when present, crlfDelay,
|
|
762
|
+
* the prompt and the signal when present. An interface that can be a
|
|
763
|
+
* terminal one (a `terminal` option that is not false, or none with
|
|
764
|
+
* process.stdout as the output, which is a terminal when it is a TTY)
|
|
765
|
+
* goes through rl.terminal with the completer. */
|
|
766
|
+
export function lowerReadlineCreateCall(lowerer, expr, loc, promises) {
|
|
229
767
|
let input = null;
|
|
230
768
|
let output = "none";
|
|
231
769
|
let crlf = numLit(0, loc);
|
|
232
770
|
let prompt = null;
|
|
233
771
|
let signal = null;
|
|
772
|
+
// the history and editing options (scr_rl_check_options' flags)
|
|
773
|
+
let tabSize = null;
|
|
774
|
+
let escapeTimeout = null;
|
|
775
|
+
let historySize = null;
|
|
776
|
+
let history = null;
|
|
777
|
+
let removeDups = null;
|
|
778
|
+
let completer = null;
|
|
779
|
+
let completerValue = null; // set in setCompleter
|
|
780
|
+
let completerAt = -1;
|
|
781
|
+
// the terminal option: null when absent, else the boolean (a literal
|
|
782
|
+
// false drops it)
|
|
783
|
+
let terminal = null; // set in setTerminal
|
|
784
|
+
let terminalFalse = false;
|
|
785
|
+
const pre = [];
|
|
786
|
+
// Only terminal interfaces call the completer. A checked-dynamic value
|
|
787
|
+
// must be callable (Node's ERR_INVALID_ARG_VALUE, after the history
|
|
788
|
+
// checks); a function is not checked. The slot in `pre` is filled once
|
|
789
|
+
// the terminal mode is known.
|
|
790
|
+
const setCompleter = (value) => {
|
|
791
|
+
completerValue = lowerer.lowerExpr(value);
|
|
792
|
+
completerAt = pre.length;
|
|
793
|
+
pre.push({ kind: "exprStmt", expr: completerValue, loc });
|
|
794
|
+
};
|
|
795
|
+
const setTerminal = (value) => {
|
|
796
|
+
if (isNullish(value))
|
|
797
|
+
return;
|
|
798
|
+
if (value.kind === ts.SyntaxKind.FalseKeyword) {
|
|
799
|
+
terminalFalse = true;
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (!(lowerer.typeOf(value).flags & ts.TypeFlags.BooleanLike)) {
|
|
803
|
+
lowerer.noLowering("the createInterface option 'terminal' with a value that is not a boolean", value);
|
|
804
|
+
}
|
|
805
|
+
const local = lowerer.declareHiddenLocal("%rlTerminal", BOOL);
|
|
806
|
+
pre.push({
|
|
807
|
+
kind: "varDecl",
|
|
808
|
+
localId: local.id,
|
|
809
|
+
init: lowerer.lowerExprExpecting(value, BOOL),
|
|
810
|
+
loc,
|
|
811
|
+
});
|
|
812
|
+
terminal = { kind: "varRef", localId: local.id, type: BOOL, loc };
|
|
813
|
+
};
|
|
234
814
|
const optsNode = expr.arguments[0];
|
|
235
815
|
if (optsNode === undefined) {
|
|
236
816
|
lowerer.noLowering("createInterface without arguments", expr, "pass { input: process.stdin, output: process.stdout } or createInterface(input, output)");
|
|
237
817
|
}
|
|
238
818
|
if (!ts.isObjectLiteralExpression(optsNode)) {
|
|
239
|
-
|
|
240
|
-
|
|
819
|
+
// createInterface(input, output?, completer?, terminal?)
|
|
820
|
+
if (expr.arguments.length > 4) {
|
|
821
|
+
lowerer.noLowering(`createInterface with ${expr.arguments.length} arguments`, expr.arguments[4], "pass createInterface(input, output, completer, terminal) or one options object");
|
|
241
822
|
}
|
|
242
823
|
input = lowerInput(lowerer, optsNode);
|
|
243
824
|
if (expr.arguments[1] !== undefined)
|
|
244
825
|
output = lowerOutput(lowerer, expr.arguments[1]);
|
|
826
|
+
const completerNode = expr.arguments[2];
|
|
827
|
+
if (completerNode !== undefined &&
|
|
828
|
+
!(ts.isIdentifier(completerNode) && completerNode.text === "undefined")) {
|
|
829
|
+
setCompleter(completerNode);
|
|
830
|
+
}
|
|
831
|
+
if (expr.arguments[3] !== undefined)
|
|
832
|
+
setTerminal(expr.arguments[3]);
|
|
245
833
|
}
|
|
246
834
|
else {
|
|
247
835
|
if (expr.arguments.length > 1) {
|
|
@@ -249,38 +837,67 @@ export function lowerReadlineCreateCall(lowerer, expr, loc) {
|
|
|
249
837
|
}
|
|
250
838
|
let sawInput = false;
|
|
251
839
|
for (const p of optsNode.properties) {
|
|
252
|
-
|
|
253
|
-
|
|
840
|
+
const shorthand = ts.isShorthandPropertyAssignment(p);
|
|
841
|
+
if (!(shorthand || (ts.isPropertyAssignment(p) && ts.isIdentifier(p.name)))) {
|
|
842
|
+
lowerer.noLowering("createInterface with this options shape", p, "spreads and computed keys have no lowering — write each member inline");
|
|
254
843
|
}
|
|
255
844
|
const member = p.name.text;
|
|
845
|
+
// `{ input }` reads the binding of the same name
|
|
846
|
+
const value = shorthand
|
|
847
|
+
? p.name
|
|
848
|
+
: p.initializer;
|
|
849
|
+
const numeric = () => {
|
|
850
|
+
if (!(lowerer.typeOf(value).flags & ts.TypeFlags.NumberLike)) {
|
|
851
|
+
lowerer.noLowering(`the createInterface option '${member}' with a value that is not a number`, value);
|
|
852
|
+
}
|
|
853
|
+
return lowerer.lowerExprExpecting(value, F64);
|
|
854
|
+
};
|
|
256
855
|
if (member === "input") {
|
|
257
|
-
input = lowerInput(lowerer,
|
|
856
|
+
input = lowerInput(lowerer, value);
|
|
258
857
|
sawInput = true;
|
|
259
858
|
}
|
|
260
859
|
else if (member === "output") {
|
|
261
|
-
output = lowerOutput(lowerer,
|
|
860
|
+
output = lowerOutput(lowerer, value);
|
|
262
861
|
}
|
|
263
|
-
else if (member === "
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
862
|
+
else if (member === "tabSize") {
|
|
863
|
+
tabSize = numeric();
|
|
864
|
+
}
|
|
865
|
+
else if (member === "escapeCodeTimeout") {
|
|
866
|
+
escapeTimeout = numeric();
|
|
867
|
+
}
|
|
868
|
+
else if (member === "historySize") {
|
|
869
|
+
historySize = numeric();
|
|
870
|
+
}
|
|
871
|
+
else if (member === "history") {
|
|
872
|
+
const h = lowerer.lowerExpr(value);
|
|
873
|
+
if (h.type.kind !== "array" || h.type.elem.kind !== "string") {
|
|
874
|
+
lowerer.noLowering("createInterface with a history that is not a string array", value, "pass the history as a string[]");
|
|
875
|
+
}
|
|
876
|
+
history = h;
|
|
877
|
+
}
|
|
878
|
+
else if (member === "removeHistoryDuplicates") {
|
|
879
|
+
if (!(lowerer.typeOf(value).flags & ts.TypeFlags.BooleanLike)) {
|
|
880
|
+
lowerer.noLowering("the createInterface option 'removeHistoryDuplicates' with a value that is not a boolean", value);
|
|
268
881
|
}
|
|
882
|
+
removeDups = lowerer.lowerExprExpecting(value, BOOL);
|
|
883
|
+
}
|
|
884
|
+
else if (member === "completer") {
|
|
885
|
+
setCompleter(value);
|
|
886
|
+
}
|
|
887
|
+
else if (member === "terminal") {
|
|
888
|
+
setTerminal(value);
|
|
269
889
|
}
|
|
270
890
|
else if (member === "crlfDelay") {
|
|
271
|
-
crlf = lowerer.lowerExprExpecting(
|
|
891
|
+
crlf = lowerer.lowerExprExpecting(value, F64);
|
|
272
892
|
}
|
|
273
893
|
else if (member === "prompt") {
|
|
274
|
-
prompt = lowerer.lowerExprExpecting(
|
|
894
|
+
prompt = lowerer.lowerExprExpecting(value, STRING);
|
|
275
895
|
}
|
|
276
896
|
else if (member === "signal") {
|
|
277
|
-
signal = lowerer.lowerExprExpecting(
|
|
278
|
-
}
|
|
279
|
-
else if (member === "completer") {
|
|
280
|
-
lowerer.noLowering("createInterface with a completer", p, "tab completion needs an interactive terminal — the lowered interface reads piped lines (terminal: false)");
|
|
897
|
+
signal = lowerer.lowerExprExpecting(value, DYN);
|
|
281
898
|
}
|
|
282
899
|
else {
|
|
283
|
-
fenceOrDropOptionKey(lowerer, p, member, "createInterface", READLINE_DOCUMENTED_OPTIONS, "input, output, terminal
|
|
900
|
+
fenceOrDropOptionKey(lowerer, p, member, "createInterface", READLINE_DOCUMENTED_OPTIONS, "input, output, terminal, crlfDelay, prompt, signal, history, historySize, removeHistoryDuplicates, completer, tabSize and escapeCodeTimeout are the supported options");
|
|
284
901
|
// An undocumented key, dropped like Node drops it.
|
|
285
902
|
}
|
|
286
903
|
}
|
|
@@ -303,12 +920,160 @@ export function lowerReadlineCreateCall(lowerer, expr, loc) {
|
|
|
303
920
|
args.push(prompt);
|
|
304
921
|
if (signal !== null)
|
|
305
922
|
args.push(signal);
|
|
306
|
-
|
|
923
|
+
const create = {
|
|
307
924
|
kind: "libCall",
|
|
308
925
|
fn: signal !== null ? "rl.createSignal" : "rl.create",
|
|
309
926
|
args,
|
|
310
927
|
type: F64,
|
|
311
928
|
loc,
|
|
312
929
|
};
|
|
930
|
+
// terminal mode: 0 the option's value, 2 output.isTTY of process.stdout
|
|
931
|
+
const terminalMode = terminal !== null ? 0 : !terminalFalse && output === "stdout" ? 2 : null;
|
|
932
|
+
// The completer is kept as a checked-dynamic value when the interface
|
|
933
|
+
// can be a terminal one; a function is otherwise only evaluated.
|
|
934
|
+
let completerChecked = false;
|
|
935
|
+
if (completerValue !== null && (terminalMode !== null || completerValue.type.kind !== "func")) {
|
|
936
|
+
const local = lowerer.declareHiddenLocal("%rlCompleter", DYN);
|
|
937
|
+
pre[completerAt] = {
|
|
938
|
+
kind: "varDecl",
|
|
939
|
+
localId: local.id,
|
|
940
|
+
init: lowerer.coerceToExpected(completerValue, DYN),
|
|
941
|
+
loc,
|
|
942
|
+
};
|
|
943
|
+
completer = { kind: "varRef", localId: local.id, type: DYN, loc };
|
|
944
|
+
completerChecked = completerValue.type.kind !== "func";
|
|
945
|
+
}
|
|
946
|
+
if (pre.length === 0 &&
|
|
947
|
+
!tabSize &&
|
|
948
|
+
!escapeTimeout &&
|
|
949
|
+
!historySize &&
|
|
950
|
+
!history &&
|
|
951
|
+
!removeDups &&
|
|
952
|
+
!completer &&
|
|
953
|
+
terminalMode === null) {
|
|
954
|
+
return create;
|
|
955
|
+
}
|
|
956
|
+
// The numeric options are evaluated once, checked in Node's order
|
|
957
|
+
// before the interface opens, then stored on it with the history.
|
|
958
|
+
const stmts = [...pre];
|
|
959
|
+
const temp = (name, v) => {
|
|
960
|
+
if (v === null)
|
|
961
|
+
return numLit(0, loc);
|
|
962
|
+
const l = lowerer.declareHiddenLocal(name, F64);
|
|
963
|
+
stmts.push({ kind: "varDecl", localId: l.id, init: v, loc });
|
|
964
|
+
return { kind: "varRef", localId: l.id, type: F64, loc };
|
|
965
|
+
};
|
|
966
|
+
const flags = (tabSize ? 1 : 0) | (escapeTimeout ? 2 : 0) | (historySize ? 4 : 0);
|
|
967
|
+
const tab = temp("%rlTabSize", tabSize);
|
|
968
|
+
const esc = temp("%rlEscapeCodeTimeout", escapeTimeout);
|
|
969
|
+
const size = temp("%rlHistorySize", historySize);
|
|
970
|
+
if (flags !== 0) {
|
|
971
|
+
stmts.push({
|
|
972
|
+
kind: "exprStmt",
|
|
973
|
+
expr: {
|
|
974
|
+
kind: "libCall",
|
|
975
|
+
fn: "rl.checkOptions",
|
|
976
|
+
args: [numLit(flags, loc), tab, esc, size],
|
|
977
|
+
type: VOID,
|
|
978
|
+
loc,
|
|
979
|
+
},
|
|
980
|
+
loc,
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
if (completer && completerChecked) {
|
|
984
|
+
stmts.push({
|
|
985
|
+
kind: "exprStmt",
|
|
986
|
+
expr: { kind: "libCall", fn: "rl.checkCompleter", args: [completer], type: VOID, loc },
|
|
987
|
+
loc,
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
const id = lowerer.declareHiddenLocal("%rl", F64);
|
|
991
|
+
const idRef = { kind: "varRef", localId: id.id, type: F64, loc };
|
|
992
|
+
stmts.push({ kind: "varDecl", localId: id.id, init: create, loc });
|
|
993
|
+
stmts.push({
|
|
994
|
+
kind: "exprStmt",
|
|
995
|
+
expr: {
|
|
996
|
+
kind: "libCall",
|
|
997
|
+
fn: "rl.setOptions",
|
|
998
|
+
args: [idRef, numLit(flags, loc), size, removeDups ?? boolLit(false, loc), tab, esc],
|
|
999
|
+
type: VOID,
|
|
1000
|
+
loc,
|
|
1001
|
+
},
|
|
1002
|
+
loc,
|
|
1003
|
+
});
|
|
1004
|
+
if (history) {
|
|
1005
|
+
stmts.push({
|
|
1006
|
+
kind: "exprStmt",
|
|
1007
|
+
expr: { kind: "libCall", fn: "rl.setHistory", args: [idRef, history], type: VOID, loc },
|
|
1008
|
+
loc,
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
if (terminalMode !== null) {
|
|
1012
|
+
stmts.push({
|
|
1013
|
+
kind: "exprStmt",
|
|
1014
|
+
expr: {
|
|
1015
|
+
kind: "libCall",
|
|
1016
|
+
fn: "rl.terminal",
|
|
1017
|
+
args: [
|
|
1018
|
+
idRef,
|
|
1019
|
+
numLit(terminalMode, loc),
|
|
1020
|
+
terminal ?? boolLit(false, loc),
|
|
1021
|
+
completer ?? dynUndefinedExpr(loc),
|
|
1022
|
+
boolLit(promises, loc),
|
|
1023
|
+
],
|
|
1024
|
+
type: VOID,
|
|
1025
|
+
loc,
|
|
1026
|
+
},
|
|
1027
|
+
loc,
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
return { kind: "seqExpr", stmts, result: idRef, type: F64, loc };
|
|
1031
|
+
}
|
|
1032
|
+
/** Property reads on an Interface: `history` (the history option itself,
|
|
1033
|
+
* or the interface's own empty array), `historySize`, `historyIndex`,
|
|
1034
|
+
* `crlfDelay`, `tabSize`, `escapeCodeTimeout`, `line`, `terminal` and
|
|
1035
|
+
* `cursor` (a non-terminal interface's undefined cursor throws SC2020).
|
|
1036
|
+
* Null for other receivers. */
|
|
1037
|
+
export function lowerReadlineProperty(lowerer, access) {
|
|
1038
|
+
if (access.questionDotToken)
|
|
1039
|
+
return null;
|
|
1040
|
+
if (!isReadlineTyped(lowerer, access.expression))
|
|
1041
|
+
return null;
|
|
1042
|
+
if (!lowerer.isStdlibMember(access))
|
|
1043
|
+
return null;
|
|
1044
|
+
const name = access.name.text;
|
|
1045
|
+
const loc = locOf(access);
|
|
1046
|
+
const numeric = {
|
|
1047
|
+
historySize: 0,
|
|
1048
|
+
historyIndex: 1,
|
|
1049
|
+
crlfDelay: 2,
|
|
1050
|
+
tabSize: 3,
|
|
1051
|
+
escapeCodeTimeout: 4,
|
|
1052
|
+
};
|
|
1053
|
+
if (name === "history") {
|
|
1054
|
+
const recv = lowerer.lowerExprExpecting(access.expression, F64);
|
|
1055
|
+
return { kind: "libCall", fn: "rl.history", args: [recv], type: arrayOf(STRING), loc };
|
|
1056
|
+
}
|
|
1057
|
+
if (numeric[name] !== undefined) {
|
|
1058
|
+
const recv = lowerer.lowerExprExpecting(access.expression, F64);
|
|
1059
|
+
return {
|
|
1060
|
+
kind: "libCall",
|
|
1061
|
+
fn: "rl.numProp",
|
|
1062
|
+
args: [recv, numLit(numeric[name], loc)],
|
|
1063
|
+
type: F64,
|
|
1064
|
+
loc,
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
const reads = {
|
|
1068
|
+
line: ["rl.line", STRING],
|
|
1069
|
+
terminal: ["rl.isTerminal", BOOL],
|
|
1070
|
+
cursor: ["rl.cursor", F64],
|
|
1071
|
+
};
|
|
1072
|
+
const read = reads[name];
|
|
1073
|
+
if (read !== undefined) {
|
|
1074
|
+
const recv = lowerer.lowerExprExpecting(access.expression, F64);
|
|
1075
|
+
return { kind: "libCall", fn: read[0], args: [recv], type: read[1], loc };
|
|
1076
|
+
}
|
|
1077
|
+
return null;
|
|
313
1078
|
}
|
|
314
1079
|
//# sourceMappingURL=readline.js.map
|