perf: Move input to state and precalculate length

This also fixes a bug with async functions
This commit is contained in:
Daniel Tschinder 2019-01-15 12:45:36 -08:00
parent ae154c86ed
commit 2dc1c91955
12 changed files with 160 additions and 126 deletions

View File

@ -16,7 +16,6 @@ export default class BaseParser {
// Initialized by Tokenizer
state: State;
input: string;
isReservedWord(word: string): boolean {
if (word === "await") {

View File

@ -1146,7 +1146,11 @@ export default class ExpressionParser extends LValParser {
const node = this.startNodeAt(startPos, startLoc);
this.addExtra(node, "rawValue", value);
this.addExtra(node, "raw", this.input.slice(startPos, this.state.end));
this.addExtra(
node,
"raw",
this.state.input.slice(startPos, this.state.end),
);
node.value = value;
this.next();
return this.finishNode(node, type);
@ -1365,7 +1369,7 @@ export default class ExpressionParser extends LValParser {
}
}
elem.value = {
raw: this.input
raw: this.state.input
.slice(this.state.start, this.state.end)
.replace(/\r\n?/g, "\n"),
cooked: this.state.value,
@ -1967,7 +1971,8 @@ export default class ExpressionParser extends LValParser {
if (
(name === "class" || name === "function") &&
(this.state.lastTokEnd !== this.state.lastTokStart + 1 ||
this.input.charCodeAt(this.state.lastTokStart) !== charCodes.dot)
this.state.input.charCodeAt(this.state.lastTokStart) !==
charCodes.dot)
) {
this.state.context.pop();
}

View File

@ -22,7 +22,6 @@ export default class Parser extends StatementParser {
this.options = options;
this.inModule = this.options.sourceType === "module";
this.input = input;
this.plugins = pluginsMap(this.options.plugins);
this.filename = options.sourceFilename;
}

View File

@ -21,7 +21,7 @@ export default class LocationParser extends CommentsParser {
code?: string,
} = {},
): empty {
const loc = getLineInfo(this.input, pos);
const loc = getLineInfo(this.state.input, pos);
message += ` (${loc.line}:${loc.column})`;
// $FlowIgnore
const err: SyntaxError & { pos: number, loc: Position } = new SyntaxError(

View File

@ -44,7 +44,7 @@ export default class StatementParser extends ExpressionParser {
const directiveLiteral = this.startNodeAt(expr.start, expr.loc.start);
const directive = this.startNodeAt(stmt.start, stmt.loc.start);
const raw = this.input.slice(expr.start, expr.end);
const raw = this.state.input.slice(expr.start, expr.end);
const val = (directiveLiteral.value = raw.slice(1, -1)); // remove quotes
this.addExtra(directiveLiteral, "raw", raw);
@ -551,7 +551,9 @@ export default class StatementParser extends ExpressionParser {
parseThrowStatement(node: N.ThrowStatement): N.ThrowStatement {
this.next();
if (
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))
lineBreak.test(
this.state.input.slice(this.state.lastTokEnd, this.state.start),
)
) {
this.raise(this.state.lastTokEnd, "Illegal newline after throw");
}
@ -1521,7 +1523,7 @@ export default class StatementParser extends ExpressionParser {
isAsyncFunction() {
if (!this.isContextual("async")) return false;
const { input, pos } = this.state;
const { input, pos, length } = this.state;
skipWhiteSpace.lastIndex = pos;
const skip = skipWhiteSpace.exec(input);
@ -1533,7 +1535,7 @@ export default class StatementParser extends ExpressionParser {
return (
!lineBreak.test(input.slice(pos, next)) &&
input.slice(next, next + 8) === "function" &&
(next + 8 === input.length || !isIdentifierChar(input.charAt(next + 8)))
(next + 8 === length || !isIdentifierChar(input.charCodeAt(next + 8)))
);
}

View File

@ -87,7 +87,7 @@ export default class UtilParser extends Tokenizer {
hasPrecedingLineBreak(): boolean {
return lineBreak.test(
this.input.slice(this.state.lastTokEnd, this.state.start),
this.state.input.slice(this.state.lastTokEnd, this.state.start),
);
}

View File

@ -1124,7 +1124,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.types = [];
this.expect(tt.bracketL);
// We allow trailing commas
while (this.state.pos < this.input.length && !this.match(tt.bracketR)) {
while (this.state.pos < this.state.length && !this.match(tt.bracketR)) {
node.types.push(this.flowParseType());
if (this.match(tt.bracketR)) break;
this.expect(tt.comma);
@ -1934,7 +1934,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// ensure that inside flow types, we bypass the jsx parser plugin
readToken(code: number): void {
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (
this.state.inType &&
(code === charCodes.greaterThan || code === charCodes.lessThan)
@ -2686,7 +2686,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
readToken_mult_modulo(code: number): void {
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (
code === charCodes.asterisk &&
next === charCodes.slash &&
@ -2728,7 +2728,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
if (this.hasPlugin("flow") && this.state.hasFlowComment) {
const end = this.input.indexOf("*-/", (this.state.pos += 2));
const end = this.state.input.indexOf("*-/", (this.state.pos += 2));
if (end === -1) this.raise(this.state.pos - 2, "Unterminated comment");
this.state.pos = end + 3;
return;
@ -2742,20 +2742,22 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let shiftToFirstNonWhiteSpace = 2;
while (
[charCodes.space, charCodes.tab].includes(
this.input.charCodeAt(pos + shiftToFirstNonWhiteSpace),
this.state.input.charCodeAt(pos + shiftToFirstNonWhiteSpace),
)
) {
shiftToFirstNonWhiteSpace++;
}
const ch2 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos);
const ch3 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos + 1);
const ch2 = this.state.input.charCodeAt(shiftToFirstNonWhiteSpace + pos);
const ch3 = this.state.input.charCodeAt(
shiftToFirstNonWhiteSpace + pos + 1,
);
if (ch2 === charCodes.colon && ch3 === charCodes.colon) {
return shiftToFirstNonWhiteSpace + 2; // check for /*::
}
if (
this.input.slice(
this.state.input.slice(
shiftToFirstNonWhiteSpace + pos,
shiftToFirstNonWhiteSpace + pos + 12,
) === "flow-include"
@ -2769,7 +2771,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
hasFlowCommentCompletion(): void {
const end = this.input.indexOf("*/", this.state.pos);
const end = this.state.input.indexOf("*/", this.state.pos);
if (end === -1) {
this.raise(this.state.pos, "Unterminated comment");
}

View File

@ -79,11 +79,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let out = "";
let chunkStart = this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated JSX contents");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
switch (ch) {
case charCodes.lessThan:
@ -95,18 +95,18 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
return this.getTokenFromCode(ch);
}
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
return this.finishToken(tt.jsxText, out);
case charCodes.ampersand:
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadEntity();
chunkStart = this.state.pos;
break;
default:
if (isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadNewLine(true);
chunkStart = this.state.pos;
} else {
@ -117,12 +117,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
jsxReadNewLine(normalizeCRLF: boolean): string {
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
let out;
++this.state.pos;
if (
ch === charCodes.carriageReturn &&
this.input.charCodeAt(this.state.pos) === charCodes.lineFeed
this.state.input.charCodeAt(this.state.pos) === charCodes.lineFeed
) {
++this.state.pos;
out = normalizeCRLF ? "\n" : "\r\n";
@ -139,25 +139,25 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let out = "";
let chunkStart = ++this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated string constant");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
if (ch === quote) break;
if (ch === charCodes.ampersand) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadEntity();
chunkStart = this.state.pos;
} else if (isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadNewLine(false);
chunkStart = this.state.pos;
} else {
++this.state.pos;
}
}
out += this.input.slice(chunkStart, this.state.pos++);
out += this.state.input.slice(chunkStart, this.state.pos++);
return this.finishToken(tt.string, out);
}
@ -165,11 +165,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let str = "";
let count = 0;
let entity;
let ch = this.input[this.state.pos];
let ch = this.state.input[this.state.pos];
const startPos = ++this.state.pos;
while (this.state.pos < this.input.length && count++ < 10) {
ch = this.input[this.state.pos++];
while (this.state.pos < this.state.length && count++ < 10) {
ch = this.state.input[this.state.pos++];
if (ch === ";") {
if (str[0] === "#") {
if (str[1] === "x") {
@ -208,11 +208,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let ch;
const start = this.state.pos;
do {
ch = this.input.charCodeAt(++this.state.pos);
ch = this.state.input.charCodeAt(++this.state.pos);
} while (isIdentifierChar(ch) || ch === charCodes.dash);
return this.finishToken(
tt.jsxName,
this.input.slice(start, this.state.pos),
this.state.input.slice(start, this.state.pos),
);
}

View File

@ -107,7 +107,9 @@ tt._function.updateContext = tt._class.updateContext = function(prevType) {
prevType !== tt._else &&
!(
prevType === tt._return &&
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))
lineBreak.test(
this.state.input.slice(this.state.lastTokEnd, this.state.start),
)
) &&
!(
(prevType === tt.colon || prevType === tt.braceL) &&

View File

@ -185,7 +185,7 @@ export default class Tokenizer extends LocationParser {
this.state.pos = this.state.start;
while (this.state.pos < this.state.lineStart) {
this.state.lineStart =
this.input.lastIndexOf("\n", this.state.lineStart - 2) + 1;
this.state.input.lastIndexOf("\n", this.state.lineStart - 2) + 1;
--this.state.curLine;
}
this.nextToken();
@ -206,7 +206,7 @@ export default class Tokenizer extends LocationParser {
this.state.octalPosition = null;
this.state.start = this.state.pos;
this.state.startLoc = this.state.curPosition();
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.finishToken(tt.eof);
return;
}
@ -214,7 +214,7 @@ export default class Tokenizer extends LocationParser {
if (curContext.override) {
curContext.override(this);
} else {
this.readToken(this.input.codePointAt(this.state.pos));
this.readToken(this.state.input.codePointAt(this.state.pos));
}
}
@ -254,14 +254,14 @@ export default class Tokenizer extends LocationParser {
skipBlockComment(): void {
const startLoc = this.state.curPosition();
const start = this.state.pos;
const end = this.input.indexOf("*/", (this.state.pos += 2));
const end = this.state.input.indexOf("*/", (this.state.pos += 2));
if (end === -1) this.raise(this.state.pos - 2, "Unterminated comment");
this.state.pos = end + 2;
lineBreakG.lastIndex = start;
let match;
while (
(match = lineBreakG.exec(this.input)) &&
(match = lineBreakG.exec(this.state.input)) &&
match.index < this.state.pos
) {
++this.state.curLine;
@ -270,7 +270,7 @@ export default class Tokenizer extends LocationParser {
this.pushComment(
true,
this.input.slice(start + 2, end),
this.state.input.slice(start + 2, end),
start,
this.state.pos,
startLoc,
@ -281,22 +281,22 @@ export default class Tokenizer extends LocationParser {
skipLineComment(startSkip: number): void {
const start = this.state.pos;
const startLoc = this.state.curPosition();
let ch = this.input.charCodeAt((this.state.pos += startSkip));
if (this.state.pos < this.input.length) {
let ch = this.state.input.charCodeAt((this.state.pos += startSkip));
if (this.state.pos < this.state.length) {
while (
ch !== charCodes.lineFeed &&
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.input.length
++this.state.pos < this.state.length
) {
ch = this.input.charCodeAt(this.state.pos);
ch = this.state.input.charCodeAt(this.state.pos);
}
}
this.pushComment(
false,
this.input.slice(start + startSkip, this.state.pos),
this.state.input.slice(start + startSkip, this.state.pos),
start,
this.state.pos,
startLoc,
@ -308,8 +308,8 @@ export default class Tokenizer extends LocationParser {
// whitespace and comments, and.
skipSpace(): void {
loop: while (this.state.pos < this.input.length) {
const ch = this.input.charCodeAt(this.state.pos);
loop: while (this.state.pos < this.state.length) {
const ch = this.state.input.charCodeAt(this.state.pos);
switch (ch) {
case charCodes.space:
case charCodes.nonBreakingSpace:
@ -318,7 +318,8 @@ export default class Tokenizer extends LocationParser {
break;
case charCodes.carriageReturn:
if (
this.input.charCodeAt(this.state.pos + 1) === charCodes.lineFeed
this.state.input.charCodeAt(this.state.pos + 1) ===
charCodes.lineFeed
) {
++this.state.pos;
}
@ -332,7 +333,7 @@ export default class Tokenizer extends LocationParser {
break;
case charCodes.slash:
switch (this.input.charCodeAt(this.state.pos + 1)) {
switch (this.state.input.charCodeAt(this.state.pos + 1)) {
case charCodes.asterisk:
this.skipBlockComment();
break;
@ -387,7 +388,7 @@ export default class Tokenizer extends LocationParser {
}
const nextPos = this.state.pos + 1;
const next = this.input.charCodeAt(nextPos);
const next = this.state.input.charCodeAt(nextPos);
if (next >= charCodes.digit0 && next <= charCodes.digit9) {
this.raise(this.state.pos, "Unexpected digit after hash token");
}
@ -410,13 +411,13 @@ export default class Tokenizer extends LocationParser {
}
readToken_dot(): void {
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next >= charCodes.digit0 && next <= charCodes.digit9) {
this.readNumber(true);
return;
}
const next2 = this.input.charCodeAt(this.state.pos + 2);
const next2 = this.state.input.charCodeAt(this.state.pos + 2);
if (next === charCodes.dot && next2 === charCodes.dot) {
this.state.pos += 3;
this.finishToken(tt.ellipsis);
@ -434,7 +435,7 @@ export default class Tokenizer extends LocationParser {
return;
}
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(tt.assign, 2);
} else {
@ -443,12 +444,12 @@ export default class Tokenizer extends LocationParser {
}
readToken_interpreter(): boolean {
if (this.state.pos !== 0 || this.state.input.length < 2) return false;
if (this.state.pos !== 0 || this.state.length < 2) return false;
const start = this.state.pos;
this.state.pos += 1;
let ch = this.input.charCodeAt(this.state.pos);
let ch = this.state.input.charCodeAt(this.state.pos);
if (ch !== charCodes.exclamationMark) return false;
while (
@ -456,12 +457,12 @@ export default class Tokenizer extends LocationParser {
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.input.length
++this.state.pos < this.state.length
) {
ch = this.input.charCodeAt(this.state.pos);
ch = this.state.input.charCodeAt(this.state.pos);
}
const value = this.input.slice(start + 2, this.state.pos);
const value = this.state.input.slice(start + 2, this.state.pos);
this.finishToken(tt.interpreterDirective, value);
@ -472,13 +473,13 @@ export default class Tokenizer extends LocationParser {
// '%*'
let type = code === charCodes.asterisk ? tt.star : tt.modulo;
let width = 1;
let next = this.input.charCodeAt(this.state.pos + 1);
let next = this.state.input.charCodeAt(this.state.pos + 1);
const exprAllowed = this.state.exprAllowed;
// Exponentiation operator **
if (code === charCodes.asterisk && next === charCodes.asterisk) {
width++;
next = this.input.charCodeAt(this.state.pos + 2);
next = this.state.input.charCodeAt(this.state.pos + 2);
type = tt.exponent;
}
@ -492,10 +493,12 @@ export default class Tokenizer extends LocationParser {
readToken_pipe_amp(code: number): void {
// '|&'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === code) {
if (this.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo) {
if (
this.state.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo
) {
this.finishOp(tt.assign, 3);
} else {
this.finishOp(
@ -531,7 +534,7 @@ export default class Tokenizer extends LocationParser {
readToken_caret(): void {
// '^'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(tt.assign, 2);
} else {
@ -541,14 +544,17 @@ export default class Tokenizer extends LocationParser {
readToken_plus_min(code: number): void {
// '+-'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === code) {
if (
next === charCodes.dash &&
!this.inModule &&
this.input.charCodeAt(this.state.pos + 2) === charCodes.greaterThan &&
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.pos))
this.state.input.charCodeAt(this.state.pos + 2) ===
charCodes.greaterThan &&
lineBreak.test(
this.state.input.slice(this.state.lastTokEnd, this.state.pos),
)
) {
// A `-->` line comment
this.skipLineComment(3);
@ -569,16 +575,20 @@ export default class Tokenizer extends LocationParser {
readToken_lt_gt(code: number): void {
// '<>'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
let size = 1;
if (next === code) {
size =
code === charCodes.greaterThan &&
this.input.charCodeAt(this.state.pos + 2) === charCodes.greaterThan
this.state.input.charCodeAt(this.state.pos + 2) ===
charCodes.greaterThan
? 3
: 2;
if (this.input.charCodeAt(this.state.pos + size) === charCodes.equalsTo) {
if (
this.state.input.charCodeAt(this.state.pos + size) ===
charCodes.equalsTo
) {
this.finishOp(tt.assign, size + 1);
return;
}
@ -590,8 +600,8 @@ export default class Tokenizer extends LocationParser {
next === charCodes.exclamationMark &&
code === charCodes.lessThan &&
!this.inModule &&
this.input.charCodeAt(this.state.pos + 2) === charCodes.dash &&
this.input.charCodeAt(this.state.pos + 3) === charCodes.dash
this.state.input.charCodeAt(this.state.pos + 2) === charCodes.dash &&
this.state.input.charCodeAt(this.state.pos + 3) === charCodes.dash
) {
// `<!--`, an XML-style comment that should be interpreted as a line comment
this.skipLineComment(4);
@ -610,11 +620,11 @@ export default class Tokenizer extends LocationParser {
readToken_eq_excl(code: number): void {
// '=!'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(
tt.equality,
this.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo
this.state.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo
? 3
: 2,
);
@ -631,8 +641,8 @@ export default class Tokenizer extends LocationParser {
readToken_question(): void {
// '?'
const next = this.input.charCodeAt(this.state.pos + 1);
const next2 = this.input.charCodeAt(this.state.pos + 2);
const next = this.state.input.charCodeAt(this.state.pos + 1);
const next2 = this.state.input.charCodeAt(this.state.pos + 2);
if (next === charCodes.questionMark && !this.state.inType) {
if (next2 === charCodes.equalsTo) {
// '??='
@ -692,7 +702,8 @@ export default class Tokenizer extends LocationParser {
case charCodes.leftCurlyBrace:
if (
this.hasPlugin("flow") &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.verticalBar
this.state.input.charCodeAt(this.state.pos + 1) ===
charCodes.verticalBar
) {
this.finishOp(tt.braceBarL, 2);
} else {
@ -709,7 +720,7 @@ export default class Tokenizer extends LocationParser {
case charCodes.colon:
if (
this.hasPlugin("functionBind") &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.colon
this.state.input.charCodeAt(this.state.pos + 1) === charCodes.colon
) {
this.finishOp(tt.doubleColon, 2);
} else {
@ -728,7 +739,7 @@ export default class Tokenizer extends LocationParser {
return;
case charCodes.digit0: {
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
// '0x', '0X' - hex number
if (next === charCodes.lowercaseX || next === charCodes.uppercaseX) {
this.readRadixNumber(16);
@ -824,7 +835,7 @@ export default class Tokenizer extends LocationParser {
}
finishOp(type: TokenType, size: number): void {
const str = this.input.slice(this.state.pos, this.state.pos + size);
const str = this.state.input.slice(this.state.pos, this.state.pos + size);
this.state.pos += size;
this.finishToken(type, str);
}
@ -833,10 +844,10 @@ export default class Tokenizer extends LocationParser {
const start = this.state.pos;
let escaped, inClass;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(start, "Unterminated regular expression");
}
const ch = this.input.charAt(this.state.pos);
const ch = this.state.input.charAt(this.state.pos);
if (lineBreak.test(ch)) {
this.raise(start, "Unterminated regular expression");
}
@ -854,14 +865,14 @@ export default class Tokenizer extends LocationParser {
}
++this.state.pos;
}
const content = this.input.slice(start, this.state.pos);
const content = this.state.input.slice(start, this.state.pos);
++this.state.pos;
let mods = "";
while (this.state.pos < this.input.length) {
const char = this.input[this.state.pos];
const charCode = this.input.codePointAt(this.state.pos);
while (this.state.pos < this.state.length) {
const char = this.state.input[this.state.pos];
const charCode = this.state.input.codePointAt(this.state.pos);
if (VALID_REGEX_FLAGS.indexOf(char) > -1) {
if (mods.indexOf(char) > -1) {
@ -908,12 +919,12 @@ export default class Tokenizer extends LocationParser {
let total = 0;
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
const code = this.input.charCodeAt(this.state.pos);
const code = this.state.input.charCodeAt(this.state.pos);
let val;
if (this.hasPlugin("numericSeparator")) {
const prev = this.input.charCodeAt(this.state.pos - 1);
const next = this.input.charCodeAt(this.state.pos + 1);
const prev = this.state.input.charCodeAt(this.state.pos - 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (code === charCodes.underscore) {
if (allowedSiblings.indexOf(next) === -1) {
this.raise(this.state.pos, "Invalid or unexpected token");
@ -967,18 +978,22 @@ export default class Tokenizer extends LocationParser {
}
if (this.hasPlugin("bigInt")) {
if (this.input.charCodeAt(this.state.pos) === charCodes.lowercaseN) {
if (
this.state.input.charCodeAt(this.state.pos) === charCodes.lowercaseN
) {
++this.state.pos;
isBigInt = true;
}
}
if (isIdentifierStart(this.input.codePointAt(this.state.pos))) {
if (isIdentifierStart(this.state.input.codePointAt(this.state.pos))) {
this.raise(this.state.pos, "Identifier directly after number");
}
if (isBigInt) {
const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");
const str = this.state.input
.slice(start, this.state.pos)
.replace(/[_n]/g, "");
this.finishToken(tt.bigint, str);
return;
}
@ -998,7 +1013,7 @@ export default class Tokenizer extends LocationParser {
}
let octal =
this.state.pos - start >= 2 &&
this.input.charCodeAt(start) === charCodes.digit0;
this.state.input.charCodeAt(start) === charCodes.digit0;
if (octal) {
if (this.state.strict) {
this.raise(
@ -1006,30 +1021,30 @@ export default class Tokenizer extends LocationParser {
"Legacy octal literals are not allowed in strict mode",
);
}
if (/[89]/.test(this.input.slice(start, this.state.pos))) {
if (/[89]/.test(this.state.input.slice(start, this.state.pos))) {
octal = false;
}
}
let next = this.input.charCodeAt(this.state.pos);
let next = this.state.input.charCodeAt(this.state.pos);
if (next === charCodes.dot && !octal) {
++this.state.pos;
this.readInt(10);
isFloat = true;
next = this.input.charCodeAt(this.state.pos);
next = this.state.input.charCodeAt(this.state.pos);
}
if (
(next === charCodes.uppercaseE || next === charCodes.lowercaseE) &&
!octal
) {
next = this.input.charCodeAt(++this.state.pos);
next = this.state.input.charCodeAt(++this.state.pos);
if (next === charCodes.plusSign || next === charCodes.dash) {
++this.state.pos;
}
if (this.readInt(10) === null) this.raise(start, "Invalid number");
isFloat = true;
next = this.input.charCodeAt(this.state.pos);
next = this.state.input.charCodeAt(this.state.pos);
}
if (this.hasPlugin("bigInt")) {
@ -1041,12 +1056,14 @@ export default class Tokenizer extends LocationParser {
}
}
if (isIdentifierStart(this.input.codePointAt(this.state.pos))) {
if (isIdentifierStart(this.state.input.codePointAt(this.state.pos))) {
this.raise(this.state.pos, "Identifier directly after number");
}
// remove "_" for numeric literal separator, and "n" for BigInts
const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");
const str = this.state.input
.slice(start, this.state.pos)
.replace(/[_n]/g, "");
if (isBigInt) {
this.finishToken(tt.bigint, str);
@ -1060,13 +1077,13 @@ export default class Tokenizer extends LocationParser {
// Read a string value, interpreting backslash-escapes.
readCodePoint(throwOnInvalid: boolean): number | null {
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
let code;
if (ch === charCodes.leftCurlyBrace) {
const codePos = ++this.state.pos;
code = this.readHexChar(
this.input.indexOf("}", this.state.pos) - this.state.pos,
this.state.input.indexOf("}", this.state.pos) - this.state.pos,
throwOnInvalid,
);
++this.state.pos;
@ -1091,13 +1108,13 @@ export default class Tokenizer extends LocationParser {
let out = "",
chunkStart = ++this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated string constant");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
if (ch === quote) break;
if (ch === charCodes.backslash) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
// $FlowFixMe
out += this.readEscapedChar(false);
chunkStart = this.state.pos;
@ -1113,7 +1130,7 @@ export default class Tokenizer extends LocationParser {
++this.state.pos;
}
}
out += this.input.slice(chunkStart, this.state.pos++);
out += this.state.input.slice(chunkStart, this.state.pos++);
this.finishToken(tt.string, out);
}
@ -1124,14 +1141,14 @@ export default class Tokenizer extends LocationParser {
chunkStart = this.state.pos,
containsInvalid = false;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated template");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
if (
ch === charCodes.graveAccent ||
(ch === charCodes.dollarSign &&
this.input.charCodeAt(this.state.pos + 1) ===
this.state.input.charCodeAt(this.state.pos + 1) ===
charCodes.leftCurlyBrace)
) {
if (this.state.pos === this.state.start && this.match(tt.template)) {
@ -1145,12 +1162,12 @@ export default class Tokenizer extends LocationParser {
return;
}
}
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
this.finishToken(tt.template, containsInvalid ? null : out);
return;
}
if (ch === charCodes.backslash) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
const escaped = this.readEscapedChar(true);
if (escaped === null) {
containsInvalid = true;
@ -1159,11 +1176,13 @@ export default class Tokenizer extends LocationParser {
}
chunkStart = this.state.pos;
} else if (isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
++this.state.pos;
switch (ch) {
case charCodes.carriageReturn:
if (this.input.charCodeAt(this.state.pos) === charCodes.lineFeed) {
if (
this.state.input.charCodeAt(this.state.pos) === charCodes.lineFeed
) {
++this.state.pos;
}
case charCodes.lineFeed:
@ -1186,7 +1205,7 @@ export default class Tokenizer extends LocationParser {
readEscapedChar(inTemplate: boolean): string | null {
const throwOnInvalid = !inTemplate;
const ch = this.input.charCodeAt(++this.state.pos);
const ch = this.state.input.charCodeAt(++this.state.pos);
++this.state.pos;
switch (ch) {
case charCodes.lowercaseN:
@ -1210,7 +1229,9 @@ export default class Tokenizer extends LocationParser {
case charCodes.lowercaseF:
return "\f";
case charCodes.carriageReturn:
if (this.input.charCodeAt(this.state.pos) === charCodes.lineFeed) {
if (
this.state.input.charCodeAt(this.state.pos) === charCodes.lineFeed
) {
++this.state.pos;
}
case charCodes.lineFeed:
@ -1221,7 +1242,7 @@ export default class Tokenizer extends LocationParser {
if (ch >= charCodes.digit0 && ch <= charCodes.digit7) {
const codePos = this.state.pos - 1;
// $FlowFixMe
let octalStr = this.input
let octalStr = this.state.input
.substr(this.state.pos - 1, 3)
.match(/^[0-7]+/)[0];
let octal = parseInt(octalStr, 8);
@ -1277,8 +1298,8 @@ export default class Tokenizer extends LocationParser {
const start = this.state.pos;
let chunkStart = this.state.pos;
while (this.state.pos < this.input.length) {
const ch = this.input.codePointAt(this.state.pos);
while (this.state.pos < this.state.length) {
const ch = this.state.input.codePointAt(this.state.pos);
if (isIdentifierChar(ch)) {
this.state.pos += ch <= 0xffff ? 1 : 2;
} else if (this.state.isIterator && ch === charCodes.atSign) {
@ -1286,12 +1307,14 @@ export default class Tokenizer extends LocationParser {
} else if (ch === charCodes.backslash) {
this.state.containsEsc = true;
word += this.input.slice(chunkStart, this.state.pos);
word += this.state.input.slice(chunkStart, this.state.pos);
const escStart = this.state.pos;
const identifierCheck =
this.state.pos === start ? isIdentifierStart : isIdentifierChar;
if (this.input.charCodeAt(++this.state.pos) !== charCodes.lowercaseU) {
if (
this.state.input.charCodeAt(++this.state.pos) !== charCodes.lowercaseU
) {
this.raise(
this.state.pos,
"Expecting Unicode escape sequence \\uXXXX",
@ -1315,7 +1338,7 @@ export default class Tokenizer extends LocationParser {
break;
}
}
return word + this.input.slice(chunkStart, this.state.pos);
return word + this.state.input.slice(chunkStart, this.state.pos);
}
isIterator(word: string): boolean {
@ -1369,7 +1392,7 @@ export default class Tokenizer extends LocationParser {
(prevType === tt.name && this.state.exprAllowed)
) {
return lineBreak.test(
this.input.slice(this.state.lastTokEnd, this.state.start),
this.state.input.slice(this.state.lastTokEnd, this.state.start),
);
}

View File

@ -24,6 +24,7 @@ type TopicContextState = {
export default class State {
strict: boolean;
input: string;
length: number;
curLine: number;
@ -37,6 +38,7 @@ export default class State {
options.strictMode === false ? false : options.sourceType === "module";
this.input = input;
this.length = input.length;
this.curLine = options.startLine;
this.startLoc = this.endLoc = this.curPosition();

View File

@ -1,4 +1,4 @@
{
"sourceType": "module",
"throws": "Unexpected token, expected \"function\" (1:21)"
"throws": "Unexpected token, expected \"=>\" (1:31)"
}