diff --git a/examples/math.rs b/examples/math.rs index 6e56a81..46e7b15 100644 --- a/examples/math.rs +++ b/examples/math.rs @@ -13,10 +13,7 @@ //! - "+" Token(Add) //! - "4" Token(Number) -use cstree::{ - interning::{Reader, Resolver}, - GreenNodeBuilder, NodeOrToken, -}; +use cstree::{interning::Resolver, GreenNodeBuilder, NodeOrToken}; use std::iter::Peekable; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -66,7 +63,7 @@ type SyntaxElement = cstree::NodeOrToken; type SyntaxElementRef<'a> = cstree::NodeOrToken<&'a SyntaxNode, &'a SyntaxToken>; struct Parser<'input, I: Iterator> { - builder: GreenNodeBuilder<'static>, + builder: GreenNodeBuilder<'static, 'static>, iter: Peekable, } impl<'input, I: Iterator> Parser<'input, I> { @@ -134,7 +131,7 @@ fn print(indent: usize, element: SyntaxElementRef<'_>, resolver: &impl Resolver) } } - NodeOrToken::Token(token) => println!("- {:?} {:?}", token.text(resolver), kind), + NodeOrToken::Token(token) => println!("- {:?} {:?}", token.resolve_text(resolver), kind), } } diff --git a/examples/s_expressions.rs b/examples/s_expressions.rs index 5142283..57fdc3d 100644 --- a/examples/s_expressions.rs +++ b/examples/s_expressions.rs @@ -62,10 +62,7 @@ impl cstree::Language for Lang { /// GreenNode is an immutable tree, which is cheap to change, /// but doesn't contain offsets and parent pointers. -use cstree::{ - interning::{Reader, Resolver}, - GreenNode, -}; +use cstree::{interning::Resolver, GreenNode}; /// You can construct GreenNodes by hand, but a builder /// is helpful for top-down parsers: it maintains a stack @@ -91,7 +88,7 @@ fn parse(text: &str) -> Parse { /// in *reverse* order. tokens: Vec<(SyntaxKind, &'input str)>, /// the in-progress tree. - builder: GreenNodeBuilder<'static>, + builder: GreenNodeBuilder<'static, 'static>, /// the list of syntax errors we've accumulated /// so far. errors: Vec, diff --git a/src/green/builder.rs b/src/green/builder.rs index 527d222..15875ab 100644 --- a/src/green/builder.rs +++ b/src/green/builder.rs @@ -19,29 +19,42 @@ use super::{node::GreenNodeHead, token::GreenTokenData}; const CHILDREN_CACHE_THRESHOLD: usize = 3; #[derive(Debug)] -pub struct NodeCache { +pub struct NodeCache<'i, I = Rodeo> { nodes: FxHashMap, tokens: FxHashMap, - interner: Rodeo, + interner: MaybeOwned<'i, I>, } -impl NodeCache { +impl NodeCache<'static, Rodeo> { pub fn new() -> Self { Self { nodes: FxHashMap::default(), tokens: FxHashMap::default(), - interner: Rodeo::with_capacity_and_hasher( + interner: MaybeOwned::Owned(Rodeo::with_capacity_and_hasher( // capacity values suggested by author of `lasso` Capacity::new(512, unsafe { NonZeroUsize::new_unchecked(4096) }), FxBuildHasher::default(), - ), + )), + } + } +} + +impl<'i, I> NodeCache<'i, I> +where + I: Interner, +{ + pub fn with_interner(interner: &'i mut I) -> Self { + Self { + nodes: FxHashMap::default(), + tokens: FxHashMap::default(), + interner: MaybeOwned::Borrowed(interner), } } - fn node(&mut self, kind: SyntaxKind, children: I) -> GreenNode + fn node(&mut self, kind: SyntaxKind, children: It) -> GreenNode where - I: IntoIterator, - I::IntoIter: ExactSizeIterator, + It: IntoIterator, + It::IntoIter: ExactSizeIterator, { let children = children.into_iter(); @@ -61,10 +74,10 @@ impl NodeCache { /// Creates a [`GreenNode`] by looking inside the cache or inserting /// a new node into the cache if it's a cache miss. - fn get_cached_node(&mut self, kind: SyntaxKind, children: I) -> GreenNode + fn get_cached_node(&mut self, kind: SyntaxKind, children: It) -> GreenNode where - I: IntoIterator, - I::IntoIter: ExactSizeIterator, + It: IntoIterator, + It::IntoIter: ExactSizeIterator, { #[derive(Clone)] struct ChildrenIter { @@ -132,6 +145,15 @@ enum MaybeOwned<'a, T> { Borrowed(&'a mut T), } +impl MaybeOwned<'_, T> { + fn as_owned(self) -> Option { + match self { + MaybeOwned::Owned(owned) => Some(owned), + MaybeOwned::Borrowed(_) => None, + } + } +} + impl std::ops::Deref for MaybeOwned<'_, T> { type Target = T; @@ -164,26 +186,31 @@ pub struct Checkpoint(usize); /// A builder for a green tree. #[derive(Debug)] -pub struct GreenNodeBuilder<'cache> { - cache: MaybeOwned<'cache, NodeCache>, +pub struct GreenNodeBuilder<'cache, 'interner, I = Rodeo> { + cache: MaybeOwned<'cache, NodeCache<'interner, I>>, parents: Vec<(SyntaxKind, usize)>, children: Vec, } -impl GreenNodeBuilder<'_> { +impl GreenNodeBuilder<'static, 'static, Rodeo> { /// Creates new builder. - pub fn new() -> GreenNodeBuilder<'static> { - GreenNodeBuilder { + pub fn new() -> Self { + Self { cache: MaybeOwned::Owned(NodeCache::new()), parents: Vec::with_capacity(8), children: Vec::with_capacity(8), } } +} +impl<'cache, 'interner, I> GreenNodeBuilder<'cache, 'interner, I> +where + I: Interner, +{ /// Reusing `NodeCache` between different `GreenNodeBuilder`s saves memory. /// It allows to structurally share underlying trees. - pub fn with_cache(cache: &mut NodeCache) -> GreenNodeBuilder<'_> { - GreenNodeBuilder { + pub fn with_cache(cache: &'cache mut NodeCache<'interner, I>) -> Self { + Self { cache: MaybeOwned::Borrowed(cache), parents: Vec::with_capacity(8), children: Vec::with_capacity(8), @@ -268,15 +295,12 @@ impl GreenNodeBuilder<'_> { /// `start_node_at` and `finish_node` calls /// are paired! #[inline] - pub fn finish(mut self) -> (GreenNode, Option>) { + pub fn finish(mut self) -> (GreenNode, Option) { assert_eq!(self.children.len(), 1); - let resolver = match self.cache { - MaybeOwned::Owned(cache) => Some(cache.interner), - MaybeOwned::Borrowed(_) => None, - }; + let resolver = self.cache.as_owned().and_then(|cache| cache.interner.as_owned()); match self.children.pop().unwrap() { NodeOrToken::Node(node) => (node, resolver), - NodeOrToken::Token(_) => panic!(), + NodeOrToken::Token(_) => panic!("called `finish` on a `GreenNodeBuilder` which only contained a token"), } } } diff --git a/src/lib.rs b/src/lib.rs index 978cc71..1259195 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,7 +53,7 @@ use std::fmt; pub use text_size::{TextLen, TextRange, TextSize}; pub use crate::{ - green::{Checkpoint, Children, GreenNode, GreenNodeBuilder, GreenToken, SyntaxKind}, + green::{Checkpoint, Children, GreenNode, GreenNodeBuilder, GreenToken, NodeCache, SyntaxKind}, syntax::{SyntaxElement, SyntaxElementChildren, SyntaxElementRef, SyntaxNode, SyntaxNodeChildren, SyntaxToken}, syntax_text::SyntaxText, utility_types::{Direction, NodeOrToken, TokenAtOffset, WalkEvent}, diff --git a/src/syntax.rs b/src/syntax.rs index 56ddf9c..0e93588 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -1,6 +1,6 @@ use std::{ cell::UnsafeCell, - fmt::Write, + fmt::{self, Write}, hash::{Hash, Hasher}, iter, ptr, sync::atomic::{AtomicU32, Ordering}, @@ -32,11 +32,11 @@ use crate::{ // - DQ 01/2021 #[repr(transparent)] -pub struct SyntaxNode { - data: *mut NodeData, +pub struct SyntaxNode { + data: *mut NodeData, } -impl SyntaxNode { +impl SyntaxNode { pub fn debug(&self, resolver: &impl Resolver, recursive: bool) -> String { // NOTE: `fmt::Write` methods on `String` never fail let mut res = String::new(); @@ -82,7 +82,7 @@ impl SyntaxNode { } } -impl Clone for SyntaxNode { +impl Clone for SyntaxNode { fn clone(&self) -> Self { // safety:: the ref count is only dropped when there are no more external references (see below) // since we are currently cloning such a reference, there is still at least one @@ -92,7 +92,7 @@ impl Clone for SyntaxNode { } } -impl Drop for SyntaxNode { +impl Drop for SyntaxNode { fn drop(&mut self) { // safety:: the ref count is only dropped when there are no more external references (see below) // and all nodes but the root have been dropped. @@ -117,9 +117,9 @@ impl Drop for SyntaxNode { } } -impl SyntaxNode { +impl SyntaxNode { #[inline] - fn data(&self) -> &NodeData { + fn data(&self) -> &NodeData { unsafe { &*self.data } } @@ -127,7 +127,7 @@ impl SyntaxNode { /// Caller must ensure that the access to the underlying data is unique (no active _mutable or immutable_ /// references). #[inline] - unsafe fn data_mut(&self) -> &mut NodeData { + unsafe fn data_mut(&self) -> &mut NodeData { &mut *self.data } @@ -136,7 +136,7 @@ impl SyntaxNode { Self { data: self.data } } - fn root(&self) -> &SyntaxNode { + fn root(&self) -> &SyntaxNode { let mut current = self; while let Some(parent) = current.parent() { current = parent; @@ -177,28 +177,28 @@ impl SyntaxNode { } // Identity semantics for hash & eq -impl PartialEq for SyntaxNode { - fn eq(&self, other: &SyntaxNode) -> bool { +impl PartialEq for SyntaxNode { + fn eq(&self, other: &SyntaxNode) -> bool { self.green().ptr() == other.green().ptr() && self.text_range().start() == other.text_range().start() } } -impl Eq for SyntaxNode {} +impl Eq for SyntaxNode {} -impl Hash for SyntaxNode { +impl Hash for SyntaxNode { fn hash(&self, state: &mut H) { ptr::hash(self.green().ptr(), state); self.text_range().start().hash(state); } } -pub struct SyntaxToken { - parent: SyntaxNode, +pub struct SyntaxToken { + parent: SyntaxNode, index: u32, offset: TextSize, } -impl Clone for SyntaxToken { +impl Clone for SyntaxToken { fn clone(&self) -> Self { Self { parent: self.parent.clone(), @@ -208,7 +208,7 @@ impl Clone for SyntaxToken { } } -impl Hash for SyntaxToken { +impl Hash for SyntaxToken { fn hash(&self, state: &mut H) { self.parent.hash(state); self.index.hash(state); @@ -216,23 +216,23 @@ impl Hash for SyntaxToken { } } -impl PartialEq for SyntaxToken { - fn eq(&self, other: &SyntaxToken) -> bool { +impl PartialEq for SyntaxToken { + fn eq(&self, other: &SyntaxToken) -> bool { self.parent == other.parent && self.index == other.index && self.offset == other.offset } } -impl Eq for SyntaxToken {} +impl Eq for SyntaxToken {} -impl SyntaxToken { +impl SyntaxToken { pub fn debug(&self, resolver: &impl Resolver) -> String { let mut res = String::new(); write!(res, "{:?}@{:?}", self.kind(), self.text_range()).unwrap(); - if self.text(resolver).len() < 25 { - write!(res, " {:?}", self.text(resolver)).unwrap(); + if self.resolve_text(resolver).len() < 25 { + write!(res, " {:?}", self.resolve_text(resolver)).unwrap(); return res; } - let text = self.text(resolver); + let text = self.resolve_text(resolver); for idx in 21..25 { if text.is_char_boundary(idx) { let text = format!("{} ...", &text[..idx]); @@ -244,25 +244,25 @@ impl SyntaxToken { } pub fn display(&self, resolver: &impl Resolver) -> String { - self.text(resolver).to_string() + self.resolve_text(resolver).to_string() } } -pub type SyntaxElement = NodeOrToken, SyntaxToken>; +pub type SyntaxElement = NodeOrToken, SyntaxToken>; -impl From> for SyntaxElement { - fn from(node: SyntaxNode) -> SyntaxElement { +impl From> for SyntaxElement { + fn from(node: SyntaxNode) -> SyntaxElement { NodeOrToken::Node(node) } } -impl From> for SyntaxElement { - fn from(token: SyntaxToken) -> SyntaxElement { +impl From> for SyntaxElement { + fn from(token: SyntaxToken) -> SyntaxElement { NodeOrToken::Token(token) } } -impl SyntaxElement { +impl SyntaxElement { pub fn display(&self, resolver: &impl Resolver) -> String { match self { NodeOrToken::Node(it) => it.display(resolver), @@ -271,22 +271,22 @@ impl SyntaxElement { } } -pub type SyntaxElementRef<'a, L, D = ()> = NodeOrToken<&'a SyntaxNode, &'a SyntaxToken>; +pub type SyntaxElementRef<'a, L, D = (), R = ()> = NodeOrToken<&'a SyntaxNode, &'a SyntaxToken>; -impl<'a, L: Language, D> From<&'a SyntaxNode> for SyntaxElementRef<'a, L, D> { - fn from(node: &'a SyntaxNode) -> Self { +impl<'a, L: Language, D, R> From<&'a SyntaxNode> for SyntaxElementRef<'a, L, D, R> { + fn from(node: &'a SyntaxNode) -> Self { NodeOrToken::Node(node) } } -impl<'a, L: Language, D> From<&'a SyntaxToken> for SyntaxElementRef<'a, L, D> { - fn from(token: &'a SyntaxToken) -> Self { +impl<'a, L: Language, D, R> From<&'a SyntaxToken> for SyntaxElementRef<'a, L, D, R> { + fn from(token: &'a SyntaxToken) -> Self { NodeOrToken::Token(token) } } -impl<'a, L: Language, D> From<&'a SyntaxElement> for SyntaxElementRef<'a, L, D> { - fn from(element: &'a SyntaxElement) -> Self { +impl<'a, L: Language, D, R> From<&'a SyntaxElement> for SyntaxElementRef<'a, L, D, R> { + fn from(element: &'a SyntaxElement) -> Self { match element { NodeOrToken::Node(it) => Self::Node(it), NodeOrToken::Token(it) => Self::Token(it), @@ -294,7 +294,7 @@ impl<'a, L: Language, D> From<&'a SyntaxElement> for SyntaxElementRef<'a, } } -impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { +impl<'a, L: Language, D, R> SyntaxElementRef<'a, L, D, R> { pub fn display(&self, resolver: &impl Resolver) -> String { match self { NodeOrToken::Node(it) => it.display(resolver), @@ -303,17 +303,17 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } } -enum Kind { - Root(GreenNode), +enum Kind { + Root(GreenNode, Arc), Child { - parent: SyntaxNode, + parent: SyntaxNode, index: u32, offset: TextSize, }, } -impl Kind { - fn as_child(&self) -> Option<(&SyntaxNode, u32, TextSize)> { +impl Kind { + fn as_child(&self) -> Option<(&SyntaxNode, u32, TextSize)> { match self { Kind::Child { parent, index, offset } => Some((parent, *index, *offset)), _ => None, @@ -321,18 +321,18 @@ impl Kind { } } -struct NodeData { - kind: Kind, +struct NodeData { + kind: Kind, green: ptr::NonNull, ref_count: *mut AtomicU32, data: RwLock>>, - children: Vec>>>, + children: Vec>>>, child_locks: Vec>, } -impl NodeData { +impl NodeData { fn new( - kind: Kind, + kind: Kind, green: ptr::NonNull, ref_count: *mut AtomicU32, n_children: usize, @@ -352,23 +352,29 @@ impl NodeData { } } -impl SyntaxNode { - fn new(data: *mut NodeData) -> SyntaxNode { +impl SyntaxNode { + pub fn new_root(green: GreenNode) -> Self { + Self::make_new_root(green, ()) + } +} + +impl SyntaxNode { + fn new(data: *mut NodeData) -> Self { Self { data } } - pub fn new_root(green: GreenNode) -> SyntaxNode { + fn make_new_root(green: GreenNode, resolver: R) -> Self { let ref_count = Box::new(AtomicU32::new(1)); let n_children = green.children().count(); let data = NodeData::new( - Kind::Root(green), + Kind::Root(green, Arc::new(resolver)), ptr::NonNull::dangling(), Box::into_raw(ref_count), n_children, ); let ret = Self::new(data); let green: ptr::NonNull = match &ret.data().kind { - Kind::Root(green) => green.into(), + Kind::Root(green, _resolver) => green.into(), _ => unreachable!(), }; // safety: we have just created `ret` and have not shared it @@ -376,15 +382,16 @@ impl SyntaxNode { ret } + pub fn new_root_with_resolver(green: GreenNode, resolver: R) -> Self + where + R: Resolver, + { + Self::make_new_root(green, resolver) + } + // Technically, unsafe, but private so that's OK. // Safety: `green` must be a descendent of `parent.green` - fn new_child( - green: &GreenNode, - parent: &SyntaxNode, - index: u32, - offset: TextSize, - ref_count: *mut AtomicU32, - ) -> SyntaxNode { + fn new_child(green: &GreenNode, parent: &Self, index: u32, offset: TextSize, ref_count: *mut AtomicU32) -> Self { let n_children = green.children().count(); let data = NodeData::new( Kind::Child { @@ -426,8 +433,15 @@ impl SyntaxNode { *ptr = None; } + pub fn resolver(&self) -> &Arc { + match &self.root().data().kind { + Kind::Root(_, resolver) => resolver, + _ => unreachable!(), + } + } + #[inline] - fn read(&self, index: usize) -> Option> { + fn read(&self, index: usize) -> Option> { // safety: children are pre-allocated and indices are determined internally let _read = unsafe { self.data().child_locks.get_unchecked(index).read() }; // safety: mutable accesses to the slot only occur below and have to take the lock @@ -435,7 +449,7 @@ impl SyntaxNode { slot.as_ref().map(|elem| elem.into()) } - fn try_write(&self, index: usize, elem: SyntaxElement) { + fn try_write(&self, index: usize, elem: SyntaxElement) { // safety: children are pre-allocated and indices are determined internally let _write = unsafe { self.data().child_locks.get_unchecked(index).write() }; // safety: we are the only writer and there are no readers as evidenced by the write lock @@ -480,7 +494,7 @@ impl SyntaxNode { } #[inline(always)] - fn get_or_add_node(&self, node: &GreenNode, index: usize, offset: TextSize) -> SyntaxElementRef<'_, L, D> { + fn get_or_add_node(&self, node: &GreenNode, index: usize, offset: TextSize) -> SyntaxElementRef<'_, L, D, R> { if let Some(elem) = self.read(index) { debug_assert_eq!(elem.text_range().start(), offset); return elem; @@ -498,7 +512,7 @@ impl SyntaxNode { element: GreenElementRef<'_>, index: usize, offset: TextSize, - ) -> SyntaxElementRef<'_, L, D> { + ) -> SyntaxElementRef<'_, L, D, R> { if let Some(elem) = self.read(index) { debug_assert_eq!(elem.text_range().start(), offset); return elem; @@ -552,7 +566,7 @@ impl SyntaxNode { } #[inline] - pub fn text<'n, 'i, I>(&'n self, resolver: &'i I) -> SyntaxText<'n, 'i, I, L, D> + pub fn resolve_text<'n, 'i, I>(&'n self, resolver: &'i I) -> SyntaxText<'n, 'i, I, L, D, R> where I: Resolver + ?Sized, { @@ -565,42 +579,42 @@ impl SyntaxNode { } #[inline] - pub fn parent(&self) -> Option<&SyntaxNode> { + pub fn parent(&self) -> Option<&SyntaxNode> { match &self.data().kind { - Kind::Root(_) => None, + Kind::Root(_, _) => None, Kind::Child { parent, .. } => Some(parent), } } #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> { iter::successors(Some(self), |&node| node.parent()) } #[inline] - pub fn children(&self) -> SyntaxNodeChildren<'_, L, D> { + pub fn children(&self) -> SyntaxNodeChildren<'_, L, D, R> { SyntaxNodeChildren::new(self) } #[inline] - pub fn children_with_tokens(&self) -> SyntaxElementChildren<'_, L, D> { + pub fn children_with_tokens(&self) -> SyntaxElementChildren<'_, L, D, R> { SyntaxElementChildren::new(self) } #[inline] - pub fn first_child(&self) -> Option<&SyntaxNode> { + pub fn first_child(&self) -> Option<&SyntaxNode> { let (node, (index, offset)) = filter_nodes(self.green().children_from(0, self.text_range().start())).next()?; self.get_or_add_node(node, index, offset).as_node().map(|node| *node) } #[inline] - pub fn first_child_or_token(&self) -> Option> { + pub fn first_child_or_token(&self) -> Option> { let (element, (index, offset)) = self.green().children_from(0, self.text_range().start()).next()?; Some(self.get_or_add_element(element, index, offset)) } #[inline] - pub fn last_child(&self) -> Option<&SyntaxNode> { + pub fn last_child(&self) -> Option<&SyntaxNode> { let (node, (index, offset)) = filter_nodes( self.green() .children_to(self.green().children().len(), self.text_range().end()), @@ -610,7 +624,7 @@ impl SyntaxNode { } #[inline] - pub fn last_child_or_token(&self) -> Option> { + pub fn last_child_or_token(&self) -> Option> { let (element, (index, offset)) = self .green() .children_to(self.green().children().len(), self.text_range().end()) @@ -619,31 +633,31 @@ impl SyntaxNode { } #[inline] - pub fn next_child_after(&self, n: usize, offset: TextSize) -> Option<&SyntaxNode> { + pub fn next_child_after(&self, n: usize, offset: TextSize) -> Option<&SyntaxNode> { let (node, (index, offset)) = filter_nodes(self.green().children_from(n + 1, offset)).next()?; self.get_or_add_node(node, index, offset).as_node().map(|node| *node) } #[inline] - pub fn next_child_or_token_after(&self, n: usize, offset: TextSize) -> Option> { + pub fn next_child_or_token_after(&self, n: usize, offset: TextSize) -> Option> { let (element, (index, offset)) = self.green().children_from(n + 1, offset).next()?; Some(self.get_or_add_element(element, index, offset)) } #[inline] - pub fn prev_child_before(&self, n: usize, offset: TextSize) -> Option<&SyntaxNode> { + pub fn prev_child_before(&self, n: usize, offset: TextSize) -> Option<&SyntaxNode> { let (node, (index, offset)) = filter_nodes(self.green().children_to(n, offset)).next()?; self.get_or_add_node(node, index, offset).as_node().map(|node| *node) } #[inline] - pub fn prev_child_or_token_before(&self, n: usize, offset: TextSize) -> Option> { + pub fn prev_child_or_token_before(&self, n: usize, offset: TextSize) -> Option> { let (element, (index, offset)) = self.green().children_to(n, offset).next()?; Some(self.get_or_add_element(element, index, offset)) } #[inline] - pub fn next_sibling(&self) -> Option<&SyntaxNode> { + pub fn next_sibling(&self) -> Option<&SyntaxNode> { let (parent, index, _) = self.data().kind.as_child()?; let (node, (index, offset)) = filter_nodes( @@ -656,7 +670,7 @@ impl SyntaxNode { } #[inline] - pub fn next_sibling_or_token(&self) -> Option> { + pub fn next_sibling_or_token(&self) -> Option> { let (parent, index, _) = self.data().kind.as_child()?; let (element, (index, offset)) = parent @@ -667,7 +681,7 @@ impl SyntaxNode { } #[inline] - pub fn prev_sibling(&self) -> Option<&SyntaxNode> { + pub fn prev_sibling(&self) -> Option<&SyntaxNode> { let (parent, index, _) = self.data().kind.as_child()?; let (node, (index, offset)) = @@ -676,7 +690,7 @@ impl SyntaxNode { } #[inline] - pub fn prev_sibling_or_token(&self) -> Option> { + pub fn prev_sibling_or_token(&self) -> Option> { let (parent, index, _) = self.data().kind.as_child()?; let (element, (index, offset)) = parent @@ -688,18 +702,18 @@ impl SyntaxNode { /// Return the leftmost token in the subtree of this node #[inline] - pub fn first_token(&self) -> Option<&SyntaxToken> { + pub fn first_token(&self) -> Option<&SyntaxToken> { self.first_child_or_token()?.first_token() } /// Return the rightmost token in the subtree of this node #[inline] - pub fn last_token(&self) -> Option<&SyntaxToken> { + pub fn last_token(&self) -> Option<&SyntaxToken> { self.last_child_or_token()?.last_token() } #[inline] - pub fn siblings(&self, direction: Direction) -> impl Iterator> { + pub fn siblings(&self, direction: Direction) -> impl Iterator> { iter::successors(Some(self), move |node| match direction { Direction::Next => node.next_sibling(), Direction::Prev => node.prev_sibling(), @@ -707,8 +721,8 @@ impl SyntaxNode { } #[inline] - pub fn siblings_with_tokens(&self, direction: Direction) -> impl Iterator> { - let me: SyntaxElementRef<'_, L, D> = self.into(); + pub fn siblings_with_tokens(&self, direction: Direction) -> impl Iterator> { + let me: SyntaxElementRef<'_, L, D, R> = self.into(); iter::successors(Some(me), move |el| match direction { Direction::Next => el.next_sibling_or_token(), Direction::Prev => el.prev_sibling_or_token(), @@ -716,7 +730,7 @@ impl SyntaxNode { } #[inline] - pub fn descendants(&self) -> impl Iterator> { + pub fn descendants(&self) -> impl Iterator> { self.preorder().filter_map(|event| match event { WalkEvent::Enter(node) => Some(node), WalkEvent::Leave(_) => None, @@ -724,7 +738,7 @@ impl SyntaxNode { } #[inline] - pub fn descendants_with_tokens(&self) -> impl Iterator> { + pub fn descendants_with_tokens(&self) -> impl Iterator> { self.preorder_with_tokens().filter_map(|event| match event { WalkEvent::Enter(it) => Some(it), WalkEvent::Leave(_) => None, @@ -733,8 +747,8 @@ impl SyntaxNode { /// Traverse the subtree rooted at the current node (including the current /// node) in preorder, excluding tokens. - #[inline] - pub fn preorder(&self) -> impl Iterator>> { + #[inline(always)] + pub fn preorder(&self) -> impl Iterator>> { iter::successors(Some(WalkEvent::Enter(self)), move |pos| { let next = match pos { WalkEvent::Enter(node) => match node.first_child() { @@ -757,8 +771,8 @@ impl SyntaxNode { /// Traverse the subtree rooted at the current node (including the current /// node) in preorder, including tokens. - #[inline] - pub fn preorder_with_tokens(&self) -> impl Iterator>> { + #[inline(always)] + pub fn preorder_with_tokens(&self) -> impl Iterator>> { let me = self.into(); iter::successors(Some(WalkEvent::Enter(me)), move |pos| { let next = match pos { @@ -785,7 +799,7 @@ impl SyntaxNode { /// Find a token in the subtree corresponding to this node, which covers the offset. /// Precondition: offset must be withing node's range. - pub fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset> { + pub fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset> { // TODO: this could be faster if we first drill-down to node, and only // then switch to token search. We should also replace explicit // recursion with a loop. @@ -823,8 +837,8 @@ impl SyntaxNode { /// contains the range. If the range is empty and is contained in two leaf /// nodes, either one can be returned. Precondition: range must be contained /// withing the current node - pub fn covering_element(&self, range: TextRange) -> SyntaxElementRef<'_, L, D> { - let mut res: SyntaxElementRef<'_, L, D> = self.into(); + pub fn covering_element(&self, range: TextRange) -> SyntaxElementRef<'_, L, D, R> { + let mut res: SyntaxElementRef<'_, L, D, R> = self.into(); loop { assert!( res.text_range().contains_range(range), @@ -848,8 +862,36 @@ impl SyntaxNode { } } -impl SyntaxToken { - fn new(parent: &SyntaxNode, index: u32, offset: TextSize) -> SyntaxToken { +impl SyntaxNode +where + R: Resolver, +{ + #[inline] + pub fn text<'n>(&'n self) -> SyntaxText<'n, 'n, R, L, D, R> { + SyntaxText::new(self, self.resolver().as_ref()) + } +} + +impl fmt::Debug for SyntaxNode +where + R: Resolver, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", Self::debug(self, self.resolver().as_ref(), f.alternate())) + } +} + +impl fmt::Display for SyntaxNode +where + R: Resolver, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", Self::display(self, self.resolver().as_ref())) + } +} + +impl SyntaxToken { + fn new(parent: &SyntaxNode, index: u32, offset: TextSize) -> SyntaxToken { Self { parent: parent.clone_uncounted(), index, @@ -893,7 +935,7 @@ impl SyntaxToken { } #[inline] - pub fn text<'i, I>(&self, resolver: &'i I) -> &'i str + pub fn resolve_text<'i, I>(&self, resolver: &'i I) -> &'i str where I: Resolver + ?Sized, { @@ -911,30 +953,30 @@ impl SyntaxToken { } #[inline] - pub fn parent(&self) -> &SyntaxNode { + pub fn parent(&self) -> &SyntaxNode { &self.parent } #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> { self.parent().ancestors() } #[inline] - pub fn next_sibling_or_token(&self) -> Option> { + pub fn next_sibling_or_token(&self) -> Option> { self.parent() .next_child_or_token_after(self.index as usize, self.text_range().end()) } #[inline] - pub fn prev_sibling_or_token(&self) -> Option> { + pub fn prev_sibling_or_token(&self) -> Option> { self.parent() .prev_child_or_token_before(self.index as usize, self.text_range().start()) } #[inline] - pub fn siblings_with_tokens(&self, direction: Direction) -> impl Iterator> { - let me: SyntaxElementRef<'_, L, D> = self.into(); + pub fn siblings_with_tokens(&self, direction: Direction) -> impl Iterator> { + let me: SyntaxElementRef<'_, L, D, R> = self.into(); iter::successors(Some(me), move |el| match direction { Direction::Next => el.next_sibling_or_token(), Direction::Prev => el.prev_sibling_or_token(), @@ -942,7 +984,7 @@ impl SyntaxToken { } /// Next token in the tree (i.e, not necessary a sibling) - pub fn next_token(&self) -> Option<&SyntaxToken> { + pub fn next_token(&self) -> Option<&SyntaxToken> { match self.next_sibling_or_token() { Some(element) => element.first_token(), None => self @@ -954,7 +996,7 @@ impl SyntaxToken { } /// Previous token in the tree (i.e, not necessary a sibling) - pub fn prev_token(&self) -> Option<&SyntaxToken> { + pub fn prev_token(&self) -> Option<&SyntaxToken> { match self.prev_sibling_or_token() { Some(element) => element.last_token(), None => self @@ -966,14 +1008,42 @@ impl SyntaxToken { } } -impl SyntaxElement { +impl SyntaxToken +where + R: Resolver, +{ + #[inline] + pub fn text(&self) -> &str { + self.green().text(self.parent().resolver().as_ref()) + } +} + +impl fmt::Debug for SyntaxToken +where + R: Resolver, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", Self::debug(self, self.parent().resolver().as_ref())) + } +} + +impl fmt::Display for SyntaxToken +where + R: Resolver, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", Self::display(self, self.parent().resolver().as_ref())) + } +} + +impl SyntaxElement { fn new( element: GreenElementRef<'_>, - parent: &SyntaxNode, + parent: &SyntaxNode, index: u32, offset: TextSize, ref_count: *mut AtomicU32, - ) -> SyntaxElement { + ) -> SyntaxElement { match element { NodeOrToken::Node(node) => SyntaxNode::new_child(node, parent, index as u32, offset, ref_count).into(), NodeOrToken::Token(_) => SyntaxToken::new(parent, index as u32, offset).into(), @@ -1005,7 +1075,7 @@ impl SyntaxElement { } #[inline] - pub fn parent(&self) -> Option<&SyntaxNode> { + pub fn parent(&self) -> Option<&SyntaxNode> { match self { NodeOrToken::Node(it) => it.parent(), NodeOrToken::Token(it) => Some(it.parent()), @@ -1013,7 +1083,7 @@ impl SyntaxElement { } #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> { match self { NodeOrToken::Node(it) => it.ancestors(), NodeOrToken::Token(it) => it.parent().ancestors(), @@ -1021,7 +1091,7 @@ impl SyntaxElement { } #[inline] - pub fn first_token(&self) -> Option<&SyntaxToken> { + pub fn first_token(&self) -> Option<&SyntaxToken> { match self { NodeOrToken::Node(it) => it.first_token(), NodeOrToken::Token(it) => Some(it), @@ -1029,7 +1099,7 @@ impl SyntaxElement { } #[inline] - pub fn last_token(&self) -> Option<&SyntaxToken> { + pub fn last_token(&self) -> Option<&SyntaxToken> { match self { NodeOrToken::Node(it) => it.last_token(), NodeOrToken::Token(it) => Some(it), @@ -1037,7 +1107,7 @@ impl SyntaxElement { } #[inline] - pub fn next_sibling_or_token(&self) -> Option> { + pub fn next_sibling_or_token(&self) -> Option> { match self { NodeOrToken::Node(it) => it.next_sibling_or_token(), NodeOrToken::Token(it) => it.next_sibling_or_token(), @@ -1045,7 +1115,7 @@ impl SyntaxElement { } #[inline] - pub fn prev_sibling_or_token(&self) -> Option> { + pub fn prev_sibling_or_token(&self) -> Option> { match self { NodeOrToken::Node(it) => it.prev_sibling_or_token(), NodeOrToken::Token(it) => it.prev_sibling_or_token(), @@ -1053,7 +1123,7 @@ impl SyntaxElement { } } -impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { +impl<'a, L: Language, D, R> SyntaxElementRef<'a, L, D, R> { #[inline] pub fn text_range(&self) -> TextRange { match self { @@ -1079,7 +1149,7 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } #[inline] - pub fn parent(&self) -> Option<&'a SyntaxNode> { + pub fn parent(&self) -> Option<&'a SyntaxNode> { match self { NodeOrToken::Node(it) => it.parent(), NodeOrToken::Token(it) => Some(it.parent()), @@ -1087,7 +1157,7 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } #[inline] - pub fn ancestors(&self) -> impl Iterator> { + pub fn ancestors(&self) -> impl Iterator> { match self { NodeOrToken::Node(it) => it.ancestors(), NodeOrToken::Token(it) => it.parent().ancestors(), @@ -1095,7 +1165,7 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } #[inline] - pub fn first_token(&self) -> Option<&'a SyntaxToken> { + pub fn first_token(&self) -> Option<&'a SyntaxToken> { match self { NodeOrToken::Node(it) => it.first_token(), NodeOrToken::Token(it) => Some(it), @@ -1103,7 +1173,7 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } #[inline] - pub fn last_token(&self) -> Option<&'a SyntaxToken> { + pub fn last_token(&self) -> Option<&'a SyntaxToken> { match self { NodeOrToken::Node(it) => it.last_token(), NodeOrToken::Token(it) => Some(it), @@ -1111,7 +1181,7 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } #[inline] - pub fn next_sibling_or_token(&self) -> Option> { + pub fn next_sibling_or_token(&self) -> Option> { match self { NodeOrToken::Node(it) => it.next_sibling_or_token(), NodeOrToken::Token(it) => it.next_sibling_or_token(), @@ -1119,7 +1189,7 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } #[inline] - pub fn prev_sibling_or_token(&self) -> Option> { + pub fn prev_sibling_or_token(&self) -> Option> { match self { NodeOrToken::Node(it) => it.prev_sibling_or_token(), NodeOrToken::Token(it) => it.prev_sibling_or_token(), @@ -1127,7 +1197,7 @@ impl<'a, L: Language, D> SyntaxElementRef<'a, L, D> { } #[inline] - fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset> { + fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset> { assert!(self.text_range().start() <= offset && offset <= self.text_range().end()); match self { NodeOrToken::Token(token) => TokenAtOffset::Single((*token).clone()), @@ -1144,7 +1214,7 @@ struct Iter<'n> { } impl<'n> Iter<'n> { - fn new(parent: &'n SyntaxNode) -> Self { + fn new(parent: &'n SyntaxNode) -> Self { let offset = parent.text_range().start(); let green: Children<'_> = parent.green().children(); Iter { @@ -1167,14 +1237,14 @@ impl<'n> Iter<'n> { } #[derive(Clone)] -pub struct SyntaxNodeChildren<'n, L: Language, D: 'static = ()> { +pub struct SyntaxNodeChildren<'n, L: Language, D: 'static = (), R: 'static = ()> { inner: Iter<'n>, - parent: &'n SyntaxNode, + parent: &'n SyntaxNode, } -impl<'n, L: Language, D> SyntaxNodeChildren<'n, L, D> { +impl<'n, L: Language, D, R> SyntaxNodeChildren<'n, L, D, R> { #[inline] - fn new(parent: &'n SyntaxNode) -> Self { + fn new(parent: &'n SyntaxNode) -> Self { Self { inner: Iter::new(parent), parent, @@ -1182,8 +1252,8 @@ impl<'n, L: Language, D> SyntaxNodeChildren<'n, L, D> { } } -impl<'n, L: Language, D> Iterator for SyntaxNodeChildren<'n, L, D> { - type Item = &'n SyntaxNode; +impl<'n, L: Language, D, R> Iterator for SyntaxNodeChildren<'n, L, D, R> { + type Item = &'n SyntaxNode; #[inline(always)] fn next(&mut self) -> Option { @@ -1197,14 +1267,14 @@ impl<'n, L: Language, D> Iterator for SyntaxNodeChildren<'n, L, D> { } #[derive(Clone)] -pub struct SyntaxElementChildren<'n, L: Language, D: 'static = ()> { +pub struct SyntaxElementChildren<'n, L: Language, D: 'static = (), R: 'static = ()> { inner: Iter<'n>, - parent: &'n SyntaxNode, + parent: &'n SyntaxNode, } -impl<'n, L: Language, D> SyntaxElementChildren<'n, L, D> { +impl<'n, L: Language, D, R> SyntaxElementChildren<'n, L, D, R> { #[inline] - fn new(parent: &'n SyntaxNode) -> Self { + fn new(parent: &'n SyntaxNode) -> Self { Self { inner: Iter::new(parent), parent, @@ -1212,8 +1282,8 @@ impl<'n, L: Language, D> SyntaxElementChildren<'n, L, D> { } } -impl<'n, L: Language, D> Iterator for SyntaxElementChildren<'n, L, D> { - type Item = SyntaxElementRef<'n, L, D>; +impl<'n, L: Language, D, R> Iterator for SyntaxElementChildren<'n, L, D, R> { + type Item = SyntaxElementRef<'n, L, D, R>; #[inline(always)] fn next(&mut self) -> Option { diff --git a/src/syntax_text.rs b/src/syntax_text.rs index ea2b98a..b3cc668 100644 --- a/src/syntax_text.rs +++ b/src/syntax_text.rs @@ -3,14 +3,14 @@ use std::fmt; use crate::{interning::Resolver, Language, SyntaxNode, SyntaxToken, TextRange, TextSize}; #[derive(Clone)] -pub struct SyntaxText<'n, 'i, I: ?Sized, L: Language, D: 'static = ()> { - node: &'n SyntaxNode, +pub struct SyntaxText<'n, 'i, I: ?Sized, L: Language, D: 'static = (), R: 'static = ()> { + node: &'n SyntaxNode, range: TextRange, resolver: &'i I, } -impl<'n, 'i, I: Resolver + ?Sized, L: Language, D> SyntaxText<'n, 'i, I, L, D> { - pub(crate) fn new(node: &'n SyntaxNode, resolver: &'i I) -> Self { +impl<'n, 'i, I: Resolver + ?Sized, L: Language, D, R> SyntaxText<'n, 'i, I, L, D, R> { + pub(crate) fn new(node: &'n SyntaxNode, resolver: &'i I) -> Self { let range = node.text_range(); SyntaxText { node, range, resolver } } @@ -56,7 +56,7 @@ impl<'n, 'i, I: Resolver + ?Sized, L: Language, D> SyntaxText<'n, 'i, I, L, D> { found(res) } - pub fn slice(&self, range: R) -> Self { + pub fn slice(&self, range: Ra) -> Self { let start = range.start().unwrap_or_default(); let end = range.end().unwrap_or(self.len()); assert!(start <= end); @@ -88,7 +88,7 @@ impl<'n, 'i, I: Resolver + ?Sized, L: Language, D> SyntaxText<'n, 'i, I, L, D> { F: FnMut(T, &str) -> Result, { self.tokens_with_ranges().try_fold(init, move |acc, (token, range)| { - f(acc, &token.text(self.resolver)[range]) + f(acc, &token.resolve_text(self.resolver)[range]) }) } @@ -104,7 +104,7 @@ impl<'n, 'i, I: Resolver + ?Sized, L: Language, D> SyntaxText<'n, 'i, I, L, D> { } } - fn tokens_with_ranges(&self) -> impl Iterator, TextRange)> { + fn tokens_with_ranges(&self) -> impl Iterator, TextRange)> { let text_range = self.range; self.node .descendants_with_tokens() @@ -124,25 +124,25 @@ fn found(res: Result<(), T>) -> Option { } } -impl fmt::Debug for SyntaxText<'_, '_, I, L, D> { +impl fmt::Debug for SyntaxText<'_, '_, I, L, D, R> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.to_string(), f) } } -impl fmt::Display for SyntaxText<'_, '_, I, L, D> { +impl fmt::Display for SyntaxText<'_, '_, I, L, D, R> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.try_for_each_chunk(|chunk| fmt::Display::fmt(chunk, f)) } } -impl From> for String { - fn from(text: SyntaxText<'_, '_, I, L, D>) -> String { +impl From> for String { + fn from(text: SyntaxText<'_, '_, I, L, D, R>) -> String { text.to_string() } } -impl PartialEq for SyntaxText<'_, '_, I, L, D> { +impl PartialEq for SyntaxText<'_, '_, I, L, D, R> { fn eq(&self, mut rhs: &str) -> bool { self.try_for_each_chunk(|chunk| { if !rhs.starts_with(chunk) { @@ -156,33 +156,33 @@ impl PartialEq for SyntaxText<'_, '_, } } -impl PartialEq> for str { - fn eq(&self, rhs: &SyntaxText<'_, '_, I, L, D>) -> bool { +impl PartialEq> for str { + fn eq(&self, rhs: &SyntaxText<'_, '_, I, L, D, R>) -> bool { rhs == self } } -impl PartialEq<&'_ str> for SyntaxText<'_, '_, I, L, D> { +impl PartialEq<&'_ str> for SyntaxText<'_, '_, I, L, D, R> { fn eq(&self, rhs: &&str) -> bool { self == *rhs } } -impl PartialEq> for &'_ str { - fn eq(&self, rhs: &SyntaxText<'_, '_, I, L, D>) -> bool { +impl PartialEq> for &'_ str { + fn eq(&self, rhs: &SyntaxText<'_, '_, I, L, D, R>) -> bool { rhs == self } } -impl<'n1, 'i1, 'n2, 'i2, I1, I2, D1, D2, L1, L2> PartialEq> - for SyntaxText<'n1, 'i1, I1, L1, D1> +impl<'n1, 'i1, 'n2, 'i2, I1, I2, L1, L2, D1, D2, R1, R2> PartialEq> + for SyntaxText<'n1, 'i1, I1, L1, D1, R1> where L1: Language, L2: Language, I1: Resolver + ?Sized, I2: Resolver + ?Sized, { - fn eq(&self, other: &SyntaxText<'_, '_, I2, L2, D2>) -> bool { + fn eq(&self, other: &SyntaxText<'_, '_, I2, L2, D2, R2>) -> bool { if self.range.len() != other.range.len() { return false; } @@ -194,19 +194,21 @@ where } } -fn zip_texts<'it1, 'it2, It1, It2, I1, I2, L1, L2, D1, D2>( +fn zip_texts<'it1, 'it2, It1, It2, I1, I2, L1, L2, D1, D2, R1, R2>( xs: &mut It1, ys: &mut It2, resolver_x: &I1, resolver_y: &I2, ) -> Option<()> where - It1: Iterator, TextRange)>, - It2: Iterator, TextRange)>, + It1: Iterator, TextRange)>, + It2: Iterator, TextRange)>, I1: Resolver + ?Sized, I2: Resolver + ?Sized, D1: 'static, D2: 'static, + R1: 'static, + R2: 'static, L1: Language + 'it1, L2: Language + 'it2, { @@ -219,8 +221,8 @@ where while y.1.is_empty() { y = ys.next()?; } - let x_text = &x.0.text(resolver_x)[x.1]; - let y_text = &y.0.text(resolver_y)[y.1]; + let x_text = &x.0.resolve_text(resolver_x)[x.1]; + let y_text = &y.0.resolve_text(resolver_y)[y.1]; if !(x_text.starts_with(y_text) || y_text.starts_with(x_text)) { return Some(()); } @@ -328,9 +330,9 @@ mod tests { fn test_text_equality() { fn do_check(t1: &[&str], t2: &[&str]) { let (t1, resolver) = build_tree(t1); - let t1 = t1.text(&resolver); + let t1 = t1.resolve_text(&resolver); let (t2, resolver) = build_tree(t2); - let t2 = t2.text(&resolver); + let t2 = t2.resolve_text(&resolver); let expected = t1.to_string() == t2.to_string(); let actual = t1 == t2; assert_eq!(expected, actual, "`{}` (SyntaxText) `{}` (SyntaxText)", t1, t2); diff --git a/tests/basic.rs b/tests/basic.rs index 382092d..54ea9f5 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -1,8 +1,10 @@ mod common; use common::TestLang; -use cstree::{GreenNodeBuilder, SyntaxKind, SyntaxNode, TextRange}; -use lasso::Resolver; +use cstree::{GreenNode, GreenNodeBuilder, NodeCache, SyntaxKind, TextRange}; +use lasso::{Interner, Resolver, Rodeo}; + +type SyntaxNode = cstree::SyntaxNode; #[derive(Debug)] enum Element<'s> { @@ -19,14 +21,28 @@ fn two_level_tree() -> Element<'static> { ]) } -fn build_tree(root: &Element<'_>) -> (SyntaxNode, impl Resolver) { +fn build_tree(root: &Element<'_>) -> (SyntaxNode, impl Resolver) { let mut builder = GreenNodeBuilder::new(); build_recursive(root, &mut builder, 0); let (node, interner) = builder.finish(); (SyntaxNode::new_root(node), interner.unwrap()) } -fn build_recursive(root: &Element<'_>, builder: &mut GreenNodeBuilder, mut from: u16) -> u16 { +fn build_tree_with_cache<'c, 'i, I>(root: &Element<'_>, cache: &'c mut NodeCache<'i, I>) -> GreenNode +where + I: Interner, +{ + let mut builder = GreenNodeBuilder::with_cache(cache); + build_recursive(root, &mut builder, 0); + let (node, interner) = builder.finish(); + assert!(interner.is_none()); + node +} + +fn build_recursive<'c, 'i, I>(root: &Element<'_>, builder: &mut GreenNodeBuilder<'c, 'i, I>, mut from: u16) -> u16 +where + I: Interner, +{ match root { Element::Node(children) => { builder.start_node(SyntaxKind(from)); @@ -53,7 +69,7 @@ fn create() { let leaf1_0 = leaf1_0.into_token().unwrap(); assert_eq!(leaf1_0.syntax_kind(), SyntaxKind(5)); assert_eq!(leaf1_0.kind(), SyntaxKind(5)); - assert_eq!(leaf1_0.text(&resolver), "1.0"); + assert_eq!(leaf1_0.resolve_text(&resolver), "1.0"); assert_eq!(leaf1_0.text_range(), TextRange::at(6.into(), 3.into())); } { @@ -61,7 +77,7 @@ fn create() { assert_eq!(node2.syntax_kind(), SyntaxKind(6)); assert_eq!(node2.kind(), SyntaxKind(6)); assert_eq!(node2.children_with_tokens().count(), 3); - assert_eq!(node2.text(&resolver), "2.02.12.2"); + assert_eq!(node2.resolve_text(&resolver), "2.02.12.2"); } } @@ -98,3 +114,56 @@ fn data() { assert_eq!(node2.get_data(), None); } } + +#[test] +fn with_interner() { + let mut interner = Rodeo::new(); + let mut cache = NodeCache::with_interner(&mut interner); + let tree = two_level_tree(); + let tree = build_tree_with_cache(&tree, &mut cache); + let tree: SyntaxNode = SyntaxNode::new_root(tree); + let resolver = interner; + { + let leaf1_0 = tree.children().nth(1).unwrap().children_with_tokens().nth(0).unwrap(); + let leaf1_0 = leaf1_0.into_token().unwrap(); + assert_eq!(leaf1_0.resolve_text(&resolver), "1.0"); + assert_eq!(leaf1_0.text_range(), TextRange::at(6.into(), 3.into())); + } + { + let node2 = tree.children().nth(2).unwrap(); + assert_eq!(node2.resolve_text(&resolver), "2.02.12.2"); + } +} + +#[test] +fn inline_resolver() { + let mut interner = Rodeo::new(); + let mut cache = NodeCache::with_interner(&mut interner); + let tree = two_level_tree(); + let tree = build_tree_with_cache(&tree, &mut cache); + let tree: SyntaxNode<(), Rodeo> = SyntaxNode::new_root_with_resolver(tree, interner); + { + let leaf1_0 = tree.children().nth(1).unwrap().children_with_tokens().nth(0).unwrap(); + let leaf1_0 = leaf1_0.into_token().unwrap(); + assert_eq!(leaf1_0.text(), "1.0"); + assert_eq!(leaf1_0.text_range(), TextRange::at(6.into(), 3.into())); + assert_eq!(format!("{}", leaf1_0), leaf1_0.text()); + assert_eq!(format!("{:?}", leaf1_0), "SyntaxKind(5)@6..9 \"1.0\""); + } + { + let node2 = tree.children().nth(2).unwrap(); + assert_eq!(node2.text(), "2.02.12.2"); + let resolver = node2.resolver(); + assert_eq!(node2.resolve_text(resolver.as_ref()), node2.text()); + assert_eq!(format!("{}", node2).as_str(), node2.text()); + assert_eq!(format!("{:?}", node2), "SyntaxKind(6)@9..18"); + assert_eq!( + format!("{:#?}", node2), + r#"SyntaxKind(6)@9..18 + SyntaxKind(7)@9..12 "2.0" + SyntaxKind(8)@12..15 "2.1" + SyntaxKind(9)@15..18 "2.2" +"# + ); + } +}