use crate::context::AnchorLocation; use crate::parser::parse::parser::TracableContext; use crate::prelude::*; use derive_new::new; use getset::Getters; use serde::Deserialize; use serde::Serialize; use std::fmt; use std::path::{Path, PathBuf}; #[derive(new, Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] pub struct Spanned { pub span: Span, pub item: T, } impl Spanned { pub fn map(self, input: impl FnOnce(T) -> U) -> Spanned { let span = self.span; let mapped = input(self.item); mapped.spanned(span) } } pub trait SpannedItem: Sized { fn spanned(self, span: impl Into) -> Spanned { Spanned { item: self, span: span.into(), } } fn spanned_unknown(self) -> Spanned { Spanned { item: self, span: Span::unknown(), } } } impl SpannedItem for T {} impl std::ops::Deref for Spanned { type Target = T; fn deref(&self) -> &T { &self.item } } #[derive(new, Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, Hash)] pub struct Tagged { pub tag: Tag, pub item: T, } impl HasTag for Tagged { fn tag(&self) -> Tag { self.tag.clone() } } impl AsRef for Tagged { fn as_ref(&self) -> &Path { self.item.as_ref() } } pub trait TaggedItem: Sized { fn tagged(self, tag: impl Into) -> Tagged { Tagged { item: self, tag: tag.into(), } } // For now, this is a temporary facility. In many cases, there are other useful spans that we // could be using, such as the original source spans of JSON or Toml files, but we don't yet // have the infrastructure to make that work. fn tagged_unknown(self) -> Tagged { Tagged { item: self, tag: Tag { span: Span::unknown(), anchor: None, }, } } } impl TaggedItem for T {} impl std::ops::Deref for Tagged { type Target = T; fn deref(&self) -> &T { &self.item } } impl Tagged { pub fn map(self, input: impl FnOnce(T) -> U) -> Tagged { let tag = self.tag(); let mapped = input(self.item); mapped.tagged(tag) } pub fn tag(&self) -> Tag { self.tag.clone() } pub fn span(&self) -> Span { self.tag.span } pub fn anchor(&self) -> Option { self.tag.anchor.clone() } pub fn anchor_name(&self) -> Option { match self.tag.anchor { Some(AnchorLocation::File(ref file)) => Some(file.clone()), Some(AnchorLocation::Url(ref url)) => Some(url.clone()), _ => None, } } pub fn item(&self) -> &T { &self.item } pub fn into_parts(self) -> (T, Tag) { (self.item, self.tag) } } impl From<&Tag> for Tag { fn from(input: &Tag) -> Tag { input.clone() } } impl From> for Span { fn from(input: nom_locate::LocatedSpanEx<&str, TracableContext>) -> Span { Span::new(input.offset, input.offset + input.fragment.len()) } } impl From> for Span { fn from(input: nom_locate::LocatedSpanEx<&str, u64>) -> Span { Span::new(input.offset, input.offset + input.fragment.len()) } } impl From<( nom_locate::LocatedSpanEx, nom_locate::LocatedSpanEx, )> for Span { fn from( input: ( nom_locate::LocatedSpanEx, nom_locate::LocatedSpanEx, ), ) -> Span { Span { start: input.0.offset, end: input.1.offset, } } } impl From<(usize, usize)> for Span { fn from(input: (usize, usize)) -> Span { Span::new(input.0, input.1) } } impl From<&std::ops::Range> for Span { fn from(input: &std::ops::Range) -> Span { Span { start: input.start, end: input.end, } } } #[derive( Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash, Getters, new, )] pub struct Tag { pub anchor: Option, pub span: Span, } impl From for Tag { fn from(span: Span) -> Self { Tag { anchor: None, span } } } impl From<&Span> for Tag { fn from(span: &Span) -> Self { Tag { anchor: None, span: *span, } } } impl From<(usize, usize, TracableContext)> for Tag { fn from((start, end, _context): (usize, usize, TracableContext)) -> Self { Tag { anchor: None, span: Span::new(start, end), } } } impl From<(usize, usize, AnchorLocation)> for Tag { fn from((start, end, anchor): (usize, usize, AnchorLocation)) -> Self { Tag { anchor: Some(anchor), span: Span::new(start, end), } } } impl From<(usize, usize, Option)> for Tag { fn from((start, end, anchor): (usize, usize, Option)) -> Self { Tag { anchor, span: Span::new(start, end), } } } impl From> for Tag { fn from(input: nom_locate::LocatedSpanEx<&str, TracableContext>) -> Tag { Tag { anchor: None, span: Span::new(input.offset, input.offset + input.fragment.len()), } } } impl From for Span { fn from(tag: Tag) -> Self { tag.span } } impl From<&Tag> for Span { fn from(tag: &Tag) -> Self { tag.span } } impl Tag { pub fn unknown_anchor(span: Span) -> Tag { Tag { anchor: None, span } } pub fn for_char(pos: usize, anchor: AnchorLocation) -> Tag { Tag { anchor: Some(anchor), span: Span { start: pos, end: pos + 1, }, } } pub fn unknown_span(anchor: AnchorLocation) -> Tag { Tag { anchor: Some(anchor), span: Span::unknown(), } } pub fn unknown() -> Tag { Tag { anchor: None, span: Span::unknown(), } } pub fn until(&self, other: impl Into) -> Tag { let other = other.into(); debug_assert!( self.anchor == other.anchor, "Can only merge two tags with the same anchor" ); Tag { span: Span::new(self.span.start, other.span.end), anchor: self.anchor.clone(), } } pub fn until_option(&self, other: Option>) -> Tag { match other { Some(other) => { let other = other.into(); debug_assert!( self.anchor == other.anchor, "Can only merge two tags with the same anchor" ); Tag { span: Span::new(self.span.start, other.span.end), anchor: self.anchor.clone(), } } None => self.clone(), } } pub fn slice<'a>(&self, source: &'a str) -> &'a str { self.span.slice(source) } pub fn string<'a>(&self, source: &'a str) -> String { self.span.slice(source).to_string() } pub fn tagged_slice<'a>(&self, source: &'a str) -> Tagged<&'a str> { self.span.slice(source).tagged(self) } pub fn tagged_string<'a>(&self, source: &'a str) -> Tagged { self.span.slice(source).to_string().tagged(self) } } #[allow(unused)] pub fn tag_for_tagged_list(mut iter: impl Iterator) -> Tag { let first = iter.next(); let first = match first { None => return Tag::unknown(), Some(first) => first, }; let last = iter.last(); match last { None => first, Some(last) => first.until(last), } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Hash)] pub struct Span { start: usize, end: usize, } impl From> for Span { fn from(input: Option) -> Span { match input { None => Span::new(0, 0), Some(span) => span, } } } impl Span { pub fn unknown() -> Span { Span::new(0, 0) } pub fn new(start: usize, end: usize) -> Span { assert!( end >= start, "Can't create a Span whose end < start, start={}, end={}", start, end ); Span { start, end } } pub fn for_char(pos: usize) -> Span { Span { start: pos, end: pos + 1, } } pub fn until(&self, other: impl Into) -> Span { let other = other.into(); Span::new(self.start, other.end) } pub fn until_option(&self, other: Option>) -> Span { match other { Some(other) => { let other = other.into(); Span::new(self.start, other.end) } None => *self, } } pub fn string<'a>(&self, source: &'a str) -> String { self.slice(source).to_string() } pub fn spanned_slice<'a>(&self, source: &'a str) -> Spanned<&'a str> { self.slice(source).spanned(*self) } pub fn spanned_string<'a>(&self, source: &'a str) -> Spanned { self.slice(source).to_string().spanned(*self) } /* pub fn unknown_with_uuid(uuid: Uuid) -> Span { Span { start: 0, end: 0, source: Some(uuid), } } */ pub fn start(&self) -> usize { self.start } pub fn end(&self) -> usize { self.end } pub fn is_unknown(&self) -> bool { self.start == 0 && self.end == 0 } pub fn slice<'a>(&self, source: &'a str) -> &'a str { &source[self.start..self.end] } } impl language_reporting::ReportingSpan for Span { fn with_start(&self, start: usize) -> Self { Span::new(start, self.end) } fn with_end(&self, end: usize) -> Self { Span::new(self.start, end) } fn start(&self) -> usize { self.start } fn end(&self) -> usize { self.end } } pub trait HasSpan: ToDebug { fn span(&self) -> Span; } pub trait HasFallibleSpan: ToDebug { fn maybe_span(&self) -> Option; } impl HasFallibleSpan for T { fn maybe_span(&self) -> Option { Some(HasSpan::span(self)) } } impl HasSpan for Spanned where Spanned: ToDebug, { fn span(&self) -> Span { self.span } } impl HasFallibleSpan for Option { fn maybe_span(&self) -> Option { *self } } impl FormatDebug for Option { fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { match self { Option::None => write!(f, "no span"), Option::Some(span) => FormatDebug::fmt_debug(span, f, source), } } } impl FormatDebug for Span { fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { write!(f, "{:?}", self.slice(source)) } } impl HasSpan for Span { fn span(&self) -> Span { *self } } impl FormatDebug for Option> where Spanned: ToDebug, { fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { match self { Option::None => write!(f, "nothing"), Option::Some(spanned) => FormatDebug::fmt_debug(spanned, f, source), } } } impl HasFallibleSpan for Option> where Spanned: ToDebug, { fn maybe_span(&self) -> Option { match self { None => None, Some(value) => Some(value.span), } } } impl FormatDebug for Option> where Tagged: ToDebug, { fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { match self { Option::None => write!(f, "nothing"), Option::Some(item) => FormatDebug::fmt_debug(item, f, source), } } } impl HasFallibleSpan for Option> where Tagged: ToDebug, { fn maybe_span(&self) -> Option { match self { None => None, Some(value) => Some(value.tag.span), } } } impl HasSpan for Tagged where Tagged: ToDebug, { fn span(&self) -> Span { self.tag.span } } impl FormatDebug for Vec { fn fmt_debug(&self, f: &mut DebugFormatter, source: &str) -> fmt::Result { write!(f, "[ ")?; write!( f, "{}", self.iter().map(|item| item.debug(source)).join(" ") )?; write!(f, " ]") } } impl FormatDebug for String { fn fmt_debug(&self, f: &mut DebugFormatter, _source: &str) -> fmt::Result { write!(f, "{}", self) } } impl FormatDebug for Spanned { fn fmt_debug(&self, f: &mut DebugFormatter, _source: &str) -> fmt::Result { write!(f, "{}", self.item) } }