Skip to main content

litcheck_core/diagnostics/
span.rs

1use core::{
2    borrow::Borrow,
3    fmt,
4    hash::{Hash, Hasher},
5    ops::{Bound, Deref, DerefMut, Index, RangeBounds},
6};
7
8use serde::{Deserialize, Serialize};
9
10use crate::range::Range;
11
12use super::{ByteIndex, ByteOffset, SourceId};
13
14/// This trait should be implemented for any type that has an associated [SourceSpan].
15pub trait Spanned {
16    fn span(&self) -> SourceSpan;
17}
18
19impl Spanned for SourceSpan {
20    #[inline(always)]
21    fn span(&self) -> SourceSpan {
22        *self
23    }
24}
25
26impl<T: ?Sized + Spanned> Spanned for &T {
27    fn span(&self) -> SourceSpan {
28        (**self).span()
29    }
30}
31
32impl<T: ?Sized + Spanned> Spanned for Box<T> {
33    fn span(&self) -> SourceSpan {
34        (**self).span()
35    }
36}
37
38impl<T: ?Sized + Spanned> Spanned for std::rc::Rc<T> {
39    fn span(&self) -> SourceSpan {
40        (**self).span()
41    }
42}
43
44impl<T: ?Sized + Spanned> Spanned for std::sync::Arc<T> {
45    fn span(&self) -> SourceSpan {
46        (**self).span()
47    }
48}
49
50// SPAN
51// ================================================================================================
52
53/// This type is used to wrap any `T` with a [SourceSpan], and is typically used when it is not
54/// convenient to add a [SourceSpan] to the type - most commonly because we don't control the type.
55pub struct Span<T> {
56    span: SourceSpan,
57    spanned: T,
58}
59
60impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for Span<T> {
61    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
62    where
63        D: serde::Deserializer<'de>,
64    {
65        let spanned = T::deserialize(deserializer)?;
66        Ok(Self {
67            span: SourceSpan::UNKNOWN,
68            spanned,
69        })
70    }
71}
72
73impl<T: serde::Serialize> serde::Serialize for Span<T> {
74    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75    where
76        S: serde::Serializer,
77    {
78        T::serialize(&self.spanned, serializer)
79    }
80}
81
82impl<T> Spanned for Span<T> {
83    fn span(&self) -> SourceSpan {
84        self.span
85    }
86}
87
88impl<T: Copy> Copy for Span<T> {}
89
90impl<T: Clone> Clone for Span<T> {
91    fn clone(&self) -> Self {
92        Self {
93            span: self.span,
94            spanned: self.spanned.clone(),
95        }
96    }
97}
98
99impl<T: Default> Default for Span<T> {
100    fn default() -> Self {
101        Self {
102            span: SourceSpan::UNKNOWN,
103            spanned: T::default(),
104        }
105    }
106}
107
108impl<T> Span<T> {
109    /// Creates a span for `spanned` with `span`.
110    #[inline]
111    pub fn new(span: SourceSpan, spanned: T) -> Self {
112        Self { span, spanned }
113    }
114
115    /// Creates a span for `spanned` representing a single location, `offset`.
116    #[inline]
117    pub fn at(source_id: SourceId, offset: usize, spanned: T) -> Self {
118        let offset = u32::try_from(offset).expect("invalid source offset: too large");
119        Self {
120            span: SourceSpan::at(source_id, offset),
121            spanned,
122        }
123    }
124
125    /// Creates a [Span] from a value with an unknown/default location.
126    pub fn unknown(spanned: T) -> Self {
127        Self {
128            span: Default::default(),
129            spanned,
130        }
131    }
132
133    /// Consume this [Span] and get a new one with `span` as the underlying source span
134    #[inline]
135    pub fn with_span(mut self, span: SourceSpan) -> Self {
136        self.span = span;
137        self
138    }
139
140    /// Gets the associated [SourceSpan] for this spanned item.
141    #[inline(always)]
142    pub const fn span(&self) -> SourceSpan {
143        self.span
144    }
145
146    /// Gets a reference to the spanned item.
147    #[inline(always)]
148    pub const fn inner(&self) -> &T {
149        &self.spanned
150    }
151
152    /// Applies a transformation to the spanned value while retaining the same [SourceSpan].
153    #[inline]
154    pub fn map<U, F>(self, mut f: F) -> Span<U>
155    where
156        F: FnMut(T) -> U,
157    {
158        Span {
159            span: self.span,
160            spanned: f(self.spanned),
161        }
162    }
163
164    /// Like [`Option<T>::as_deref`], this constructs a [`Span<U>`] wrapping the result of
165    /// dereferencing the inner value of type `T` as a value of type `U`.
166    pub fn as_deref<U>(&self) -> Span<&U>
167    where
168        U: ?Sized,
169        T: Deref<Target = U>,
170    {
171        Span {
172            span: self.span,
173            spanned: self.spanned.deref(),
174        }
175    }
176
177    /// Gets a new [Span] that borrows the inner value.
178    pub fn as_ref(&self) -> Span<&T> {
179        Span {
180            span: self.span,
181            spanned: &self.spanned,
182        }
183    }
184
185    /// Manually set the source id for the span of this item
186    ///
187    /// See also [SourceSpan::set_source_id].
188    pub fn set_source_id(&mut self, id: SourceId) {
189        self.span.set_source_id(id);
190    }
191
192    /// Shifts the span right by `count` units
193    #[inline]
194    pub fn shift(&mut self, count: ByteOffset) {
195        self.span.start += count;
196        self.span.end += count;
197    }
198
199    /// Extends the end of the span by `count` units.
200    #[inline]
201    pub fn extend(&mut self, count: ByteOffset) {
202        self.span.end += count;
203    }
204
205    /// Consumes this span, returning the component parts, i.e. the [SourceSpan] and value of type
206    /// `T`.
207    #[inline]
208    pub fn into_parts(self) -> (SourceSpan, T) {
209        (self.span, self.spanned)
210    }
211
212    /// Unwraps the spanned value of type `T`.
213    #[inline]
214    pub fn into_inner(self) -> T {
215        self.spanned
216    }
217}
218
219impl<T> Borrow<T> for Span<T> {
220    fn borrow(&self) -> &T {
221        &self.spanned
222    }
223}
224
225impl<T: Borrow<str>> Borrow<str> for Span<T> {
226    fn borrow(&self) -> &str {
227        self.spanned.borrow()
228    }
229}
230
231impl<U, T: Borrow<[U]>> Borrow<[U]> for Span<T> {
232    fn borrow(&self) -> &[U] {
233        self.spanned.borrow()
234    }
235}
236
237impl<T> Deref for Span<T> {
238    type Target = T;
239
240    #[inline(always)]
241    fn deref(&self) -> &Self::Target {
242        &self.spanned
243    }
244}
245
246impl<T> DerefMut for Span<T> {
247    #[inline(always)]
248    fn deref_mut(&mut self) -> &mut Self::Target {
249        &mut self.spanned
250    }
251}
252
253impl<T: ?Sized, U: AsRef<T>> AsRef<T> for Span<U> {
254    fn as_ref(&self) -> &T {
255        self.spanned.as_ref()
256    }
257}
258
259impl<T: ?Sized, U: AsMut<T>> AsMut<T> for Span<U> {
260    fn as_mut(&mut self) -> &mut T {
261        self.spanned.as_mut()
262    }
263}
264
265impl<T: fmt::Debug> fmt::Debug for Span<T> {
266    #[inline]
267    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268        fmt::Debug::fmt(&self.spanned, f)
269    }
270}
271
272impl<T: fmt::Display> fmt::Display for Span<T> {
273    #[inline]
274    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
275        fmt::Display::fmt(&self.spanned, f)
276    }
277}
278
279impl<T: Eq> Eq for Span<T> {}
280
281impl<T: PartialEq> PartialEq for Span<T> {
282    #[inline]
283    fn eq(&self, other: &Self) -> bool {
284        self.spanned.eq(&other.spanned)
285    }
286}
287
288impl<T: PartialEq> PartialEq<T> for Span<T> {
289    #[inline]
290    fn eq(&self, other: &T) -> bool {
291        self.spanned.eq(other)
292    }
293}
294
295impl<T: Ord> Ord for Span<T> {
296    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
297        self.spanned.cmp(&other.spanned)
298    }
299}
300
301impl<T: PartialOrd> PartialOrd for Span<T> {
302    #[inline]
303    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
304        self.spanned.partial_cmp(&other.spanned)
305    }
306}
307
308impl<T: Hash> Hash for Span<T> {
309    fn hash<H: Hasher>(&self, state: &mut H) {
310        self.spanned.hash(state);
311    }
312}
313
314// SOURCE SPAN
315// ================================================================================================
316
317/// This represents a span of bytes in a Miden Assembly source file.
318///
319/// It is compact, using only 8 bytes to represent the full span. This does, however, come at the
320/// tradeoff of only supporting source files of up to 2^32 bytes.
321///
322/// This type is produced by the lexer and carried through parsing. It can be converted into a
323/// line/column range as well, if needed.
324///
325/// This representation is more convenient to produce, and allows showing source spans in error
326/// messages, whereas line/column information is useful at a glance in debug output, it is harder
327/// to produce nice errors with it compared to this representation.
328#[derive(
329    Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
330)]
331pub struct SourceSpan {
332    #[serde(default, skip_serializing_if = "SourceId::is_unknown")]
333    source_id: SourceId,
334    start: ByteIndex,
335    end: ByteIndex,
336}
337
338#[derive(Debug, thiserror::Error)]
339#[error("invalid byte index range: maximum supported byte index is 2^32")]
340pub struct InvalidByteIndexRange;
341
342impl SourceSpan {
343    /// A sentinel [SourceSpan] that indicates the span is unknown/invalid
344    pub const UNKNOWN: Self = Self {
345        source_id: SourceId::UNKNOWN,
346        start: ByteIndex::new(0),
347        end: ByteIndex::new(0),
348    };
349
350    /// Creates a new [SourceSpan] from the given range.
351    pub fn new<B>(source_id: SourceId, range: Range<B>) -> Self
352    where
353        B: Into<ByteIndex>,
354    {
355        Self {
356            source_id,
357            start: range.start.into(),
358            end: range.end.into(),
359        }
360    }
361
362    /// Creates a new [SourceSpan] for a specific offset.
363    pub fn at(source_id: SourceId, offset: impl Into<ByteIndex>) -> Self {
364        let offset = offset.into();
365        Self {
366            source_id,
367            start: offset,
368            end: offset,
369        }
370    }
371
372    /// Try to create a new [SourceSpan] from the given range with `usize` bounds.
373    pub fn try_from_range(
374        source_id: SourceId,
375        range: core::ops::Range<usize>,
376    ) -> Result<Self, InvalidByteIndexRange> {
377        const MAX: usize = u32::MAX as usize;
378        if range.start > MAX || range.end > MAX {
379            return Err(InvalidByteIndexRange);
380        }
381
382        Ok(SourceSpan::from_range_unchecked(source_id, range))
383    }
384
385    /// Create a new [SourceSpan] from the given range with `usize` bounds, truncating the bounds
386    /// if they are not valid u32 values.
387    #[inline]
388    pub fn from_range_unchecked(source_id: SourceId, range: core::ops::Range<usize>) -> Self {
389        SourceSpan {
390            source_id,
391            start: ByteIndex::from(range.start as u32),
392            end: ByteIndex::from(range.end as u32),
393        }
394    }
395
396    /// Returns `true` if this [SourceSpan] represents the unknown span
397    pub const fn is_unknown(&self) -> bool {
398        self.source_id.is_unknown()
399    }
400
401    /// Get the [SourceId] associated with this source span
402    #[inline(always)]
403    pub fn source_id(&self) -> SourceId {
404        self.source_id
405    }
406
407    /// Manually set the [SourceId] associated with this source span
408    ///
409    /// This is useful in cases where the range of the span is known, but the source id itself
410    /// is not available yet, due to scope or some other limitation. In such cases you might wish
411    /// to visit parsed objects once the source id is available, and update all of their spans
412    /// accordingly.
413    pub fn set_source_id(&mut self, id: SourceId) {
414        self.source_id = id;
415    }
416
417    /// Gets the offset in bytes corresponding to the start of this span (inclusive).
418    #[inline(always)]
419    pub fn start(&self) -> ByteIndex {
420        self.start
421    }
422
423    /// Gets the offset in bytes corresponding to the end of this span (exclusive).
424    #[inline(always)]
425    pub fn end(&self) -> ByteIndex {
426        self.end
427    }
428
429    /// Gets the length of this span in bytes.
430    #[inline(always)]
431    pub fn len(&self) -> usize {
432        self.end.to_usize() - self.start.to_usize()
433    }
434
435    /// Returns true if this span is empty.
436    pub fn is_empty(&self) -> bool {
437        self.len() == 0
438    }
439
440    /// Converts this span into a [`Range<u32>`].
441    #[inline]
442    pub fn into_range(self) -> Range<u32> {
443        Range::new(self.start.to_u32(), self.end.to_u32())
444    }
445
446    /// Converts this span into a [`Range<usize>`].
447    #[inline]
448    pub fn into_slice_index(self) -> Range<usize> {
449        Range::new(self.start.to_usize(), self.end.to_usize())
450    }
451}
452
453impl From<SourceSpan> for miette::SourceSpan {
454    fn from(span: SourceSpan) -> Self {
455        Self::new(
456            miette::SourceOffset::from(span.start().to_usize()),
457            span.len(),
458        )
459    }
460}
461
462impl From<SourceSpan> for Range<u32> {
463    #[inline(always)]
464    fn from(span: SourceSpan) -> Self {
465        span.into_range()
466    }
467}
468
469impl From<SourceSpan> for Range<usize> {
470    #[inline(always)]
471    fn from(span: SourceSpan) -> Self {
472        span.into_slice_index()
473    }
474}
475
476impl From<SourceSpan> for core::ops::Range<u32> {
477    fn from(value: SourceSpan) -> Self {
478        value.start.to_u32()..value.end.to_u32()
479    }
480}
481
482impl From<SourceSpan> for core::ops::Range<usize> {
483    fn from(value: SourceSpan) -> Self {
484        value.start.to_usize()..value.end.to_usize()
485    }
486}
487
488impl Index<SourceSpan> for [u8] {
489    type Output = [u8];
490
491    #[inline]
492    fn index(&self, index: SourceSpan) -> &Self::Output {
493        &self[index.start().to_usize()..index.end().to_usize()]
494    }
495}
496
497impl RangeBounds<ByteIndex> for SourceSpan {
498    #[inline(always)]
499    fn start_bound(&self) -> Bound<&ByteIndex> {
500        Bound::Included(&self.start)
501    }
502
503    #[inline(always)]
504    fn end_bound(&self) -> Bound<&ByteIndex> {
505        Bound::Excluded(&self.end)
506    }
507}