bril_frontend/
loc.rs

1// Copyright (C) 2024 Ethan Uppal.
2//
3// This Source Code Form is subject to the terms of the Mozilla Public License,
4// v. 2.0. If a copy of the MPL was not distributed with this file, You can
5// obtain one at https://mozilla.org/MPL/2.0/.
6
7use std::{
8    fmt,
9    ops::{Deref, DerefMut},
10};
11
12pub use logos::Span;
13
14#[derive(Debug, Clone)]
15pub struct Loc<T> {
16    pub inner: T,
17    pub span: Span,
18}
19
20impl<T> Loc<T> {
21    pub fn new(inner: T, span: Span) -> Self {
22        Self { inner, span }
23    }
24
25    pub fn without_inner(&self) -> Loc<()> {
26        Loc::new((), self.span.clone())
27    }
28
29    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Loc<U> {
30        Loc::new(f(self.inner), self.span)
31    }
32}
33
34impl<T> Deref for Loc<T> {
35    type Target = T;
36
37    fn deref(&self) -> &Self::Target {
38        &self.inner
39    }
40}
41
42impl<T> DerefMut for Loc<T> {
43    fn deref_mut(&mut self) -> &mut Self::Target {
44        &mut self.inner
45    }
46}
47
48impl<T: fmt::Display> fmt::Display for Loc<T> {
49    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50        self.inner.fmt(f)
51    }
52}
53
54pub trait Spanned {
55    fn span(&self) -> Span;
56}
57
58impl Spanned for Span {
59    fn span(&self) -> Span {
60        self.clone()
61    }
62}
63
64impl Spanned for &Span {
65    fn span(&self) -> Span {
66        (*self).clone()
67    }
68}
69
70impl<T> Spanned for Loc<T> {
71    fn span(&self) -> Span {
72        self.span.clone()
73    }
74}
75
76impl<T> Spanned for &Loc<T> {
77    fn span(&self) -> Span {
78        self.span.clone()
79    }
80}
81
82pub trait WithLocation {
83    fn at(self, spanned: impl Spanned) -> Loc<Self>
84    where
85        Self: Sized,
86    {
87        Loc::new(self, spanned.span())
88    }
89
90    fn between(self, start: impl Spanned, end: impl Spanned) -> Loc<Self>
91    where
92        Self: Sized,
93    {
94        Loc::new(self, start.span().start..end.span().end)
95    }
96}
97
98impl<T> WithLocation for T {}
99
100pub trait MaybeSpanned {
101    fn try_span(&self) -> Option<Span>;
102}
103
104impl<T: Spanned> MaybeSpanned for T {
105    fn try_span(&self) -> Option<Span> {
106        Some(self.span())
107    }
108}
109
110impl<T: Spanned> MaybeSpanned for Vec<T> {
111    fn try_span(&self) -> Option<Span> {
112        if self.is_empty() {
113            None
114        } else {
115            Some(self.first().unwrap().span().start..self.last().unwrap().span().end)
116        }
117    }
118}
119
120impl<T: Spanned> MaybeSpanned for Option<T> {
121    fn try_span(&self) -> Option<Span> {
122        self.as_ref().map(|inner| inner.span())
123    }
124}