perf: minimize identifier lookahead when parsing let (#13328)
This commit is contained in:
parent
f7a9f10ba4
commit
2a5b23186a
@ -0,0 +1,22 @@
|
||||
import Benchmark from "benchmark";
|
||||
import baseline from "@babel-baseline/parser";
|
||||
import current from "../../lib/index.js";
|
||||
import { report } from "../util.mjs";
|
||||
|
||||
const suite = new Benchmark.Suite();
|
||||
function createInput(length) {
|
||||
return "{ let foecnatsni };".repeat(length);
|
||||
}
|
||||
function benchCases(name, implementation, options) {
|
||||
for (const length of [64, 128, 256, 512]) {
|
||||
const input = createInput(length);
|
||||
suite.add(`${name} ${length} let and length-10 binding identifiers`, () => {
|
||||
implementation.parse(input, options);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
benchCases("baseline", baseline);
|
||||
benchCases("current", current);
|
||||
|
||||
suite.on("cycle", report).run();
|
||||
@ -4,11 +4,7 @@ import * as N from "../types";
|
||||
import { types as tt, type TokenType } from "../tokenizer/types";
|
||||
import ExpressionParser from "./expression";
|
||||
import { Errors, SourceTypeModuleErrors } from "./error";
|
||||
import {
|
||||
isIdentifierChar,
|
||||
isIdentifierStart,
|
||||
keywordRelationalOperator,
|
||||
} from "../util/identifier";
|
||||
import { isIdentifierChar, isIdentifierStart } from "../util/identifier";
|
||||
import { lineBreak } from "../util/whitespace";
|
||||
import * as charCodes from "charcodes";
|
||||
import {
|
||||
@ -49,6 +45,8 @@ const FUNC_NO_FLAGS = 0b000,
|
||||
|
||||
const loneSurrogate = /[\uD800-\uDFFF]/u;
|
||||
|
||||
const keywordRelationalOperator = /in(?:stanceof)?/y;
|
||||
|
||||
/**
|
||||
* Convert tt.privateName to tt.hash + tt.name for backward Babel 7 compat.
|
||||
* For performance reasons this routine mutates `tokens`, it is okay
|
||||
@ -183,7 +181,7 @@ export default class StatementParser extends ExpressionParser {
|
||||
*/
|
||||
isLetKeyword(context: ?string): boolean {
|
||||
const next = this.nextTokenStart();
|
||||
const nextCh = this.input.charCodeAt(next);
|
||||
const nextCh = this.codePointAtPos(next);
|
||||
// For ambiguous cases, determine if a LexicalDeclaration (or only a
|
||||
// Statement) is allowed here. If context is not empty then only a Statement
|
||||
// is allowed. However, `let [` is an explicit negative lookahead for
|
||||
@ -200,12 +198,17 @@ export default class StatementParser extends ExpressionParser {
|
||||
if (nextCh === charCodes.leftCurlyBrace) return true;
|
||||
|
||||
if (isIdentifierStart(nextCh)) {
|
||||
let pos = next + 1;
|
||||
while (isIdentifierChar(this.input.charCodeAt(pos))) {
|
||||
++pos;
|
||||
keywordRelationalOperator.lastIndex = next;
|
||||
const matched = keywordRelationalOperator.exec(this.input);
|
||||
if (matched !== null) {
|
||||
// We have seen `in` or `instanceof` so far, now check if the identfier
|
||||
// ends here
|
||||
const endCh = this.codePointAtPos(next + matched[0].length);
|
||||
if (!isIdentifierChar(endCh) && endCh !== charCodes.backslash) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const ident = this.input.slice(next, pos);
|
||||
if (!keywordRelationalOperator.test(ident)) return true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
1
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-escape-id/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-escape-id/input.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
let in\u0061;
|
||||
30
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-escape-id/output.json
vendored
Normal file
30
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-escape-id/output.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"type": "File",
|
||||
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
|
||||
"sourceType": "script",
|
||||
"interpreter": null,
|
||||
"body": [
|
||||
{
|
||||
"type": "VariableDeclaration",
|
||||
"start":0,"end":13,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":13}},
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"start":4,"end":12,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":12}},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"start":4,"end":12,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":12},"identifierName":"ina"},
|
||||
"name": "ina"
|
||||
},
|
||||
"init": null
|
||||
}
|
||||
],
|
||||
"kind": "let"
|
||||
}
|
||||
],
|
||||
"directives": []
|
||||
}
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-non-BMP/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-non-BMP/input.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
let in𝐬𝐭𝐚𝐧𝐜𝐞𝐨𝐟;
|
||||
30
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-non-BMP/output.json
vendored
Normal file
30
packages/babel-parser/test/fixtures/es2015/let/let-declaration-in-non-BMP/output.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"type": "File",
|
||||
"start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}},
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}},
|
||||
"sourceType": "script",
|
||||
"interpreter": null,
|
||||
"body": [
|
||||
{
|
||||
"type": "VariableDeclaration",
|
||||
"start":0,"end":23,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":23}},
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"start":4,"end":22,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":22}},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"start":4,"end":22,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":22},"identifierName":"in𝐬𝐭𝐚𝐧𝐜𝐞𝐨𝐟"},
|
||||
"name": "in𝐬𝐭𝐚𝐧𝐜𝐞𝐨𝐟"
|
||||
},
|
||||
"init": null
|
||||
}
|
||||
],
|
||||
"kind": "let"
|
||||
}
|
||||
],
|
||||
"directives": []
|
||||
}
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/es2015/let/let-declaration-non-BMP-identifier/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/es2015/let/let-declaration-non-BMP-identifier/input.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
let 𝐢𝐧;
|
||||
30
packages/babel-parser/test/fixtures/es2015/let/let-declaration-non-BMP-identifier/output.json
vendored
Normal file
30
packages/babel-parser/test/fixtures/es2015/let/let-declaration-non-BMP-identifier/output.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"type": "File",
|
||||
"start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
|
||||
"program": {
|
||||
"type": "Program",
|
||||
"start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
|
||||
"sourceType": "script",
|
||||
"interpreter": null,
|
||||
"body": [
|
||||
{
|
||||
"type": "VariableDeclaration",
|
||||
"start":0,"end":9,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":9}},
|
||||
"declarations": [
|
||||
{
|
||||
"type": "VariableDeclarator",
|
||||
"start":4,"end":8,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":8}},
|
||||
"id": {
|
||||
"type": "Identifier",
|
||||
"start":4,"end":8,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":8},"identifierName":"𝐢𝐧"},
|
||||
"name": "𝐢𝐧"
|
||||
},
|
||||
"init": null
|
||||
}
|
||||
],
|
||||
"kind": "let"
|
||||
}
|
||||
],
|
||||
"directives": []
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user