Skip to main content

cl_structures/
span.rs

1//! - [struct@Span]: Stores the start and end position of a notable AST node
2#![allow(non_snake_case)]
3use std::ops::Range;
4
5use crate::intern::interned::Symbol;
6
7/// Stores the start and end byte position
8#[derive(Clone, Copy, PartialEq, Eq, Hash)]
9pub struct Span {
10    pub path: Symbol,
11    pub head: u32,
12    pub tail: u32,
13}
14
15impl std::fmt::Debug for Span {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        let Self { path, head, tail } = self;
18        match path.0 {
19            "" => write!(f, "[{head}:{tail}]"),
20            _ => write!(f, "[{path}:{head}:{tail}]"),
21        }
22    }
23}
24
25#[expect(non_snake_case)]
26/// Stores the start and end byte position
27pub const fn Span(path: Symbol, head: u32, tail: u32) -> Span {
28    Span { path, head, tail }
29}
30
31impl Span {
32    /// Computes the [struct@Span] containing both `self` and `other`
33    pub fn merge(self, other: Span) -> Span {
34        if !(self.path.is_empty() || other.path.is_empty()) {
35            assert_eq!(self.path, other.path, "Attempted to merge unrelated paths!")
36        }
37        Span { path: self.path, head: self.head.min(other.head), tail: self.tail.max(other.tail) }
38    }
39}
40
41impl From<Span> for Range<usize> {
42    fn from(value: Span) -> Self {
43        let Span { path: _, head, tail } = value;
44        (head as usize)..(tail as usize)
45    }
46}
47
48impl std::fmt::Display for Span {
49    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        let Self { path, head, tail } = self;
51        match path.0 {
52            "" => write!(f, "{head}:{tail}"),
53            _ => write!(f, "{path}:{head}:{tail}"),
54        }
55    }
56}