import { ASSERT_EXISTS as e, ASSERT_NEVER_REACH_HERE as t, addFlag as n, cc as r, insertToSet as i, isCharacter as a } from "./utils.js";
import { digitsCharCodes as o, whitespaceCodes as s, wordCharCodes as c } from "./character-classes.js";
//#region ../../node_modules/@chevrotain/regexp-to-ast/lib/src/regexp-parser.js
var l = /[0-9a-fA-F]/, u = /[0-9]/, d = /[1-9]/, f = class {
	constructor() {
		this.idx = 0, this.input = "", this.groupIdx = 0;
	}
	saveState() {
		return {
			idx: this.idx,
			input: this.input,
			groupIdx: this.groupIdx
		};
	}
	restoreState(e) {
		this.idx = e.idx, this.input = e.input, this.groupIdx = e.groupIdx;
	}
	pattern(e) {
		this.idx = 0, this.input = e, this.groupIdx = 0, this.consumeChar("/");
		let t = this.disjunction();
		this.consumeChar("/");
		let r = {
			type: "Flags",
			loc: {
				begin: this.idx,
				end: e.length
			},
			global: !1,
			ignoreCase: !1,
			multiLine: !1,
			unicode: !1,
			sticky: !1
		};
		for (; this.isRegExpFlag();) switch (this.popChar()) {
			case "g":
				n(r, "global");
				break;
			case "i":
				n(r, "ignoreCase");
				break;
			case "m":
				n(r, "multiLine");
				break;
			case "u":
				n(r, "unicode");
				break;
			case "y":
				n(r, "sticky");
				break;
		}
		if (this.idx !== this.input.length) throw Error("Redundant input: " + this.input.substring(this.idx));
		return {
			type: "Pattern",
			flags: r,
			value: t,
			loc: this.loc(0)
		};
	}
	disjunction() {
		let e = [], t = this.idx;
		for (e.push(this.alternative()); this.peekChar() === "|";) this.consumeChar("|"), e.push(this.alternative());
		return {
			type: "Disjunction",
			value: e,
			loc: this.loc(t)
		};
	}
	alternative() {
		let e = [], t = this.idx;
		for (; this.isTerm();) e.push(this.term());
		return {
			type: "Alternative",
			value: e,
			loc: this.loc(t)
		};
	}
	term() {
		return this.isAssertion() ? this.assertion() : this.atom();
	}
	assertion() {
		let n = this.idx;
		switch (this.popChar()) {
			case "^": return {
				type: "StartAnchor",
				loc: this.loc(n)
			};
			case "$": return {
				type: "EndAnchor",
				loc: this.loc(n)
			};
			case "\\":
				switch (this.popChar()) {
					case "b": return {
						type: "WordBoundary",
						loc: this.loc(n)
					};
					case "B": return {
						type: "NonWordBoundary",
						loc: this.loc(n)
					};
				}
				/* c8 ignore next */
				throw Error("Invalid Assertion Escape");
			case "(":
				this.consumeChar("?");
				let t;
				switch (this.popChar()) {
					case "=":
						t = "Lookahead";
						break;
					case "!":
						t = "NegativeLookahead";
						break;
					case "<":
						switch (this.popChar()) {
							case "=":
								t = "Lookbehind";
								break;
							case "!": t = "NegativeLookbehind";
						}
						break;
				}
				e(t);
				let r = this.disjunction();
				return this.consumeChar(")"), {
					type: t,
					value: r,
					loc: this.loc(n)
				};
		}
		// istanbul ignore next
		return t();
	}
	quantifier(t = !1) {
		let n, r = this.idx;
		switch (this.popChar()) {
			case "*":
				n = {
					atLeast: 0,
					atMost: Infinity
				};
				break;
			case "+":
				n = {
					atLeast: 1,
					atMost: Infinity
				};
				break;
			case "?":
				n = {
					atLeast: 0,
					atMost: 1
				};
				break;
			case "{":
				let r = this.integerIncludingZero();
				switch (this.popChar()) {
					case "}":
						n = {
							atLeast: r,
							atMost: r
						};
						break;
					case ",":
						let e;
						this.isDigit() ? (e = this.integerIncludingZero(), n = {
							atLeast: r,
							atMost: e
						}) : n = {
							atLeast: r,
							atMost: Infinity
						}, this.consumeChar("}");
						break;
				}
				if (t === !0 && n === void 0) return;
				e(n);
				break;
		}
		if (!(t === !0 && n === void 0) && e(n)) return this.peekChar(0) === "?" ? (this.consumeChar("?"), n.greedy = !1) : n.greedy = !0, n.type = "Quantifier", n.loc = this.loc(r), n;
	}
	atom() {
		let n, r = this.idx;
		switch (this.peekChar()) {
			case ".":
				n = this.dotAll();
				break;
			case "\\":
				n = this.atomEscape();
				break;
			case "[":
				n = this.characterClass();
				break;
			case "(":
				n = this.group();
				break;
		}
		// istanbul ignore next
		return n === void 0 && this.isPatternCharacter() && (n = this.patternCharacter()), e(n) ? (n.loc = this.loc(r), this.isQuantifier() && (n.quantifier = this.quantifier()), n) : t();
	}
	dotAll() {
		return this.consumeChar("."), {
			type: "Set",
			complement: !0,
			value: [
				r("\n"),
				r("\r"),
				r("\u2028"),
				r("\u2029")
			]
		};
	}
	atomEscape() {
		switch (this.consumeChar("\\"), this.peekChar()) {
			case "1":
			case "2":
			case "3":
			case "4":
			case "5":
			case "6":
			case "7":
			case "8":
			case "9": return this.decimalEscapeAtom();
			case "d":
			case "D":
			case "s":
			case "S":
			case "w":
			case "W": return this.characterClassEscape();
			case "f":
			case "n":
			case "r":
			case "t":
			case "v": return this.controlEscapeAtom();
			case "c": return this.controlLetterEscapeAtom();
			case "0": return this.nulCharacterAtom();
			case "x": return this.hexEscapeSequenceAtom();
			case "u": return this.regExpUnicodeEscapeSequenceAtom();
			default: return this.identityEscapeAtom();
		}
	}
	decimalEscapeAtom() {
		return {
			type: "GroupBackReference",
			value: this.positiveInteger()
		};
	}
	characterClassEscape() {
		let n, r = !1;
		switch (this.popChar()) {
			case "d":
				n = o;
				break;
			case "D":
				n = o, r = !0;
				break;
			case "s":
				n = s;
				break;
			case "S":
				n = s, r = !0;
				break;
			case "w":
				n = c;
				break;
			case "W":
				n = c, r = !0;
				break;
		}
		// istanbul ignore next
		return e(n) ? {
			type: "Set",
			value: n,
			complement: r
		} : t();
	}
	controlEscapeAtom() {
		let n;
		switch (this.popChar()) {
			case "f":
				n = r("\f");
				break;
			case "n":
				n = r("\n");
				break;
			case "r":
				n = r("\r");
				break;
			case "t":
				n = r("	");
				break;
			case "v":
				n = r("\v");
				break;
		}
		// istanbul ignore next
		return e(n) ? {
			type: "Character",
			value: n
		} : t();
	}
	controlLetterEscapeAtom() {
		this.consumeChar("c");
		let e = this.popChar();
		if (/[a-zA-Z]/.test(e) === !1) throw Error("Invalid ");
		return {
			type: "Character",
			value: e.toUpperCase().charCodeAt(0) - 64
		};
	}
	nulCharacterAtom() {
		return this.consumeChar("0"), {
			type: "Character",
			value: r("\0")
		};
	}
	hexEscapeSequenceAtom() {
		return this.consumeChar("x"), this.parseHexDigits(2);
	}
	regExpUnicodeEscapeSequenceAtom() {
		return this.consumeChar("u"), this.parseHexDigits(4);
	}
	identityEscapeAtom() {
		return {
			type: "Character",
			value: r(this.popChar())
		};
	}
	classPatternCharacterAtom() {
		switch (this.peekChar()) {
			// istanbul ignore next
			case "\n":
			// istanbul ignore next
			case "\r":
			// istanbul ignore next
			case "\u2028":
			// istanbul ignore next
			case "\u2029":
			// istanbul ignore next
			case "\\":
			// istanbul ignore next
			case "]": throw Error("TBD");
			default: return {
				type: "Character",
				value: r(this.popChar())
			};
		}
	}
	characterClass() {
		let e = [], t = !1;
		for (this.consumeChar("["), this.peekChar(0) === "^" && (this.consumeChar("^"), t = !0); this.isClassAtom();) {
			let t = this.classAtom();
			if (t.type, a(t) && this.isRangeDash()) {
				this.consumeChar("-");
				let n = this.classAtom();
				if (n.type, a(n)) {
					if (n.value < t.value) throw Error("Range out of order in character class");
					e.push({
						from: t.value,
						to: n.value
					});
				} else i(t.value, e), e.push(r("-")), i(n.value, e);
			} else i(t.value, e);
		}
		return this.consumeChar("]"), {
			type: "Set",
			complement: t,
			value: e
		};
	}
	classAtom() {
		switch (this.peekChar()) {
			// istanbul ignore next
			case "]":
			// istanbul ignore next
			case "\n":
			// istanbul ignore next
			case "\r":
			// istanbul ignore next
			case "\u2028":
			// istanbul ignore next
			case "\u2029": throw Error("TBD");
			case "\\": return this.classEscape();
			default: return this.classPatternCharacterAtom();
		}
	}
	classEscape() {
		switch (this.consumeChar("\\"), this.peekChar()) {
			case "b": return this.consumeChar("b"), {
				type: "Character",
				value: r("\b")
			};
			case "d":
			case "D":
			case "s":
			case "S":
			case "w":
			case "W": return this.characterClassEscape();
			case "f":
			case "n":
			case "r":
			case "t":
			case "v": return this.controlEscapeAtom();
			case "c": return this.controlLetterEscapeAtom();
			case "0": return this.nulCharacterAtom();
			case "x": return this.hexEscapeSequenceAtom();
			case "u": return this.regExpUnicodeEscapeSequenceAtom();
			default: return this.identityEscapeAtom();
		}
	}
	group() {
		let e = !0;
		switch (this.consumeChar("("), this.peekChar(0)) {
			case "?":
				this.consumeChar("?"), this.consumeChar(":"), e = !1;
				break;
			default:
				this.groupIdx++;
				break;
		}
		let t = this.disjunction();
		this.consumeChar(")");
		let n = {
			type: "Group",
			capturing: e,
			value: t
		};
		return e && (n.idx = this.groupIdx), n;
	}
	positiveInteger() {
		let e = this.popChar();
		// istanbul ignore next - can't ever get here due to previous lookahead checks
		if (d.test(e) === !1) throw Error("Expecting a positive integer");
		for (; u.test(this.peekChar(0));) e += this.popChar();
		return parseInt(e, 10);
	}
	integerIncludingZero() {
		let e = this.popChar();
		if (u.test(e) === !1) throw Error("Expecting an integer");
		for (; u.test(this.peekChar(0));) e += this.popChar();
		return parseInt(e, 10);
	}
	patternCharacter() {
		let e = this.popChar();
		switch (e) {
			// istanbul ignore next
			case "\n":
			// istanbul ignore next
			case "\r":
			// istanbul ignore next
			case "\u2028":
			// istanbul ignore next
			case "\u2029":
			// istanbul ignore next
			case "^":
			// istanbul ignore next
			case "$":
			// istanbul ignore next
			case "\\":
			// istanbul ignore next
			case ".":
			// istanbul ignore next
			case "*":
			// istanbul ignore next
			case "+":
			// istanbul ignore next
			case "?":
			// istanbul ignore next
			case "(":
			// istanbul ignore next
			case ")":
			// istanbul ignore next
			case "[":
			// istanbul ignore next
			case "|":
 // istanbul ignore next
			throw Error("TBD");
			default: return {
				type: "Character",
				value: r(e)
			};
		}
	}
	isRegExpFlag() {
		switch (this.peekChar(0)) {
			case "g":
			case "i":
			case "m":
			case "u":
			case "y": return !0;
			default: return !1;
		}
	}
	isRangeDash() {
		return this.peekChar() === "-" && this.isClassAtom(1);
	}
	isDigit() {
		return u.test(this.peekChar(0));
	}
	isClassAtom(e = 0) {
		switch (this.peekChar(e)) {
			case "]":
			case "\n":
			case "\r":
			case "\u2028":
			case "\u2029": return !1;
			default: return !0;
		}
	}
	isTerm() {
		return this.isAtom() || this.isAssertion();
	}
	isAtom() {
		if (this.isPatternCharacter()) return !0;
		switch (this.peekChar(0)) {
			case ".":
			case "\\":
			case "[":
			case "(": return !0;
			default: return !1;
		}
	}
	isAssertion() {
		switch (this.peekChar(0)) {
			case "^":
			case "$": return !0;
			case "\\": switch (this.peekChar(1)) {
				case "b":
				case "B": return !0;
				default: return !1;
			}
			case "(": return this.peekChar(1) === "?" && (this.peekChar(2) === "=" || this.peekChar(2) === "!" || this.peekChar(2) === "<" && (this.peekChar(3) === "=" || this.peekChar(3) === "!"));
			default: return !1;
		}
	}
	isQuantifier() {
		let e = this.saveState();
		try {
			return this.quantifier(!0) !== void 0;
		} catch {
			return !1;
		} finally {
			this.restoreState(e);
		}
	}
	isPatternCharacter() {
		switch (this.peekChar()) {
			case "^":
			case "$":
			case "\\":
			case ".":
			case "*":
			case "+":
			case "?":
			case "(":
			case ")":
			case "[":
			case "|":
			case "/":
			case "\n":
			case "\r":
			case "\u2028":
			case "\u2029": return !1;
			default: return !0;
		}
	}
	parseHexDigits(e) {
		let t = "";
		for (let n = 0; n < e; n++) {
			let e = this.popChar();
			if (l.test(e) === !1) throw Error("Expecting a HexDecimal digits");
			t += e;
		}
		return {
			type: "Character",
			value: parseInt(t, 16)
		};
	}
	peekChar(e = 0) {
		return this.input[this.idx + e];
	}
	popChar() {
		let e = this.peekChar(0);
		return this.consumeChar(void 0), e;
	}
	consumeChar(e) {
		if (e !== void 0 && this.input[this.idx] !== e) throw Error("Expected: '" + e + "' but found: '" + this.input[this.idx] + "' at offset: " + this.idx);
		if (this.idx >= this.input.length) throw Error("Unexpected end of input");
		this.idx++;
	}
	loc(e) {
		return {
			begin: e,
			end: this.idx
		};
	}
};
//#endregion
export { f as RegExpParser };
