diff options
Diffstat (limited to 'src/syntax/span.rs')
| -rw-r--r-- | src/syntax/span.rs | 58 |
1 files changed, 52 insertions, 6 deletions
diff --git a/src/syntax/span.rs b/src/syntax/span.rs index 5dcd8fc1..35425801 100644 --- a/src/syntax/span.rs +++ b/src/syntax/span.rs @@ -62,20 +62,25 @@ impl<T: Debug> Debug for Spanned<T> { pub struct Span(NonZeroU64); impl Span { + // Data layout: + // | 2 bits span pos | 16 bits source id | 46 bits number | + // Number of bits for and minimum and maximum numbers assignable to spans. - const BITS: usize = 48; + const BITS: usize = 46; const DETACHED: u64 = 1; - const MIN: u64 = 2; - const MAX: u64 = (1 << Self::BITS) - 1; /// The full range of numbers available to spans. - pub const FULL: Range<u64> = Self::MIN .. Self::MAX + 1; + pub const FULL: Range<u64> = 2 .. (1 << Self::BITS); /// Create a new span from a source id and a unique number. /// /// Panics if the `number` is not contained in `FULL`. pub const fn new(id: SourceId, number: u64) -> Self { - assert!(number >= Self::MIN && number <= Self::MAX); + assert!( + Self::FULL.start <= number && number < Self::FULL.end, + "span number outside valid range" + ); + let bits = ((id.into_raw() as u64) << Self::BITS) | number; Self(to_non_zero(bits)) } @@ -85,6 +90,12 @@ impl Span { Self(to_non_zero(Self::DETACHED)) } + /// Return a new span with updated position. + pub const fn with_pos(self, pos: SpanPos) -> Self { + let bits = (self.0.get() & ((1 << 62) - 1)) | ((pos as u64) << 62); + Self(to_non_zero(bits)) + } + /// The id of the source file the span points into. pub const fn source(self) -> SourceId { SourceId::from_raw((self.0.get() >> Self::BITS) as u16) @@ -94,16 +105,37 @@ impl Span { pub const fn number(self) -> u64 { self.0.get() & ((1 << Self::BITS) - 1) } + + /// Where in the node the span points to. + pub const fn pos(self) -> SpanPos { + match self.0.get() >> 62 { + 0 => SpanPos::Full, + 1 => SpanPos::Start, + 2 => SpanPos::End, + _ => panic!("span pos encoding is invalid"), + } + } } /// Convert to a non zero u64. const fn to_non_zero(v: u64) -> NonZeroU64 { match NonZeroU64::new(v) { Some(v) => v, - None => unreachable!(), + None => panic!("span encoding is zero"), } } +/// Where in a node a span points. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub enum SpanPos { + /// Over the full width of the node. + Full = 0, + /// At the start of the node. + Start = 1, + /// At the end of the node. + End = 2, +} + /// Result of numbering a node within an interval. pub type NumberingResult = Result<(), Unnumberable>; @@ -118,3 +150,17 @@ impl Display for Unnumberable { } impl std::error::Error for Unnumberable {} + +#[cfg(test)] +mod tests { + use super::{SourceId, Span, SpanPos}; + + #[test] + fn test_span_encoding() { + let id = SourceId::from_raw(5); + let span = Span::new(id, 10).with_pos(SpanPos::End); + assert_eq!(span.source(), id); + assert_eq!(span.number(), 10); + assert_eq!(span.pos(), SpanPos::End); + } +} |
