diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-06-10 23:53:20 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-06-10 23:54:16 +0200 |
| commit | ed6550fdb08eae92bffab6b6b137b1e0eebf62c6 (patch) | |
| tree | 74152a38f7aa2ed2ac2fa190e81494422700ca36 /src/syntax | |
| parent | 6aff11057bc88257c9383137952bb41b5b85c3dc (diff) | |
Bump dependencies
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/mod.rs | 26 | ||||
| -rw-r--r-- | src/syntax/span.rs | 58 |
2 files changed, 70 insertions, 14 deletions
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index 9114872d..7086ad4c 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -13,7 +13,7 @@ pub use highlight::*; pub use span::*; use self::ast::{MathNode, RawNode, TypedNode, Unit}; -use crate::diag::{Error, ErrorPos}; +use crate::diag::Error; use crate::source::SourceId; use crate::util::EcoString; @@ -82,7 +82,7 @@ impl SyntaxNode { match self.kind() { &NodeKind::Error(pos, ref message) => { - vec![Error { pos, ..Error::new(self.span(), message) }] + vec![Error::new(self.span().with_pos(pos), message)] } _ => self .children() @@ -150,9 +150,7 @@ impl SyntaxNode { pub fn range(&self, span: Span, offset: usize) -> Option<Range<usize>> { match self { Self::Inner(inner) => inner.range(span, offset), - Self::Leaf(leaf) => { - (span == leaf.span).then(|| offset .. offset + self.len()) - } + Self::Leaf(leaf) => leaf.range(span, offset), } } @@ -324,8 +322,8 @@ impl InnerNode { /// If the span points into this node, convert it to a byte range. pub fn range(&self, span: Span, mut offset: usize) -> Option<Range<usize>> { // Check whether we found it. - if self.data.span == span { - return Some(offset .. offset + self.len()); + if let Some(range) = self.data.range(span, offset) { + return Some(range); } // The parent of a subtree has a smaller span number than all of its @@ -536,6 +534,18 @@ impl NodeData { Err(Unnumberable) } } + + /// If the span points into this node, convert it to a byte range. + pub fn range(&self, span: Span, offset: usize) -> Option<Range<usize>> { + (span.with_pos(SpanPos::Full) == self.span).then(|| { + let end = offset + self.len(); + match span.pos() { + SpanPos::Full => offset .. end, + SpanPos::Start => offset .. offset, + SpanPos::End => end .. end, + } + }) + } } impl From<NodeData> for SyntaxNode { @@ -787,7 +797,7 @@ pub enum NodeKind { /// The comment can contain nested block comments. BlockComment, /// Tokens that appear in the wrong place. - Error(ErrorPos, EcoString), + Error(SpanPos, EcoString), /// Unknown character sequences. Unknown(EcoString), } 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); + } +} |
