1use nom::Slice;
4
5use crate::{
6 alloc::{format, String, ToOwned},
7 Error,
8};
9
10pub type InputSpan<'a> = nom_locate::LocatedSpan<&'a str, ()>;
12pub type NomResult<'a, T> = nom::IResult<InputSpan<'a>, T, Error<'a>>;
14
15#[derive(Debug, Clone, Copy)]
25pub struct LocatedSpan<Span, T = ()> {
26 offset: usize,
27 line: u32,
28 column: usize,
29 fragment: Span,
30
31 pub extra: T,
33}
34
35impl<Span: PartialEq, T> PartialEq for LocatedSpan<Span, T> {
36 fn eq(&self, other: &Self) -> bool {
37 self.line == other.line && self.offset == other.offset && self.fragment == other.fragment
38 }
39}
40
41impl<Span, T> LocatedSpan<Span, T> {
42 pub fn location_offset(&self) -> usize {
45 self.offset
46 }
47
48 pub fn location_line(&self) -> u32 {
50 self.line
51 }
52
53 pub fn get_column(&self) -> usize {
55 self.column
56 }
57
58 pub fn fragment(&self) -> &Span {
60 &self.fragment
61 }
62
63 pub fn map_extra<U>(self, map_fn: impl FnOnce(T) -> U) -> LocatedSpan<Span, U> {
65 LocatedSpan {
66 offset: self.offset,
67 line: self.line,
68 column: self.column,
69 fragment: self.fragment,
70 extra: map_fn(self.extra),
71 }
72 }
73
74 pub fn map_fragment<U>(self, map_fn: impl FnOnce(Span) -> U) -> LocatedSpan<U, T> {
76 LocatedSpan {
77 offset: self.offset,
78 line: self.line,
79 column: self.column,
80 fragment: map_fn(self.fragment),
81 extra: self.extra,
82 }
83 }
84}
85
86impl<Span: Copy, T> LocatedSpan<Span, T> {
87 pub fn as_ref(&self) -> LocatedSpan<Span, &T> {
89 LocatedSpan {
90 offset: self.offset,
91 line: self.line,
92 column: self.column,
93 fragment: self.fragment,
94 extra: &self.extra,
95 }
96 }
97
98 pub fn copy_with_extra<U>(&self, value: U) -> LocatedSpan<Span, U> {
100 LocatedSpan {
101 offset: self.offset,
102 line: self.line,
103 column: self.column,
104 fragment: self.fragment,
105 extra: value,
106 }
107 }
108
109 pub fn with_no_extra(&self) -> LocatedSpan<Span> {
111 self.copy_with_extra(())
112 }
113}
114
115impl<'a, T> From<nom_locate::LocatedSpan<&'a str, T>> for LocatedSpan<&'a str, T> {
116 fn from(value: nom_locate::LocatedSpan<&'a str, T>) -> Self {
117 Self {
118 offset: value.location_offset(),
119 line: value.location_line(),
120 column: value.get_column(),
121 fragment: *value.fragment(),
122 extra: value.extra,
123 }
124 }
125}
126
127pub type Spanned<'a, T = ()> = LocatedSpan<&'a str, T>;
129
130impl<'a, T> Spanned<'a, T> {
131 pub(crate) fn new(span: InputSpan<'a>, extra: T) -> Self {
132 Self {
133 offset: span.location_offset(),
134 line: span.location_line(),
135 column: span.get_column(),
136 fragment: *span.fragment(),
137 extra,
138 }
139 }
140}
141
142impl<'a> Spanned<'a> {
143 pub fn from_str<R>(code: &'a str, range: R) -> Self
145 where
146 InputSpan<'a>: Slice<R>,
147 {
148 let input = InputSpan::new(code);
149 Self::new(input.slice(range), ())
150 }
151}
152
153#[derive(Debug, Clone, Copy, PartialEq)]
159pub enum CodeFragment<'a> {
160 Str(&'a str),
162 Stripped(usize),
164}
165
166impl PartialEq<&str> for CodeFragment<'_> {
167 fn eq(&self, &other: &&str) -> bool {
168 match self {
169 Self::Str(string) => *string == other,
170 Self::Stripped(_) => false,
171 }
172 }
173}
174
175impl CodeFragment<'_> {
176 pub fn strip(self) -> CodeFragment<'static> {
178 match self {
179 Self::Str(string) => CodeFragment::Stripped(string.len()),
180 Self::Stripped(len) => CodeFragment::Stripped(len),
181 }
182 }
183
184 pub fn len(self) -> usize {
186 match self {
187 Self::Str(string) => string.len(),
188 Self::Stripped(len) => len,
189 }
190 }
191
192 pub fn is_empty(self) -> bool {
194 self.len() == 0
195 }
196}
197
198impl<'a> From<&'a str> for CodeFragment<'a> {
199 fn from(value: &'a str) -> Self {
200 CodeFragment::Str(value)
201 }
202}
203
204pub type MaybeSpanned<'a, T = ()> = LocatedSpan<CodeFragment<'a>, T>;
206
207impl<'a> MaybeSpanned<'a> {
208 pub fn from_str<R>(code: &'a str, range: R) -> Self
210 where
211 InputSpan<'a>: Slice<R>,
212 {
213 Spanned::from_str(code, range).into()
214 }
215}
216
217impl<T> MaybeSpanned<'_, T> {
218 pub fn code_or_location(&self, default_name: &str) -> String {
221 match self.fragment {
222 CodeFragment::Str(code) => code.to_owned(),
223 CodeFragment::Stripped(_) => {
224 format!("{} at {}:{}", default_name, self.line, self.column)
225 }
226 }
227 }
228}
229
230impl<'a, T> From<Spanned<'a, T>> for MaybeSpanned<'a, T> {
231 fn from(value: Spanned<'a, T>) -> Self {
232 value.map_fragment(CodeFragment::from)
233 }
234}
235
236pub trait StripCode {
241 type Stripped: 'static;
243
244 fn strip_code(self) -> Self::Stripped;
246}
247
248impl<T: Clone + 'static> StripCode for MaybeSpanned<'_, T> {
249 type Stripped = MaybeSpanned<'static, T>;
250
251 fn strip_code(self) -> Self::Stripped {
252 self.map_fragment(CodeFragment::strip)
253 }
254}
255
256pub fn with_span<'a, O>(
258 mut parser: impl FnMut(InputSpan<'a>) -> NomResult<'a, O>,
259) -> impl FnMut(InputSpan<'a>) -> NomResult<'a, Spanned<'_, O>> {
260 move |input: InputSpan<'_>| {
261 parser(input).map(|(rest, output)| {
262 let len = rest.location_offset() - input.location_offset();
263 let spanned = Spanned {
264 offset: input.location_offset(),
265 line: input.location_line(),
266 column: input.get_column(),
267 fragment: &input.fragment()[..len],
268 extra: output,
269 };
270 (rest, spanned)
271 })
272 }
273}
274
275pub(crate) fn unite_spans<'a, T, U>(
276 input: InputSpan<'a>,
277 start: &Spanned<'_, T>,
278 end: &Spanned<'_, U>,
279) -> Spanned<'a> {
280 debug_assert!(input.location_offset() <= start.location_offset());
281 debug_assert!(start.location_offset() <= end.location_offset());
282 debug_assert!(
283 input.location_offset() + input.fragment().len()
284 >= end.location_offset() + end.fragment().len()
285 );
286
287 let start_idx = start.location_offset() - input.location_offset();
288 let end_idx = end.location_offset() + end.fragment().len() - input.location_offset();
289 Spanned {
290 offset: start.offset,
291 line: start.line,
292 column: start.column,
293 fragment: &input.fragment()[start_idx..end_idx],
294 extra: (),
295 }
296}
297
298pub trait StripResultExt {
300 type Ok;
302 type StrippedErr: 'static;
304
305 fn strip_err(self) -> Result<Self::Ok, Self::StrippedErr>;
307}
308
309impl<T, E: StripCode> StripResultExt for Result<T, E> {
310 type Ok = T;
311 type StrippedErr = E::Stripped;
312
313 fn strip_err(self) -> Result<T, Self::StrippedErr> {
314 self.map_err(StripCode::strip_code)
315 }
316}