summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/mod.rs94
-rw-r--r--src/syntax/span.rs11
2 files changed, 105 insertions, 0 deletions
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
index d9ad42a8..b0911c63 100644
--- a/src/syntax/mod.rs
+++ b/src/syntax/mod.rs
@@ -127,6 +127,92 @@ impl GreenNode {
pub fn children(&self) -> &[Green] {
&self.children
}
+
+ /// The node's children, mutably.
+ pub fn children_mut(&mut self) -> &mut [Green] {
+ &mut self.children
+ }
+
+ /// The node's metadata.
+ pub fn data(&self) -> &GreenData {
+ &self.data
+ }
+
+ /// The node's type.
+ pub fn kind(&self) -> &NodeKind {
+ self.data().kind()
+ }
+
+ /// The node's length.
+ pub fn len(&self) -> usize {
+ self.data().len()
+ }
+
+ /// Find the parent of the deepest incremental-safe node and the index of
+ /// the found child.
+ pub fn incremental_parent(
+ &mut self,
+ span: Span,
+ ) -> Option<(usize, &mut GreenNode, usize)> {
+ self.incremental_parent_internal(span, 0)
+ }
+
+ fn incremental_parent_internal(
+ &mut self,
+ span: Span,
+ mut offset: usize,
+ ) -> Option<(usize, &mut GreenNode, usize)> {
+ let x = unsafe { &mut *(self as *mut _) };
+
+ for (i, child) in self.children.iter_mut().enumerate() {
+ match child {
+ Green::Token(n) => {
+ if offset < span.start {
+ // the token is strictly before the span
+ offset += n.len();
+ } else {
+ // the token is within or after the span; tokens are
+ // never safe, so we return.
+ return None;
+ }
+ }
+ Green::Node(n) => {
+ let end = n.len() + offset;
+ if offset < span.start && end < span.start {
+ // the node is strictly before the span
+ offset += n.len();
+ } else if span.start >= offset
+ && span.start < end
+ && span.end <= end
+ && span.end > offset
+ {
+ // the node is within the span.
+ if n.kind().is_incremental_safe() {
+ let res =
+ Rc::make_mut(n).incremental_parent_internal(span, offset);
+ if res.is_none() {
+ return Some((i, x, offset));
+ }
+ } else {
+ return Rc::make_mut(n)
+ .incremental_parent_internal(span, offset);
+ }
+ } else {
+ // the node is overlapping or after after the span; nodes are
+ // never safe, so we return.
+ return None;
+ }
+ }
+ }
+ }
+
+ return None;
+ }
+
+ /// Replace one of the node's children.
+ pub fn replace_child(&mut self, index: usize, child: impl Into<Green>) {
+ self.children[index] = child.into();
+ }
}
impl From<GreenNode> for Green {
@@ -653,6 +739,14 @@ impl NodeKind {
matches!(self, NodeKind::Error(_, _) | NodeKind::Unknown(_))
}
+ /// Whether it is safe to do incremental parsing on this node.
+ pub fn is_incremental_safe(&self) -> bool {
+ match self {
+ Self::Block | Self::Markup => true,
+ _ => false,
+ }
+ }
+
/// A human-readable name for the kind.
pub fn as_str(&self) -> &'static str {
match self {
diff --git a/src/syntax/span.rs b/src/syntax/span.rs
index 4d5b8819..a707d3d9 100644
--- a/src/syntax/span.rs
+++ b/src/syntax/span.rs
@@ -125,6 +125,17 @@ impl Span {
*self = self.join(other)
}
+ /// Create a new span with n characters inserted inside of this span.
+ pub fn inserted(mut self, other: Self, n: usize) -> Self {
+ if !self.contains(other.start) || !self.contains(other.end) {
+ panic!();
+ }
+
+ let len_change = (n as isize - other.len() as isize) as usize;
+ self.end += len_change;
+ self
+ }
+
/// Test whether a position is within the span.
pub fn contains(&self, pos: usize) -> bool {
self.start <= pos && self.end >= pos