Skip to content
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
  • Loading branch information
BridgeAR committed Apr 24, 2019
commit 39a5a384303e3ca4db183d9f475eb72134519538
71 changes: 45 additions & 26 deletions lib/internal/repl/utils.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,27 @@
'use strict';

const acorn = require('internal/deps/acorn/acorn/dist/acorn');
const privateMethods =
require('internal/deps/acorn/acorn-private-methods/index');
const bigInt = require('internal/deps/acorn/acorn-bigint/index');
const classFields = require('internal/deps/acorn/acorn-class-fields/index');
const numericSeparator =
require('internal/deps/acorn/acorn-numeric-separator/index');
const staticClassFeatures =
require('internal/deps/acorn/acorn-static-class-features/index');
const { tokTypes: tt, Parser: AcornParser } = 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 implementation,
// but may be needed in the future.
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;

// Determine if the point of any error raised is at the end of the input.
Expand All @@ -26,34 +40,39 @@ function isRecoverableError(e, code) {
// change these messages in the future, this will lead to a test
// failure, indicating that this code needs to be updated.
//
const RecoverableParser = AcornParser.extend((Parser) => {
return class extends Parser {
nextToken() {
super.nextToken();
if (this.type === tt.eof) recoverable = true;
}
raise(pos, message) {
switch (message) {
case 'Unterminated template':
case 'Unterminated comment':
recoverable = true;
break;
const RecoverableParser = AcornParser
.extend(
privateMethods,
bigInt,
classFields,
numericSeparator,
staticClassFeatures,
(Parser) => {
return class extends Parser {
nextToken() {
super.nextToken();
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':
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);
}
super.raise(pos, message);
case 'Unterminated string constant':
const token = this.input.slice(this.lastTokStart, this.pos);
// See https://www.ecma-international.org/ecma-262/#sec-line-terminators
if (/\\(?:\r\n?|\n|\u2028|\u2029)$/.test(token)) {
recoverable = true;
}
}
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
// error and return the recoverable status.
Expand Down