def parse_array_index_expression(stream)
      pos = 0
      parts = [nil, nil, nil]
      expected = NUM_COLON_RBRACKET

      begin
        if stream.token.type == Lexer::T_COLON
          pos += 1
          expected = NUM_COLON_RBRACKET
        elsif stream.token.type == Lexer::T_NUMBER
          parts[pos] = stream.token.value
          expected = COLON_RBRACKET
        end
        stream.next(match: expected)
      end while stream.token.type != Lexer::T_RBRACKET

      stream.next # consume the closing bracket

      if pos == 0
        # no colons found, this is a single index extraction
        Nodes::Index.new(parts[0])
      elsif pos > 2
        raise Errors::SyntaxError, 'invalid array slice syntax: too many colons'
      else
        Nodes::ArrayProjection.new(
          Nodes::Slice.new(*parts),
          parse_projection(stream, Token::BINDING_POWER[Lexer::T_STAR])
        )
      end
    end
def parse_array_index_expression(stream)
      pos = 0
      parts = [nil, nil, nil]
      expected = NUM_COLON_RBRACKET

      begin
        if stream.token.type == Lexer::T_COLON
          pos += 1
          expected = NUM_COLON_RBRACKET
        elsif stream.token.type == Lexer::T_NUMBER
          parts[pos] = stream.token.value
          expected = COLON_RBRACKET
        end
        stream.next(match: expected)
      end while stream.token.type != Lexer::T_RBRACKET

      stream.next # consume the closing bracket

      if pos == 0
        # no colons found, this is a single index extraction
        Nodes::Index.new(parts[0])
      elsif pos > 2
        raise Errors::SyntaxError, 'invalid array slice syntax: too many colons'
      else
        Nodes::ArrayProjection.new(
          Nodes::Slice.new(*parts),
          parse_projection(stream, Token::BINDING_POWER[Lexer::T_STAR])
        )
      end
    end
parse array index expressions, for example [0], [1:2:3], etc.