{
  "version": 3,
  "sources": ["../../../src/parser/parser.ts"],
  "sourcesContent": [
    "import { columnToIndex, indexToColumn } from \"../core/utils.mjs\";\nimport { FormulaError, type SpreadsheetRange } from \"../core/types.mjs\";\nimport type { ASTNode, RangeNode, ReferenceNode } from \"./ast.mjs\";\nimport {\n  createArrayNode,\n  createBinaryOpNode,\n  createEmptyNode,\n  createErrorNode,\n  createFunctionNode,\n  createInfinityNode,\n  createNamedExpressionNode,\n  createRangeNode,\n  createReferenceNode,\n  createStructuredReferenceNode,\n  createThreeDRangeNode,\n  createUnaryOpNode,\n  createValueNode,\n} from \"./ast.mjs\";\nimport {\n  getOperatorAssociativity,\n  getOperatorPrecedence,\n  isBinaryOperator,\n  parseCellReference,\n  parseInfiniteRange,\n  parseOpenEndedRange,\n  SPECIAL_FUNCTIONS,\n} from \"./grammar.mjs\";\nimport { Lexer, TokenStream, type Token } from \"./lexer.mjs\";\n\n/**\n * Parser error class\n */\nexport class ParseError extends Error {\n  constructor(\n    message: string,\n    public position?: { start: number; end: number }\n  ) {\n    super(message);\n    this.name = \"ParseError\";\n  }\n}\n\n/**\n * Formula parser class\n */\nexport class Parser {\n  private tokens: TokenStream;\n  private input: string;\n\n  constructor(tokens: Token[], input?: string) {\n    this.tokens = new TokenStream(tokens);\n    this.input = input || \"\";\n  }\n\n  /**\n   * Look ahead to determine if this is a workbook reference like\n   * [Workbook]!Table[...] or [Workbook]Sheet...\n   */\n  private lookAheadForWorkbookReference(): { isWorkbookReference: boolean } {\n    let pos = 1; // Start after the opening [\n    \n    // Skip through the workbook name (could be multiple tokens)\n    while (pos < 10) { // Reasonable lookahead limit\n      const token = this.tokens.peekAhead(pos);\n      if (!token || token.type === \"EOF\") {\n        return { isWorkbookReference: false };\n      }\n      \n      if (token.type === \"RBRACKET\") {\n        const nextToken = this.tokens.peekAhead(pos + 1);\n        if (nextToken?.type === \"EXCLAMATION\") {\n          return { isWorkbookReference: true };\n        }\n        if (nextToken && nextToken.type === \"IDENTIFIER\") {\n          // Look ahead further to find an exclamation mark or end of tokens\n          // This handles both simple sheet references and 3D ranges\n          let lookPos = pos + 2;\n          while (lookPos < pos + 10) { // Reasonable limit\n            const lookToken = this.tokens.peekAhead(lookPos);\n            if (!lookToken || lookToken.type === \"EOF\") {\n              // End of tokens - this is a sheet alias\n              return { isWorkbookReference: true };\n            }\n            if (lookToken.type === \"EXCLAMATION\") {\n              // Found exclamation mark - this is a workbook reference\n              return { isWorkbookReference: true };\n            }\n            // Continue looking for exclamation mark\n            lookPos++;\n          }\n        }\n        return { isWorkbookReference: false };\n      }\n      \n      // Continue if it's part of the workbook name\n      if (token.type === \"IDENTIFIER\" || token.type === \"FUNCTION\" || token.type === \"NUMBER\" || \n          (token.type === \"OPERATOR\" && (token.value === \"-\" || token.value === \"=\" || token.value === \"%\")) ||\n          token.type === \"LPAREN\" || token.type === \"RPAREN\") {\n        pos++;\n        continue;\n      }\n      \n      // If we hit something unexpected, it's not a workbook reference\n      return { isWorkbookReference: false };\n    }\n    \n    return { isWorkbookReference: false };\n  }\n\n  /**\n   * Parse workbook reference like [Workbook]!Table[Column] or [Workbook]Sheet!A1\n   */\n  private parseWorkbookReference(): ASTNode {\n    const start = this.tokens.peek().position.start;\n    this.tokens.consume(); // [\n\n    // Parse workbook name (similar to parseColumnName but for workbook)\n    const workbookStartPos = this.tokens.peek().position.start;\n    let workbookEndPos = workbookStartPos;\n    \n    // Consume tokens until we hit the closing bracket\n    while (!this.tokens.match(\"RBRACKET\")) {\n      if (this.tokens.isAtEnd()) {\n        throw new ParseError(\n          \"Expected ] to close workbook reference\",\n          this.tokens.peek().position\n        );\n      }\n      \n      // Make sure we're consuming valid workbook name tokens\n      const token = this.tokens.peek();\n      if (token.type === \"IDENTIFIER\" || token.type === \"FUNCTION\" || token.type === \"NUMBER\" || \n          (token.type === \"OPERATOR\" && (token.value === \"-\" || token.value === \"=\" || token.value === \"%\")) ||\n          token.type === \"LPAREN\" || token.type === \"RPAREN\") {\n        const consumedToken = this.tokens.consume();\n        workbookEndPos = consumedToken.position.end;\n      } else {\n        throw new ParseError(\n          `Invalid character in workbook name: ${token.value}`,\n          token.position\n        );\n      }\n    }\n    \n    // Extract workbook name from input\n    const workbookName = this.input.substring(workbookStartPos, workbookEndPos);\n    \n    this.tokens.consume(); // ]\n    \n    if (this.tokens.match(\"EXCLAMATION\")) {\n      this.tokens.consume(); // !\n      return this.parseWorkbookQualifiedTableReference(workbookName, start);\n    }\n\n    // Parse sheet name - could be start of 3D range\n    if (!this.tokens.match(\"IDENTIFIER\")) {\n      throw new ParseError(\n        \"Expected sheet name after workbook reference\",\n        this.tokens.peek().position\n      );\n    }\n    \n    const sheetToken = this.tokens.consume();\n    let sheetName = sheetToken.value;\n    \n    // Handle quoted sheet names\n    if (sheetName.startsWith(\"'\") && sheetName.endsWith(\"'\")) {\n      sheetName = sheetName.slice(1, -1).replace(/''/g, \"'\");\n    }\n    \n    // Check if this is a 3D range (Sheet1:Sheet3!)\n    if (this.tokens.match(\"COLON\")) {\n      const nextToken = this.tokens.peekAhead(1);\n      const tokenAfterNext = this.tokens.peekAhead(2);\n      \n      if (\n        nextToken?.type === \"IDENTIFIER\" &&\n        tokenAfterNext?.type === \"EXCLAMATION\"\n      ) {\n        // This is a 3D range\n        this.tokens.consume(); // :\n        const endSheetToken = this.tokens.consume(); // end sheet name\n        let endSheetName = endSheetToken.value;\n        \n        // Handle quoted end sheet names\n        if (endSheetName.startsWith(\"'\") && endSheetName.endsWith(\"'\")) {\n          endSheetName = endSheetName.slice(1, -1).replace(/''/g, \"'\");\n        }\n        \n        this.tokens.consume(); // !\n        \n        // Parse the reference after the 3D range\n        const ref = this.parseCellOrRangeAfterSheets();\n        \n        return createThreeDRangeNode(\n          sheetName,\n          endSheetName,\n          ref,\n          {\n            start,\n            end: this.tokens.peek().position?.end ?? 0,\n          },\n          workbookName\n        );\n      }\n    }\n    \n    // Check if there's an exclamation mark (explicit cell/range reference)\n    if (this.tokens.match(\"EXCLAMATION\")) {\n      this.tokens.consume(); // !\n      \n      // Parse the cell/range reference after the !\n      const cellRef = this.parseCellOrRangeWithWorkbookAndSheet(workbookName, sheetName, start);\n      return cellRef;\n    } else {\n      // This is a sheet alias: [Workbook]Sheet = [Workbook]Sheet!A1:INFINITY\n      // Create an infinite range starting from A1\n      const range: SpreadsheetRange = {\n        start: {\n          col: 0, // Column A\n          row: 0, // Row 1 (0-based)\n        },\n        end: {\n          col: {\n            type: \"infinity\",\n            sign: \"positive\",\n          },\n          row: {\n            type: \"infinity\",\n            sign: \"positive\",\n          },\n        },\n      };\n\n      return createRangeNode({\n        workbookName,\n        sheetName,\n        range,\n        isAbsolute: {\n          start: { col: false, row: false },\n          end: { col: false, row: false },\n        },\n        position: {\n          start,\n          end: this.tokens.peek().position?.start ?? 0,\n        },\n      });\n    }\n  }\n\n  private parseWorkbookQualifiedTableReference(\n    workbookName: string,\n    startPos: number\n  ): ASTNode {\n    if (!this.tokens.match(\"IDENTIFIER\")) {\n      throw new ParseError(\n        `Expected table name after [${workbookName}]!`,\n        this.tokens.peek().position\n      );\n    }\n\n    const tableName = this.tokens.consume().value;\n    if (!this.tokens.match(\"LBRACKET\")) {\n      throw new ParseError(\n        `Workbook-qualified references without a sheet only support tables. Use [${workbookName}]!${tableName}[...] for tables or [${workbookName}]Sheet!A1 for sheet references`,\n        this.tokens.peek().position\n      );\n    }\n\n    return this.parseTableReference(tableName, startPos, { workbookName });\n  }\n\n  /**\n   * Parse bare column reference like [Column] or [Column1:Column2]\n   */\n  private parseBareColumnReference(): ASTNode {\n    const startPos = this.tokens.peek().position.start;\n    this.tokens.consume(); // [\n\n    let selector: \"#All\" | \"#Data\" | \"#Headers\" | undefined;\n    let cols: { startCol: string; endCol: string } | undefined;\n    let isCurrentRow = false;\n\n    if (this.tokens.match(\"HASH\")) {\n      // Selector like [#Data]\n      this.tokens.consume(); // #\n      if (!this.tokens.match(\"IDENTIFIER\")) {\n        throw new ParseError(\n          \"Expected selector name after #\",\n          this.tokens.peek().position\n        );\n      }\n      const selectorName = this.tokens.consume().value;\n      selector = `#${selectorName}` as \"#All\" | \"#Data\" | \"#Headers\";\n    } else if (this.tokens.match(\"IDENTIFIER\")) {\n      // Column reference like [Column] or [Column1:Column2]\n      const colStart = this.parseColumnName();\n\n      // Check if it's a column range Column1:Column2\n      if (this.tokens.match(\"COLON\")) {\n        this.tokens.consume(); // :\n        const colEnd = this.parseColumnName();\n\n        cols = {\n          startCol: colStart,\n          endCol: colEnd,\n        };\n      } else {\n        // Single column\n        cols = {\n          startCol: colStart,\n          endCol: colStart,\n        };\n      }\n    } else {\n      throw new ParseError(\n        \"Expected column name or selector in bare column reference\",\n        this.tokens.peek().position\n      );\n    }\n\n    if (!this.tokens.match(\"RBRACKET\")) {\n      throw new ParseError(\n        \"Expected ] to close column reference\",\n        this.tokens.peek().position\n      );\n    }\n    this.tokens.consume(); // ]\n\n    return createStructuredReferenceNode({\n      tableName: undefined, // No table name for bare references\n      cols,\n      selector,\n      isCurrentRow,\n      position: {\n        start: startPos,\n        end: this.tokens.peek().position?.end ?? 0,\n      },\n    });\n  }\n\n  /**\n   * Parse a column name that might consist of multiple identifiers separated by spaces, contain dashes, or have parentheses\n   */\n  private parseColumnName(): string {\n    if (\n      !this.tokens.match(\"IDENTIFIER\") &&\n      !this.tokens.match(\"FUNCTION\") &&\n      !this.tokens.match(\"NUMBER\") &&\n      !this.tokens.match(\"OPERATOR\")\n    ) {\n      throw new ParseError(\"Expected column name\", this.tokens.peek().position);\n    }\n\n    // Track the start and end positions to reconstruct the original column name\n    const startToken = this.tokens.peek();\n    const startPos = startToken.position.start;\n\n    // Consume the first token\n    this.tokens.consume();\n\n    // Use a blacklist approach: consume all tokens until we hit a token that definitely ends a column name\n    // These are tokens that have special meaning in structured references and should not be part of column names\n    // Note: COLON is NOT in this list because colons can be part of column names (e.g., \"CAR:ERC ratio\")\n    // Column ranges must use explicit double-bracket syntax: Table[[Col1]:[Col2]]\n    const endTokens = new Set([\n      \"RBRACKET\",  // ] - ends the column reference\n      \"COMMA\",     // , - separates elements in complex structured references\n      \"EOF\"        // End of input\n    ]);\n\n    // Continue consuming tokens that are part of the column name\n    while (!endTokens.has(this.tokens.peek().type)) {\n      // Handle special cases where we need to validate token sequences\n      if (this.tokens.match(\"OPERATOR\")) {\n        // All operators are allowed in column names, including at the end\n        // No special validation needed - just consume the operator\n        this.tokens.consume();\n      } else {\n        // For all other token types (IDENTIFIER, FUNCTION, NUMBER, LPAREN, RPAREN, etc.)\n        // just consume them as part of the column name\n        this.tokens.consume();\n      }\n    }\n\n    // Get the end position from the last consumed token\n    const currentPos = this.tokens.getPosition();\n    let endPos =\n      currentPos > 0\n        ? this.tokens.getTokens()[currentPos - 1]?.position?.end || startPos\n        : startPos;\n\n    // For structured references, we need to include trailing spaces before the closing bracket\n    // Look ahead to see if we're about to hit a closing bracket, and if so, include any trailing spaces\n    if (this.tokens.match(\"RBRACKET\")) {\n      const nextTokenPos = this.tokens.peek().position.start;\n      // Include any whitespace between the last token and the closing bracket\n      endPos = nextTokenPos;\n    }\n\n    // Extract the original column name from the input, preserving all spacing and case\n    const columnName = this.input.substring(startPos, endPos);\n\n    return columnName;\n  }\n\n  /**\n   * Parse a formula string\n   */\n  static parse(formula: string): ASTNode {\n    // Tokenize\n    const lexer = new Lexer(formula);\n    const tokens = lexer.tokenize();\n\n    // Parse\n    const parser = new Parser(tokens, formula);\n    return parser.parseFormula();\n  }\n\n  /**\n   * Parse the entire formula\n   */\n  parseFormula(): ASTNode {\n    if (this.tokens.isAtEnd()) {\n      // Empty formula\n      return createEmptyNode();\n    }\n\n    if (this.tokens.peek().type === \"EOF\") {\n      // Handle edge case of just '=' with nothing after\n      return createErrorNode(FormulaError.ERROR, \"Empty formula\");\n    }\n\n    try {\n      const expr = this.parseExpression();\n\n      // Ensure we've consumed all tokens\n      if (!this.tokens.isAtEnd()) {\n        throw new ParseError(\n          `Unexpected token: ${this.tokens.peek().value}`,\n          this.tokens.peek().position\n        );\n      }\n\n      return expr;\n    } catch (error) {\n      if (error instanceof ParseError) {\n        throw error;\n      }\n      throw new ParseError(String(error));\n    }\n  }\n\n  /**\n   * Parse an expression (entry point for recursive descent)\n   */\n  private parseExpression(): ASTNode {\n    return this.parseBinaryExpression(0);\n  }\n\n  /**\n   * Parse binary expressions using precedence climbing\n   */\n  private parseBinaryExpression(minPrecedence: number): ASTNode {\n    let left = this.parseUnaryExpression();\n\n    while (true) {\n      const token = this.tokens.peek();\n\n      if (token.type !== \"OPERATOR\" || !isBinaryOperator(token.value)) {\n        break;\n      }\n\n      const precedence = getOperatorPrecedence(token.value);\n      if (precedence < minPrecedence) {\n        break;\n      }\n\n      const operator = token.value;\n      const associativity = getOperatorAssociativity(operator);\n      const start = token.position.start;\n\n      this.tokens.consume(); // Consume operator\n\n      // For right-associative operators, use same precedence\n      // For left-associative, use precedence + 1\n      const nextMinPrecedence =\n        associativity === \"right\" ? precedence : precedence + 1;\n      const right = this.parseBinaryExpression(nextMinPrecedence);\n\n      left = createBinaryOpNode(\n        operator,\n        left,\n        right,\n        right.position?.end\n          ? {\n              start,\n              end: right.position.end,\n            }\n          : undefined\n      );\n    }\n\n    return left;\n  }\n\n  /**\n   * Parse unary expressions\n   */\n  private parseUnaryExpression(): ASTNode {\n    const token = this.tokens.peek();\n\n    // Check for unary operators\n    if (\n      token.type === \"OPERATOR\" &&\n      (token.value === \"+\" || token.value === \"-\")\n    ) {\n      const start = token.position.start;\n      const operator = token.value as \"+\" | \"-\";\n\n      this.tokens.consume();\n      const operand = this.parseUnaryExpression();\n\n      return createUnaryOpNode(\n        operator,\n        operand,\n        operand.position\n          ? {\n              start,\n              end: operand.position.end,\n            }\n          : undefined\n      );\n    }\n\n    return this.parsePostfixExpression();\n  }\n\n  /**\n   * Parse postfix expressions (currently just %)\n   */\n  private parsePostfixExpression(): ASTNode {\n    let expr = this.parsePrimaryExpression();\n\n    // Check for percentage operator\n    if (this.tokens.match(\"OPERATOR\") && this.tokens.peek().value === \"%\") {\n      const token = this.tokens.consume();\n      expr = createUnaryOpNode(\n        \"%\",\n        expr,\n        expr.position\n          ? {\n              start: expr.position.start,\n              end: token.position.end,\n            }\n          : undefined\n      );\n    }\n\n    return expr;\n  }\n\n  /**\n   * Parse primary expressions\n   */\n  private parsePrimaryExpression(): ASTNode {\n    const token = this.tokens.peek();\n    const start = token.position.start;\n\n    switch (token.type) {\n      case \"NUMBER\":\n        return this.parseNumber();\n\n      case \"STRING\":\n        return this.parseString();\n\n      case \"BOOLEAN\":\n        return this.parseBoolean();\n\n      case \"ERROR\":\n        return this.parseError();\n\n      case \"FUNCTION\":\n        return this.parseFunctionCall();\n\n      case \"IDENTIFIER\":\n        return this.parseIdentifier();\n\n      case \"INFINITY\":\n        const infinityToken = this.tokens.consume();\n        return createInfinityNode(infinityToken.position);\n\n      case \"AT\":\n        return this.parseCurrentRowReference();\n\n      case \"HASH\":\n        return this.parseTableSelector();\n\n      case \"DOLLAR\":\n        // Handle absolute reference starting with $\n        return this.parseAbsoluteReference();\n\n      case \"LPAREN\":\n        return this.parseParenthesizedExpression();\n\n      case \"LBRACE\":\n        return this.parseArrayLiteral();\n\n      case \"LBRACKET\":\n        // Could be [@Column], [Column], [#Selector], or [Workbook]Sheet syntax\n        if (this.tokens.peekAhead(1)?.type === \"AT\") {\n          return this.parseCurrentRowReference();\n        } else if (\n          this.tokens.peekAhead(1)?.type === \"IDENTIFIER\" ||\n          this.tokens.peekAhead(1)?.type === \"FUNCTION\" ||\n          this.tokens.peekAhead(1)?.type === \"NUMBER\" ||\n          this.tokens.peekAhead(1)?.type === \"HASH\"\n        ) {\n          // Check if this is a workbook reference [Workbook]Sheet\n          // Look ahead to see if there's a closing bracket followed by an identifier (sheet name)\n          const lookahead = this.lookAheadForWorkbookReference();\n          if (lookahead.isWorkbookReference) {\n            return this.parseWorkbookReference();\n          }\n          // Bare column reference like [result] or [#Data]\n          return this.parseBareColumnReference();\n        }\n        throw new ParseError(\n          `Unexpected bracket: ${token.value}`,\n          token.position\n        );\n\n      default:\n        throw new ParseError(\n          `Unexpected token: ${token.value}`,\n          token.position\n        );\n    }\n  }\n\n  /**\n   * Parse an absolute reference starting with $\n   */\n  private parseAbsoluteReference(): ASTNode {\n    const start = this.tokens.peek().position.start;\n    let ref = \"\";\n\n    // First $\n    ref += this.tokens.consume().value;\n\n    // Get next token\n    if (this.tokens.match(\"IDENTIFIER\")) {\n      const identifier = this.tokens.consume().value;\n\n      // Check if this identifier contains both column and row (e.g., \"C3\")\n      const match = identifier.match(/^([A-Z]+)(\\d+)$/i);\n      if (match) {\n        // It's a complete cell reference like $C3\n        ref += identifier;\n      } else if (/^[A-Z]+$/i.test(identifier)) {\n        // It's just the column part\n        ref += identifier;\n\n        // Check for $ before row\n        if (this.tokens.match(\"DOLLAR\")) {\n          ref += this.tokens.consume().value;\n        }\n\n        // Row number (optional for infinite column ranges)\n        if (this.tokens.match(\"NUMBER\")) {\n          ref += this.tokens.consume().value;\n        } else if (!this.tokens.match(\"COLON\")) {\n          // Only require row number if this isn't a range starting with colon\n          throw new ParseError(\n            \"Expected row number\",\n            this.tokens.peek().position\n          );\n        }\n      } else {\n        throw new ParseError(\n          \"Invalid cell reference format\",\n          this.tokens.peek().position\n        );\n      }\n    } else if (this.tokens.match(\"NUMBER\")) {\n      // Handle absolute row ranges like $1:$100\n      const number = this.tokens.consume().value;\n      ref += number;\n    } else {\n      throw new ParseError(\n        \"Expected column letter or row number after $\",\n        this.tokens.peek().position\n      );\n    }\n\n    // Check for range\n    if (this.tokens.match(\"COLON\")) {\n      this.tokens.consume();\n      const endRef = this.parseRangeEnd();\n      return this.parseRange(\n        ref,\n        endRef,\n        start,\n        this.tokens.peek().position.start\n      );\n    }\n\n    // Parse as single cell reference\n    const cellRef = this.parseCellReferenceString(ref);\n    if (cellRef) {\n      return cellRef;\n    }\n\n    throw new ParseError(`Invalid cell reference: ${ref}`, {\n      start,\n      end: this.tokens.peek().position.start,\n    });\n  }\n\n  /**\n   * Parse a number literal or row range\n   */\n  private parseNumber(): ASTNode {\n    const token = this.tokens.peek();\n    const start = token.position.start;\n\n    // Check if this could be a row range (e.g., 5:5, 1:10)\n    if (this.tokens.peekNext() && this.tokens.peekNext()!.type === \"COLON\") {\n      // This is a row range\n      const startRow = this.tokens.consume().value;\n      this.tokens.consume(); // Consume ':'\n\n      // Get the end row (handle absolute references like $5)\n      let endRow: string = \"\";\n      if (this.tokens.match(\"DOLLAR\")) {\n        endRow += this.tokens.consume().value;\n      }\n      if (this.tokens.match(\"NUMBER\")) {\n        endRow += this.tokens.consume().value;\n      } else {\n        throw new ParseError(\n          \"Expected row number after :\",\n          this.tokens.peek().position\n        );\n      }\n\n      // Parse as an infinite row range\n      return this.parseRange(\n        startRow,\n        endRow,\n        start,\n        this.tokens.peek().position.start\n      );\n    }\n\n    // Otherwise, parse as a regular number\n    this.tokens.consume();\n    const value = parseFloat(token.value);\n\n    if (isNaN(value)) {\n      throw new ParseError(`Invalid number: ${token.value}`, token.position);\n    }\n\n    return createValueNode(\n      {\n        type: \"number\",\n        value,\n      },\n      {\n        start: token.position.start,\n        end: token.position.end,\n      }\n    );\n  }\n\n  /**\n   * Parse a string literal\n   */\n  private parseString(): ASTNode {\n    const token = this.tokens.consume();\n    return createValueNode(\n      {\n        type: \"string\",\n        value: token.value,\n      },\n      {\n        start: token.position.start,\n        end: token.position.end,\n      }\n    );\n  }\n\n  /**\n   * Parse a boolean literal\n   */\n  private parseBoolean(): ASTNode {\n    const token = this.tokens.consume();\n    const value = token.value.toUpperCase() === \"TRUE\";\n    return createValueNode(\n      {\n        type: \"boolean\",\n        value,\n      },\n      {\n        start: token.position.start,\n        end: token.position.end,\n      }\n    );\n  }\n\n  /**\n   * Parse an error literal\n   */\n  private parseError(): ASTNode {\n    const token = this.tokens.consume();\n    const error = token.value as FormulaError;\n    return createErrorNode(error, `Error literal: ${error}`, {\n      start: token.position.start,\n      end: token.position.end,\n    });\n  }\n\n  /**\n   * Parse a function call\n   */\n  private parseFunctionCall(): ASTNode {\n    const nameToken = this.tokens.consume();\n    const functionName = nameToken.value;\n    const start = nameToken.position.start;\n\n    // Check for special functions that don't require parentheses\n    if (\n      SPECIAL_FUNCTIONS.has(functionName.toUpperCase()) &&\n      !this.tokens.match(\"LPAREN\")\n    ) {\n      return createFunctionNode(functionName, [], {\n        start: start,\n        end: nameToken.position.end,\n      });\n    }\n\n    // Expect opening parenthesis\n    if (!this.tokens.match(\"LPAREN\")) {\n      throw new ParseError(\n        `Expected '(' after function name ${functionName}`,\n        this.tokens.peek().position\n      );\n    }\n\n    this.tokens.consume(); // Consume '('\n\n    // Parse arguments\n    const args: ASTNode[] = [];\n\n    // Handle empty argument list\n    if (this.tokens.match(\"RPAREN\")) {\n      const rparenToken = this.tokens.consume();\n      const endPos = rparenToken.position.end;\n      const node = createFunctionNode(functionName, args, {\n        start: start,\n        end: endPos,\n      });\n\n      return node;\n    }\n\n    // Parse arguments\n    while (true) {\n      args.push(this.parseExpression());\n\n      if (this.tokens.match(\"COMMA\")) {\n        this.tokens.consume();\n        // Continue parsing next argument\n      } else if (this.tokens.match(\"RPAREN\")) {\n        const rparenToken = this.tokens.consume();\n        const end = rparenToken.position.end;\n        const node = createFunctionNode(functionName, args, {\n          start: start,\n          end: end,\n        });\n\n        return node;\n      } else {\n        throw new ParseError(\n          `Expected ',' or ')' in function arguments`,\n          this.tokens.peek().position\n        );\n      }\n    }\n\n    // This should never be reached\n    throw new ParseError(\n      \"Unexpected end of function argument parsing\",\n      this.tokens.peek().position\n    );\n  }\n\n  /**\n   * Parse an identifier (cell reference, range, or named expression)\n   */\n  private parseIdentifier(): ASTNode {\n    const start = this.tokens.peek().position.start;\n\n    // Regular identifier\n    const token = this.tokens.consume();\n    let value = token.value;\n\n    // Check if this could be a 3D range (Sheet1:Sheet3!)\n    // To distinguish from normal ranges, we check:\n    // 1. If there's a colon\n    // 2. If what follows the colon is an identifier\n    // 3. If that identifier is followed by !\n    if (this.tokens.match(\"COLON\")) {\n      const colonPos = this.tokens.getPosition();\n\n      // Look ahead to see if this looks like a 3D range\n      const nextToken = this.tokens.peekAhead(1);\n      const tokenAfterNext = this.tokens.peekAhead(2);\n\n      if (\n        nextToken?.type === \"IDENTIFIER\" &&\n        tokenAfterNext?.type === \"EXCLAMATION\"\n      ) {\n        // This looks like a 3D range, consume the tokens\n        this.tokens.consume(); // :\n        const endSheetToken = this.tokens.consume(); // sheet name\n        const endSheet = endSheetToken.value;\n        this.tokens.consume(); // !\n\n        // Extract sheet names\n        let startSheet = value;\n        if (startSheet.startsWith(\"'\") && startSheet.endsWith(\"'\")) {\n          startSheet = startSheet.slice(1, -1).replace(/''/g, \"'\");\n        }\n\n        let endSheetName = endSheet;\n        if (endSheetName.startsWith(\"'\") && endSheetName.endsWith(\"'\")) {\n          endSheetName = endSheetName.slice(1, -1).replace(/''/g, \"'\");\n        }\n\n        // Parse the reference after the sheet range\n        const ref = this.parseCellOrRangeAfterSheets();\n        return createThreeDRangeNode(\n          startSheet,\n          endSheetName,\n          ref as ReferenceNode | RangeNode,\n          {\n            start,\n            end: this.tokens.peek().position?.end ?? 0,\n          }\n        );\n      }\n      // Not a 3D range, continue with normal parsing\n    }\n\n    // Check if this is a sheet reference (Sheet1! or 'My Sheet'!)\n    if (this.tokens.match(\"EXCLAMATION\")) {\n      this.tokens.consume(); // Consume '!'\n\n      // Extract sheet name (remove quotes if present)\n      let sheetName = value;\n      if (sheetName.startsWith(\"'\") && sheetName.endsWith(\"'\")) {\n        sheetName = sheetName.slice(1, -1).replace(/''/g, \"'\"); // Remove quotes and unescape\n      }\n\n      // Now parse the cell reference after the sheet name\n      const cellRef = this.parseCellOrRangeWithSheet(sheetName, start);\n      return cellRef;\n    }\n\n    // Check if this is a table reference (Table1[Column1])\n    if (this.tokens.match(\"LBRACKET\")) {\n      return this.parseTableReference(value, start);\n    }\n\n    // Check if this could be part of a cell reference (e.g., D in D$4)\n    if (this.tokens.match(\"DOLLAR\") && this.isColumnIdentifier(value)) {\n      // This is a mixed reference like D$4\n      value += this.tokens.consume().value; // Add $\n\n      // Get the row number\n      if (this.tokens.match(\"NUMBER\")) {\n        value += this.tokens.consume().value;\n      } else {\n        throw new ParseError(\n          \"Expected row number after $\",\n          this.tokens.peek().position\n        );\n      }\n    } else if (this.tokens.match(\"NUMBER\") && this.isColumnIdentifier(value)) {\n      // Regular cell reference like D4\n      value += this.tokens.consume().value;\n    }\n\n    // Check for colon (range operator)\n    if (this.tokens.match(\"COLON\")) {\n      this.tokens.consume(); // Consume ':'\n\n      // Parse end of range with potential $ signs\n      const endStart = this.tokens.peek().position.start;\n      const endRef = this.parseRangeEnd();\n      const endPos = this.tokens.peek().position.start;\n\n      // Parse as range\n      return this.parseRange(value, endRef, start, endPos);\n    }\n\n    // Try to parse as cell reference\n    const parsedCellRef = this.parseCellReferenceString(value);\n    if (parsedCellRef) {\n      return parsedCellRef;\n    }\n\n    // Otherwise, it's a named expression\n    return createNamedExpressionNode(value, {\n      start: start,\n      end: token.position.end,\n    });\n  }\n\n  /**\n   * Check if a string is a valid column identifier (A-Z, AA-ZZ, etc.)\n   */\n  private isColumnIdentifier(str: string): boolean {\n    return /^[A-Z]+$/i.test(str);\n  }\n\n  /**\n   * Parse the end part of a range (handling $ signs, infinite ranges, and open-ended ranges)\n   */\n  private parseRangeEnd(): string {\n    let result = \"\";\n\n    // Check for INFINITY token (for A5:INFINITY syntax)\n    if (this.tokens.match(\"INFINITY\")) {\n      result += this.tokens.consume().value;\n      return result;\n    }\n\n    // Check for $ before column or row\n    if (this.tokens.match(\"DOLLAR\")) {\n      result += this.tokens.consume().value;\n    }\n\n    // Get identifier part (for column) or number part (for row)\n    if (this.tokens.match(\"IDENTIFIER\")) {\n      result += this.tokens.consume().value;\n\n      // For normal ranges, check for $ before row\n      if (this.tokens.match(\"DOLLAR\")) {\n        result += this.tokens.consume().value;\n      }\n\n      // Get number part if present (normal range)\n      if (this.tokens.match(\"NUMBER\")) {\n        result += this.tokens.consume().value;\n      }\n      // If no number, it's an infinite column range (e.g., A:A) or open-ended range (e.g., A5:D)\n    } else if (this.tokens.match(\"NUMBER\")) {\n      // This handles cases like:\n      // - Infinite row range (e.g., 5:5)\n      // - Open-ended range (e.g., A5:15)\n      // - Absolute row reference (e.g., A5:$15)\n      result += this.tokens.consume().value;\n    } else {\n      throw new ParseError(\n        \"Expected cell reference, column, row, or INFINITY after :\",\n        this.tokens.peek().position\n      );\n    }\n\n    return result;\n  }\n\n  /**\n   * Parse a parenthesized expression\n   */\n  private parseParenthesizedExpression(): ASTNode {\n    const start = this.tokens.peek().position.start;\n    this.tokens.consume(); // Consume '('\n\n    const expr = this.parseExpression();\n\n    if (!this.tokens.match(\"RPAREN\")) {\n      throw new ParseError(`Expected ')'`, this.tokens.peek().position);\n    }\n\n    const end = this.tokens.peek().position.end;\n    this.tokens.consume(); // Consume ')'\n\n    // Update position to include parentheses\n    if (expr.position) {\n      expr.position.start = start;\n      expr.position.end = end;\n    }\n\n    return expr;\n  }\n\n  /**\n   * Parse an array literal\n   */\n  private parseArrayLiteral(): ASTNode {\n    const start = this.tokens.peek().position.start;\n    this.tokens.consume(); // Consume '{'\n\n    const rows: ASTNode[][] = [];\n    let currentRow: ASTNode[] = [];\n\n    // Handle empty array\n    if (this.tokens.match(\"RBRACE\")) {\n      this.tokens.consume();\n      return createArrayNode([[createEmptyNode()]], {\n        start: start,\n        end: this.tokens.peek().position.start,\n      });\n    }\n\n    // Parse array elements\n    while (true) {\n      currentRow.push(this.parseExpression());\n\n      if (this.tokens.match(\"COMMA\")) {\n        this.tokens.consume();\n        // Continue current row\n      } else if (this.tokens.match(\"SEMICOLON\")) {\n        this.tokens.consume();\n        // Start new row\n        rows.push(currentRow);\n        currentRow = [];\n      } else if (this.tokens.match(\"RBRACE\")) {\n        this.tokens.consume();\n        // End of array\n        rows.push(currentRow);\n        break;\n      } else {\n        throw new ParseError(\n          `Expected ',', ';', or '}' in array literal`,\n          this.tokens.peek().position\n        );\n      }\n    }\n\n    // Validate that all rows have the same length\n    if (rows.length > 0 && rows[0]) {\n      const rowLength = rows[0].length;\n      for (let i = 1; i < rows.length; i++) {\n        const row = rows[i];\n        if (row && row.length !== rowLength) {\n          throw new ParseError(`Inconsistent row lengths in array literal`, {\n            start,\n            end: this.tokens.peek().position.start,\n          });\n        }\n      }\n    }\n\n    return createArrayNode(rows, {\n      start: start,\n      end: this.tokens.peek().position.start,\n    });\n  }\n\n  /**\n   * Parse a cell reference string\n   */\n  private parseCellReferenceString(value: string): ReferenceNode | null {\n    const parsed = parseCellReference(value);\n    if (!parsed) {\n      return null;\n    }\n\n    // Convert to SimpleCellAddress\n    const colNum = columnToIndex(parsed.col);\n    const rowNum = parseInt(parsed.row) - 1; // Convert to 0-based\n\n    if (colNum < 0 || rowNum < 0) {\n      return null;\n    }\n\n    return createReferenceNode({\n      address: {\n        colIndex: colNum,\n        rowIndex: rowNum,\n      },\n      isAbsolute: {\n        col: parsed.colAbsolute,\n        row: parsed.rowAbsolute,\n      },\n      sheetName: parsed.sheet,\n    });\n  }\n\n  /**\n   * Parse table reference (e.g., Table1[Column1])\n   */\n  private parseTableReference(\n    tableName: string,\n    startPos: number,\n    qualifiers?: {\n      sheetName?: string;\n      workbookName?: string;\n    }\n  ): ASTNode {\n    const { sheetName, workbookName } = qualifiers ?? {};\n    this.tokens.consume(); // [\n\n    let selector: \"#All\" | \"#Data\" | \"#Headers\" | undefined;\n    let cols: { startCol: string; endCol: string } | undefined;\n    let isCurrentRow = false;\n\n    // Check for complex syntax like [[#Headers],[Column1]] or [[Column1]:[Column2]]\n    if (this.tokens.match(\"LBRACKET\")) {\n      this.tokens.consume(); // second [\n\n      if (this.tokens.match(\"HASH\")) {\n        this.tokens.consume(); // #\n        if (!this.tokens.match(\"IDENTIFIER\")) {\n          throw new ParseError(\n            \"Expected selector name after #\",\n            this.tokens.peek().position\n          );\n        }\n        const selectorName = this.tokens.consume().value;\n        selector = `#${selectorName}` as \"#All\" | \"#Data\" | \"#Headers\";\n\n        if (!this.tokens.match(\"RBRACKET\")) {\n          throw new ParseError(\n            \"Expected ] after selector\",\n            this.tokens.peek().position\n          );\n        }\n        this.tokens.consume(); // ]\n\n        // Check for column part\n        if (this.tokens.match(\"COMMA\")) {\n          this.tokens.consume(); // ,\n\n          if (!this.tokens.match(\"LBRACKET\")) {\n            throw new ParseError(\n              \"Expected [ after comma\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // [\n\n          // Parse column specification - could be [Column1], [Column1:Column2], or [Column1]:[Column2]\n          if (\n            !this.tokens.match(\"IDENTIFIER\") &&\n            !this.tokens.match(\"FUNCTION\") &&\n            !this.tokens.match(\"NUMBER\") &&\n            !this.tokens.match(\"OPERATOR\")\n          ) {\n            throw new ParseError(\n              \"Expected column name\",\n              this.tokens.peek().position\n            );\n          }\n          const colStart = this.parseColumnName();\n\n          // Check if it's a column range inside single brackets [Column1:Column2]\n          // But not if followed by ] (which would be the Excel-style [Column1]:[Column2])\n          if (this.tokens.match(\"COLON\") && !this.tokens.peekAhead(1)?.type.match(/RBRACKET/)) {\n            this.tokens.consume(); // :\n\n            if (\n              !this.tokens.match(\"IDENTIFIER\") &&\n              !this.tokens.match(\"FUNCTION\") &&\n              !this.tokens.match(\"NUMBER\") &&\n              !this.tokens.match(\"OPERATOR\")\n            ) {\n              throw new ParseError(\n                \"Expected end column name after :\",\n                this.tokens.peek().position\n              );\n            }\n            const colEnd = this.parseColumnName();\n\n            cols = {\n              startCol: colStart,\n              endCol: colEnd,\n            };\n          } else {\n            // Single column\n            cols = {\n              startCol: colStart,\n              endCol: colStart,\n            };\n          }\n\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] after column specification\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // ]\n\n          // Check for Excel-style column range [Column1]:[Column2]\n          if (this.tokens.match(\"COLON\")) {\n            this.tokens.consume(); // :\n\n            if (!this.tokens.match(\"LBRACKET\")) {\n              throw new ParseError(\n                \"Expected [ after : in column range\",\n                this.tokens.peek().position\n              );\n            }\n            this.tokens.consume(); // [\n\n            if (\n              !this.tokens.match(\"IDENTIFIER\") &&\n              !this.tokens.match(\"FUNCTION\") &&\n              !this.tokens.match(\"NUMBER\") &&\n              !this.tokens.match(\"OPERATOR\")\n            ) {\n              throw new ParseError(\n                \"Expected end column name\",\n                this.tokens.peek().position\n              );\n            }\n            const colEnd = this.parseColumnName();\n\n            if (!this.tokens.match(\"RBRACKET\")) {\n              throw new ParseError(\n                \"Expected ] after end column name\",\n                this.tokens.peek().position\n              );\n            }\n            this.tokens.consume(); // ]\n\n            cols = {\n              startCol: colStart,\n              endCol: colEnd,\n            };\n          }\n        }\n\n        if (!this.tokens.match(\"RBRACKET\")) {\n          throw new ParseError(\n            \"Expected ] to close table reference\",\n            this.tokens.peek().position\n          );\n        }\n        this.tokens.consume(); // outer ]\n      } else if (\n        this.tokens.match(\"IDENTIFIER\") ||\n        this.tokens.match(\"FUNCTION\") ||\n        this.tokens.match(\"NUMBER\") ||\n        this.tokens.match(\"OPERATOR\")\n      ) {\n        // Handle [[Column]] or [[Column1]:[Column2]] syntax\n        const colStart = this.parseColumnName();\n\n        if (!this.tokens.match(\"RBRACKET\")) {\n          throw new ParseError(\n            \"Expected ] after column name\",\n            this.tokens.peek().position\n          );\n        }\n        this.tokens.consume(); // ]\n\n        // Check if this is a column range [[Column1]:[Column2]] or single column [[Column]]\n        if (this.tokens.match(\"COLON\")) {\n          this.tokens.consume(); // :\n\n          if (!this.tokens.match(\"LBRACKET\")) {\n            throw new ParseError(\n              \"Expected [ before second column name\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // [\n\n          const colEnd = this.parseColumnName();\n\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] after second column name\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // ]\n\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] to close table reference\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // outer ]\n\n          cols = {\n            startCol: colStart,\n            endCol: colEnd,\n          };\n        } else {\n          // Single column with double brackets [[Column]]\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] to close table reference\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // outer ]\n\n          cols = {\n            startCol: colStart,\n            endCol: colStart,\n          };\n        }\n      }\n    } else if (this.tokens.match(\"AT\")) {\n      // Current row reference like Table1[@Column]\n      this.tokens.consume(); // @\n      isCurrentRow = true;\n\n      if (this.tokens.match(\"LBRACKET\")) {\n        // Handle [@[Column]] or [@[Column1]:[Column2]] syntax\n        this.tokens.consume(); // [\n\n        const colStart = this.parseColumnName();\n\n        if (!this.tokens.match(\"RBRACKET\")) {\n          throw new ParseError(\n            \"Expected ] after column name\",\n            this.tokens.peek().position\n          );\n        }\n        this.tokens.consume(); // ]\n\n        // Check if this is a column range [@[Column1]:[Column2]]\n        if (this.tokens.match(\"COLON\")) {\n          this.tokens.consume(); // :\n\n          if (!this.tokens.match(\"LBRACKET\")) {\n            throw new ParseError(\n              \"Expected [ before second column name\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // [\n\n          const colEnd = this.parseColumnName();\n\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] after second column name\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // ]\n\n          cols = {\n            startCol: colStart,\n            endCol: colEnd,\n          };\n        } else {\n          // Single column [@[Column]]\n          cols = {\n            startCol: colStart,\n            endCol: colStart,\n          };\n        }\n\n        if (!this.tokens.match(\"RBRACKET\")) {\n          throw new ParseError(\n            \"Expected ] to close table reference\",\n            this.tokens.peek().position\n          );\n        }\n        this.tokens.consume(); // ]\n      } else {\n        // Handle [@Column] or [@Column1:Column2] syntax (simple current row)\n        const colStart = this.parseColumnName();\n\n        // Check if it's a column range Column1:Column2\n        if (this.tokens.match(\"COLON\")) {\n          this.tokens.consume(); // :\n\n          const colEnd = this.parseColumnName();\n\n          cols = {\n            startCol: colStart,\n            endCol: colEnd,\n          };\n        } else {\n          // Single column\n          cols = {\n            startCol: colStart,\n            endCol: colStart,\n          };\n        }\n\n        if (!this.tokens.match(\"RBRACKET\")) {\n          throw new ParseError(\n            \"Expected ] after column reference\",\n            this.tokens.peek().position\n          );\n        }\n        this.tokens.consume(); // ]\n      }\n    } else if (\n      this.tokens.match(\"IDENTIFIER\") ||\n      this.tokens.match(\"FUNCTION\") ||\n      this.tokens.match(\"NUMBER\") ||\n      this.tokens.match(\"OPERATOR\")\n    ) {\n      // Simple column reference like Table1[Column1] or range Table1[Column1:Column2]\n      const colStart = this.parseColumnName();\n\n      // Check if it's a column range Column1:Column2\n      if (this.tokens.match(\"COLON\")) {\n        this.tokens.consume(); // :\n\n        const colEnd = this.parseColumnName();\n\n        cols = {\n          startCol: colStart,\n          endCol: colEnd,\n        };\n      } else {\n        // Single column\n        cols = {\n          startCol: colStart,\n          endCol: colStart,\n        };\n      }\n\n      if (!this.tokens.match(\"RBRACKET\")) {\n        throw new ParseError(\n          \"Expected ] after column name\",\n          this.tokens.peek().position\n        );\n      }\n      this.tokens.consume(); // ]\n    } else if (this.tokens.match(\"HASH\")) {\n      // Simple selector reference like Table1[#Data]\n      this.tokens.consume(); // #\n\n      if (!this.tokens.match(\"IDENTIFIER\")) {\n        throw new ParseError(\n          \"Expected selector name after #\",\n          this.tokens.peek().position\n        );\n      }\n      const selectorName = this.tokens.consume().value;\n      selector = `#${selectorName}` as \"#All\" | \"#Data\" | \"#Headers\";\n\n      if (!this.tokens.match(\"RBRACKET\")) {\n        throw new ParseError(\n          \"Expected ] after selector\",\n          this.tokens.peek().position\n        );\n      }\n      this.tokens.consume(); // ]\n    } else {\n      throw new ParseError(\n        \"Expected column name or selector in table reference\",\n        this.tokens.peek().position\n      );\n    }\n\n    return createStructuredReferenceNode({\n      tableName,\n      sheetName,\n      workbookName,\n      cols,\n      selector,\n      isCurrentRow,\n      position: {\n        start: startPos,\n        end: this.tokens.peek().position?.end ?? 0,\n      },\n    });\n  }\n\n  /**\n   * Parse table reference with sheet name (e.g., Sheet1!Table1[Column1])\n   */\n  private parseTableReferenceWithSheet(\n    tableName: string,\n    sheetName: string,\n    startPos: number\n  ): ASTNode {\n    return this.parseTableReference(tableName, startPos, { sheetName });\n  }\n\n  /**\n   * Parse cell or range after sheet range in 3D reference\n   */\n  private parseCellOrRangeAfterSheets(): RangeNode | ReferenceNode {\n    const start = this.tokens.peek().position?.start ?? 0;\n\n    // Could be a simple cell reference like A1, or a range like A1:B2\n    if (this.tokens.match(\"IDENTIFIER\")) {\n      const firstIdent = this.tokens.consume().value;\n\n      // Check if it's a complete cell reference (e.g., A1)\n      const cellRef = this.parseCellReferenceString(firstIdent);\n      if (cellRef) {\n        // Check if this is part of a range\n        if (this.tokens.match(\"COLON\")) {\n          this.tokens.consume(); // :\n\n          // Parse end of range\n          const endRef = this.parseRangeEnd();\n          const endPos = this.tokens.peek().position?.end ?? 0;\n\n          // Parse as range without sheet (sheet is handled by 3D range)\n          const parsed = this.parseRange(firstIdent, endRef, start, endPos);\n\n          // Remove sheet from range node if present\n          if (parsed.type === \"range\") {\n            parsed.sheetName = undefined;\n          }\n\n          return parsed;\n        }\n\n        // Single cell reference\n        if (cellRef.type === \"reference\") {\n          cellRef.sheetName = undefined;\n        }\n        return cellRef;\n      }\n    }\n\n    // Handle absolute references starting with $\n    if (this.tokens.match(\"DOLLAR\")) {\n      const dollarStart = this.tokens.getPosition();\n      this.tokens.consume(); // $\n\n      let ref = \"$\";\n\n      // Get column\n      if (this.tokens.match(\"IDENTIFIER\")) {\n        const col = this.tokens.consume().value;\n        if (this.isColumnIdentifier(col)) {\n          ref += col;\n        }\n      }\n\n      // Check for row absolute\n      if (this.tokens.match(\"DOLLAR\")) {\n        ref += this.tokens.consume().value;\n      }\n\n      // Get row number\n      if (this.tokens.match(\"NUMBER\")) {\n        ref += this.tokens.consume().value;\n      }\n\n      // Check if this is a range\n      if (this.tokens.match(\"COLON\")) {\n        this.tokens.consume(); // :\n\n        // Parse end of range\n        const endRef = this.parseRangeEnd();\n        const endPos = this.tokens.peek().position?.end ?? 0;\n\n        // Parse as range without sheet (sheet is handled by 3D range)\n        const parsed = this.parseRange(ref, endRef, start, endPos);\n\n        // Remove sheet from range node if present\n        if (parsed.type === \"range\") {\n          parsed.sheetName = undefined;\n        }\n\n        return parsed;\n      }\n\n      // Single cell reference\n      const cellRef = this.parseCellReferenceString(ref);\n      if (!cellRef) {\n        throw new ParseError(\n          `Invalid cell reference: ${ref}`,\n          this.tokens.peek().position\n        );\n      }\n\n      // Remove sheet from reference node if present\n      if (cellRef.type === \"reference\") {\n        cellRef.sheetName = undefined;\n      }\n\n      return cellRef;\n    }\n\n    throw new ParseError(\n      \"Expected cell or range reference after sheet range\",\n      this.tokens.peek().position\n    );\n  }\n\n  /**\n   * Parse current row reference (e.g., [@Column], [@[Column Name]], or just @Column)\n   */\n  private parseCurrentRowReference(): ASTNode {\n    const start = this.tokens.getPosition();\n\n    // Handle [@Column] or [@[Column Name]] format\n    if (this.tokens.match(\"LBRACKET\")) {\n      this.tokens.consume(); // [\n\n      if (!this.tokens.match(\"AT\")) {\n        throw new ParseError(\"Expected @ after [\", this.tokens.peek().position);\n      }\n      this.tokens.consume(); // @\n\n      let columnName: string;\n\n      // Check if we have double brackets [@[Column Name]] or [@[Column1]:[Column2]]\n      if (this.tokens.match(\"LBRACKET\")) {\n        this.tokens.consume(); // [\n        const colStart = this.parseColumnName();\n\n        if (!this.tokens.match(\"RBRACKET\")) {\n          throw new ParseError(\n            \"Expected ] to close column name\",\n            this.tokens.peek().position\n          );\n        }\n        this.tokens.consume(); // ]\n\n        // Check if this is a column range [@[Column1]:[Column2]]\n        if (this.tokens.match(\"COLON\")) {\n          this.tokens.consume(); // :\n\n          if (!this.tokens.match(\"LBRACKET\")) {\n            throw new ParseError(\n              \"Expected [ before second column name\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // [\n\n          const colEnd = this.parseColumnName();\n\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] after second column name\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // ]\n\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] to close column range\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // ]\n\n          return createStructuredReferenceNode({\n            tableName: undefined,\n            cols: {\n              startCol: colStart,\n              endCol: colEnd,\n            },\n            isCurrentRow: true,\n            position: {\n              start: this.tokens.getTokens()[start]?.position?.start ?? 0,\n              end: this.tokens.peek().position?.end ?? 0,\n            },\n          });\n        } else {\n          // Single column [@[Column]]\n          if (!this.tokens.match(\"RBRACKET\")) {\n            throw new ParseError(\n              \"Expected ] after column reference\",\n              this.tokens.peek().position\n            );\n          }\n          this.tokens.consume(); // ]\n\n          return createStructuredReferenceNode({\n            tableName: undefined,\n            cols: {\n              startCol: colStart,\n              endCol: colStart,\n            },\n            isCurrentRow: true,\n            position: {\n              start: this.tokens.getTokens()[start]?.position?.start ?? 0,\n              end: this.tokens.peek().position?.end ?? 0,\n            },\n          });\n        }\n      } else {\n        // Single bracket format [@Column] - colons in column names are preserved\n        columnName = this.parseColumnName();\n      }\n\n      if (!this.tokens.match(\"RBRACKET\")) {\n        throw new ParseError(\n          \"Expected ] after column reference\",\n          this.tokens.peek().position\n        );\n      }\n      this.tokens.consume(); // ]\n\n      return createStructuredReferenceNode({\n        tableName: undefined,\n        cols: {\n          startCol: columnName,\n          endCol: columnName,\n        },\n        isCurrentRow: true,\n        position: {\n          start: this.tokens.getTokens()[start]?.position?.start ?? 0,\n          end: this.tokens.peek().position?.end ?? 0,\n        },\n      });\n    }\n\n    // Handle @Column format (without brackets)\n    this.tokens.consume(); // @\n    const columnName = this.parseColumnName();\n\n    return createStructuredReferenceNode({\n      tableName: undefined,\n      cols: {\n        startCol: columnName,\n        endCol: columnName,\n      },\n      isCurrentRow: true,\n      position: {\n        start: this.tokens.getTokens()[start]?.position?.start ?? 0,\n        end: this.tokens.peek().position?.end ?? 0,\n      },\n    });\n  }\n\n  /**\n   * Parse table selector (e.g., #Headers, #Data)\n   */\n  private parseTableSelector(): ASTNode {\n    const hashToken = this.tokens.consume(); // #\n\n    if (!this.tokens.match(\"IDENTIFIER\")) {\n      throw new ParseError(\n        \"Expected selector name after #\",\n        this.tokens.peek().position\n      );\n    }\n\n    const selectorName = this.tokens.consume().value;\n    const selector = `#${selectorName}`;\n\n    // Check if it's a valid selector\n    if (![\"#All\", \"#Data\", \"#Headers\"].includes(selector.toUpperCase())) {\n      throw new ParseError(\n        `Invalid table selector: ${selector}`,\n        hashToken.position\n      );\n    }\n\n    // For now, return an error node as selectors need to be part of a table reference\n    throw new ParseError(\n      \"Table selector must be part of a table reference\",\n      hashToken.position\n    );\n  }\n\n  /**\n   * Parse a range reference with workbook name\n   */\n  private parseRangeWithWorkbook(\n    startRef: string,\n    endRef: string,\n    workbookName: string,\n    startPos: number,\n    endPos: number\n  ): RangeNode {\n    const rangeNode = this.parseRange(startRef, endRef, startPos, endPos);\n    rangeNode.workbookName = workbookName;\n    return rangeNode;\n  }\n\n  /**\n   * Parse a range reference (including infinite ranges)\n   */\n  private parseRange(\n    startRef: string,\n    endRef: string,\n    startPos: number,\n    endPos: number\n  ): RangeNode {\n    // For cross-sheet ranges, handle the case where only startRef includes the sheet\n    let fullRange = `${startRef}:${endRef}`;\n    let sheetName: string | undefined;\n\n    // Check if start has a sheet prefix\n    const sheetMatch = startRef.match(\n      /^(?:([A-Za-z_][A-Za-z0-9_]*)|'([^']+)')!/\n    );\n    if (sheetMatch) {\n      sheetName = sheetMatch[1] || sheetMatch[2];\n\n      // First, try to parse as an infinite range or open-ended range without modifying the range\n      // This handles cases like Sheet1!A:A, Sheet1!5:5, Sheet1!A5:INFINITY, etc.\n      const infiniteTest = parseInfiniteRange(fullRange);\n      const openEndedTest = parseOpenEndedRange(fullRange);\n      if (infiniteTest || openEndedTest) {\n        // It's an infinite or open-ended range, skip to processing it below\n      } else {\n        // Not an infinite or open-ended range, so handle normal cross-sheet ranges\n        const endSheetMatch = endRef.match(\n          /^(?:([A-Za-z_][A-Za-z0-9_]*)|'([^']+)')!/\n        );\n        if (!endSheetMatch && sheetName) {\n          // Normal case: prepend sheet name to endRef for consistent parsing\n          const quotedSheetName = sheetName.includes(\" \")\n            ? `'${sheetName}'`\n            : sheetName;\n          endRef = `${quotedSheetName}!${endRef}`;\n          fullRange = `${startRef}:${endRef}`;\n        }\n      }\n    }\n\n    // Try to parse as an infinite range\n    const infiniteParsed = parseInfiniteRange(fullRange);\n\n    if (infiniteParsed) {\n      // Handle infinite range\n      sheetName = sheetName ?? infiniteParsed.sheet;\n\n      if (infiniteParsed.type === \"column\") {\n        // Infinite column range (e.g., A:A, B:D)\n        const startCol = columnToIndex(infiniteParsed.start);\n        const endCol = columnToIndex(infiniteParsed.end);\n\n        if (startCol < 0 || endCol < 0) {\n          throw new ParseError(`Invalid column range: ${startRef}:${endRef}`, {\n            start: startPos,\n            end: endPos,\n          });\n        }\n\n        // Use special row values to indicate infinite range\n        // We'll use -1 to indicate infinite\n        const range: SpreadsheetRange = {\n          start: {\n            col: Math.min(startCol, endCol),\n            row: 0, // Start from row 0\n          },\n          end: {\n            col: {\n              type: \"number\",\n              value: Math.max(startCol, endCol),\n            },\n            row: {\n              type: \"infinity\",\n              sign: \"positive\",\n            },\n          },\n        };\n\n        return createRangeNode({\n          sheetName,\n          range,\n          isAbsolute: {\n            start: {\n              col: infiniteParsed.startAbsolute,\n              row: false,\n            },\n            end: {\n              col: infiniteParsed.endAbsolute,\n              row: false,\n            },\n          },\n          position: {\n            start: startPos,\n            end: endPos,\n          },\n        });\n      } else {\n        // Infinite row range (e.g., 5:5, 1:10)\n        const startRow = parseInt(infiniteParsed.start) - 1;\n        const endRow = parseInt(infiniteParsed.end) - 1;\n\n        if (startRow < 0 || endRow < 0) {\n          throw new ParseError(`Invalid row range: ${startRef}:${endRef}`, {\n            start: startPos,\n            end: endPos,\n          });\n        }\n\n        const range: SpreadsheetRange = {\n          start: {\n            col: 0, // Start from column 0\n            row: Math.min(startRow, endRow),\n          },\n          end: {\n            col: {\n              type: \"infinity\",\n              sign: \"positive\",\n            },\n            row: {\n              type: \"number\",\n              value: Math.max(startRow, endRow),\n            },\n          },\n        };\n\n        return createRangeNode({\n          sheetName,\n          range,\n          isAbsolute: {\n            start: {\n              col: false,\n              row: infiniteParsed.startAbsolute,\n            },\n            end: {\n              col: false,\n              row: infiniteParsed.endAbsolute,\n            },\n          },\n          position: {\n            start: startPos,\n            end: endPos,\n          },\n        });\n      }\n    }\n\n    // Try to parse as an open-ended range (A5:INFINITY, A5:D, A5:15)\n    const openEndedParsed = parseOpenEndedRange(fullRange);\n\n    if (openEndedParsed) {\n      // Handle open-ended range\n      sheetName = sheetName ?? openEndedParsed.sheet;\n\n      const startCol = columnToIndex(openEndedParsed.startCol);\n      const startRow = parseInt(openEndedParsed.startRow) - 1; // Convert to 0-based\n\n      if (startCol < 0 || startRow < 0) {\n        throw new ParseError(`Invalid range reference: ${startRef}:${endRef}`, {\n          start: startPos,\n          end: endPos,\n        });\n      }\n\n      if (openEndedParsed.type === \"infinity\") {\n        // A5:INFINITY - both row and column unbounded\n        const range: SpreadsheetRange = {\n          start: {\n            col: startCol,\n            row: startRow,\n          },\n          end: {\n            col: {\n              type: \"infinity\",\n              sign: \"positive\",\n            },\n            row: {\n              type: \"infinity\",\n              sign: \"positive\",\n            },\n          },\n        };\n\n        return createRangeNode({\n          sheetName,\n          range,\n          isAbsolute: {\n            start: {\n              col: openEndedParsed.startColAbsolute,\n              row: openEndedParsed.startRowAbsolute,\n            },\n            end: {\n              col: false, // INFINITY is never absolute\n              row: false, // INFINITY is never absolute\n            },\n          },\n          position: {\n            start: startPos,\n            end: endPos,\n          },\n        });\n      } else if (openEndedParsed.type === \"column-bounded\") {\n        // A5:D - open down only (bounded columns, unbounded rows)\n        const endCol = columnToIndex(openEndedParsed.endCol!);\n\n        if (endCol < 0) {\n          throw new ParseError(`Invalid column range: ${startRef}:${endRef}`, {\n            start: startPos,\n            end: endPos,\n          });\n        }\n\n        const range: SpreadsheetRange = {\n          start: {\n            col: Math.min(startCol, endCol),\n            row: startRow,\n          },\n          end: {\n            col: {\n              type: \"number\",\n              value: Math.max(startCol, endCol),\n            },\n            row: {\n              type: \"infinity\",\n              sign: \"positive\",\n            },\n          },\n        };\n\n        return createRangeNode({\n          sheetName,\n          range,\n          isAbsolute: {\n            start: {\n              col: openEndedParsed.startColAbsolute,\n              row: openEndedParsed.startRowAbsolute,\n            },\n            end: {\n              col: openEndedParsed.endColAbsolute!,\n              row: false, // Row is infinite, so not absolute\n            },\n          },\n          position: {\n            start: startPos,\n            end: endPos,\n          },\n        });\n      } else if (openEndedParsed.type === \"row-bounded\") {\n        // A5:15 - open right only (bounded rows, unbounded columns)\n        const endRow = parseInt(openEndedParsed.endRow!) - 1; // Convert to 0-based\n\n        if (endRow < 0) {\n          throw new ParseError(`Invalid row range: ${startRef}:${endRef}`, {\n            start: startPos,\n            end: endPos,\n          });\n        }\n\n        const range: SpreadsheetRange = {\n          start: {\n            col: startCol,\n            row: Math.min(startRow, endRow),\n          },\n          end: {\n            col: {\n              type: \"infinity\",\n              sign: \"positive\",\n            },\n            row: {\n              type: \"number\",\n              value: Math.max(startRow, endRow),\n            },\n          },\n        };\n\n        return createRangeNode({\n          sheetName,\n          range,\n          isAbsolute: {\n            start: {\n              col: openEndedParsed.startColAbsolute,\n              row: openEndedParsed.startRowAbsolute,\n            },\n            end: {\n              col: false, // Column is infinite, so not absolute\n              row: openEndedParsed.endRowAbsolute!,\n            },\n          },\n          position: {\n            start: startPos,\n            end: endPos,\n          },\n        });\n      }\n    }\n\n    // Otherwise, parse as normal range\n    const startParsed = parseCellReference(startRef);\n    const endParsed = parseCellReference(endRef);\n\n    if (!startParsed || !endParsed) {\n      throw new ParseError(`Invalid range reference: ${startRef}:${endRef}`, {\n        start: startPos,\n        end: endPos,\n      });\n    }\n\n    // Ensure both references are on the same sheet\n    const startSheet = startParsed.sheet;\n    const endSheet = endParsed.sheet;\n\n    if (startSheet !== endSheet) {\n      throw new ParseError(`Range references must be on the same sheet`, {\n        start: startPos,\n        end: endPos,\n      });\n    }\n\n    sheetName = sheetName ?? startSheet;\n\n    // Convert to SimpleCellRange\n    const startCol = columnToIndex(startParsed.col);\n    const startRow = parseInt(startParsed.row) - 1;\n    const endCol = columnToIndex(endParsed.col);\n    const endRow = parseInt(endParsed.row) - 1;\n\n    if (startCol < 0 || startRow < 0 || endCol < 0 || endRow < 0) {\n      throw new ParseError(`Invalid range reference: ${startRef}:${endRef}`, {\n        start: startPos,\n        end: endPos,\n      });\n    }\n\n    const range: SpreadsheetRange = {\n      start: {\n        col: Math.min(startCol, endCol),\n        row: Math.min(startRow, endRow),\n      },\n      end: {\n        col: {\n          type: \"number\",\n          value: Math.max(startCol, endCol),\n        },\n        row: {\n          type: \"number\",\n          value: Math.max(startRow, endRow),\n        },\n      },\n    };\n\n    return createRangeNode({\n      sheetName,\n      range,\n      isAbsolute: {\n        start: {\n          col: startParsed.colAbsolute,\n          row: startParsed.rowAbsolute,\n        },\n        end: {\n          col: endParsed.colAbsolute,\n          row: endParsed.rowAbsolute,\n        },\n      },\n      position: {\n        start: startPos,\n        end: endPos,\n      },\n    });\n  }\n\n  /**\n   * Parse a cell or range reference with a known workbook and sheet name\n   */\n  private parseCellOrRangeWithWorkbookAndSheet(\n    workbookName: string,\n    sheetName: string,\n    startPos: number\n  ): ASTNode {\n    // Build the full reference string for parsing\n    let ref = sheetName.includes(\" \") ? `'${sheetName}'!` : sheetName + \"!\";\n\n    // Check for $ before column\n    if (this.tokens.match(\"DOLLAR\")) {\n      ref += this.tokens.consume().value;\n    }\n\n    // Get the cell reference part\n    if (this.tokens.match(\"IDENTIFIER\")) {\n      const identifier = this.tokens.consume();\n      ref += identifier.value;\n\n      // Workbook-qualified table references use [Workbook]!Table1[...]\n      if (this.tokens.match(\"LBRACKET\")) {\n        throw new ParseError(\n          `Cross-workbook table references use [${workbookName}]!${identifier.value}[...] instead of [${workbookName}]${sheetName}!${identifier.value}[...]`,\n          this.tokens.peek().position\n        );\n      }\n\n      // Check if this is an infinite column range ([Workbook]Sheet!A:A)\n      if (this.tokens.match(\"COLON\")) {\n        this.tokens.consume();\n        const endRef = this.parseRangeEnd();\n        return this.parseRangeWithWorkbook(\n          ref,\n          endRef,\n          workbookName,\n          startPos,\n          this.tokens.peek().position.start\n        );\n      }\n\n      // Check for $ before row or just row number\n      if (this.tokens.match(\"DOLLAR\")) {\n        ref += this.tokens.consume().value;\n      }\n\n      if (this.tokens.match(\"NUMBER\")) {\n        ref += this.tokens.consume().value;\n      }\n    } else if (this.tokens.match(\"NUMBER\")) {\n      // Handle infinite row range ([Workbook]Sheet!5:5)\n      const number = this.tokens.consume();\n      ref += number.value;\n\n      // Check for range\n      if (this.tokens.match(\"COLON\")) {\n        this.tokens.consume();\n        const endRef = this.parseRangeEnd();\n        return this.parseRangeWithWorkbook(\n          ref,\n          endRef,\n          workbookName,\n          startPos,\n          this.tokens.peek().position.start\n        );\n      }\n    } else {\n      throw new ParseError(\n        `Expected cell reference after [${workbookName}]${sheetName}!`,\n        this.tokens.peek().position\n      );\n    }\n\n    // Check for range (normal cell range like [Workbook]Sheet!A1:B2)\n    if (this.tokens.match(\"COLON\")) {\n      this.tokens.consume();\n      const endRef = this.parseRangeEnd();\n      return this.parseRangeWithWorkbook(\n        ref,\n        endRef,\n        workbookName,\n        startPos,\n        this.tokens.peek().position.start\n      );\n    }\n\n    // Parse as single cell reference\n    const cellRef = this.parseCellReferenceString(ref);\n    if (cellRef) {\n      cellRef.workbookName = workbookName;\n      return cellRef;\n    }\n\n    // If it's not a cell reference, check if it's a named expression\n    const sheetPrefix = sheetName.includes(\" \")\n      ? `'${sheetName}'!`\n      : `${sheetName}!`;\n    const identifier = ref.substring(sheetPrefix.length);\n\n    // Validate it's a valid identifier for a named expression\n    if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(identifier)) {\n      return createNamedExpressionNode(\n        identifier,\n        {\n          start: startPos,\n          end: this.tokens.peek().position.start,\n        },\n        sheetName,\n        workbookName\n      );\n    }\n\n    throw new ParseError(`Invalid cell reference: ${ref}`, {\n      start: startPos,\n      end: this.tokens.peek().position.start,\n    });\n  }\n\n  /**\n   * Parse a cell or range reference with a known sheet name\n   */\n  private parseCellOrRangeWithSheet(\n    sheetName: string,\n    startPos: number\n  ): ASTNode {\n    // Build the full reference string for parsing\n    let ref = sheetName.includes(\" \") ? `'${sheetName}'!` : sheetName + \"!\";\n\n    // Check for $ before column\n    if (this.tokens.match(\"DOLLAR\")) {\n      ref += this.tokens.consume().value;\n    }\n\n    // Get the cell reference part\n    if (this.tokens.match(\"IDENTIFIER\")) {\n      const identifier = this.tokens.consume();\n      ref += identifier.value;\n\n      // Check if this is a table reference (Sheet1!Table1[...])\n      if (this.tokens.match(\"LBRACKET\")) {\n        // This is a table reference with sheet name\n        return this.parseTableReferenceWithSheet(\n          identifier.value,\n          sheetName,\n          startPos\n        );\n      }\n\n      // Check if this is an infinite column range (Sheet1!A:A)\n      if (this.tokens.match(\"COLON\")) {\n        this.tokens.consume();\n        const endRef = this.parseRangeEnd();\n        // For cross-sheet ranges, do NOT prepend the sheet name to the end reference\n        // parseRange will handle sheet name extraction from the start reference\n        return this.parseRange(\n          ref,\n          endRef,\n          startPos,\n          this.tokens.peek().position.start\n        );\n      }\n\n      // Check for $ before row or just row number\n      if (this.tokens.match(\"DOLLAR\")) {\n        ref += this.tokens.consume().value;\n      }\n\n      if (this.tokens.match(\"NUMBER\")) {\n        ref += this.tokens.consume().value;\n      }\n    } else if (this.tokens.match(\"NUMBER\")) {\n      // Handle infinite row range (Sheet1!5:5)\n      const number = this.tokens.consume();\n      ref += number.value;\n\n      // Check for range\n      if (this.tokens.match(\"COLON\")) {\n        this.tokens.consume();\n        const endRef = this.parseRangeEnd();\n        // For cross-sheet ranges, do NOT prepend the sheet name to the end reference\n        // parseRange will handle sheet name extraction from the start reference\n        return this.parseRange(\n          ref,\n          endRef,\n          startPos,\n          this.tokens.peek().position.start\n        );\n      }\n    } else {\n      throw new ParseError(\n        `Expected cell reference after ${sheetName}!`,\n        this.tokens.peek().position\n      );\n    }\n\n    // Check for range (normal cell range like Sheet1!A1:B2)\n    if (this.tokens.match(\"COLON\")) {\n      this.tokens.consume();\n      const endRef = this.parseRangeEnd();\n      // For cross-sheet ranges, do NOT prepend the sheet name to the end reference\n      // parseRange will handle sheet name extraction from the start reference\n      return this.parseRange(\n        ref,\n        endRef,\n        startPos,\n        this.tokens.peek().position.start\n      );\n    }\n\n    // Parse as single cell reference\n    const cellRef = this.parseCellReferenceString(ref);\n    if (cellRef) {\n      return cellRef;\n    }\n\n    // If it's not a cell reference, check if the remaining tokens represent a named expression\n    // At this point, we've consumed the sheet name and !, but have an identifier that's not a cell/range/table\n    if (this.tokens.isAtEnd() || !this.tokens.match(\"IDENTIFIER\")) {\n      // If we're at the end or the next token isn't an identifier, treat the current identifier as a named expression\n      // Extract the identifier after the sheet name from ref (remove \"SheetName!\" prefix)\n      const sheetPrefix = sheetName.includes(\" \")\n        ? `'${sheetName}'!`\n        : `${sheetName}!`;\n      const identifier = ref.substring(sheetPrefix.length);\n\n      // Validate it's a valid identifier for a named expression\n      if (/^[A-Za-z_][A-Za-z0-9_]*$/.test(identifier)) {\n        return createNamedExpressionNode(\n          identifier,\n          {\n            start: startPos,\n            end: this.tokens.peek().position.start,\n          },\n          sheetName\n        );\n      }\n    }\n\n    throw new ParseError(`Invalid cell reference: ${ref}`, {\n      start: startPos,\n      end: this.tokens.peek().position.start,\n    });\n  }\n}\n\n/**\n * Parse a formula string into an AST\n */\nexport function parseFormula(formula: string): ASTNode {\n  return Parser.parse(formula);\n}\n"
  ],
  "mappings": "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",
  "debugId": "E7749E5263A4F26E64756E2164756E21",
  "names": []
}