import isFunction_default from "../../../../../../lodash-es/isFunction.js";
import isArray_default from "../../../../../../lodash-es/isArray.js";
import last_default from "../../../../../../lodash-es/last.js";
import forEach_default from "../../../../../../lodash-es/forEach.js";
import has_default from "../../../../../../lodash-es/has.js";
import some_default from "../../../../../../lodash-es/some.js";
import { Alternation, Alternative, NonTerminal, Option, Repetition, RepetitionMandatory, RepetitionMandatoryWithSeparator, RepetitionWithSeparator, Rule, Terminal } from "../../../../../../@chevrotain/gast/lib/src/model.js";
import { augmentTokenTypes, hasShortKeyProperty } from "../../../scan/tokens.js";
import { Lexer } from "../../../scan/lexer_public.js";
import { createToken, createTokenInstance } from "../../../scan/tokens_public.js";
import { BITS_FOR_OCCURRENCE_IDX } from "../../grammar/keys.js";
import { END_OF_FILE } from "../parser.js";
var RECORDING_NULL_OBJECT = { description: "This Object indicates the Parser is during Recording Phase" };
Object.freeze(RECORDING_NULL_OBJECT);
var HANDLE_SEPARATOR = !0, MAX_METHOD_IDX = 2 ** 8 - 1, RFT = createToken({
	name: "RECORDING_PHASE_TOKEN",
	pattern: Lexer.NA
});
augmentTokenTypes([RFT]);
var RECORDING_PHASE_TOKEN = createTokenInstance(RFT, "This IToken indicates the Parser is in Recording Phase\n	See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details", -1, -1, -1, -1, -1, -1);
Object.freeze(RECORDING_PHASE_TOKEN);
var RECORDING_PHASE_CSTNODE = {
	name: "This CSTNode indicates the Parser is in Recording Phase\n	See: https://chevrotain.io/docs/guide/internals.html#grammar-recording for details",
	children: {}
}, GastRecorder = class {
	initGastRecorder(i) {
		this.recordingProdStack = [], this.RECORDING_PHASE = !1;
	}
	enableRecording() {
		this.RECORDING_PHASE = !0, this.TRACE_INIT("Enable Recording", () => {
			for (let i = 0; i < 10; i++) {
				let x = i > 0 ? i : "";
				this[`CONSUME${x}`] = function(x, S) {
					return this.consumeInternalRecord(x, i, S);
				}, this[`SUBRULE${x}`] = function(x, S) {
					return this.subruleInternalRecord(x, i, S);
				}, this[`OPTION${x}`] = function(x) {
					return this.optionInternalRecord(x, i);
				}, this[`OR${x}`] = function(x) {
					return this.orInternalRecord(x, i);
				}, this[`MANY${x}`] = function(x) {
					this.manyInternalRecord(i, x);
				}, this[`MANY_SEP${x}`] = function(x) {
					this.manySepFirstInternalRecord(i, x);
				}, this[`AT_LEAST_ONE${x}`] = function(x) {
					this.atLeastOneInternalRecord(i, x);
				}, this[`AT_LEAST_ONE_SEP${x}`] = function(x) {
					this.atLeastOneSepFirstInternalRecord(i, x);
				};
			}
			this.consume = function(i, x, S) {
				return this.consumeInternalRecord(x, i, S);
			}, this.subrule = function(i, x, S) {
				return this.subruleInternalRecord(x, i, S);
			}, this.option = function(i, x) {
				return this.optionInternalRecord(x, i);
			}, this.or = function(i, x) {
				return this.orInternalRecord(x, i);
			}, this.many = function(i, x) {
				this.manyInternalRecord(i, x);
			}, this.atLeastOne = function(i, x) {
				this.atLeastOneInternalRecord(i, x);
			}, this.ACTION = this.ACTION_RECORD, this.BACKTRACK = this.BACKTRACK_RECORD, this.LA = this.LA_RECORD;
		});
	}
	disableRecording() {
		this.RECORDING_PHASE = !1, this.TRACE_INIT("Deleting Recording methods", () => {
			let i = this;
			for (let x = 0; x < 10; x++) {
				let S = x > 0 ? x : "";
				delete i[`CONSUME${S}`], delete i[`SUBRULE${S}`], delete i[`OPTION${S}`], delete i[`OR${S}`], delete i[`MANY${S}`], delete i[`MANY_SEP${S}`], delete i[`AT_LEAST_ONE${S}`], delete i[`AT_LEAST_ONE_SEP${S}`];
			}
			delete i.consume, delete i.subrule, delete i.option, delete i.or, delete i.many, delete i.atLeastOne, delete i.ACTION, delete i.BACKTRACK, delete i.LA;
		});
	}
	ACTION_RECORD(i) {}
	BACKTRACK_RECORD(i, x) {
		return () => !0;
	}
	LA_RECORD(i) {
		return END_OF_FILE;
	}
	topLevelRuleRecord(i, x) {
		try {
			let S = new Rule({
				definition: [],
				name: i
			});
			return S.name = i, this.recordingProdStack.push(S), x.call(this), this.recordingProdStack.pop(), S;
		} catch (i) {
			if (i.KNOWN_RECORDER_ERROR !== !0) try {
				i.message += "\n	 This error was thrown during the \"grammar recording phase\" For more info see:\n	https://chevrotain.io/docs/guide/internals.html#grammar-recording";
			} catch {
				throw i;
			}
			throw i;
		}
	}
	optionInternalRecord(i, x) {
		return recordProd.call(this, Option, i, x);
	}
	atLeastOneInternalRecord(i, x) {
		recordProd.call(this, RepetitionMandatory, x, i);
	}
	atLeastOneSepFirstInternalRecord(i, x) {
		recordProd.call(this, RepetitionMandatoryWithSeparator, x, i, HANDLE_SEPARATOR);
	}
	manyInternalRecord(i, x) {
		recordProd.call(this, Repetition, x, i);
	}
	manySepFirstInternalRecord(i, x) {
		recordProd.call(this, RepetitionWithSeparator, x, i, HANDLE_SEPARATOR);
	}
	orInternalRecord(i, x) {
		return recordOrProd.call(this, i, x);
	}
	subruleInternalRecord(i, x, C) {
		if (assertMethodIdxIsValid(x), !i || has_default(i, "ruleName") === !1) {
			let S = /* @__PURE__ */ Error(`<SUBRULE${getIdxSuffix(x)}> argument is invalid expecting a Parser method reference but got: <${JSON.stringify(i)}>\n inside top level rule: <${this.recordingProdStack[0].name}>`);
			throw S.KNOWN_RECORDER_ERROR = !0, S;
		}
		let T = last_default(this.recordingProdStack), E = i.ruleName, D = new NonTerminal({
			idx: x,
			nonTerminalName: E,
			label: C?.LABEL,
			referencedRule: void 0
		});
		return T.definition.push(D), this.outputCst ? RECORDING_PHASE_CSTNODE : RECORDING_NULL_OBJECT;
	}
	consumeInternalRecord(i, x, C) {
		if (assertMethodIdxIsValid(x), !hasShortKeyProperty(i)) {
			let S = /* @__PURE__ */ Error(`<CONSUME${getIdxSuffix(x)}> argument is invalid expecting a TokenType reference but got: <${JSON.stringify(i)}>\n inside top level rule: <${this.recordingProdStack[0].name}>`);
			throw S.KNOWN_RECORDER_ERROR = !0, S;
		}
		let w = last_default(this.recordingProdStack), T = new Terminal({
			idx: x,
			terminalType: i,
			label: C?.LABEL
		});
		return w.definition.push(T), RECORDING_PHASE_TOKEN;
	}
};
function recordProd(x, C, T, E = !1) {
	assertMethodIdxIsValid(T);
	let D = last_default(this.recordingProdStack), O = isFunction_default(C) ? C : C.DEF, k = new x({
		definition: [],
		idx: T
	});
	return E && (k.separator = C.SEP), has_default(C, "MAX_LOOKAHEAD") && (k.maxLookahead = C.MAX_LOOKAHEAD), this.recordingProdStack.push(k), O.call(this), D.definition.push(k), this.recordingProdStack.pop(), RECORDING_NULL_OBJECT;
}
function recordOrProd(O, k) {
	assertMethodIdxIsValid(k);
	let A = last_default(this.recordingProdStack), j = isArray_default(O) === !1, M = j === !1 ? O : O.DEF, N = new Alternation({
		definition: [],
		idx: k,
		ignoreAmbiguities: j && O.IGNORE_AMBIGUITIES === !0
	});
	return has_default(O, "MAX_LOOKAHEAD") && (N.maxLookahead = O.MAX_LOOKAHEAD), N.hasPredicates = some_default(M, (x) => isFunction_default(x.GATE)), A.definition.push(N), forEach_default(M, (i) => {
		let x = new Alternative({ definition: [] });
		N.definition.push(x), has_default(i, "IGNORE_AMBIGUITIES") ? x.ignoreAmbiguities = i.IGNORE_AMBIGUITIES : has_default(i, "GATE") && (x.ignoreAmbiguities = !0), this.recordingProdStack.push(x), i.ALT.call(this), this.recordingProdStack.pop();
	}), RECORDING_NULL_OBJECT;
}
function getIdxSuffix(i) {
	return i === 0 ? "" : `${i}`;
}
function assertMethodIdxIsValid(i) {
	if (i < 0 || i > MAX_METHOD_IDX) {
		let x = /* @__PURE__ */ Error(`Invalid DSL Method idx value: <${i}>\n\tIdx value must be a none negative value smaller than ${MAX_METHOD_IDX + 1}`);
		throw x.KNOWN_RECORDER_ERROR = !0, x;
	}
}
export { GastRecorder };
