summaryrefslogtreecommitdiff
path: root/src/syntax/span.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-06-10 23:53:20 +0200
committerLaurenz <laurmaedje@gmail.com>2022-06-10 23:54:16 +0200
commited6550fdb08eae92bffab6b6b137b1e0eebf62c6 (patch)
tree74152a38f7aa2ed2ac2fa190e81494422700ca36 /src/syntax/span.rs
parent6aff11057bc88257c9383137952bb41b5b85c3dc (diff)
Bump dependencies
Diffstat (limited to 'src/syntax/span.rs')
-rw-r--r--src/syntax/span.rs58
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);
+ }
+}