cfgrammar/
span.rs

1#[cfg(feature = "bincode")]
2use bincode::{Decode, Encode};
3use proc_macro2::TokenStream;
4use quote::{quote, ToTokens, TokenStreamExt};
5#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8/// A `Span` records what portion of the user's input something (e.g. a lexeme or production)
9/// references (i.e. the `Span` doesn't hold a reference / copy of the actual input).
10#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
13pub struct Span {
14    start: usize,
15    end: usize,
16}
17
18impl Span {
19    /// Create a new span starting at byte `start` and ending at byte `end`.
20    ///
21    /// # Panics
22    ///
23    /// If `end` is less than `start`.
24    pub fn new(start: usize, end: usize) -> Self {
25        if end < start {
26            panic!("Span starts ({}) after it ends ({})!", start, end);
27        }
28        Span { start, end }
29    }
30
31    /// Byte offset of the start of the span.
32    pub fn start(&self) -> usize {
33        self.start
34    }
35
36    /// Byte offset of the end of the span.
37    pub fn end(&self) -> usize {
38        self.end
39    }
40
41    /// Length in bytes of the span.
42    pub fn len(&self) -> usize {
43        self.end - self.start
44    }
45
46    /// Returns `true` if this `Span` covers 0 bytes, or `false` otherwise.
47    pub fn is_empty(&self) -> bool {
48        self.len() == 0
49    }
50}
51
52/// Implemented for errors and warnings to provide access to their spans.
53pub trait Spanned: std::fmt::Display {
54    /// Returns the spans associated with the error, always containing at least 1 span.
55    ///
56    /// Refer to [SpansKind](crate::yacc::parser::SpansKind) via [spanskind](Self::spanskind)
57    /// for the meaning and interpretation of spans and their ordering.
58    fn spans(&self) -> &[Span];
59    /// Returns the `SpansKind` associated with this error.
60    fn spanskind(&self) -> crate::yacc::parser::SpansKind;
61}
62
63impl ToTokens for Span {
64    fn to_tokens(&self, tokens: &mut TokenStream) {
65        let Span { start, end } = self;
66        tokens.append_all(quote! {::cfgrammar::Span::new(#start, #end)});
67    }
68}
69
70/// A possibly inexact location which could either be a `Span`,
71/// a command-line option, or some other location described textually.
72#[derive(Clone, Debug, Eq, PartialEq)]
73pub enum Location {
74    Span(Span),
75    CommandLine,
76    Other(String),
77}
78
79impl From<Span> for Location {
80    fn from(span: Span) -> Location {
81        Location::Span(span)
82    }
83}