-
Notifications
You must be signed in to change notification settings - Fork 29.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: #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>
- Loading branch information
Showing
4 changed files
with
97 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
'use strict'; | ||
|
||
const acorn = require('internal/deps/acorn/dist/acorn'); | ||
const { tokTypes: tt } = acorn; | ||
|
||
// If the error is that we've unexpectedly ended the input, | ||
// then let the user try to recover by adding more input. | ||
// Note: `e` (the original exception) is not used by the current implemention, | ||
// but may be needed in the future. | ||
function isRecoverableError(e, code) { | ||
let recoverable = false; | ||
|
||
// Determine if the point of the any error raised is at the end of the input. | ||
// There are two cases to consider: | ||
// | ||
// 1. Any error raised after we have encountered the 'eof' token. | ||
// This prevents us from declaring partial tokens (like '2e') as | ||
// recoverable. | ||
// | ||
// 2. Three cases where tokens can legally span lines. This is | ||
// template, comment, and strings with a backslash at the end of | ||
// the line, indicating a continuation. Note that we need to look | ||
// for the specific errors of 'unterminated' kind (not, for example, | ||
// a syntax error in a ${} expression in a template), and the only | ||
// way to do that currently is to look at the message. Should Acorn | ||
// change these messages in the future, this will lead to a test | ||
// failure, indicating that this code needs to be updated. | ||
// | ||
acorn.plugins.replRecoverable = (parser) => { | ||
parser.extend('nextToken', (nextToken) => { | ||
return function() { | ||
Reflect.apply(nextToken, this, []); | ||
|
||
if (this.type === tt.eof) recoverable = true; | ||
}; | ||
}); | ||
|
||
parser.extend('raise', (raise) => { | ||
return function(pos, message) { | ||
switch (message) { | ||
case 'Unterminated template': | ||
case 'Unterminated comment': | ||
recoverable = true; | ||
break; | ||
|
||
case 'Unterminated string constant': | ||
const token = this.input.slice(this.lastTokStart, this.pos); | ||
// see https://www.ecma-international.org/ecma-262/#sec-line-terminators | ||
recoverable = /\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token); | ||
} | ||
|
||
Reflect.apply(raise, this, [pos, message]); | ||
}; | ||
}); | ||
}; | ||
|
||
// For similar reasons as `defaultEval`, wrap expressions starting with a | ||
// curly brace with parenthesis. Note: only the open parenthesis is added | ||
// here as the point is to test for potentially valid but incomplete | ||
// expressions. | ||
if (/^\s*\{/.test(code) && isRecoverableError(e, `(${code}`)) return true; | ||
|
||
// Try to parse the code with acorn. If the parse fails, ignore the acorn | ||
// error and return the recoverable status. | ||
try { | ||
acorn.parse(code, { plugins: { replRecoverable: true } }); | ||
|
||
// Odd case: the underlying JS engine (V8, Chakra) rejected this input | ||
// but Acorn detected no issue. Presume that additional text won't | ||
// address this issue. | ||
return false; | ||
} catch { | ||
return recoverable; | ||
} | ||
} | ||
|
||
module.exports = { | ||
isRecoverableError | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters