百科.dev
全部条目AI 编程趋势榜开源项目技术资讯提交条目
登录
返回工具页/返回 Issues 列表
#2132·esprima

由于扁平状态跟踪, Tokenizer 将 Regex 误识别为嵌套括号后的除法

作者: gh-markt创建于 2025年11月29日更新于 2025年11月29日

The Issue:

  1. When an outer ( is encountered, this.paren is set to its index.
  2. When a nested ( is encountered, this.paren is overwritten with the new index. The reference to the outer ( is lost.
  3. When the nested group closes ), no state restoration occurs.
  4. When the outer group closes ), this.paren still refers to the inner start index. Reproduction: Consider the following valid JavaScript. The / following the if condition should be parsed as the start of a Regex literal.
javascript
// 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:

  1. this.paren is initially set to the index of the ( after if.
  2. this.paren is overwritten by the index of the ( after isValid.
  3. When the tokenizer reaches the /, it looks back using the current value of this.paren (the inner parenthesis).
  4. It checks the token preceding that inner index: isValid (an Identifier).
  5. 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).
  6. 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 the Reader class to maintain the history of open delimiters. We can keep this.paren and this.curly as the properties used by isRegexStart, but they should be updated by popping from these stacks. 1. Update Reader properties and constructor:
typescript
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:

typescript
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

查看 GitHub 原文在 GitHub 查看讨论