lwb_parser/sources/
span.rs

1use crate::sources::source_file::SourceFile;
2use miette::{MietteError, SourceCode, SourceSpan, SpanContents};
3use serde::{Deserialize, Serialize};
4use std::fmt::{Debug, Formatter};
5
6/// Represents a certain range of a file. This is useful for marking the locations that certain tokens or errors occur.
7/// The position and length are both in BYTES. The byte offsets provided should be valid.
8#[derive(Clone, Serialize, Deserialize)]
9pub struct Span {
10    pub position: usize,
11    pub length: usize,
12    pub source: SourceFile,
13}
14
15impl Debug for Span {
16    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
17        f.debug_struct("Span")
18            .field("position", &self.position)
19            .field("length", &self.length)
20            .finish()
21    }
22}
23
24impl Span {
25    /// Creates a new span, given a file, starting position and the length that the span should be.
26    pub fn from_length(source: &SourceFile, position: usize, length: usize) -> Self {
27        Self {
28            source: source.clone(),
29            position,
30            length,
31        }
32    }
33
34    /// Creates a new span, given a file, starting position and end position.
35    pub fn from_end(source: &SourceFile, position: usize, end: usize) -> Self {
36        assert!(end >= position);
37        Self {
38            source: source.clone(),
39            position,
40            length: end - position,
41        }
42    }
43
44    pub fn end(&self) -> usize {
45        self.position + self.length
46    }
47
48    /// Get a string from the source file, described by this span.
49    /// ```
50    /// // TODO
51    /// ```
52    pub fn as_str(&self) -> &str {
53        &self.source.contents()[self.position..self.position + self.length]
54    }
55
56    /// Merge two spans.
57    pub fn merge(&self, other: &Span) -> Self {
58        // TODO: add unique ids to source files to make this comparison
59        // assert!(self.source == other.source)
60
61        Self::from_end(
62            &self.source,
63            self.position.min(other.position),
64            self.end().max(other.end()),
65        )
66    }
67}
68
69impl SourceCode for Span {
70    fn read_span<'a>(
71        &'a self,
72        span: &SourceSpan,
73        context_lines_before: usize,
74        context_lines_after: usize,
75    ) -> Result<Box<dyn SpanContents<'a> + 'a>, MietteError> {
76        <str as SourceCode>::read_span(
77            self.source.contents_for_display(),
78            span,
79            context_lines_before,
80            context_lines_after,
81        )
82    }
83}
84
85impl From<Span> for SourceSpan {
86    fn from(span: Span) -> Self {
87        SourceSpan::from((span.position, span.length))
88    }
89}