repl: handle stage-3 language features properly

This adds stage-3 language features to acorn so that the REPL is
able to parse these features properly. Otherwise these would cause
SyntaxErrors.

PR-URL: https://github.com/nodejs/node/pull/27400
Fixes: https://github.com/nodejs/node/issues/27391
Fixes: https://github.com/nodejs/node/issues/25835
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
This commit is contained in:
Ruben Bridgewater 2019-04-24 23:56:35 +02:00
parent f37e40af2b
commit e939b8f13b
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762

View File

@ -1,6 +1,15 @@
'use strict'; 'use strict';
const acorn = require('internal/deps/acorn/acorn/dist/acorn'); const acorn = require('internal/deps/acorn/acorn/dist/acorn');
const privateMethods =
require('internal/deps/acorn-plugins/acorn-private-methods/index');
const bigInt = require('internal/deps/acorn-plugins/acorn-bigint/index');
const classFields =
require('internal/deps/acorn-plugins/acorn-class-fields/index');
const numericSeparator =
require('internal/deps/acorn-plugins/acorn-numeric-separator/index');
const staticClassFeatures =
require('internal/deps/acorn-plugins/acorn-static-class-features/index');
const { tokTypes: tt, Parser: AcornParser } = acorn; const { tokTypes: tt, Parser: AcornParser } = acorn;
// If the error is that we've unexpectedly ended the input, // If the error is that we've unexpectedly ended the input,
@ -8,6 +17,12 @@ const { tokTypes: tt, Parser: AcornParser } = acorn;
// Note: `e` (the original exception) is not used by the current implementation, // Note: `e` (the original exception) is not used by the current implementation,
// but may be needed in the future. // but may be needed in the future.
function isRecoverableError(e, code) { function isRecoverableError(e, code) {
// 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;
let recoverable = false; let recoverable = false;
// Determine if the point of any error raised is at the end of the input. // Determine if the point of any error raised is at the end of the input.
@ -26,34 +41,39 @@ function isRecoverableError(e, code) {
// change these messages in the future, this will lead to a test // change these messages in the future, this will lead to a test
// failure, indicating that this code needs to be updated. // failure, indicating that this code needs to be updated.
// //
const RecoverableParser = AcornParser.extend((Parser) => { const RecoverableParser = AcornParser
return class extends Parser { .extend(
nextToken() { privateMethods,
super.nextToken(); bigInt,
if (this.type === tt.eof) recoverable = true; classFields,
} numericSeparator,
raise(pos, message) { staticClassFeatures,
switch (message) { (Parser) => {
case 'Unterminated template': return class extends Parser {
case 'Unterminated comment': nextToken() {
recoverable = true; super.nextToken();
break; if (this.type === tt.eof)
recoverable = true;
}
raise(pos, message) {
switch (message) {
case 'Unterminated template':
case 'Unterminated comment':
recoverable = true;
break;
case 'Unterminated string constant': case 'Unterminated string constant':
const token = this.input.slice(this.lastTokStart, this.pos); const token = this.input.slice(this.lastTokStart, this.pos);
// See https://www.ecma-international.org/ecma-262/#sec-line-terminators // See https://www.ecma-international.org/ecma-262/#sec-line-terminators
recoverable = /\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token); if (/\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token)) {
} recoverable = true;
super.raise(pos, message); }
}
super.raise(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 // Try to parse the code with acorn. If the parse fails, ignore the acorn
// error and return the recoverable status. // error and return the recoverable status.