1use std::{
8 fmt,
9 ops::{Deref, DerefMut},
10};
11
12pub use logos::Span;
13
14#[derive(Debug, Clone)]
15pub struct Loc<T> {
16 pub inner: T,
17 pub span: Span,
18}
19
20impl<T> Loc<T> {
21 pub fn new(inner: T, span: Span) -> Self {
22 Self { inner, span }
23 }
24
25 pub fn without_inner(&self) -> Loc<()> {
26 Loc::new((), self.span.clone())
27 }
28
29 pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Loc<U> {
30 Loc::new(f(self.inner), self.span)
31 }
32}
33
34impl<T> Deref for Loc<T> {
35 type Target = T;
36
37 fn deref(&self) -> &Self::Target {
38 &self.inner
39 }
40}
41
42impl<T> DerefMut for Loc<T> {
43 fn deref_mut(&mut self) -> &mut Self::Target {
44 &mut self.inner
45 }
46}
47
48impl<T: fmt::Display> fmt::Display for Loc<T> {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 self.inner.fmt(f)
51 }
52}
53
54pub trait Spanned {
55 fn span(&self) -> Span;
56}
57
58impl Spanned for Span {
59 fn span(&self) -> Span {
60 self.clone()
61 }
62}
63
64impl Spanned for &Span {
65 fn span(&self) -> Span {
66 (*self).clone()
67 }
68}
69
70impl<T> Spanned for Loc<T> {
71 fn span(&self) -> Span {
72 self.span.clone()
73 }
74}
75
76impl<T> Spanned for &Loc<T> {
77 fn span(&self) -> Span {
78 self.span.clone()
79 }
80}
81
82pub trait WithLocation {
83 fn at(self, spanned: impl Spanned) -> Loc<Self>
84 where
85 Self: Sized,
86 {
87 Loc::new(self, spanned.span())
88 }
89
90 fn between(self, start: impl Spanned, end: impl Spanned) -> Loc<Self>
91 where
92 Self: Sized,
93 {
94 Loc::new(self, start.span().start..end.span().end)
95 }
96}
97
98impl<T> WithLocation for T {}
99
100pub trait MaybeSpanned {
101 fn try_span(&self) -> Option<Span>;
102}
103
104impl<T: Spanned> MaybeSpanned for T {
105 fn try_span(&self) -> Option<Span> {
106 Some(self.span())
107 }
108}
109
110impl<T: Spanned> MaybeSpanned for Vec<T> {
111 fn try_span(&self) -> Option<Span> {
112 if self.is_empty() {
113 None
114 } else {
115 Some(self.first().unwrap().span().start..self.last().unwrap().span().end)
116 }
117 }
118}
119
120impl<T: Spanned> MaybeSpanned for Option<T> {
121 fn try_span(&self) -> Option<Span> {
122 self.as_ref().map(|inner| inner.span())
123 }
124}