use core::ops::{Add, AddAssign};
use derive_more::{From, IsVariant, TryUnwrap, Unwrap};
use super::{CharLen, PositionedChar, SimpleSpan};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, IsVariant, Unwrap, TryUnwrap, From)]
#[unwrap(ref, ref_mut)]
#[try_unwrap(ref, ref_mut)]
pub enum Lexeme<Char = char, O = usize> {
Char(PositionedChar<Char, O>),
Range(SimpleSpan<O>),
}
impl<Char, O> core::fmt::Display for Lexeme<Char, O>
where
Char: super::human_display::DisplayHuman,
O: core::fmt::Display,
{
#[cfg_attr(not(tarpaulin), inline(always))]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Char(pc) => write!(f, "'{}' at {}", pc.char_ref().display(), pc.position_ref()),
Self::Range(span) => write!(f, "{}", span),
}
}
}
impl<Char, O> Lexeme<Char, O> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_char(pos: O, ch: Char) -> Self {
Self::Char(PositionedChar::with_position(ch, pos))
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn from_range(range: impl Into<SimpleSpan<O>>) -> Self {
Self::Range(range.into())
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn from_range_const(span: SimpleSpan<O>) -> Self {
Self::Range(span)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn start(&self) -> O
where
O: Copy,
{
match self {
Self::Char(pc) => pc.position(),
Self::Range(r) => r.start(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub const fn start_ref(&self) -> &O {
match self {
Self::Char(pc) => pc.position_ref(),
Self::Range(r) => r.start_ref(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn end(&self) -> O
where
Char: CharLen,
O: Clone,
for<'a> &'a O: Add<usize, Output = O>,
{
match self {
Self::Char(pc) => pc.position_ref() + pc.char_ref().char_len(),
Self::Range(r) => r.end_ref().clone(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn map<F, NewChar>(self, f: F) -> Lexeme<NewChar, O>
where
F: FnOnce(Char) -> NewChar,
{
match self {
Self::Char(pc) => Lexeme::Char(pc.map(f)),
Self::Range(r) => Lexeme::Range(r),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn span_with(&self, len_of: impl FnOnce(&Char) -> usize) -> SimpleSpan<O>
where
O: Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
match self {
Self::Char(pc) => {
let start = pc.position_ref();
let end = start + len_of(pc.char_ref());
SimpleSpan::new(start.clone(), end)
}
Self::Range(r) => r.clone(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn span(&self) -> SimpleSpan<O>
where
Char: CharLen,
O: Clone + Ord,
for<'a> &'a O: Add<usize, Output = O>,
{
match self {
Self::Char(pc) => pc.span(),
Self::Range(r) => r.clone(),
}
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn bump(&mut self, n: &O) -> &mut Self
where
O: for<'a> AddAssign<&'a O> + Clone,
{
match self {
Self::Char(positioned_char) => {
positioned_char.position += n;
self
}
Self::Range(span) => {
span.bump(n);
self
}
}
}
}