Skip to main content

elm_ast/
span.rs

1/// A position in source code (byte offset + line/column).
2#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
3#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
4pub struct Position {
5    /// Byte offset from the start of the source.
6    pub offset: usize,
7    /// 1-based line number.
8    pub line: u32,
9    /// 1-based column number (in UTF-8 bytes).
10    pub column: u32,
11}
12
13/// A span in source code, defined by a start and end position.
14///
15/// Spans are half-open: they include the start position and exclude the end.
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
18pub struct Span {
19    pub start: Position,
20    pub end: Position,
21}
22
23impl Span {
24    /// Create a new span from start and end positions.
25    pub fn new(start: Position, end: Position) -> Self {
26        Self { start, end }
27    }
28
29    /// Create a dummy span for synthesized nodes (not from source).
30    pub fn dummy() -> Self {
31        let pos = Position {
32            offset: 0,
33            line: 0,
34            column: 0,
35        };
36        Self {
37            start: pos,
38            end: pos,
39        }
40    }
41
42    /// Merge two spans into one that covers both.
43    pub fn merge(self, other: Span) -> Span {
44        let start = if self.start.offset <= other.start.offset {
45            self.start
46        } else {
47            other.start
48        };
49        let end = if self.end.offset >= other.end.offset {
50            self.end
51        } else {
52            other.end
53        };
54        Span { start, end }
55    }
56}