import { __export } from "../../../../_virtual/rolldown_runtime.js";
import { isCompositeCstNode, isLeafCstNode, isRootCstNode } from "../syntax-tree.js";
import { TreeStreamImpl } from "./stream.js";
import { getContainerOfType } from "./ast-utils.js";
import { isParserRule } from "../languages/generated/ast.js";
var cst_utils_exports = /* @__PURE__ */ __export({
	DefaultNameRegexp: () => DefaultNameRegexp,
	RangeComparison: () => RangeComparison,
	compareRange: () => compareRange,
	findCommentNode: () => findCommentNode,
	findDeclarationNodeAtOffset: () => findDeclarationNodeAtOffset,
	findLeafNodeAtOffset: () => findLeafNodeAtOffset,
	findLeafNodeBeforeOffset: () => findLeafNodeBeforeOffset,
	flattenCst: () => flattenCst,
	getDatatypeNode: () => getDatatypeNode,
	getInteriorNodes: () => getInteriorNodes,
	getNextNode: () => getNextNode,
	getPreviousNode: () => getPreviousNode,
	getStartlineNode: () => getStartlineNode,
	inRange: () => inRange,
	isChildNode: () => isChildNode,
	isCommentNode: () => isCommentNode,
	streamCst: () => streamCst,
	toDocumentSegment: () => toDocumentSegment,
	tokenToRange: () => tokenToRange
}, 1);
function getDatatypeNode(e) {
	let C = e, w = !1;
	for (; C;) {
		let e = getContainerOfType(C.grammarSource, isParserRule);
		if (e && e.dataType) C = C.container, w = !0;
		else if (w) return C;
		else return;
	}
}
function streamCst(e) {
	return new TreeStreamImpl(e, (e) => isCompositeCstNode(e) ? e.content : [], { includeRoot: !0 });
}
function flattenCst(e) {
	return streamCst(e).filter(isLeafCstNode);
}
function isChildNode(e, C) {
	for (; e.container;) if (e = e.container, e === C) return !0;
	return !1;
}
function tokenToRange(e) {
	return {
		start: {
			character: e.startColumn - 1,
			line: e.startLine - 1
		},
		end: {
			character: e.endColumn,
			line: e.endLine - 1
		}
	};
}
function toDocumentSegment(e) {
	if (!e) return;
	let { offset: C, end: w, range: T } = e;
	return {
		range: T,
		offset: C,
		end: w,
		length: w - C
	};
}
var RangeComparison;
(function(e) {
	e[e.Before = 0] = "Before", e[e.After = 1] = "After", e[e.OverlapFront = 2] = "OverlapFront", e[e.OverlapBack = 3] = "OverlapBack", e[e.Inside = 4] = "Inside", e[e.Outside = 5] = "Outside";
})(RangeComparison ||= {});
function compareRange(e, C) {
	if (e.end.line < C.start.line || e.end.line === C.start.line && e.end.character <= C.start.character) return RangeComparison.Before;
	if (e.start.line > C.end.line || e.start.line === C.end.line && e.start.character >= C.end.character) return RangeComparison.After;
	let w = e.start.line > C.start.line || e.start.line === C.start.line && e.start.character >= C.start.character, T = e.end.line < C.end.line || e.end.line === C.end.line && e.end.character <= C.end.character;
	return w && T ? RangeComparison.Inside : w ? RangeComparison.OverlapBack : T ? RangeComparison.OverlapFront : RangeComparison.Outside;
}
function inRange(e, C) {
	return compareRange(e, C) > RangeComparison.After;
}
const DefaultNameRegexp = /^[\w\p{L}]$/u;
function findDeclarationNodeAtOffset(e, C, w = DefaultNameRegexp) {
	if (e) {
		if (C > 0) {
			let T = C - e.offset, E = e.text.charAt(T);
			w.test(E) || C--;
		}
		return findLeafNodeAtOffset(e, C);
	}
}
function findCommentNode(e, C) {
	if (e) {
		let w = getPreviousNode(e, !0);
		if (w && isCommentNode(w, C)) return w;
		if (isRootCstNode(e)) {
			let w = e.content.findIndex((e) => !e.hidden);
			for (let T = w - 1; T >= 0; T--) {
				let w = e.content[T];
				if (isCommentNode(w, C)) return w;
			}
		}
	}
}
function isCommentNode(e, C) {
	return isLeafCstNode(e) && C.includes(e.tokenType.name);
}
function findLeafNodeAtOffset(e, T) {
	if (isLeafCstNode(e)) return e;
	if (isCompositeCstNode(e)) {
		let C = binarySearch(e, T, !1);
		if (C) return findLeafNodeAtOffset(C, T);
	}
}
function findLeafNodeBeforeOffset(e, T) {
	if (isLeafCstNode(e)) return e;
	if (isCompositeCstNode(e)) {
		let C = binarySearch(e, T, !0);
		if (C) return findLeafNodeBeforeOffset(C, T);
	}
}
function binarySearch(e, C, w) {
	let T = 0, E = e.content.length - 1, D;
	for (; T <= E;) {
		let O = Math.floor((T + E) / 2), k = e.content[O];
		if (k.offset <= C && k.end > C) return k;
		k.end <= C ? (D = w ? k : void 0, T = O + 1) : E = O - 1;
	}
	return D;
}
function getPreviousNode(e, C = !0) {
	for (; e.container;) {
		let w = e.container, T = w.content.indexOf(e);
		for (; T > 0;) {
			T--;
			let e = w.content[T];
			if (C || !e.hidden) return e;
		}
		e = w;
	}
}
function getNextNode(e, C = !0) {
	for (; e.container;) {
		let w = e.container, T = w.content.indexOf(e), E = w.content.length - 1;
		for (; T < E;) {
			T++;
			let e = w.content[T];
			if (C || !e.hidden) return e;
		}
		e = w;
	}
}
function getStartlineNode(e) {
	if (e.range.start.character === 0) return e;
	let C = e.range.start.line, w = e, T;
	for (; e.container;) {
		let E = e.container, D = T ?? E.content.indexOf(e);
		if (D === 0 ? (e = E, T = void 0) : (T = D - 1, e = E.content[T]), e.range.start.line !== C) break;
		w = e;
	}
	return w;
}
function getInteriorNodes(e, C) {
	let w = getCommonParent(e, C);
	return w ? w.parent.content.slice(w.a + 1, w.b) : [];
}
function getCommonParent(e, C) {
	let w = getParentChain(e), T = getParentChain(C), E;
	for (let e = 0; e < w.length && e < T.length; e++) {
		let C = w[e], D = T[e];
		if (C.parent === D.parent) E = {
			parent: C.parent,
			a: C.index,
			b: D.index
		};
		else break;
	}
	return E;
}
function getParentChain(e) {
	let C = [];
	for (; e.container;) {
		let w = e.container, T = w.content.indexOf(e);
		C.push({
			parent: w,
			index: T
		}), e = w;
	}
	return C.reverse();
}
export { DefaultNameRegexp, cst_utils_exports, findCommentNode, inRange, isChildNode, streamCst, toDocumentSegment, tokenToRange };
