import { assertUnreachable as S } from "./errors.js";
import { isTerminalRule as m, isInferredType as v, isAction as h, isParserRule as u, isInterface as w, isType as N, isRuleCall as y, isTerminalAlternatives as I, isTerminalGroup as E, isCharacterRange as M, isTerminalRuleCall as _, isNegatedToken as b, isUntilToken as F, isRegexToken as D, isWildcard as j, isAssignment as l, isSimpleType as P, isKeyword as k, isReturnType as K } from "../languages/generated/ast.js";
import { isCompositeCstNode as O } from "../syntax-tree.js";
import { streamAllContents as g, getContainerOfType as T } from "./ast-utils.js";
import { streamCst as U } from "./cst-utils.js";
import { escapeRegExp as W, isWhitespace as G } from "./regexp-utils.js";
function L(e) {
  return e.rules.find((r) => u(r) && r.entry);
}
function B(e) {
  return e.rules.filter((r) => m(r) && r.hidden);
}
function se(e, r) {
  const n = /* @__PURE__ */ new Set(), i = L(e);
  if (!i)
    return new Set(e.rules);
  const t = [i].concat(B(e));
  for (const o of t)
    $(o, n, r);
  const a = /* @__PURE__ */ new Set();
  for (const o of e.rules)
    (n.has(o.name) || m(o) && o.hidden) && a.add(o);
  return a;
}
function $(e, r, n) {
  r.add(e.name), g(e).forEach((i) => {
    if (y(i) || n) {
      const t = i.rule.ref;
      t && !r.has(t.name) && $(t, r, n);
    }
  });
}
function le(e) {
  if (e.terminal)
    return e.terminal;
  if (e.type.ref) {
    const r = q(e.type.ref);
    return r == null ? void 0 : r.terminal;
  }
}
function de(e) {
  return e.hidden && !G(V(e));
}
function ce(e, r) {
  return !e || !r ? [] : p(e, r, e.astNode, !0);
}
function me(e, r, n) {
  if (!e || !r)
    return;
  const i = p(e, r, e.astNode, !0);
  if (i.length !== 0)
    return n !== void 0 ? n = Math.max(0, Math.min(n, i.length - 1)) : n = 0, i[n];
}
function p(e, r, n, i) {
  if (!i) {
    const t = T(e.grammarSource, l);
    if (t && t.feature === r)
      return [e];
  }
  return O(e) && e.astNode === n ? e.content.flatMap((t) => p(t, r, n, !1)) : [];
}
function he(e, r, n) {
  if (!e)
    return;
  const i = H(e, r, e == null ? void 0 : e.astNode);
  if (i.length !== 0)
    return n !== void 0 ? n = Math.max(0, Math.min(n, i.length - 1)) : n = 0, i[n];
}
function H(e, r, n) {
  if (e.astNode !== n)
    return [];
  if (k(e.grammarSource) && e.grammarSource.value === r)
    return [e];
  const i = U(e).iterator();
  let t;
  const a = [];
  do
    if (t = i.next(), !t.done) {
      const o = t.value;
      o.astNode === n ? k(o.grammarSource) && o.grammarSource.value === r && a.push(o) : i.prune();
    }
  while (!t.done);
  return a;
}
function ye(e) {
  var r;
  const n = e.astNode;
  for (; n === ((r = e.container) === null || r === void 0 ? void 0 : r.astNode); ) {
    const i = T(e.grammarSource, l);
    if (i)
      return i;
    e = e.container;
  }
}
function q(e) {
  let r = e;
  return v(r) && (h(r.$container) ? r = r.$container.$container : u(r.$container) ? r = r.$container : S(r.$container)), A(e, r, /* @__PURE__ */ new Map());
}
function A(e, r, n) {
  var i;
  function t(a, o) {
    let d;
    return T(a, l) || (d = A(o, o, n)), n.set(e, d), d;
  }
  if (n.has(e))
    return n.get(e);
  n.set(e, void 0);
  for (const a of g(r)) {
    if (l(a) && a.feature.toLowerCase() === "name")
      return n.set(e, a), a;
    if (y(a) && u(a.rule.ref))
      return t(a, a.rule.ref);
    if (P(a) && (!((i = a.typeRef) === null || i === void 0) && i.ref))
      return t(a, a.typeRef.ref);
  }
}
function z(e) {
  return C(e, /* @__PURE__ */ new Set());
}
function C(e, r) {
  if (r.has(e))
    return !0;
  r.add(e);
  for (const n of g(e))
    if (y(n)) {
      if (!n.rule.ref || u(n.rule.ref) && !C(n.rule.ref, r))
        return !1;
    } else {
      if (l(n))
        return !1;
      if (h(n))
        return !1;
    }
  return !!e.definition;
}
function x(e) {
  if (e.inferredType)
    return e.inferredType.name;
  if (e.dataType)
    return e.dataType;
  if (e.returnType) {
    const r = e.returnType.ref;
    if (r) {
      if (u(r))
        return r.name;
      if (w(r) || N(r))
        return r.name;
    }
  }
}
function J(e) {
  var r;
  if (u(e))
    return z(e) ? e.name : (r = x(e)) !== null && r !== void 0 ? r : e.name;
  if (w(e) || N(e) || K(e))
    return e.name;
  if (h(e)) {
    const n = Q(e);
    if (n)
      return n;
  } else if (v(e))
    return e.name;
  throw new Error("Cannot get name of Unknown Type");
}
function Q(e) {
  var r;
  if (e.inferredType)
    return e.inferredType.name;
  if (!((r = e.type) === null || r === void 0) && r.ref)
    return J(e.type.ref);
}
function ge(e) {
  var r, n, i;
  return m(e) ? (n = (r = e.type) === null || r === void 0 ? void 0 : r.name) !== null && n !== void 0 ? n : "string" : (i = x(e)) !== null && i !== void 0 ? i : e.name;
}
function V(e) {
  const r = {
    s: !1,
    i: !1,
    u: !1
  }, n = s(e.definition, r), i = Object.entries(r).filter(([, t]) => t).map(([t]) => t).join("");
  return new RegExp(n, i);
}
const R = /[\s\S]/.source;
function s(e, r) {
  if (I(e))
    return X(e);
  if (E(e))
    return Y(e);
  if (M(e))
    return re(e);
  if (_(e)) {
    const n = e.rule.ref;
    if (!n)
      throw new Error("Missing rule reference.");
    return f(s(n.definition), {
      cardinality: e.cardinality,
      lookahead: e.lookahead
    });
  } else {
    if (b(e))
      return ee(e);
    if (F(e))
      return Z(e);
    if (D(e)) {
      const n = e.regex.lastIndexOf("/"), i = e.regex.substring(1, n), t = e.regex.substring(n + 1);
      return r && (r.i = t.includes("i"), r.s = t.includes("s"), r.u = t.includes("u")), f(i, {
        cardinality: e.cardinality,
        lookahead: e.lookahead,
        wrap: !1
      });
    } else {
      if (j(e))
        return f(R, {
          cardinality: e.cardinality,
          lookahead: e.lookahead
        });
      throw new Error(`Invalid terminal element: ${e == null ? void 0 : e.$type}`);
    }
  }
}
function X(e) {
  return f(e.elements.map((r) => s(r)).join("|"), {
    cardinality: e.cardinality,
    lookahead: e.lookahead
  });
}
function Y(e) {
  return f(e.elements.map((r) => s(r)).join(""), {
    cardinality: e.cardinality,
    lookahead: e.lookahead
  });
}
function Z(e) {
  return f(`${R}*?${s(e.terminal)}`, {
    cardinality: e.cardinality,
    lookahead: e.lookahead
  });
}
function ee(e) {
  return f(`(?!${s(e.terminal)})${R}*?`, {
    cardinality: e.cardinality,
    lookahead: e.lookahead
  });
}
function re(e) {
  return e.right ? f(`[${c(e.left)}-${c(e.right)}]`, {
    cardinality: e.cardinality,
    lookahead: e.lookahead,
    wrap: !1
  }) : f(c(e.left), {
    cardinality: e.cardinality,
    lookahead: e.lookahead,
    wrap: !1
  });
}
function c(e) {
  return W(e.value);
}
function f(e, r) {
  var n;
  return (r.wrap !== !1 || r.lookahead) && (e = `(${(n = r.lookahead) !== null && n !== void 0 ? n : ""}${e})`), r.cardinality ? `${e}${r.cardinality}` : e;
}
export {
  ye as findAssignment,
  q as findNameAssignment,
  he as findNodeForKeyword,
  me as findNodeForProperty,
  H as findNodesForKeywordInternal,
  ce as findNodesForProperty,
  Q as getActionType,
  se as getAllReachableRules,
  le as getCrossReferenceTerminal,
  L as getEntryRule,
  x as getExplicitRuleType,
  B as getHiddenRules,
  ge as getRuleType,
  J as getTypeName,
  de as isCommentTerminal,
  z as isDataTypeRule,
  V as terminalRegex
};
