Skip to content

Commit

Permalink
perf: replace lookahead by lookaheadCharCode (#10371)
Browse files Browse the repository at this point in the history
* perf: replace lookahead by lookaheadCharCode

* fix: flow ignore

* refactor: add nextTokenStart method

* refactor: duplicated isNewLine code

* refactor: remove lookahead usage from babylon core
  • Loading branch information
JLHwung authored and nicolo-ribaudo committed Oct 8, 2019
1 parent bc0966a commit 0856618
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 49 deletions.
2 changes: 1 addition & 1 deletion packages/babel-parser/src/parser/expression.js
Expand Up @@ -613,7 +613,7 @@ export default class ExpressionParser extends LValParser {
} else if (this.match(tt.questionDot)) {
this.expectPlugin("optionalChaining");
state.optionalChainMember = true;
if (noCalls && this.lookahead().type === tt.parenL) {
if (noCalls && this.lookaheadCharCode() === charCodes.leftParenthesis) {
state.stop = true;
return base;
}
Expand Down
45 changes: 17 additions & 28 deletions packages/babel-parser/src/parser/statement.js
Expand Up @@ -8,7 +8,7 @@ import {
isIdentifierStart,
keywordRelationalOperator,
} from "../util/identifier";
import { lineBreak, skipWhiteSpace } from "../util/whitespace";
import { lineBreak } from "../util/whitespace";
import * as charCodes from "charcodes";
import {
BIND_CLASS,
Expand Down Expand Up @@ -105,10 +105,7 @@ export default class StatementParser extends ExpressionParser {
if (!this.isContextual("let")) {
return false;
}
skipWhiteSpace.lastIndex = this.state.pos;
const skip = skipWhiteSpace.exec(this.input);
// $FlowIgnore
const next = this.state.pos + skip[0].length;
const next = this.nextTokenStart();
const nextCh = this.input.charCodeAt(next);
// For ambiguous cases, determine if a LexicalDeclaration (or only a
// Statement) is allowed here. If context is not empty then only a Statement
Expand Down Expand Up @@ -170,7 +167,7 @@ export default class StatementParser extends ExpressionParser {
case tt._for:
return this.parseForStatement(node);
case tt._function:
if (this.lookahead().type === tt.dot) break;
if (this.lookaheadCharCode() === charCodes.dot) break;
if (context) {
if (this.state.strict) {
this.raise(
Expand Down Expand Up @@ -223,8 +220,11 @@ export default class StatementParser extends ExpressionParser {
return this.parseEmptyStatement(node);
case tt._export:
case tt._import: {
const nextToken = this.lookahead();
if (nextToken.type === tt.parenL || nextToken.type === tt.dot) {
const nextTokenCharCode = this.lookaheadCharCode();
if (
nextTokenCharCode === charCodes.leftParenthesis ||
nextTokenCharCode === charCodes.dot
) {
break;
}

Expand Down Expand Up @@ -1746,11 +1746,11 @@ export default class StatementParser extends ExpressionParser {
maybeParseExportDeclaration(node: N.Node): boolean {
if (this.shouldParseExportDeclaration()) {
if (this.isContextual("async")) {
const next = this.lookahead();
const next = this.nextTokenStart();

// export async;
if (next.type !== tt._function) {
this.unexpected(next.start, `Unexpected token, expected "function"`);
if (!this.isUnparsedContextual(next, "function")) {
this.unexpected(next, `Unexpected token, expected "function"`);
}
}

Expand All @@ -1765,21 +1765,10 @@ export default class StatementParser extends ExpressionParser {

isAsyncFunction(): boolean {
if (!this.isContextual("async")) return false;

const { pos } = this.state;

skipWhiteSpace.lastIndex = pos;
const skip = skipWhiteSpace.exec(this.input);

if (!skip || !skip.length) return false;

const next = pos + skip[0].length;

const next = this.nextTokenStart();
return (
!lineBreak.test(this.input.slice(pos, next)) &&
this.input.slice(next, next + 8) === "function" &&
(next + 8 === this.length ||
!isIdentifierChar(this.input.charCodeAt(next + 8)))
!lineBreak.test(this.input.slice(this.state.pos, next)) &&
this.isUnparsedContextual(next, "function")
);
}

Expand Down Expand Up @@ -1841,10 +1830,10 @@ export default class StatementParser extends ExpressionParser {
return false;
}

const lookahead = this.lookahead();
const next = this.nextTokenStart();
return (
lookahead.type === tt.comma ||
(lookahead.type === tt.name && lookahead.value === "from")
this.input.charCodeAt(next) === charCodes.comma ||
this.isUnparsedContextual(next, "from")
);
}

Expand Down
26 changes: 22 additions & 4 deletions packages/babel-parser/src/parser/util.js
Expand Up @@ -4,6 +4,8 @@ import { types as tt, type TokenType } from "../tokenizer/types";
import Tokenizer from "../tokenizer";
import type { Node } from "../types";
import { lineBreak, skipWhiteSpace } from "../util/whitespace";
import { isIdentifierChar } from "../util/identifier";
import * as charCodes from "charcodes";

const literal = /^('|")((?:\\?.)*?)\1/;

Expand All @@ -26,8 +28,15 @@ export default class UtilParser extends Tokenizer {
}

isLookaheadRelational(op: "<" | ">"): boolean {
const l = this.lookahead();
return l.type === tt.relational && l.value === op;
const next = this.nextTokenStart();
if (this.input.charAt(next) === op) {
if (next + 1 === this.input.length) {
return true;
}
const afterNext = this.input.charCodeAt(next + 1);
return afterNext !== op.charCodeAt(0) && afterNext !== charCodes.equalsTo;
}
return false;
}

// TODO
Expand Down Expand Up @@ -60,9 +69,18 @@ export default class UtilParser extends Tokenizer {
);
}

isUnparsedContextual(nameStart: number, name: string): boolean {
const nameEnd = nameStart + name.length;
return (
this.input.slice(nameStart, nameEnd) === name &&
(nameEnd === this.input.length ||
!isIdentifierChar(this.input.charCodeAt(nameEnd)))
);
}

isLookaheadContextual(name: string): boolean {
const l = this.lookahead();
return l.type === tt.name && l.value === name;
const next = this.nextTokenStart();
return this.isUnparsedContextual(next, name);
}

// Consumes contextual keyword if possible.
Expand Down
9 changes: 7 additions & 2 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -19,6 +19,7 @@ import {
BIND_CLASS,
} from "../../util/scopeflags";
import TypeScriptScopeHandler from "./scope";
import * as charCodes from "charcodes";

type TsModifier =
| "readonly"
Expand Down Expand Up @@ -657,7 +658,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
: this.match(tt._null)
? "TSNullKeyword"
: keywordTypeFromName(this.state.value);
if (type !== undefined && this.lookahead().type !== tt.dot) {
if (
type !== undefined &&
this.lookaheadCharCode() !== charCodes.dot
) {
const node: N.TsKeywordType = this.startNode();
this.next();
return this.finishNode(node, type);
Expand Down Expand Up @@ -1203,7 +1207,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>

tsIsExternalModuleReference(): boolean {
return (
this.isContextual("require") && this.lookahead().type === tt.parenL
this.isContextual("require") &&
this.lookaheadCharCode() === charCodes.leftParenthesis
);
}

Expand Down
29 changes: 15 additions & 14 deletions packages/babel-parser/src/tokenizer/index.js
Expand Up @@ -13,6 +13,7 @@ import {
lineBreakG,
isNewLine,
isWhitespace,
skipWhiteSpace,
} from "../util/whitespace";
import State from "./state";

Expand Down Expand Up @@ -168,6 +169,18 @@ export default class Tokenizer extends LocationParser {
return curr;
}

nextTokenStart(): number {
const thisTokEnd = this.state.pos;
skipWhiteSpace.lastIndex = thisTokEnd;
const skip = skipWhiteSpace.exec(this.input);
// $FlowIgnore: The skipWhiteSpace ensures to match any string
return thisTokEnd + skip[0].length;
}

lookaheadCharCode(): number {
return this.input.charCodeAt(this.nextTokenStart());
}

// Toggle strict mode. Re-reads the next number or string to please
// pedantic tests (`"use strict"; 010;` should fail).

Expand Down Expand Up @@ -267,13 +280,7 @@ export default class Tokenizer extends LocationParser {
const startLoc = this.state.curPosition();
let ch = this.input.charCodeAt((this.state.pos += startSkip));
if (this.state.pos < this.length) {
while (
ch !== charCodes.lineFeed &&
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.length
) {
while (!isNewLine(ch) && ++this.state.pos < this.length) {
ch = this.input.charCodeAt(this.state.pos);
}
}
Expand Down Expand Up @@ -441,13 +448,7 @@ export default class Tokenizer extends LocationParser {
let ch = this.input.charCodeAt(this.state.pos);
if (ch !== charCodes.exclamationMark) return false;

while (
ch !== charCodes.lineFeed &&
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.length
) {
while (!isNewLine(ch) && ++this.state.pos < this.length) {
ch = this.input.charCodeAt(this.state.pos);
}

Expand Down

0 comments on commit 0856618

Please sign in to comment.