use alloc::sync::Arc;
use core::fmt::{self, Debug};
use core::ptr;
use crate::types::ErrorLocationProvider;
pub trait LexerInterface {
fn input(&self) -> &str;
}
impl Debug for dyn LexerInterface + '_ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "LexerInterface")
}
}
impl PartialEq for dyn LexerInterface + '_ {
fn eq(&self, other: &Self) -> bool {
ptr::eq(self, other)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SourceLocation {
pub input: Arc<str>,
pub start: usize,
pub end: usize,
}
impl SourceLocation {
#[must_use]
pub const fn new(input: Arc<str>, start: usize, end: usize) -> Self {
Self { input, start, end }
}
#[must_use]
pub fn from_str(input: &str, start: usize, end: usize) -> Self {
Self::new(Arc::from(input), start, end)
}
#[must_use]
pub const fn start(&self) -> usize {
self.start
}
#[must_use]
pub const fn end(&self) -> usize {
self.end
}
#[must_use]
pub fn input(&self) -> &str {
&self.input
}
#[must_use]
pub fn input_arc(&self) -> Arc<str> {
Arc::clone(&self.input)
}
#[must_use]
pub fn range(first: Option<Self>, second: Option<Self>) -> Option<Self> {
match (first, second) {
(Some(fp), None) => Some(fp),
(None, Some(sp)) => Some(sp),
(Some(fp), Some(sp)) => {
if !Arc::ptr_eq(&fp.input, &sp.input) {
return None;
}
Some(Self {
input: Arc::clone(&fp.input),
start: fp.start,
end: sp.end,
})
}
_ => None,
}
}
}
pub trait SourceRangeRef {
#[must_use]
fn range_ref(self, second: Self) -> Option<SourceLocation>;
}
impl SourceRangeRef for Option<&SourceLocation> {
fn range_ref(self, second: Self) -> Option<SourceLocation> {
match (self, second) {
(Some(fp), None) => Some(fp.clone()),
(None, Some(sp)) => Some(sp.clone()),
(Some(fp), Some(sp)) => {
if !Arc::ptr_eq(&fp.input, &sp.input) {
return None;
}
Some(SourceLocation {
input: Arc::clone(&fp.input),
start: fp.start,
end: sp.end,
})
}
_ => None,
}
}
}
impl ErrorLocationProvider for SourceLocation {
fn loc(&self) -> Option<&SourceLocation> {
Some(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_source_location_creation() {
let input = Arc::from("This is a test expression with invalid syntax");
let loc = SourceLocation::new(Arc::clone(&input), 10, 20);
assert_eq!(loc.start(), 10);
assert_eq!(loc.end(), 20);
assert_eq!(loc.input(), "This is a test expression with invalid syntax");
}
#[test]
fn test_from_str_creation() {
let loc = SourceLocation::from_str("test input", 5, 15);
assert_eq!(loc.start(), 5);
assert_eq!(loc.end(), 15);
assert_eq!(loc.input(), "test input");
}
#[test]
fn test_range_method() {
let input = Arc::from("test input");
let loc1 = SourceLocation::new(Arc::clone(&input), 5, 15);
let result = SourceLocation::range(Some(loc1.clone()), None);
assert_eq!(result.as_ref().unwrap().end(), 15);
let loc2 = SourceLocation::new(Arc::clone(&input), 20, 30);
let result = SourceLocation::range(Some(loc1.clone()), Some(loc2));
assert_eq!(result.as_ref().unwrap().end(), 30);
let different_input = Arc::from("different input");
let loc3 = SourceLocation::new(Arc::clone(&different_input), 40, 50);
let result = SourceLocation::range(Some(loc1), Some(loc3));
assert!(result.is_none()); }
}