use std::{
borrow::Cow,
error::Error,
fmt::{self, Display, Formatter},
hash::Hash,
ops::Deref,
ops::Sub,
path::{Path, PathBuf},
sync::Arc,
};
use crate::*;
use derive_more::Display;
#[derive(Debug, Default, Clone, Hash, PartialEq, Eq)]
pub struct Loc<T> {
pub value: T,
pub span: Option<Span>,
}
impl<T> Loc<T> {
pub const fn new(value: T) -> Loc<T> {
Loc { span: None, value }
}
pub fn map<F, R>(self, f: F) -> Loc<R>
where
F: FnOnce(T) -> R,
{
Loc {
value: f(self.value),
span: self.span,
}
}
}
impl<T> Located for Loc<T> {
fn span(&self) -> Option<Span> {
self.span.clone()
}
}
impl<T> Locatable for Loc<T> {
type Located = Loc<T>;
fn over(self, span: impl Into<Option<Span>>) -> Loc<T> {
Loc {
span: span.into(),
..self
}
}
}
impl<T: Display> Display for Loc<T> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Display::fmt(&self.value, f)
}
}
impl<T: Error> Error for Loc<T> {}
impl<T> From<T> for Loc<T> {
fn from(value: T) -> Self {
Loc::new(value)
}
}
impl<T> Deref for Loc<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
#[derive(Debug, Clone, Default, Hash, PartialEq, Eq)]
pub enum Origin {
#[default]
Unknown,
Buffer,
StdIn,
Path(Arc<PathBuf>),
}
impl Display for Origin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Origin::Unknown => f.write_str("<unknown>"),
Origin::StdIn => f.write_str("<stdin>"),
Origin::Buffer => f.write_str("<buffer>"),
Origin::Path(path) => Display::fmt(&path.display(), f),
}
}
}
impl<T: AsRef<Path>> From<T> for Origin {
fn from(value: T) -> Self {
Origin::Path(Arc::new(PathBuf::from(value.as_ref())))
}
}
#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct Location {
pub position: usize,
pub line: usize,
pub column: usize,
}
impl Display for Location {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}:{}", self.line + 1, self.column)
}
}
impl Sub for Location {
type Output = usize;
fn sub(self, rhs: Self) -> usize {
self.position - rhs.position
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum Span {
Whole(Origin),
Builtin,
Span {
origin: Origin,
begin: Location,
end: Location,
},
}
impl Default for Span {
fn default() -> Self {
Span::Whole(Origin::default())
}
}
impl Span {
pub fn new() -> Span {
Span::default()
}
}
impl Display for Span {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Span::Whole(origin) => Display::fmt(origin, f),
Span::Builtin => write!(f, "builtin"),
Span::Span { origin, begin, end } => {
if end.column > begin.column + 1 {
write!(
f,
"{}:[{}:{}, {}:{})",
origin,
begin.line + 1,
begin.column,
end.line + 1,
end.column
)
} else {
write!(f, "{}:{}:{}", origin, begin.line + 1, begin.column)
}
}
}
}
}
pub trait Located {
fn span(&self) -> Option<Span>;
}
impl Located for Option<Span> {
fn span(&self) -> Option<Span> {
self.clone()
}
}
pub trait Locatable: Sized {
type Located: Located;
fn over(self, span: impl Into<Option<Span>>) -> Self::Located;
}
impl Locatable for Option<Span> {
type Located = Option<Span>;
fn over(self, span: impl Into<Option<Span>>) -> Self::Located {
span.into()
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, Display, Located, Locatable)]
#[display("{name}")]
pub struct Identifier<'a> {
name: Cow<'a, str>,
span: Option<Span>,
}
impl<'a> Identifier<'a> {
pub const fn new(name: &'a str) -> Self {
Identifier {
name: Cow::Borrowed(name),
span: None,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn into_inner(self) -> Cow<'a, str> {
self.name
}
pub fn into_string(self) -> String {
self.name.into_owned()
}
pub fn into_owned(self) -> Identifier<'static> {
match self.name {
Cow::Borrowed(name) => Identifier {
name: Cow::Owned(name.to_string()),
span: self.span,
},
Cow::Owned(name) => Identifier {
name: Cow::Owned(name),
span: self.span,
},
}
}
}
impl Deref for Identifier<'_> {
type Target = str;
fn deref(&self) -> &str {
&self.name
}
}
impl From<String> for Identifier<'_> {
fn from(name: String) -> Self {
Identifier {
name: Cow::from(name),
span: None,
}
}
}
impl<'a> From<&'a str> for Identifier<'a> {
fn from(name: &'a str) -> Self {
Identifier::new(name)
}
}
impl<'a> From<Cow<'a, str>> for Identifier<'a> {
fn from(name: Cow<'a, str>) -> Self {
Identifier { name, span: None }
}
}