leo_span/
span.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17//! Defines the `Span` type used to track where code comes from.
18
19use serde::{Deserialize, Serialize};
20use std::fmt;
21
22use crate::symbol::with_session_globals;
23
24/// The span type which tracks where formatted errors originate from in a Leo file.
25/// This is used in many spots throughout the rest of the Leo crates.
26#[derive(Copy, Clone, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
27pub struct Span {
28    /// The start (low) position of the span, inclusive.
29    pub lo: u32,
30    /// The end (high) position of the span, exclusive.
31    /// The length of the span is `hi - lo`.
32    pub hi: u32,
33}
34
35impl Span {
36    /// Generate a new span from the `start`ing and `end`ing positions.
37    pub fn new(start: u32, end: u32) -> Self {
38        Self { lo: start, hi: end }
39    }
40
41    /// Generates a dummy span with all defaults.
42    /// Should only be used in temporary situations.
43    pub const fn dummy() -> Self {
44        Self { lo: 0, hi: 0 }
45    }
46
47    /// Is the span a dummy?
48    pub fn is_dummy(&self) -> bool {
49        self == &Self::dummy()
50    }
51}
52
53impl fmt::Display for Span {
54    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55        with_session_globals(|s| {
56            let source_file = s.source_map.find_source_file(self.lo).unwrap();
57            let (start_line, start_col) = source_file.line_col(self.lo);
58            let (end_line, end_col) = source_file.line_col(self.hi);
59            if start_line == end_line {
60                write!(f, "{}:{}-{}", start_line + 1, start_col + 1, end_col + 1)
61            } else {
62                write!(f, "{}:{}-{}:{}", start_line + 1, start_col + 1, end_line + 1, end_col + 1)
63            }
64        })
65    }
66}
67
68impl std::ops::Add for &Span {
69    type Output = Span;
70
71    /// Add two spans (by reference) together.
72    fn add(self, other: &Span) -> Span {
73        *self + *other
74    }
75}
76
77impl std::ops::Add for Span {
78    type Output = Self;
79
80    /// Add two spans together.
81    /// The resulting span is the smallest span that includes both.
82    fn add(self, other: Self) -> Self {
83        let lo = self.lo.min(other.lo);
84        let hi = self.hi.max(other.hi);
85        Self::new(lo, hi)
86    }
87}