由于扁平状态跟踪, Tokenizer 将 Regex 误识别为嵌套括号后的除法
作者: gh-markt创建于 2025年11月29日更新于 2025年11月29日
The Issue:
- When an outer
(is encountered,this.parenis set to its index. - When a nested
(is encountered,this.parenis overwritten with the new index. The reference to the outer(is lost. - When the nested group closes
), no state restoration occurs. - When the outer group closes
),this.parenstill refers to the inner start index. Reproduction: Consider the following valid JavaScript. The/following theifcondition should be parsed as the start of a Regex literal.
// The condition includes a nested grouping (function call)
if (isValid(x)) /abc/.test(x);Expected Behavior:
The tokenizer sees the ) closing the if statement. It looks back at the matching (. It sees the if keyword preceding it. It determines that /abc/ is a Regex.
Actual Behavior:
this.parenis initially set to the index of the(afterif.this.parenis overwritten by the index of the(afterisValid.- When the tokenizer reaches the
/, it looks back using the current value ofthis.paren(the inner parenthesis). - It checks the token preceding that inner index:
isValid(an Identifier). - Standard grammar rules suggest that an identifier followed by a parenthesized group implies a function call, and a slash following that implies division (e.g.
fn() / 2). - The tokenizer incorrectly identifies
/abc/as a series of division operators and identifiers, likely causing a parse error later. Proposed Fix: We should add stacks to theReaderclass to maintain the history of open delimiters. We can keepthis.parenandthis.curlyas the properties used byisRegexStart, but they should be updated by popping from these stacks. 1. UpdateReaderproperties and constructor:
class Reader {
readonly values: ReaderEntry[];
curly: number;
paren: number;
// Add stacks to track nesting history
curlyStack: number[];
parenStack: number[];
constructor() {
this.values = [];
this.curly = this.paren = -1;
this.curlyStack = [];
this.parenStack = [];
}
// ...
}2. Update Reader.push to manage the stack:
push(token): void {
if (token.type === Token.Punctuator || token.type === Token.Keyword) {
if (token.value === '{') {
this.curlyStack.push(this.values.length);
} else if (token.value === '(') {
…内容来源: jquery/esprima