function fallbackParser({ source, startRule }) {
  const { tokens } = mergeTokenGroups(lexerWithRecovery.tokenize(source));
  function nextNonWhitespace(index) {
    while (++index < tokens.length && tokens[index].tokenType === WhiteSpace) {
      // this block intentionally left blank
    }
    return tokens[index];
  }

  const root = { type: "group", children: [] };
  let current = root;
  let outsideAggregation = startRule === "aggregation";

  const stack = [];
  const push = element => {
    current.children.push(element);
    stack.push(current);
    current = element;
  };
  const pop = () => {
    if (stack.length === 0) {
      return;
    }
    current = stack.pop();
  };
  for (let i = 0; i < tokens.length; i++) {
    const t = tokens[i];
    const next = nextNonWhitespace(i);
    if (isTokenType(t.tokenType, FunctionName)) {
      const { type } = CLAUSE_TOKENS.get(t.tokenType);
      const clause = syntaxNode(type, tokenNode("function-name", t));
      if (next && next.tokenType === LParen) {
        if (type === "aggregation") {
          outsideAggregation = false;
        }
        push(clause);
      } else {
        current.children.push(clause);
      }
    } else if (
      isTokenType(t.tokenType, Identifier) ||
      isTokenType(t.tokenType, IdentifierString)
    ) {
      current.children.push(
        syntaxNode(
          outsideAggregation ? "metric" : "unknown", // "dimension" + "segment"
          syntaxNode("identifier", tokenNode(t)),
        ),
      );
    } else if (t.tokenType === LParen) {
      push(syntaxNode("group"));
      current.children.push(tokenNode("open-paren", t));
    } else if (t.tokenType === RParen) {
      current.children.push(tokenNode("close-paren", t));
      pop();
      if (current.type === "aggregation") {
        outsideAggregation = true;
        pop();
      }
    } else {
      current.children.push(tokenNode(t));
    }
  }
  return root;
}
// hand-rolled parser that parses enough for syntax highlighting
hand-rolled parser that parses enough for syntax highlighting
hand - rolled parser that parses enough for syntax highlighting
function fallbackParser({ source, startRule }) {
  const { tokens } = mergeTokenGroups(lexerWithRecovery.tokenize(source));
  function nextNonWhitespace(index) {
    while (++index < tokens.length && tokens[index].tokenType === WhiteSpace) {
    }
    return tokens[index];
  }
  const root = { type: "group", children: [] };
  let current = root;
  let outsideAggregation = startRule === "aggregation";
  const stack = [];
  const push = element => {
    current.children.push(element);
    stack.push(current);
    current = element;
  };
  const pop = () => {
    if (stack.length === 0) {
      return;
    }
    current = stack.pop();
  };
  for (let i = 0; i < tokens.length; i++) {
    const t = tokens[i];
    const next = nextNonWhitespace(i);
    if (isTokenType(t.tokenType, FunctionName)) {
      const { type } = CLAUSE_TOKENS.get(t.tokenType);
      const clause = syntaxNode(type, tokenNode("function-name", t));
      if (next && next.tokenType === LParen) {
        if (type === "aggregation") {
          outsideAggregation = false;
        }
        push(clause);
      } else {
        current.children.push(clause);
      }
    } else if (
      isTokenType(t.tokenType, Identifier) ||
      isTokenType(t.tokenType, IdentifierString)
    ) {
      current.children.push(
        syntaxNode(
          outsideAggregation ? "metric" : "unknown", 
          syntaxNode("identifier", tokenNode(t)),
        ),
      );
    } else if (t.tokenType === LParen) {
      push(syntaxNode("group"));
      current.children.push(tokenNode("open-paren", t));
    } else if (t.tokenType === RParen) {
      current.children.push(tokenNode("close-paren", t));
      pop();
      if (current.type === "aggregation") {
        outsideAggregation = true;
        pop();
      }
    } else {
      current.children.push(tokenNode(t));
    }
  }
  return root;
}
function fallbackParser ( { source , startRule } ) { const { tokens } = mergeTokenGroups ( lexerWithRecovery . tokenize ( source ) ) ; function nextNonWhitespace ( index ) { while ( ++ index < tokens . length && tokens [ index ] . tokenType === WhiteSpace ) { } return tokens [ index ] ; } const root = { type : "group" , children : [ ] } ; let current = root ; let outsideAggregation = startRule === "aggregation" ; const stack = [ ] ; const push = element => { current . children . push ( element ) ; stack . push ( current ) ; current = element ; } ; const pop = ( ) => { if ( stack . length === 0 ) { return ; } current = stack . pop ( ) ; } ; for ( let i = 0 ; i < tokens . length ; i ++ ) { const t = tokens [ i ] ; const next = nextNonWhitespace ( i ) ; if ( isTokenType ( t . tokenType , FunctionName ) ) { const { type } = CLAUSE_TOKENS . get ( t . tokenType ) ; const clause = syntaxNode ( type , tokenNode ( "function-name" , t ) ) ; if ( next && next . tokenType === LParen ) { if ( type === "aggregation" ) { outsideAggregation = false ; } push ( clause ) ; } else { current . children . push ( clause ) ; } } else if ( isTokenType ( t . tokenType , Identifier ) || isTokenType ( t . tokenType , IdentifierString ) ) { current . children . push ( syntaxNode ( outsideAggregation ? "metric" : "unknown" , syntaxNode ( "identifier" , tokenNode ( t ) ) , ) , ) ; } else if ( t . tokenType === LParen ) { push ( syntaxNode ( "group" ) ) ; current . children . push ( tokenNode ( "open-paren" , t ) ) ; } else if ( t . tokenType === RParen ) { current . children . push ( tokenNode ( "close-paren" , t ) ) ; pop ( ) ; if ( current . type === "aggregation" ) { outsideAggregation = true ; pop ( ) ; } } else { current . children . push ( tokenNode ( t ) ) ; } } return root ; }
hand-rolled parser that parses enough for syntax highlighting
hand - rolled parser that parses enough for syntax highlighting
// this block intentionally left blank // "dimension" + "segment"