Documentation

This commit is contained in:
Laurenz 2022-06-01 14:16:12 +02:00
parent 94b375ce55
commit af10b08cc1
3 changed files with 52 additions and 34 deletions

View File

@ -141,7 +141,8 @@ impl SourceStore {
self.sources[id.0 as usize].edit(replace, with)
}
/// Map a span that points into this source store to a byte range.
/// Map a span that points into a [file](SourceFile::range) stored in this
/// source store to a byte range.
///
/// Panics if the span does not point into this source store.
pub fn range(&self, span: Span) -> Range<usize> {

View File

@ -122,7 +122,7 @@ impl SyntaxNode {
}
}
/// Set a synthetic node id for the node and all its descendants.
/// Set a synthetic span for the node and all its descendants.
pub fn synthesize(&mut self, span: Span) {
match self {
Self::Inner(inner) => Arc::make_mut(inner).synthesize(span),
@ -258,7 +258,7 @@ impl InnerNode {
self.children.iter()
}
/// Set a synthetic node id for the node and all its descendants.
/// Set a synthetic span for the node and all its descendants.
pub fn synthesize(&mut self, span: Span) {
self.data.synthesize(span);
for child in &mut self.children {
@ -266,13 +266,15 @@ impl InnerNode {
}
}
/// Assign spans to this subtree or some a range of children.
/// Assign span numbers `within` an interval to this node's subtree or just
/// a `range` of its children.
pub fn numberize(
&mut self,
id: SourceId,
range: Option<Range<usize>>,
within: Range<u64>,
) -> NumberingResult {
// Determine how many nodes we will number.
let descendants = match &range {
Some(range) if range.is_empty() => return Ok(()),
Some(range) => self.children[range.clone()]
@ -282,6 +284,9 @@ impl InnerNode {
None => self.descendants,
};
// Determine the distance between two neighbouring assigned numbers. If
// possible, we try to fit all numbers into the left half of `within`
// so that there is space for future insertions.
let space = within.end - within.start;
let mut stride = space / (2 * descendants as u64);
if stride == 0 {
@ -291,6 +296,7 @@ impl InnerNode {
}
}
// Number this node itself.
let mut start = within.start;
if range.is_none() {
let end = start + stride;
@ -299,6 +305,7 @@ impl InnerNode {
start = end;
}
// Number the children.
let len = self.children.len();
for child in &mut self.children[range.unwrap_or(0 .. len)] {
let end = start + child.descendants() as u64 * stride;
@ -309,7 +316,7 @@ impl InnerNode {
Ok(())
}
/// The maximum assigned number in this subtree.
/// The upper bound of assigned numbers in this subtree.
pub fn upper(&self) -> u64 {
self.upper
}
@ -387,39 +394,44 @@ impl InnerNode {
self.children.splice(range.clone(), replacement);
range.end = range.start + replacement_count;
// Renumber the new children. Retries until it works taking
// Renumber the new children. Retries until it works, taking
// exponentially more children into account.
let max_left = range.start;
let max_right = self.children.len() - range.end;
let mut left = 0;
let mut right = 0;
let max_left = range.start;
let max_right = self.children.len() - range.end;
loop {
let renumber = range.start - left .. range.end + right;
// The minimum assignable number is the upper bound of the node
// right before the to-be-renumbered children (or the number after
// this inner node's span if renumbering starts at the first child).
// The minimum assignable number is either
// - the upper bound of the node right before the to-be-renumbered
// children,
// - or this inner node's span number plus one if renumbering starts
// at the first child.
let start_number = renumber
.start
.checked_sub(1)
.and_then(|i| self.children.get(i))
.map_or(self.span().number() + 1, |child| child.upper());
// The upper bound of the is the span of the first child after the to-be-renumbered children
// or this node's upper bound.
// The upper bound for renumbering is either
// - the span number of the first child after the to-be-renumbered
// children,
// - or this node's upper bound if renumbering ends behind the last
// child.
let end_number = self
.children
.get(renumber.end)
.map_or(self.upper(), |next| next.span().number());
// Try to renumber within the number range.
// Try to renumber.
let within = start_number .. end_number;
let id = self.span().source();
if self.numberize(id, Some(renumber), within).is_ok() {
return Ok(());
}
// Doesn't even work with all children, so we give up.
// If it didn't even work with all children, we give up.
if left == max_left && right == max_right {
return Err(Unnumberable);
}
@ -430,8 +442,8 @@ impl InnerNode {
}
}
/// Update the length of this node given the old and new length of
/// replaced children.
/// Update the this node given after changes were made to one of its
/// children.
pub(crate) fn update_parent(
&mut self,
prev_len: usize,

View File

@ -42,42 +42,47 @@ impl<T: Debug> Debug for Spanned<T> {
/// A unique identifier for a syntax node.
///
/// This is used throughout the compiler to track which source section an error
/// or element stems from. Can be mapped back to a source id + byte range for
/// user facing display.
/// or element stems from. Can be [mapped back](crate::source::SourceStore::range)
/// to a source id + byte range for user facing display.
///
/// Node ids are ordered in the tree to enable quickly finding the node with
/// Span ids are ordered in the tree to enable quickly finding the node with
/// some id:
/// - The id of a parent is always smaller than the ids of any of its children.
/// - The id of a node is always greater than any id in the subtrees of any left
/// sibling and smaller than any id the subtrees of any right sibling.
/// sibling and smaller than any id in the subtrees of any right sibling.
///
/// Node ids stay mostly stable, even for nodes behind an insertion. This is not
/// true for simple spans/ranges as they shift. Node ids can be used as inputs
/// to memoized functions without hurting cache performance when text is
/// inserted somewhere in the document other than the end.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
/// The internal ids of spans stay mostly stable, even for nodes behind an
/// insertion. This is not true for simple ranges as they shift. Spans can be
/// used as inputs to memoized functions without hurting cache performance when
/// text is inserted somewhere in the document other than the end.
///
/// This type takes 8 bytes and is null-optimized (i.e. `Option<Span>` also
/// takes 8 bytes).
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Span(NonZeroU64);
impl Span {
// Number of bits for and minimum and maximum numbers assigned to nodes.
// Number of bits for and minimum and maximum numbers assignable to spans.
const BITS: usize = 48;
const DETACHED: u64 = 1;
const MIN: u64 = 2;
const MAX: u64 = (1 << Self::BITS) - 1;
// The root numbering range.
/// The full range of numbers available to spans.
pub const FULL: Range<u64> = Self::MIN .. Self::MAX + 1;
/// Create a new span from a source id and a unique number.
pub fn new(id: SourceId, number: u64) -> Self {
assert!(number >= Self::MIN && number <= Self::MAX, "{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);
let bits = ((id.into_raw() as u64) << Self::BITS) | number;
Self(convert(bits))
Self(to_non_zero(bits))
}
/// A node that does not belong to any source file.
/// A span that does not point into any source file.
pub const fn detached() -> Self {
Self(convert(Self::DETACHED))
Self(to_non_zero(Self::DETACHED))
}
/// The id of the source file the span points into.
@ -92,7 +97,7 @@ impl Span {
}
/// Convert to a non zero u64.
const fn convert(v: u64) -> NonZeroU64 {
const fn to_non_zero(v: u64) -> NonZeroU64 {
match NonZeroU64::new(v) {
Some(v) => v,
None => unreachable!(),