summaryrefslogtreecommitdiff
path: root/src/syntax
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
parent6aff11057bc88257c9383137952bb41b5b85c3dc (diff)
Bump dependencies
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/mod.rs26
-rw-r--r--src/syntax/span.rs58
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);
+ }
+}