import { EMPTY_ALT as v } from "../../../../../chevrotain@11.0.3/node_modules/chevrotain/lib/src/parse/parser/parser.js";
import "../../../../../chevrotain@11.0.3/node_modules/chevrotain/lib/src/scan/lexer_public.js";
import { EOF as P } from "../../../../../chevrotain@11.0.3/node_modules/chevrotain/lib/src/scan/tokens_public.js";
import "../../../../../chevrotain@11.0.3/node_modules/chevrotain/lib/src/parse/grammar/lookahead.js";
import "../../../../../chevrotain@11.0.3/node_modules/chevrotain/lib/src/parse/errors_public.js";
import "../../../../../chevrotain@11.0.3/node_modules/chevrotain/lib/src/parse/exceptions_public.js";
import { isParserRule as T, isKeyword as y, isAction as j, isAssignment as D, isCrossReference as U, isRuleCall as g, isAlternatives as L, isUnorderedGroup as $, isGroup as w, isEndOfFile as M, isTerminalRule as R, isDisjunction as I, isConjunction as S, isNegation as _, isParameterReference as B, isBooleanLiteral as K } from "../languages/generated/ast.js";
import { ErrorWithLocation as k, assertUnreachable as G } from "../utils/errors.js";
import { stream as W } from "../utils/stream.js";
import { getAllReachableRules as Y, getTypeName as N, findNameAssignment as q } from "../utils/grammar-utils.js";
function de(e, r, s) {
  return z({
    parser: r,
    tokens: s,
    ruleNames: /* @__PURE__ */ new Map()
  }, e), r;
}
function z(e, r) {
  const s = Y(r, !1), n = W(r.rules).filter(T).filter((t) => s.has(t));
  for (const t of n) {
    const o = Object.assign(Object.assign({}, e), { consume: 1, optional: 1, subrule: 1, many: 1, or: 1 });
    e.parser.rule(t, c(o, t.definition));
  }
}
function c(e, r, s = !1) {
  let n;
  if (y(r))
    n = x(e, r);
  else if (j(r))
    n = H(e, r);
  else if (D(r))
    n = c(e, r.terminal);
  else if (U(r))
    n = C(e, r);
  else if (g(r))
    n = J(e, r);
  else if (L(r))
    n = V(e, r);
  else if ($(r))
    n = X(e, r);
  else if (w(r))
    n = Z(e, r);
  else if (M(r)) {
    const t = e.consume++;
    n = () => e.parser.consume(t, P, r);
  } else
    throw new k(r.$cstNode, `Unexpected element type: ${r.$type}`);
  return F(e, s ? void 0 : E(r), n, r.cardinality);
}
function H(e, r) {
  const s = N(r);
  return () => e.parser.action(s, r);
}
function J(e, r) {
  const s = r.rule.ref;
  if (T(s)) {
    const n = e.subrule++, t = s.fragment, o = r.arguments.length > 0 ? Q(s, r.arguments) : () => ({});
    return (u) => e.parser.subrule(n, O(e, s), t, r, o(u));
  } else if (R(s)) {
    const n = e.consume++, t = h(e, s.name);
    return () => e.parser.consume(n, t, r);
  } else if (s)
    G();
  else
    throw new k(r.$cstNode, `Undefined rule: ${r.rule.$refText}`);
}
function Q(e, r) {
  const s = r.map((n) => a(n.value));
  return (n) => {
    const t = {};
    for (let o = 0; o < s.length; o++) {
      const u = e.parameters[o], i = s[o];
      t[u.name] = i(n);
    }
    return t;
  };
}
function a(e) {
  if (I(e)) {
    const r = a(e.left), s = a(e.right);
    return (n) => r(n) || s(n);
  } else if (S(e)) {
    const r = a(e.left), s = a(e.right);
    return (n) => r(n) && s(n);
  } else if (_(e)) {
    const r = a(e.value);
    return (s) => !r(s);
  } else if (B(e)) {
    const r = e.parameter.ref.name;
    return (s) => s !== void 0 && s[r] === !0;
  } else if (K(e)) {
    const r = !!e.true;
    return () => r;
  }
  G();
}
function V(e, r) {
  if (r.elements.length === 1)
    return c(e, r.elements[0]);
  {
    const s = [];
    for (const t of r.elements) {
      const o = {
        // Since we handle the guard condition in the alternative already
        // We can ignore the group guard condition inside
        ALT: c(e, t, !0)
      }, u = E(t);
      u && (o.GATE = a(u)), s.push(o);
    }
    const n = e.or++;
    return (t) => e.parser.alternatives(n, s.map((o) => {
      const u = {
        ALT: () => o.ALT(t)
      }, i = o.GATE;
      return i && (u.GATE = () => i(t)), u;
    }));
  }
}
function X(e, r) {
  if (r.elements.length === 1)
    return c(e, r.elements[0]);
  const s = [];
  for (const i of r.elements) {
    const l = {
      // Since we handle the guard condition in the alternative already
      // We can ignore the group guard condition inside
      ALT: c(e, i, !0)
    }, f = E(i);
    f && (l.GATE = a(f)), s.push(l);
  }
  const n = e.or++, t = (i, l) => {
    const f = l.getRuleStack().join("-");
    return `uGroup_${i}_${f}`;
  }, o = (i) => e.parser.alternatives(n, s.map((l, f) => {
    const A = { ALT: () => !0 }, d = e.parser;
    A.ALT = () => {
      if (l.ALT(i), !d.isRecording()) {
        const p = t(n, d);
        d.unorderedGroups.get(p) || d.unorderedGroups.set(p, []);
        const m = d.unorderedGroups.get(p);
        typeof (m == null ? void 0 : m[f]) > "u" && (m[f] = !0);
      }
    };
    const b = l.GATE;
    return b ? A.GATE = () => b(i) : A.GATE = () => {
      const p = d.unorderedGroups.get(t(n, d));
      return !(p != null && p[f]);
    }, A;
  })), u = F(e, E(r), o, "*");
  return (i) => {
    u(i), e.parser.isRecording() || e.parser.unorderedGroups.delete(t(n, e.parser));
  };
}
function Z(e, r) {
  const s = r.elements.map((n) => c(e, n));
  return (n) => s.forEach((t) => t(n));
}
function E(e) {
  if (w(e))
    return e.guardCondition;
}
function C(e, r, s = r.terminal) {
  if (s)
    if (g(s) && T(s.rule.ref)) {
      const n = s.rule.ref, t = e.subrule++;
      return (o) => e.parser.subrule(t, O(e, n), !1, r, o);
    } else if (g(s) && R(s.rule.ref)) {
      const n = e.consume++, t = h(e, s.rule.ref.name);
      return () => e.parser.consume(n, t, r);
    } else if (y(s)) {
      const n = e.consume++, t = h(e, s.value);
      return () => e.parser.consume(n, t, r);
    } else
      throw new Error("Could not build cross reference parser");
  else {
    if (!r.type.ref)
      throw new Error("Could not resolve reference to type: " + r.type.$refText);
    const n = q(r.type.ref), t = n == null ? void 0 : n.terminal;
    if (!t)
      throw new Error("Could not find name assignment for type: " + N(r.type.ref));
    return C(e, r, t);
  }
}
function x(e, r) {
  const s = e.consume++, n = e.tokens[r.value];
  if (!n)
    throw new Error("Could not find token for keyword: " + r.value);
  return () => e.parser.consume(s, n, r);
}
function F(e, r, s, n) {
  const t = r && a(r);
  if (!n)
    if (t) {
      const o = e.or++;
      return (u) => e.parser.alternatives(o, [
        {
          ALT: () => s(u),
          GATE: () => t(u)
        },
        {
          ALT: v(),
          GATE: () => !t(u)
        }
      ]);
    } else
      return s;
  if (n === "*") {
    const o = e.many++;
    return (u) => e.parser.many(o, {
      DEF: () => s(u),
      GATE: t ? () => t(u) : void 0
    });
  } else if (n === "+") {
    const o = e.many++;
    if (t) {
      const u = e.or++;
      return (i) => e.parser.alternatives(u, [
        {
          ALT: () => e.parser.atLeastOne(o, {
            DEF: () => s(i)
          }),
          GATE: () => t(i)
        },
        {
          ALT: v(),
          GATE: () => !t(i)
        }
      ]);
    } else
      return (u) => e.parser.atLeastOne(o, {
        DEF: () => s(u)
      });
  } else if (n === "?") {
    const o = e.optional++;
    return (u) => e.parser.optional(o, {
      DEF: () => s(u),
      GATE: t ? () => t(u) : void 0
    });
  } else
    G();
}
function O(e, r) {
  const s = ee(e, r), n = e.parser.getRule(s);
  if (!n)
    throw new Error(`Rule "${s}" not found."`);
  return n;
}
function ee(e, r) {
  if (T(r))
    return r.name;
  if (e.ruleNames.has(r))
    return e.ruleNames.get(r);
  {
    let s = r, n = s.$container, t = r.$type;
    for (; !T(n); )
      (w(n) || L(n) || $(n)) && (t = n.elements.indexOf(s).toString() + ":" + t), s = n, n = n.$container;
    return t = n.name + ":" + t, e.ruleNames.set(r, t), t;
  }
}
function h(e, r) {
  const s = e.tokens[r];
  if (!s)
    throw new Error(`Token "${r}" not found."`);
  return s;
}
export {
  de as createParser
};
