summaryrefslogtreecommitdiff
path: root/lib/repl.js
diff options
context:
space:
mode:
authorSam Ruby <rubys@intertwingly.net>2018-07-13 15:46:21 -0700
committerRich Trott <rtrott@gmail.com>2018-08-03 20:20:00 -0700
commita2ec80851ceff8ba6745d6909c8a2434ddfdf568 (patch)
tree4ee42b57302d9f3f78a1753b76521afc64c03da7 /lib/repl.js
parentf19fa7ca4deea517f66cb0ef8b5fd9574bb33a66 (diff)
downloadandroid-node-v8-a2ec80851ceff8ba6745d6909c8a2434ddfdf568.tar.gz
android-node-v8-a2ec80851ceff8ba6745d6909c8a2434ddfdf568.tar.bz2
android-node-v8-a2ec80851ceff8ba6745d6909c8a2434ddfdf568.zip
repl: support mult-line string-keyed objects
isRecoverableError is completely reimplemented using acorn and an acorn plugin that examines the state of the parser at the time of the error to determine if the code could be completed on a subsequent line. PR-URL: https://github.com/nodejs/node/pull/21805 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com> Reviewed-By: John-David Dalton <john.david.dalton@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'lib/repl.js')
-rw-r--r--lib/repl.js74
1 files changed, 3 insertions, 71 deletions
diff --git a/lib/repl.js b/lib/repl.js
index 92c90de7bb..4a01595ce1 100644
--- a/lib/repl.js
+++ b/lib/repl.js
@@ -73,6 +73,7 @@ const {
} = require('internal/errors').codes;
const { sendInspectorCommand } = require('internal/util/inspector');
const { experimentalREPLAwait } = process.binding('config');
+const { isRecoverableError } = require('internal/repl/recoverable');
// Lazy-loaded.
let processTopLevelAwait;
@@ -227,7 +228,8 @@ function REPLServer(prompt,
// It's confusing for `{ a : 1 }` to be interpreted as a block
// statement rather than an object literal. So, we first try
// to wrap it in parentheses, so that it will be interpreted as
- // an expression.
+ // an expression. Note that if the above condition changes,
+ // lib/internal/repl/recoverable.js needs to be changed to match.
code = `(${code.trim()})\n`;
wrappedCmd = true;
}
@@ -1505,76 +1507,6 @@ function regexpEscape(s) {
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
-// If the error is that we've unexpectedly ended the input,
-// then let the user try to recover by adding more input.
-function isRecoverableError(e, code) {
- if (e && e.name === 'SyntaxError') {
- var message = e.message;
- if (message === 'Unterminated template literal' ||
- message === 'Unexpected end of input') {
- return true;
- }
-
- if (message === 'missing ) after argument list') {
- const frames = e.stack.split(/\r?\n/);
- const pos = frames.findIndex((f) => f.match(/^\s*\^+$/));
- return pos > 0 && frames[pos - 1].length === frames[pos].length;
- }
-
- if (message === 'Invalid or unexpected token')
- return isCodeRecoverable(code);
- }
- return false;
-}
-
-// Check whether a code snippet should be forced to fail in the REPL.
-function isCodeRecoverable(code) {
- var current, previous, stringLiteral;
- var isBlockComment = false;
- var isSingleComment = false;
- var isRegExpLiteral = false;
- var lastChar = code.charAt(code.length - 2);
- var prevTokenChar = null;
-
- for (var i = 0; i < code.length; i++) {
- previous = current;
- current = code[i];
-
- if (previous === '\\' && (stringLiteral || isRegExpLiteral)) {
- current = null;
- } else if (stringLiteral) {
- if (stringLiteral === current) {
- stringLiteral = null;
- }
- } else if (isRegExpLiteral && current === '/') {
- isRegExpLiteral = false;
- } else if (isBlockComment && previous === '*' && current === '/') {
- isBlockComment = false;
- } else if (isSingleComment && current === '\n') {
- isSingleComment = false;
- } else if (!isBlockComment && !isRegExpLiteral && !isSingleComment) {
- if (current === '/' && previous === '/') {
- isSingleComment = true;
- } else if (previous === '/') {
- if (current === '*') {
- isBlockComment = true;
- // Distinguish between a division operator and the start of a regex
- // by examining the non-whitespace character that precedes the /
- } else if ([null, '(', '[', '{', '}', ';'].includes(prevTokenChar)) {
- isRegExpLiteral = true;
- }
- } else {
- if (current.trim()) prevTokenChar = current;
- if (current === '\'' || current === '"') {
- stringLiteral = current;
- }
- }
- }
- }
-
- return stringLiteral ? lastChar === '\\' : isBlockComment;
-}
-
function Recoverable(err) {
this.err = err;
}