"use strict";
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const map = require("../lodash-es/map.cjs");
const filter = require("../lodash-es/filter.cjs");
require("../chevrotain/lib-src-parse-parser-parser.cjs");
require("../chevrotain/lib-src-scan-lexer_public.cjs");
require("../chevrotain/lib-src-scan-tokens_public.cjs");
require("../chevrotain/lib-src-parse-grammar-lookahead.cjs");
require("../chevrotain/lib-src-parse-errors_public.cjs");
const model = require("../@chevrotain/gast/lib-src-model.cjs");
require("../chevrotain/lib-src-parse-exceptions_public.cjs");
function buildATNKey(rule, type, occurrence) {
  return `${rule.name}_${type}_${occurrence}`;
}
const ATN_BASIC = 1;
const ATN_RULE_START = 2;
const ATN_PLUS_BLOCK_START = 4;
const ATN_STAR_BLOCK_START = 5;
const ATN_RULE_STOP = 7;
const ATN_BLOCK_END = 8;
const ATN_STAR_LOOP_BACK = 9;
const ATN_STAR_LOOP_ENTRY = 10;
const ATN_PLUS_LOOP_BACK = 11;
const ATN_LOOP_END = 12;
class AbstractTransition {
  constructor(target) {
    this.target = target;
  }
  isEpsilon() {
    return false;
  }
}
class AtomTransition extends AbstractTransition {
  constructor(target, tokenType) {
    super(target);
    this.tokenType = tokenType;
  }
}
class EpsilonTransition extends AbstractTransition {
  constructor(target) {
    super(target);
  }
  isEpsilon() {
    return true;
  }
}
class RuleTransition extends AbstractTransition {
  constructor(ruleStart, rule, followState) {
    super(ruleStart);
    this.rule = rule;
    this.followState = followState;
  }
  isEpsilon() {
    return true;
  }
}
function createATN(rules) {
  const atn = {
    decisionMap: {},
    decisionStates: [],
    ruleToStartState: /* @__PURE__ */ new Map(),
    ruleToStopState: /* @__PURE__ */ new Map(),
    states: []
  };
  createRuleStartAndStopATNStates(atn, rules);
  const ruleLength = rules.length;
  for (let i = 0; i < ruleLength; i++) {
    const rule = rules[i];
    const ruleBlock = block(atn, rule, rule);
    if (ruleBlock === void 0) {
      continue;
    }
    buildRuleHandle(atn, rule, ruleBlock);
  }
  return atn;
}
function createRuleStartAndStopATNStates(atn, rules) {
  const ruleLength = rules.length;
  for (let i = 0; i < ruleLength; i++) {
    const rule = rules[i];
    const start = newState(atn, rule, void 0, {
      type: ATN_RULE_START
    });
    const stop = newState(atn, rule, void 0, {
      type: ATN_RULE_STOP
    });
    start.stop = stop;
    atn.ruleToStartState.set(rule, start);
    atn.ruleToStopState.set(rule, stop);
  }
}
function atom(atn, rule, production) {
  if (production instanceof model.Terminal) {
    return tokenRef(atn, rule, production.terminalType, production);
  } else if (production instanceof model.NonTerminal) {
    return ruleRef(atn, rule, production);
  } else if (production instanceof model.Alternation) {
    return alternation(atn, rule, production);
  } else if (production instanceof model.Option) {
    return option(atn, rule, production);
  } else if (production instanceof model.Repetition) {
    return repetition(atn, rule, production);
  } else if (production instanceof model.RepetitionWithSeparator) {
    return repetitionSep(atn, rule, production);
  } else if (production instanceof model.RepetitionMandatory) {
    return repetitionMandatory(atn, rule, production);
  } else if (production instanceof model.RepetitionMandatoryWithSeparator) {
    return repetitionMandatorySep(atn, rule, production);
  } else {
    return block(atn, rule, production);
  }
}
function repetition(atn, rule, repetition2) {
  const starState = newState(atn, rule, repetition2, {
    type: ATN_STAR_BLOCK_START
  });
  defineDecisionState(atn, starState);
  const handle = makeAlts(atn, rule, starState, repetition2, block(atn, rule, repetition2));
  return star(atn, rule, repetition2, handle);
}
function repetitionSep(atn, rule, repetition2) {
  const starState = newState(atn, rule, repetition2, {
    type: ATN_STAR_BLOCK_START
  });
  defineDecisionState(atn, starState);
  const handle = makeAlts(atn, rule, starState, repetition2, block(atn, rule, repetition2));
  const sep = tokenRef(atn, rule, repetition2.separator, repetition2);
  return star(atn, rule, repetition2, handle, sep);
}
function repetitionMandatory(atn, rule, repetition2) {
  const plusState = newState(atn, rule, repetition2, {
    type: ATN_PLUS_BLOCK_START
  });
  defineDecisionState(atn, plusState);
  const handle = makeAlts(atn, rule, plusState, repetition2, block(atn, rule, repetition2));
  return plus(atn, rule, repetition2, handle);
}
function repetitionMandatorySep(atn, rule, repetition2) {
  const plusState = newState(atn, rule, repetition2, {
    type: ATN_PLUS_BLOCK_START
  });
  defineDecisionState(atn, plusState);
  const handle = makeAlts(atn, rule, plusState, repetition2, block(atn, rule, repetition2));
  const sep = tokenRef(atn, rule, repetition2.separator, repetition2);
  return plus(atn, rule, repetition2, handle, sep);
}
function alternation(atn, rule, alternation2) {
  const start = newState(atn, rule, alternation2, {
    type: ATN_BASIC
  });
  defineDecisionState(atn, start);
  const alts = map.default(alternation2.definition, (e) => atom(atn, rule, e));
  const handle = makeAlts(atn, rule, start, alternation2, ...alts);
  return handle;
}
function option(atn, rule, option2) {
  const start = newState(atn, rule, option2, {
    type: ATN_BASIC
  });
  defineDecisionState(atn, start);
  const handle = makeAlts(atn, rule, start, option2, block(atn, rule, option2));
  return optional(atn, rule, option2, handle);
}
function block(atn, rule, block2) {
  const handles = filter.default(map.default(block2.definition, (e) => atom(atn, rule, e)), (e) => e !== void 0);
  if (handles.length === 1) {
    return handles[0];
  } else if (handles.length === 0) {
    return void 0;
  } else {
    return makeBlock(atn, handles);
  }
}
function plus(atn, rule, plus2, handle, sep) {
  const blkStart = handle.left;
  const blkEnd = handle.right;
  const loop = newState(atn, rule, plus2, {
    type: ATN_PLUS_LOOP_BACK
  });
  defineDecisionState(atn, loop);
  const end = newState(atn, rule, plus2, {
    type: ATN_LOOP_END
  });
  blkStart.loopback = loop;
  end.loopback = loop;
  atn.decisionMap[buildATNKey(rule, sep ? "RepetitionMandatoryWithSeparator" : "RepetitionMandatory", plus2.idx)] = loop;
  epsilon(blkEnd, loop);
  if (sep === void 0) {
    epsilon(loop, blkStart);
    epsilon(loop, end);
  } else {
    epsilon(loop, end);
    epsilon(loop, sep.left);
    epsilon(sep.right, blkStart);
  }
  return {
    left: blkStart,
    right: end
  };
}
function star(atn, rule, star2, handle, sep) {
  const start = handle.left;
  const end = handle.right;
  const entry = newState(atn, rule, star2, {
    type: ATN_STAR_LOOP_ENTRY
  });
  defineDecisionState(atn, entry);
  const loopEnd = newState(atn, rule, star2, {
    type: ATN_LOOP_END
  });
  const loop = newState(atn, rule, star2, {
    type: ATN_STAR_LOOP_BACK
  });
  entry.loopback = loop;
  loopEnd.loopback = loop;
  epsilon(entry, start);
  epsilon(entry, loopEnd);
  epsilon(end, loop);
  if (sep !== void 0) {
    epsilon(loop, loopEnd);
    epsilon(loop, sep.left);
    epsilon(sep.right, start);
  } else {
    epsilon(loop, entry);
  }
  atn.decisionMap[buildATNKey(rule, sep ? "RepetitionWithSeparator" : "Repetition", star2.idx)] = entry;
  return {
    left: entry,
    right: loopEnd
  };
}
function optional(atn, rule, optional2, handle) {
  const start = handle.left;
  const end = handle.right;
  epsilon(start, end);
  atn.decisionMap[buildATNKey(rule, "Option", optional2.idx)] = start;
  return handle;
}
function defineDecisionState(atn, state) {
  atn.decisionStates.push(state);
  state.decision = atn.decisionStates.length - 1;
  return state.decision;
}
function makeAlts(atn, rule, start, production, ...alts) {
  const end = newState(atn, rule, production, {
    type: ATN_BLOCK_END,
    start
  });
  start.end = end;
  for (const alt of alts) {
    if (alt !== void 0) {
      epsilon(start, alt.left);
      epsilon(alt.right, end);
    } else {
      epsilon(start, end);
    }
  }
  const handle = {
    left: start,
    right: end
  };
  atn.decisionMap[buildATNKey(rule, getProdType(production), production.idx)] = start;
  return handle;
}
function getProdType(production) {
  if (production instanceof model.Alternation) {
    return "Alternation";
  } else if (production instanceof model.Option) {
    return "Option";
  } else if (production instanceof model.Repetition) {
    return "Repetition";
  } else if (production instanceof model.RepetitionWithSeparator) {
    return "RepetitionWithSeparator";
  } else if (production instanceof model.RepetitionMandatory) {
    return "RepetitionMandatory";
  } else if (production instanceof model.RepetitionMandatoryWithSeparator) {
    return "RepetitionMandatoryWithSeparator";
  } else {
    throw new Error("Invalid production type encountered");
  }
}
function makeBlock(atn, alts) {
  const altsLength = alts.length;
  for (let i = 0; i < altsLength - 1; i++) {
    const handle = alts[i];
    let transition;
    if (handle.left.transitions.length === 1) {
      transition = handle.left.transitions[0];
    }
    const isRuleTransition = transition instanceof RuleTransition;
    const ruleTransition = transition;
    const next = alts[i + 1].left;
    if (handle.left.type === ATN_BASIC && handle.right.type === ATN_BASIC && transition !== void 0 && (isRuleTransition && ruleTransition.followState === handle.right || transition.target === handle.right)) {
      if (isRuleTransition) {
        ruleTransition.followState = next;
      } else {
        transition.target = next;
      }
      removeState(atn, handle.right);
    } else {
      epsilon(handle.right, next);
    }
  }
  const first = alts[0];
  const last = alts[altsLength - 1];
  return {
    left: first.left,
    right: last.right
  };
}
function tokenRef(atn, rule, tokenType, production) {
  const left = newState(atn, rule, production, {
    type: ATN_BASIC
  });
  const right = newState(atn, rule, production, {
    type: ATN_BASIC
  });
  addTransition(left, new AtomTransition(right, tokenType));
  return {
    left,
    right
  };
}
function ruleRef(atn, currentRule, nonTerminal) {
  const rule = nonTerminal.referencedRule;
  const start = atn.ruleToStartState.get(rule);
  const left = newState(atn, currentRule, nonTerminal, {
    type: ATN_BASIC
  });
  const right = newState(atn, currentRule, nonTerminal, {
    type: ATN_BASIC
  });
  const call = new RuleTransition(start, rule, right);
  addTransition(left, call);
  return {
    left,
    right
  };
}
function buildRuleHandle(atn, rule, block2) {
  const start = atn.ruleToStartState.get(rule);
  epsilon(start, block2.left);
  const stop = atn.ruleToStopState.get(rule);
  epsilon(block2.right, stop);
  const handle = {
    left: start,
    right: stop
  };
  return handle;
}
function epsilon(a, b) {
  const transition = new EpsilonTransition(b);
  addTransition(a, transition);
}
function newState(atn, rule, production, partial) {
  const t = Object.assign({
    atn,
    production,
    epsilonOnlyTransitions: false,
    rule,
    transitions: [],
    nextTokenWithinRule: [],
    stateNumber: atn.states.length
  }, partial);
  atn.states.push(t);
  return t;
}
function addTransition(state, transition) {
  if (state.transitions.length === 0) {
    state.epsilonOnlyTransitions = transition.isEpsilon();
  }
  state.transitions.push(transition);
}
function removeState(atn, state) {
  atn.states.splice(atn.states.indexOf(state), 1);
}
exports.ATN_BASIC = ATN_BASIC;
exports.ATN_BLOCK_END = ATN_BLOCK_END;
exports.ATN_LOOP_END = ATN_LOOP_END;
exports.ATN_PLUS_BLOCK_START = ATN_PLUS_BLOCK_START;
exports.ATN_PLUS_LOOP_BACK = ATN_PLUS_LOOP_BACK;
exports.ATN_RULE_START = ATN_RULE_START;
exports.ATN_RULE_STOP = ATN_RULE_STOP;
exports.ATN_STAR_BLOCK_START = ATN_STAR_BLOCK_START;
exports.ATN_STAR_LOOP_BACK = ATN_STAR_LOOP_BACK;
exports.ATN_STAR_LOOP_ENTRY = ATN_STAR_LOOP_ENTRY;
exports.AbstractTransition = AbstractTransition;
exports.AtomTransition = AtomTransition;
exports.EpsilonTransition = EpsilonTransition;
exports.RuleTransition = RuleTransition;
exports.buildATNKey = buildATNKey;
exports.createATN = createATN;
//# sourceMappingURL=lib-atn.cjs.map
