summaryrefslogtreecommitdiff
path: root/cli/rt
diff options
context:
space:
mode:
authorCasper Beyer <caspervonb@pm.me>2020-10-02 07:14:55 +0800
committerGitHub <noreply@github.com>2020-10-02 01:14:55 +0200
commit4c779b5e8ca427faf24c26443a8054004827d450 (patch)
treeddb8ded427e4987f2edbb63c1be3661569e0d204 /cli/rt
parent5590b97670206df957c43742f47601356982c658 (diff)
refactor(repl): use an inspector session (#7763)
This ports the REPL over to Rust and makes use of an inspector session to run a REPL on top of any isolate which lets make full use of rustylines various things like validators and completors without having to introduce a bunch of hard to test internal ops and glue code. An accidental but good side effect of this is that the multiple line input we previously had is now an editable multi-line input prompt that is correctly stored in the history as a single entry.
Diffstat (limited to 'cli/rt')
-rw-r--r--cli/rt/40_repl.js197
-rw-r--r--cli/rt/99_main.js8
2 files changed, 1 insertions, 204 deletions
diff --git a/cli/rt/40_repl.js b/cli/rt/40_repl.js
deleted file mode 100644
index a249b578d..000000000
--- a/cli/rt/40_repl.js
+++ /dev/null
@@ -1,197 +0,0 @@
-// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
-
-((window) => {
- const core = window.Deno.core;
- const exit = window.__bootstrap.os.exit;
- const version = window.__bootstrap.version.version;
- const inspectArgs = window.__bootstrap.console.inspectArgs;
-
- function opStartRepl(historyFile) {
- return core.jsonOpSync("op_repl_start", { historyFile });
- }
-
- function opReadline(rid, prompt) {
- return core.jsonOpAsync("op_repl_readline", { rid, prompt });
- }
-
- function replLog(...args) {
- core.print(inspectArgs(args) + "\n");
- }
-
- function replError(...args) {
- core.print(inspectArgs(args) + "\n", true);
- }
-
- // Error messages that allow users to continue input
- // instead of throwing an error to REPL
- // ref: https://github.com/v8/v8/blob/master/src/message-template.h
- // TODO(kevinkassimo): this list might not be comprehensive
- const recoverableErrorMessages = [
- "Unexpected end of input", // { or [ or (
- "Missing initializer in const declaration", // const a
- "Missing catch or finally after try", // try {}
- "missing ) after argument list", // console.log(1
- "Unterminated template literal", // `template
- // TODO(kevinkassimo): need a parser to handling errors such as:
- // "Missing } in template expression" // `${ or `${ a 123 }`
- ];
-
- function isRecoverableError(e) {
- return recoverableErrorMessages.includes(e.message);
- }
-
- // Returns `true` if `close()` is called in REPL.
- // We should quit the REPL when this function returns `true`.
- function isCloseCalled() {
- return globalThis.closed;
- }
-
- let lastEvalResult = undefined;
- let lastThrownError = undefined;
-
- // Evaluate code.
- // Returns true if code is consumed (no error/irrecoverable error).
- // Returns false if error is recoverable
- function evaluate(code, preprocess = true) {
- const rawCode = code;
- if (preprocess) {
- // It is a bit unexpected that { "foo": "bar" } is interpreted as a block
- // statement rather than an object literal so we interpret it as an expression statement
- // to match the behavior found in a typical prompt including browser developer tools.
- if (code.trimLeft().startsWith("{") && !code.trimRight().endsWith(";")) {
- code = `(${code})`;
- }
- }
-
- // each evalContext is a separate function body, and we want strict mode to
- // work, so we should ensure that the code starts with "use strict"
- const [result, errInfo] = core.evalContext(`"use strict";\n\n${code}`);
-
- if (!errInfo) {
- // when a function is eval'ed with just "use strict" sometimes the result
- // is "use strict" which should be discarded
- lastEvalResult = typeof result === "string" && result === "use strict"
- ? undefined
- : result;
- if (!isCloseCalled()) {
- replLog("%o", lastEvalResult);
- }
- } else if (errInfo.isCompileError && code.length != rawCode.length) {
- return evaluate(rawCode, false);
- } else if (errInfo.isCompileError && isRecoverableError(errInfo.thrown)) {
- // Recoverable compiler error
- return false; // don't consume code.
- } else {
- lastThrownError = errInfo.thrown;
- if (errInfo.isNativeError) {
- const formattedError = core.formatError(errInfo.thrown);
- replError(formattedError);
- } else {
- replError("Thrown:", errInfo.thrown);
- }
- }
- return true;
- }
-
- async function replLoop() {
- const { console } = globalThis;
-
- const historyFile = "deno_history.txt";
- const rid = opStartRepl(historyFile);
-
- const quitRepl = (exitCode) => {
- // Special handling in case user calls deno.close(3).
- try {
- core.close(rid); // close signals Drop on REPL and saves history.
- } catch {}
- exit(exitCode);
- };
-
- // Configure globalThis._ to give the last evaluation result.
- Object.defineProperty(globalThis, "_", {
- configurable: true,
- get: () => lastEvalResult,
- set: (value) => {
- Object.defineProperty(globalThis, "_", {
- value: value,
- writable: true,
- enumerable: true,
- configurable: true,
- });
- console.log("Last evaluation result is no longer saved to _.");
- },
- });
-
- // Configure globalThis._error to give the last thrown error.
- Object.defineProperty(globalThis, "_error", {
- configurable: true,
- get: () => lastThrownError,
- set: (value) => {
- Object.defineProperty(globalThis, "_error", {
- value: value,
- writable: true,
- enumerable: true,
- configurable: true,
- });
- console.log("Last thrown error is no longer saved to _error.");
- },
- });
-
- replLog(`Deno ${version.deno}`);
- replLog("exit using ctrl+d or close()");
-
- while (true) {
- if (isCloseCalled()) {
- quitRepl(0);
- }
-
- let code = "";
- // Top level read
- try {
- code = await opReadline(rid, "> ");
- if (code.trim() === "") {
- continue;
- }
- } catch (err) {
- if (err.message === "EOF") {
- quitRepl(0);
- } else {
- // If interrupted, don't print error.
- if (err.message !== "Interrupted") {
- // e.g. this happens when we have deno.close(3).
- // We want to display the problem.
- const formattedError = core.formatError(err);
- replError(formattedError);
- }
- // Quit REPL anyways.
- quitRepl(1);
- }
- }
- // Start continued read
- while (!evaluate(code)) {
- code += "\n";
- try {
- code += await opReadline(rid, " ");
- } catch (err) {
- // If interrupted on continued read,
- // abort this read instead of quitting.
- if (err.message === "Interrupted") {
- break;
- } else if (err.message === "EOF") {
- quitRepl(0);
- } else {
- // e.g. this happens when we have deno.close(3).
- // We want to display the problem.
- const formattedError = core.formatError(err);
- replError(formattedError);
- quitRepl(1);
- }
- }
- }
- }
- }
-
- window.__bootstrap.repl = {
- replLoop,
- };
-})(this);
diff --git a/cli/rt/99_main.js b/cli/rt/99_main.js
index 26e8fd6da..d8462ce66 100644
--- a/cli/rt/99_main.js
+++ b/cli/rt/99_main.js
@@ -14,7 +14,6 @@ delete Object.prototype.__proto__;
const errorStack = window.__bootstrap.errorStack;
const os = window.__bootstrap.os;
const timers = window.__bootstrap.timers;
- const replLoop = window.__bootstrap.repl.replLoop;
const Console = window.__bootstrap.console.Console;
const worker = window.__bootstrap.worker;
const signals = window.__bootstrap.signals;
@@ -294,8 +293,7 @@ delete Object.prototype.__proto__;
}
});
- const { args, cwd, noColor, pid, ppid, repl, unstableFlag } =
- runtimeStart();
+ const { args, cwd, noColor, pid, ppid, unstableFlag } = runtimeStart();
registerErrors();
@@ -329,10 +327,6 @@ delete Object.prototype.__proto__;
util.log("cwd", cwd);
util.log("args", args);
-
- if (repl) {
- replLoop();
- }
}
function bootstrapWorkerRuntime(name, useDenoNamespace, internalName) {