Use set in parser scope (#13408)
* chore: rename benchmark * perf: back parser scope names storage by set * chore: add benchmark
This commit is contained in:
@@ -21,13 +21,13 @@ import { Errors, type raiseFunction } from "../parser/error";
|
||||
|
||||
// Start an AST node, attaching a start offset.
|
||||
export class Scope {
|
||||
flags: ScopeFlags;
|
||||
// A list of var-declared names in the current lexical scope
|
||||
var: string[] = [];
|
||||
// A list of lexically-declared names in the current lexical scope
|
||||
lexical: string[] = [];
|
||||
// A list of lexically-declared FunctionDeclaration names in the current lexical scope
|
||||
functions: string[] = [];
|
||||
declare flags: ScopeFlags;
|
||||
// A set of var-declared names in the current lexical scope
|
||||
var: Set<string> = new Set();
|
||||
// A set of lexically-declared names in the current lexical scope
|
||||
lexical: Set<string> = new Set();
|
||||
// A set of lexically-declared FunctionDeclaration names in the current lexical scope
|
||||
functions: Set<string> = new Set();
|
||||
|
||||
constructor(flags: ScopeFlags) {
|
||||
this.flags = flags;
|
||||
@@ -104,9 +104,9 @@ export default class ScopeHandler<IScope: Scope = Scope> {
|
||||
this.checkRedeclarationInScope(scope, name, bindingType, pos);
|
||||
|
||||
if (bindingType & BIND_SCOPE_FUNCTION) {
|
||||
scope.functions.push(name);
|
||||
scope.functions.add(name);
|
||||
} else {
|
||||
scope.lexical.push(name);
|
||||
scope.lexical.add(name);
|
||||
}
|
||||
|
||||
if (bindingType & BIND_SCOPE_LEXICAL) {
|
||||
@@ -116,7 +116,7 @@ export default class ScopeHandler<IScope: Scope = Scope> {
|
||||
for (let i = this.scopeStack.length - 1; i >= 0; --i) {
|
||||
scope = this.scopeStack[i];
|
||||
this.checkRedeclarationInScope(scope, name, bindingType, pos);
|
||||
scope.var.push(name);
|
||||
scope.var.add(name);
|
||||
this.maybeExportDefined(scope, name);
|
||||
|
||||
if (scope.flags & SCOPE_VAR) break;
|
||||
@@ -153,38 +153,41 @@ export default class ScopeHandler<IScope: Scope = Scope> {
|
||||
|
||||
if (bindingType & BIND_SCOPE_LEXICAL) {
|
||||
return (
|
||||
scope.lexical.indexOf(name) > -1 ||
|
||||
scope.functions.indexOf(name) > -1 ||
|
||||
scope.var.indexOf(name) > -1
|
||||
scope.lexical.has(name) ||
|
||||
scope.functions.has(name) ||
|
||||
scope.var.has(name)
|
||||
);
|
||||
}
|
||||
|
||||
if (bindingType & BIND_SCOPE_FUNCTION) {
|
||||
return (
|
||||
scope.lexical.indexOf(name) > -1 ||
|
||||
(!this.treatFunctionsAsVarInScope(scope) &&
|
||||
scope.var.indexOf(name) > -1)
|
||||
scope.lexical.has(name) ||
|
||||
(!this.treatFunctionsAsVarInScope(scope) && scope.var.has(name))
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
(scope.lexical.indexOf(name) > -1 &&
|
||||
!(scope.flags & SCOPE_SIMPLE_CATCH && scope.lexical[0] === name)) ||
|
||||
(!this.treatFunctionsAsVarInScope(scope) &&
|
||||
scope.functions.indexOf(name) > -1)
|
||||
(scope.lexical.has(name) &&
|
||||
!(
|
||||
scope.flags & SCOPE_SIMPLE_CATCH &&
|
||||
scope.lexical.values().next().value === name
|
||||
)) ||
|
||||
(!this.treatFunctionsAsVarInScope(scope) && scope.functions.has(name))
|
||||
);
|
||||
}
|
||||
|
||||
checkLocalExport(id: N.Identifier) {
|
||||
const { name } = id;
|
||||
const topLevelScope = this.scopeStack[0];
|
||||
if (
|
||||
this.scopeStack[0].lexical.indexOf(id.name) === -1 &&
|
||||
this.scopeStack[0].var.indexOf(id.name) === -1 &&
|
||||
!topLevelScope.lexical.has(name) &&
|
||||
!topLevelScope.var.has(name) &&
|
||||
// In strict mode, scope.functions will always be empty.
|
||||
// Modules are strict by default, but the `scriptMode` option
|
||||
// can overwrite this behavior.
|
||||
this.scopeStack[0].functions.indexOf(id.name) === -1
|
||||
!topLevelScope.functions.has(name)
|
||||
) {
|
||||
this.undefinedExports.set(id.name, id.start);
|
||||
this.undefinedExports.set(name, id.start);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user