import { NonTerminal, Terminal } from "../@chevrotain/gast/lib-src-model.js";
import { isSequenceProd, isBranchingProd, isOptionalProd } from "../@chevrotain/gast/lib-src-helpers.js";
import uniq from "../lodash-es/uniq.js";
import map from "../lodash-es/map.js";
import flatten from "../lodash-es/flatten.js";
function first(prod) {
  if (prod instanceof NonTerminal) {
    return first(prod.referencedRule);
  } else if (prod instanceof Terminal) {
    return firstForTerminal(prod);
  } else if (isSequenceProd(prod)) {
    return firstForSequence(prod);
  } else if (isBranchingProd(prod)) {
    return firstForBranching(prod);
  } else {
    throw Error("non exhaustive match");
  }
}
function firstForSequence(prod) {
  let firstSet = [];
  const seq = prod.definition;
  let nextSubProdIdx = 0;
  let hasInnerProdsRemaining = seq.length > nextSubProdIdx;
  let currSubProd;
  let isLastInnerProdOptional = true;
  while (hasInnerProdsRemaining && isLastInnerProdOptional) {
    currSubProd = seq[nextSubProdIdx];
    isLastInnerProdOptional = isOptionalProd(currSubProd);
    firstSet = firstSet.concat(first(currSubProd));
    nextSubProdIdx = nextSubProdIdx + 1;
    hasInnerProdsRemaining = seq.length > nextSubProdIdx;
  }
  return uniq(firstSet);
}
function firstForBranching(prod) {
  const allAlternativesFirsts = map(prod.definition, (innerProd) => {
    return first(innerProd);
  });
  return uniq(flatten(allAlternativesFirsts));
}
function firstForTerminal(terminal) {
  return [terminal.terminalType];
}
export {
  first,
  firstForBranching,
  firstForSequence,
  firstForTerminal
};
//# sourceMappingURL=lib-src-parse-grammar-first.js.map
