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}