use std::{
convert::{TryFrom, TryInto},
fmt::Display,
};
use text_size::{TextRange, TextSize};
use crate::FileId;
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(rserde::Serialize, rserde::Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "rserde"))]
pub struct LexerPosition {
pub source_id: FileId,
pub offset: TextSize,
}
impl LexerPosition {
pub fn new(source_id: FileId, offset: TextSize) -> Self {
Self { source_id, offset }
}
pub fn new_raw<E: std::fmt::Debug>(
source_id: FileId,
offset: impl TryInto<u32, Error = E>,
) -> Self {
Self {
source_id,
offset: offset.try_into().expect("input too large").into(),
}
}
}
impl Display for LexerPosition {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}:{}", self.source_id, u32::from(self.offset))
}
}
impl From<LexerPosition> for FileId {
fn from(value: LexerPosition) -> Self {
value.source_id
}
}
impl From<LexerPosition> for TextSize {
fn from(value: LexerPosition) -> Self {
value.offset
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(rserde::Serialize, rserde::Deserialize))]
#[cfg_attr(feature = "serde", serde(crate = "rserde"))]
pub struct NodeSpan {
source_id: FileId,
range: TextRange,
}
impl NodeSpan {
pub fn new(source_id: FileId, range: TextRange) -> Self {
Self { source_id, range }
}
pub fn from_lexer(start: LexerPosition, end: LexerPosition) -> Self {
Self {
source_id: start.source_id,
range: TextRange::new(start.offset, end.offset),
}
}
pub fn new_start(source_id: FileId) -> Self {
Self {
source_id,
range: TextRange::default(),
}
}
pub fn new_end(source_id: FileId, length: usize) -> Self {
let length = TextSize::try_from(length).expect("length is too large");
Self {
source_id,
range: TextRange::new(length, length),
}
}
pub fn source_id(&self) -> FileId {
self.source_id
}
pub fn range(&self) -> TextRange {
self.range
}
pub fn is_empty(&self) -> bool {
self.range.is_empty()
}
pub fn len(&self) -> TextSize {
self.range.len()
}
pub fn start(&self) -> LexerPosition {
LexerPosition::new(self.source_id, self.range.start())
}
pub fn end(&self) -> LexerPosition {
LexerPosition::new(self.source_id, self.range.end())
}
}
impl PartialOrd for NodeSpan {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl Ord for NodeSpan {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.source_id
.cmp(&other.source_id)
.then(self.range.start().cmp(&other.range.start()))
.then(self.range.len().cmp(&other.range.len()))
}
}
impl From<NodeSpan> for FileId {
fn from(value: NodeSpan) -> Self {
value.source_id
}
}
impl From<NodeSpan> for TextRange {
fn from(value: NodeSpan) -> Self {
value.range
}
}