mirror of
https://github.com/RGBCube/cstree
synced 2025-07-27 17:17:45 +00:00
Merge pull request #31 from domenicquirl/interning-exports
This commit is contained in:
commit
08d381612c
16 changed files with 464 additions and 230 deletions
|
@ -15,7 +15,7 @@ readme = "README.md"
|
||||||
debug = true
|
debug = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lasso = { version = "0.6", features = ["inline-more"] }
|
lasso = { version = "0.6", features = ["inline-more", "multi-threaded"] }
|
||||||
text-size = "1.1.0"
|
text-size = "1.1.0"
|
||||||
fxhash = "0.2.1"
|
fxhash = "0.2.1"
|
||||||
parking_lot = "0.11.2"
|
parking_lot = "0.11.2"
|
||||||
|
@ -41,8 +41,8 @@ name = "main"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
serde1 = ["serde"]
|
serialize = ["serde", "lasso/serialize"]
|
||||||
|
|
||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["serde1"]
|
features = ["serialize"]
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
mod builder;
|
mod builder;
|
||||||
mod element;
|
mod element;
|
||||||
mod interner;
|
mod interner;
|
||||||
|
mod iter;
|
||||||
mod node;
|
mod node;
|
||||||
mod token;
|
mod token;
|
||||||
|
|
||||||
|
@ -14,7 +15,8 @@ use self::element::{GreenElement, PackedGreenElement};
|
||||||
pub use self::{
|
pub use self::{
|
||||||
builder::{Checkpoint, GreenNodeBuilder, NodeCache},
|
builder::{Checkpoint, GreenNodeBuilder, NodeCache},
|
||||||
interner::TokenInterner,
|
interner::TokenInterner,
|
||||||
node::{Children, GreenNode},
|
iter::GreenNodeChildren,
|
||||||
|
node::GreenNode,
|
||||||
token::GreenToken,
|
token::GreenToken,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -356,6 +356,26 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shortcut to construct a builder that uses an existing interner.
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`from_cache`](GreenNodeBuilder::from_cache) with a node cache
|
||||||
|
/// obtained from [`NodeCache::with_interner`].
|
||||||
|
#[inline]
|
||||||
|
pub fn with_interner(interner: &'interner mut I) -> Self {
|
||||||
|
let cache = NodeCache::with_interner(interner);
|
||||||
|
Self::from_cache(cache)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Shortcut to construct a builder that uses an existing interner.
|
||||||
|
///
|
||||||
|
/// This is equivalent to using [`from_cache`](GreenNodeBuilder::from_cache) with a node cache
|
||||||
|
/// obtained from [`NodeCache::from_interner`].
|
||||||
|
#[inline]
|
||||||
|
pub fn from_interner(interner: I) -> Self {
|
||||||
|
let cache = NodeCache::from_interner(interner);
|
||||||
|
Self::from_cache(cache)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a reference to the interner used to deduplicate source text (strings).
|
/// Get a reference to the interner used to deduplicate source text (strings).
|
||||||
///
|
///
|
||||||
/// This is the same interner as used by the underlying [`NodeCache`].
|
/// This is the same interner as used by the underlying [`NodeCache`].
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use std::num::NonZeroUsize;
|
use std::num::NonZeroUsize;
|
||||||
|
|
||||||
|
use crate::interning::{
|
||||||
|
Capacity, Interner, IntoReader, IntoReaderAndResolver, IntoResolver, Key, Reader, Resolver, Rodeo,
|
||||||
|
};
|
||||||
use fxhash::FxBuildHasher;
|
use fxhash::FxBuildHasher;
|
||||||
use lasso::{Capacity, Interner, IntoReader, IntoReaderAndResolver, IntoResolver, Reader, Resolver, Rodeo, Spur};
|
|
||||||
|
|
||||||
/// The default [`Interner`] used to deduplicate green token strings.
|
/// The default [`Interner`] used to deduplicate green token strings.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TokenInterner {
|
pub struct TokenInterner {
|
||||||
rodeo: Rodeo<Spur, FxBuildHasher>,
|
rodeo: Rodeo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TokenInterner {
|
impl TokenInterner {
|
||||||
|
@ -23,22 +25,22 @@ impl TokenInterner {
|
||||||
|
|
||||||
impl Resolver for TokenInterner {
|
impl Resolver for TokenInterner {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn resolve<'a>(&'a self, key: &Spur) -> &'a str {
|
fn resolve<'a>(&'a self, key: &Key) -> &'a str {
|
||||||
self.rodeo.resolve(key)
|
self.rodeo.resolve(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_resolve<'a>(&'a self, key: &Spur) -> Option<&'a str> {
|
fn try_resolve<'a>(&'a self, key: &Key) -> Option<&'a str> {
|
||||||
self.rodeo.try_resolve(key)
|
self.rodeo.try_resolve(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn resolve_unchecked<'a>(&'a self, key: &Spur) -> &'a str {
|
unsafe fn resolve_unchecked<'a>(&'a self, key: &Key) -> &'a str {
|
||||||
self.rodeo.resolve_unchecked(key)
|
self.rodeo.resolve_unchecked(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn contains_key(&self, key: &Spur) -> bool {
|
fn contains_key(&self, key: &Key) -> bool {
|
||||||
self.rodeo.contains_key(key)
|
self.rodeo.contains_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +52,7 @@ impl Resolver for TokenInterner {
|
||||||
|
|
||||||
impl Reader for TokenInterner {
|
impl Reader for TokenInterner {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(&self, val: &str) -> Option<Spur> {
|
fn get(&self, val: &str) -> Option<Key> {
|
||||||
self.rodeo.get(val)
|
self.rodeo.get(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +63,7 @@ impl Reader for TokenInterner {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoResolver for TokenInterner {
|
impl IntoResolver for TokenInterner {
|
||||||
type Resolver = <Rodeo<Spur, FxBuildHasher> as IntoResolver>::Resolver;
|
type Resolver = <Rodeo as IntoResolver>::Resolver;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_resolver(self) -> Self::Resolver
|
fn into_resolver(self) -> Self::Resolver
|
||||||
|
@ -76,34 +78,34 @@ impl IntoResolver for TokenInterner {
|
||||||
where
|
where
|
||||||
Self: 'static,
|
Self: 'static,
|
||||||
{
|
{
|
||||||
Rodeo::<Spur, FxBuildHasher>::into_resolver_boxed(Box::new(self.rodeo))
|
Rodeo::into_resolver_boxed(Box::new(self.rodeo))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Interner for TokenInterner {
|
impl Interner for TokenInterner {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_or_intern(&mut self, val: &str) -> Spur {
|
fn get_or_intern(&mut self, val: &str) -> Key {
|
||||||
self.rodeo.get_or_intern(val)
|
self.rodeo.get_or_intern(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_get_or_intern(&mut self, val: &str) -> lasso::LassoResult<Spur> {
|
fn try_get_or_intern(&mut self, val: &str) -> lasso::LassoResult<Key> {
|
||||||
self.rodeo.try_get_or_intern(val)
|
self.rodeo.try_get_or_intern(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_or_intern_static(&mut self, val: &'static str) -> Spur {
|
fn get_or_intern_static(&mut self, val: &'static str) -> Key {
|
||||||
self.rodeo.get_or_intern_static(val)
|
self.rodeo.get_or_intern_static(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_get_or_intern_static(&mut self, val: &'static str) -> lasso::LassoResult<Spur> {
|
fn try_get_or_intern_static(&mut self, val: &'static str) -> lasso::LassoResult<Key> {
|
||||||
self.rodeo.try_get_or_intern_static(val)
|
self.rodeo.try_get_or_intern_static(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoReader for TokenInterner {
|
impl IntoReader for TokenInterner {
|
||||||
type Reader = <Rodeo<Spur, FxBuildHasher> as IntoReader>::Reader;
|
type Reader = <Rodeo as IntoReader>::Reader;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_reader(self) -> Self::Reader
|
fn into_reader(self) -> Self::Reader
|
||||||
|
@ -117,7 +119,7 @@ impl IntoReader for TokenInterner {
|
||||||
where
|
where
|
||||||
Self: 'static,
|
Self: 'static,
|
||||||
{
|
{
|
||||||
Rodeo::<Spur, FxBuildHasher>::into_reader_boxed(Box::new(self.rodeo))
|
Rodeo::into_reader_boxed(Box::new(self.rodeo))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
92
src/green/iter.rs
Normal file
92
src/green/iter.rs
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
//! Green tree iterators.
|
||||||
|
|
||||||
|
use std::{iter::FusedIterator, slice};
|
||||||
|
|
||||||
|
use super::{element::PackedGreenElement, GreenElementRef};
|
||||||
|
|
||||||
|
/// An iterator over a [`GreenNode`](crate::GreenNode)'s children.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GreenNodeChildren<'a> {
|
||||||
|
pub(super) inner: slice::Iter<'a, PackedGreenElement>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB: forward everything stable that iter::Slice specializes as of Rust 1.39.0
|
||||||
|
impl ExactSizeIterator for GreenNodeChildren<'_> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Iterator for GreenNodeChildren<'a> {
|
||||||
|
type Item = GreenElementRef<'a>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn next(&mut self) -> Option<GreenElementRef<'a>> {
|
||||||
|
self.inner.next().map(PackedGreenElement::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.inner.size_hint()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn count(self) -> usize
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.inner.count()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
self.inner.nth(n).map(PackedGreenElement::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn last(mut self) -> Option<Self::Item>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.next_back()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn fold<Acc, Fold>(self, init: Acc, mut f: Fold) -> Acc
|
||||||
|
where
|
||||||
|
Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||||
|
{
|
||||||
|
let mut accum = init;
|
||||||
|
for x in self {
|
||||||
|
accum = f(accum, x);
|
||||||
|
}
|
||||||
|
accum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DoubleEndedIterator for GreenNodeChildren<'a> {
|
||||||
|
#[inline]
|
||||||
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
|
self.inner.next_back().map(PackedGreenElement::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
self.inner.nth_back(n).map(PackedGreenElement::as_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn rfold<Acc, Fold>(mut self, init: Acc, mut f: Fold) -> Acc
|
||||||
|
where
|
||||||
|
Fold: FnMut(Acc, Self::Item) -> Acc,
|
||||||
|
{
|
||||||
|
let mut accum = init;
|
||||||
|
while let Some(x) = self.next_back() {
|
||||||
|
accum = f(accum, x);
|
||||||
|
}
|
||||||
|
accum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FusedIterator for GreenNodeChildren<'_> {}
|
|
@ -1,13 +1,12 @@
|
||||||
use std::{
|
use std::{
|
||||||
hash::{Hash, Hasher},
|
hash::{Hash, Hasher},
|
||||||
iter::FusedIterator,
|
|
||||||
slice,
|
slice,
|
||||||
};
|
};
|
||||||
|
|
||||||
use fxhash::FxHasher32;
|
use fxhash::FxHasher32;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
green::{GreenElement, GreenElementRef, PackedGreenElement, SyntaxKind},
|
green::{iter::GreenNodeChildren, GreenElement, PackedGreenElement, SyntaxKind},
|
||||||
TextSize,
|
TextSize,
|
||||||
};
|
};
|
||||||
use triomphe::{Arc, HeaderWithLength, ThinArc};
|
use triomphe::{Arc, HeaderWithLength, ThinArc};
|
||||||
|
@ -135,8 +134,8 @@ impl GreenNode {
|
||||||
|
|
||||||
/// Iterator over all children of this node.
|
/// Iterator over all children of this node.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn children(&self) -> Children<'_> {
|
pub fn children(&self) -> GreenNodeChildren<'_> {
|
||||||
Children {
|
GreenNodeChildren {
|
||||||
inner: self.data.slice.iter(),
|
inner: self.data.slice.iter(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,90 +155,3 @@ impl PartialEq for GreenNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for GreenNode {}
|
impl Eq for GreenNode {}
|
||||||
|
|
||||||
/// An iterator over a [`GreenNode`]'s children.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Children<'a> {
|
|
||||||
inner: slice::Iter<'a, PackedGreenElement>,
|
|
||||||
}
|
|
||||||
|
|
||||||
// NB: forward everything stable that iter::Slice specializes as of Rust 1.39.0
|
|
||||||
impl ExactSizeIterator for Children<'_> {
|
|
||||||
#[inline(always)]
|
|
||||||
fn len(&self) -> usize {
|
|
||||||
self.inner.len()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Iterator for Children<'a> {
|
|
||||||
type Item = GreenElementRef<'a>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn next(&mut self) -> Option<GreenElementRef<'a>> {
|
|
||||||
self.inner.next().map(PackedGreenElement::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
|
||||||
self.inner.size_hint()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn count(self) -> usize
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
self.inner.count()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
|
||||||
self.inner.nth(n).map(PackedGreenElement::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn last(mut self) -> Option<Self::Item>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
self.next_back()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn fold<Acc, Fold>(self, init: Acc, mut f: Fold) -> Acc
|
|
||||||
where
|
|
||||||
Fold: FnMut(Acc, Self::Item) -> Acc,
|
|
||||||
{
|
|
||||||
let mut accum = init;
|
|
||||||
for x in self {
|
|
||||||
accum = f(accum, x);
|
|
||||||
}
|
|
||||||
accum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> DoubleEndedIterator for Children<'a> {
|
|
||||||
#[inline]
|
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
|
||||||
self.inner.next_back().map(PackedGreenElement::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
|
||||||
self.inner.nth_back(n).map(PackedGreenElement::as_ref)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rfold<Acc, Fold>(mut self, init: Acc, mut f: Fold) -> Acc
|
|
||||||
where
|
|
||||||
Fold: FnMut(Acc, Self::Item) -> Acc,
|
|
||||||
{
|
|
||||||
let mut accum = init;
|
|
||||||
while let Some(x) = self.next_back() {
|
|
||||||
accum = f(accum, x);
|
|
||||||
}
|
|
||||||
accum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FusedIterator for Children<'_> {}
|
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
use std::{fmt, hash, mem::ManuallyDrop, ptr};
|
use std::{fmt, hash, mem::ManuallyDrop, ptr};
|
||||||
|
|
||||||
use crate::{green::SyntaxKind, interning::Resolver, TextSize};
|
use crate::{
|
||||||
use lasso::Spur;
|
green::SyntaxKind,
|
||||||
|
interning::{Key, Resolver},
|
||||||
|
TextSize,
|
||||||
|
};
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
|
|
||||||
#[repr(align(2))] // to use 1 bit for pointer tagging. NB: this is an at-least annotation
|
#[repr(align(2))] // to use 1 bit for pointer tagging. NB: this is an at-least annotation
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
|
||||||
pub(super) struct GreenTokenData {
|
pub(super) struct GreenTokenData {
|
||||||
pub(super) kind: SyntaxKind,
|
pub(super) kind: SyntaxKind,
|
||||||
pub(super) text: Spur,
|
pub(super) text: Key,
|
||||||
pub(super) text_len: TextSize,
|
pub(super) text_len: TextSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,8 +73,12 @@ impl GreenToken {
|
||||||
self.data().text_len
|
self.data().text_len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the interned key of text covered by this token.
|
||||||
|
/// This key may be used for comparisons with other keys of strings interned by the same interner.
|
||||||
|
///
|
||||||
|
/// See also [`text`](GreenToken::text).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn text_key(&self) -> Spur {
|
pub fn text_key(&self) -> Key {
|
||||||
self.data().text
|
self.data().text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
47
src/interning.rs
Normal file
47
src/interning.rs
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
//! Types and Traits for efficient String storage and deduplication.
|
||||||
|
//!
|
||||||
|
//! Interning functionality is provided by the [`lasso`](lasso) crate.
|
||||||
|
|
||||||
|
pub use fxhash::FxBuildHasher as Hasher;
|
||||||
|
|
||||||
|
pub use crate::green::TokenInterner;
|
||||||
|
|
||||||
|
/// The index type for all interners. Each key represents
|
||||||
|
pub type Key = lasso::Spur;
|
||||||
|
pub use lasso::{Interner, IntoReader, IntoReaderAndResolver, IntoResolver, Reader, Resolver};
|
||||||
|
|
||||||
|
/// A string interner that caches strings quickly with a minimal memory footprint, returning a unique key to re-access
|
||||||
|
/// it with `O(1)` times. By default, `Rodeo` uses an [`fxhash`] [`Hasher`].
|
||||||
|
pub type Rodeo<S = Hasher> = lasso::Rodeo<Key, S>;
|
||||||
|
|
||||||
|
/// Constructs a new, single-threaded interner.
|
||||||
|
///
|
||||||
|
/// If you need the interner to be multi-threaded, see [`new_threaded_interner`].
|
||||||
|
#[inline]
|
||||||
|
pub fn new_interner() -> Rodeo {
|
||||||
|
Rodeo::with_hasher(Hasher::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A string interner that caches strings quickly with a minimal memory footprint, returning a unique key to re-access
|
||||||
|
/// it with `O(1)` times. By default, `ThreadedRodeo` uses an [`fxhash`] [`Hasher`].
|
||||||
|
pub type ThreadedRodeo<S = Hasher> = lasso::ThreadedRodeo<Key, S>;
|
||||||
|
|
||||||
|
/// Constructs a new interner that can be used across multiple threads.
|
||||||
|
#[inline]
|
||||||
|
pub fn new_threaded_interner() -> ThreadedRodeo {
|
||||||
|
ThreadedRodeo::with_hasher(Hasher::default())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A read-only view of a [`Rodeo`] or [`ThreadedRodeo`] that allows contention-free access to interned strings, both
|
||||||
|
/// key to string resolution and string to key lookups.
|
||||||
|
///
|
||||||
|
/// The hasher is the same as the Rodeo or ThreadedRodeo that created it.
|
||||||
|
/// Can be acquired with the `into_reader` methods (see also [`IntoReader`]).
|
||||||
|
pub type RodeoReader<S = Hasher> = lasso::RodeoReader<Key, S>;
|
||||||
|
|
||||||
|
/// A read-only view of a [`Rodeo`] or [`ThreadedRodeo`] that allows contention-free access to interned strings with
|
||||||
|
/// only key to string resolution.
|
||||||
|
///
|
||||||
|
/// Can be acquired with the `into_resolver` methods (see also [`IntoResolver`]).
|
||||||
|
pub type RodeoResolver = lasso::RodeoResolver<Key>;
|
||||||
|
pub use lasso::{Capacity, Iter, LassoError, LassoErrorKind, LassoResult, MemoryLimits, Strings};
|
15
src/lib.rs
15
src/lib.rs
|
@ -49,26 +49,23 @@
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
mod green;
|
mod green;
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub mod syntax;
|
mod syntax;
|
||||||
|
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serialize")]
|
||||||
mod serde_impls;
|
mod serde_impls;
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
mod utility_types;
|
mod utility_types;
|
||||||
|
|
||||||
/// Types and Traits for efficient String storage and deduplication.
|
pub mod interning;
|
||||||
pub mod interning {
|
|
||||||
pub use crate::green::TokenInterner;
|
|
||||||
pub use lasso::{Interner, IntoReader, IntoReaderAndResolver, IntoResolver, Reader, Resolver};
|
|
||||||
}
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
// Reexport types for working with strings.
|
// Reexport types for working with strings.
|
||||||
pub use text_size::{TextLen, TextRange, TextSize};
|
pub use text_size::{TextLen, TextRange, TextSize};
|
||||||
|
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use crate::syntax::*;
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
green::{Checkpoint, Children, GreenNode, GreenNodeBuilder, GreenToken, NodeCache, SyntaxKind},
|
green::{Checkpoint, GreenNode, GreenNodeBuilder, GreenNodeChildren, GreenToken, NodeCache, SyntaxKind},
|
||||||
syntax::*,
|
|
||||||
utility_types::{Direction, NodeOrToken, TokenAtOffset, WalkEvent},
|
utility_types::{Direction, NodeOrToken, TokenAtOffset, WalkEvent},
|
||||||
};
|
};
|
||||||
pub use triomphe::Arc;
|
pub use triomphe::Arc;
|
||||||
|
|
164
src/syntax/iter.rs
Normal file
164
src/syntax/iter.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
//! Red tree iterators.
|
||||||
|
|
||||||
|
use std::iter::FusedIterator;
|
||||||
|
|
||||||
|
use text_size::TextSize;
|
||||||
|
|
||||||
|
use crate::{green::GreenElementRef, GreenNodeChildren, Language, SyntaxElementRef, SyntaxNode};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Iter<'n> {
|
||||||
|
green: GreenNodeChildren<'n>,
|
||||||
|
offset: TextSize,
|
||||||
|
index: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n> Iter<'n> {
|
||||||
|
fn new<L: Language, D>(parent: &'n SyntaxNode<L, D>) -> Self {
|
||||||
|
let offset = parent.text_range().start();
|
||||||
|
let green: GreenNodeChildren<'_> = parent.green().children();
|
||||||
|
Iter {
|
||||||
|
green,
|
||||||
|
offset,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n> Iterator for Iter<'n> {
|
||||||
|
type Item = (GreenElementRef<'n>, usize, TextSize);
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
self.green.next().map(|element| {
|
||||||
|
let offset = self.offset;
|
||||||
|
let index = self.index;
|
||||||
|
self.offset += element.text_len();
|
||||||
|
self.index += 1;
|
||||||
|
(element, index, offset)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.green.size_hint()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn count(self) -> usize
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.green.count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n> ExactSizeIterator for Iter<'n> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.green.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n> FusedIterator for Iter<'n> {}
|
||||||
|
|
||||||
|
/// An iterator over the child nodes of a [`SyntaxNode`].
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SyntaxNodeChildren<'n, L: Language, D: 'static = ()> {
|
||||||
|
inner: Iter<'n>,
|
||||||
|
parent: &'n SyntaxNode<L, D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n, L: Language, D> SyntaxNodeChildren<'n, L, D> {
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn new(parent: &'n SyntaxNode<L, D>) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Iter::new(parent),
|
||||||
|
parent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n, L: Language, D> Iterator for SyntaxNodeChildren<'n, L, D> {
|
||||||
|
type Item = &'n SyntaxNode<L, D>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
for (element, index, offset) in &mut self.inner {
|
||||||
|
if let Some(&node) = element.as_node() {
|
||||||
|
return Some(self.parent.get_or_add_node(node, index, offset).as_node().unwrap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.inner.size_hint()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn count(self) -> usize
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.inner.count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n, L: Language, D> ExactSizeIterator for SyntaxNodeChildren<'n, L, D> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, L: Language, D> FusedIterator for SyntaxNodeChildren<'n, L, D> {}
|
||||||
|
|
||||||
|
/// An iterator over the children of a [`SyntaxNode`].
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct SyntaxElementChildren<'n, L: Language, D: 'static = ()> {
|
||||||
|
inner: Iter<'n>,
|
||||||
|
parent: &'n SyntaxNode<L, D>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n, L: Language, D> SyntaxElementChildren<'n, L, D> {
|
||||||
|
#[inline]
|
||||||
|
pub(super) fn new(parent: &'n SyntaxNode<L, D>) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Iter::new(parent),
|
||||||
|
parent,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n, L: Language, D> Iterator for SyntaxElementChildren<'n, L, D> {
|
||||||
|
type Item = SyntaxElementRef<'n, L, D>;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let parent = self.parent;
|
||||||
|
self.inner
|
||||||
|
.next()
|
||||||
|
.map(|(green, index, offset)| parent.get_or_add_element(green, index, offset))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
|
self.inner.size_hint()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn count(self) -> usize
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.inner.count()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'n, L: Language, D> ExactSizeIterator for SyntaxElementChildren<'n, L, D> {
|
||||||
|
#[inline(always)]
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.inner.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'n, L: Language, D> FusedIterator for SyntaxElementChildren<'n, L, D> {}
|
|
@ -8,11 +8,13 @@
|
||||||
mod element;
|
mod element;
|
||||||
pub use element::{SyntaxElement, SyntaxElementRef};
|
pub use element::{SyntaxElement, SyntaxElementRef};
|
||||||
mod node;
|
mod node;
|
||||||
pub use node::{SyntaxElementChildren, SyntaxNode, SyntaxNodeChildren};
|
pub use node::SyntaxNode;
|
||||||
mod token;
|
mod token;
|
||||||
pub use token::SyntaxToken;
|
pub use token::SyntaxToken;
|
||||||
mod resolved;
|
mod resolved;
|
||||||
pub use resolved::{ResolvedElement, ResolvedElementRef, ResolvedNode, ResolvedToken};
|
pub use resolved::{ResolvedElement, ResolvedElementRef, ResolvedNode, ResolvedToken};
|
||||||
|
mod iter;
|
||||||
|
pub use iter::{SyntaxElementChildren, SyntaxNodeChildren};
|
||||||
|
|
||||||
mod text;
|
mod text;
|
||||||
pub use text::SyntaxText;
|
pub use text::SyntaxText;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serialize")]
|
||||||
use crate::serde_impls::{SerializeWithData, SerializeWithResolver};
|
use crate::serde_impls::{SerializeWithData, SerializeWithResolver};
|
||||||
use crate::{
|
use crate::{
|
||||||
green::{GreenElementRef, SyntaxKind},
|
green::{GreenElementRef, SyntaxKind},
|
||||||
|
@ -507,7 +507,12 @@ impl<L: Language, D> SyntaxNode<L, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get_or_add_node(&self, node: &GreenNode, index: usize, offset: TextSize) -> SyntaxElementRef<'_, L, D> {
|
pub(super) fn get_or_add_node(
|
||||||
|
&self,
|
||||||
|
node: &GreenNode,
|
||||||
|
index: usize,
|
||||||
|
offset: TextSize,
|
||||||
|
) -> SyntaxElementRef<'_, L, D> {
|
||||||
if let Some(elem) = self.read(index) {
|
if let Some(elem) = self.read(index) {
|
||||||
debug_assert_eq!(elem.text_range().start(), offset);
|
debug_assert_eq!(elem.text_range().start(), offset);
|
||||||
return elem;
|
return elem;
|
||||||
|
@ -520,7 +525,7 @@ impl<L: Language, D> SyntaxNode<L, D> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn get_or_add_element(
|
pub(super) fn get_or_add_element(
|
||||||
&self,
|
&self,
|
||||||
element: GreenElementRef<'_>,
|
element: GreenElementRef<'_>,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
@ -946,7 +951,7 @@ impl<L: Language, D> SyntaxNode<L, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serialize")]
|
||||||
impl<L, D> SyntaxNode<L, D>
|
impl<L, D> SyntaxNode<L, D>
|
||||||
where
|
where
|
||||||
L: Language,
|
L: Language,
|
||||||
|
@ -973,96 +978,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct Iter<'n> {
|
|
||||||
green: Children<'n>,
|
|
||||||
offset: TextSize,
|
|
||||||
index: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'n> Iter<'n> {
|
|
||||||
fn new<L: Language, D>(parent: &'n SyntaxNode<L, D>) -> Self {
|
|
||||||
let offset = parent.text_range().start();
|
|
||||||
let green: Children<'_> = parent.green().children();
|
|
||||||
Iter {
|
|
||||||
green,
|
|
||||||
offset,
|
|
||||||
index: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn next(&mut self) -> Option<(GreenElementRef, usize, TextSize)> {
|
|
||||||
self.green.next().map(|element| {
|
|
||||||
let offset = self.offset;
|
|
||||||
let index = self.index;
|
|
||||||
self.offset += element.text_len();
|
|
||||||
self.index += 1;
|
|
||||||
(element, index, offset)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator over the child nodes of a [`SyntaxNode`].
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct SyntaxNodeChildren<'n, L: Language, D: 'static = ()> {
|
|
||||||
inner: Iter<'n>,
|
|
||||||
parent: &'n SyntaxNode<L, D>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'n, L: Language, D> SyntaxNodeChildren<'n, L, D> {
|
|
||||||
#[inline]
|
|
||||||
fn new(parent: &'n SyntaxNode<L, D>) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Iter::new(parent),
|
|
||||||
parent,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'n, L: Language, D> Iterator for SyntaxNodeChildren<'n, L, D> {
|
|
||||||
type Item = &'n SyntaxNode<L, D>;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
while let Some((element, index, offset)) = self.inner.next() {
|
|
||||||
if let Some(&node) = element.as_node() {
|
|
||||||
return Some(self.parent.get_or_add_node(node, index, offset).as_node().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An iterator over the children of a [`SyntaxNode`].
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct SyntaxElementChildren<'n, L: Language, D: 'static = ()> {
|
|
||||||
inner: Iter<'n>,
|
|
||||||
parent: &'n SyntaxNode<L, D>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'n, L: Language, D> SyntaxElementChildren<'n, L, D> {
|
|
||||||
#[inline]
|
|
||||||
fn new(parent: &'n SyntaxNode<L, D>) -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Iter::new(parent),
|
|
||||||
parent,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'n, L: Language, D> Iterator for SyntaxElementChildren<'n, L, D> {
|
|
||||||
type Item = SyntaxElementRef<'n, L, D>;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
let parent = self.parent;
|
|
||||||
self.inner
|
|
||||||
.next()
|
|
||||||
.map(|(green, index, offset)| parent.get_or_add_element(green, index, offset))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GreenNode {
|
impl GreenNode {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn children_from(
|
fn children_from(
|
||||||
|
|
|
@ -214,7 +214,7 @@ impl<L: Language, D> fmt::Display for ResolvedToken<L, D> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serialize")]
|
||||||
impl<L, D> ResolvedNode<L, D>
|
impl<L, D> ResolvedNode<L, D>
|
||||||
where
|
where
|
||||||
L: Language,
|
L: Language,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use lasso::Resolver;
|
||||||
use text_size::{TextRange, TextSize};
|
use text_size::{TextRange, TextSize};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{Direction, GreenNode, GreenToken, Language, SyntaxKind};
|
use crate::{interning::Key, Direction, GreenNode, GreenToken, Language, SyntaxKind};
|
||||||
|
|
||||||
/// Syntax tree token.
|
/// Syntax tree token.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -69,6 +69,7 @@ impl<L: Language, D> SyntaxToken<L, D> {
|
||||||
/// Returns this token's [`Debug`](fmt::Debug) representation as a string.
|
/// Returns this token's [`Debug`](fmt::Debug) representation as a string.
|
||||||
///
|
///
|
||||||
/// To avoid allocating for every token, see [`write_debug`](SyntaxToken::write_debug).
|
/// To avoid allocating for every token, see [`write_debug`](SyntaxToken::write_debug).
|
||||||
|
#[inline]
|
||||||
pub fn debug<R>(&self, resolver: &R) -> String
|
pub fn debug<R>(&self, resolver: &R) -> String
|
||||||
where
|
where
|
||||||
R: Resolver + ?Sized,
|
R: Resolver + ?Sized,
|
||||||
|
@ -182,16 +183,86 @@ impl<L: Language, D> SyntaxToken<L, D> {
|
||||||
/// This method is different from the `PartialEq` and `Eq` implementations in that it compares
|
/// This method is different from the `PartialEq` and `Eq` implementations in that it compares
|
||||||
/// the text and not the token position.
|
/// the text and not the token position.
|
||||||
/// It is more efficient than comparing the result of
|
/// It is more efficient than comparing the result of
|
||||||
/// [`resolve_text`](SyntaxToken::resolve_text) because it compares the tokens' interned string
|
/// [`resolve_text`](SyntaxToken::resolve_text) because it compares the tokens' interned
|
||||||
/// keys.
|
/// [`text_key`s](SyntaxToken::text_key).
|
||||||
/// Therefore, it also does not require a [`Resolver`].
|
/// Therefore, it also does not require a [`Resolver`].
|
||||||
/// **Note** that the result of the comparison may be wrong when comparing two tokens from
|
/// **Note** that the result of the comparison may be wrong when comparing two tokens from
|
||||||
/// different trees that use different interners.
|
/// different trees that use different interners.
|
||||||
|
#[inline]
|
||||||
pub fn text_eq(&self, other: &Self) -> bool {
|
pub fn text_eq(&self, other: &Self) -> bool {
|
||||||
self.green().text_key() == other.green().text_key()
|
self.text_key() == other.text_key()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the interned key of text covered by this token.
|
||||||
|
/// This key may be used for comparisons with other keys of strings interned by the same interner.
|
||||||
|
///
|
||||||
|
/// See also [`resolve_text`](SyntaxToken::resolve_text) and [`text_eq`](SyntaxToken::text_eq).
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// If you intern strings inside of your application, e.g. inside of a compiler, you can use
|
||||||
|
/// token's text keys to cross-reference between the syntax tree and the rest of your
|
||||||
|
/// implementation by re-using the interner in both.
|
||||||
|
/// ```
|
||||||
|
/// # use cstree::*;
|
||||||
|
/// # use cstree::interning::{Hasher, Rodeo, Key, new_interner};
|
||||||
|
/// # #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
/// # #[repr(u16)]
|
||||||
|
/// # enum SyntaxKind {
|
||||||
|
/// # ROOT,
|
||||||
|
/// # INT,
|
||||||
|
/// # }
|
||||||
|
/// # #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
/// # enum Lang {}
|
||||||
|
/// # impl cstree::Language for Lang {
|
||||||
|
/// # type Kind = SyntaxKind;
|
||||||
|
/// #
|
||||||
|
/// # fn kind_from_raw(raw: cstree::SyntaxKind) -> Self::Kind {
|
||||||
|
/// # assert!(raw.0 <= SyntaxKind::INT as u16);
|
||||||
|
/// # unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
|
||||||
|
/// # }
|
||||||
|
/// #
|
||||||
|
/// # fn kind_to_raw(kind: Self::Kind) -> cstree::SyntaxKind {
|
||||||
|
/// # cstree::SyntaxKind(kind as u16)
|
||||||
|
/// # }
|
||||||
|
/// # }
|
||||||
|
/// # type SyntaxNode<L> = cstree::SyntaxNode<L, ()>;
|
||||||
|
/// # const ROOT: cstree::SyntaxKind = cstree::SyntaxKind(0);
|
||||||
|
/// # const IDENT: cstree::SyntaxKind = cstree::SyntaxKind(1);
|
||||||
|
/// # fn parse(b: &mut GreenNodeBuilder<Rodeo>, s: &str) {}
|
||||||
|
/// #
|
||||||
|
/// struct TypeTable {
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// impl TypeTable {
|
||||||
|
/// fn type_of(&self, ident: Key) -> &str {
|
||||||
|
/// // ...
|
||||||
|
/// # ""
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// # struct State {
|
||||||
|
/// # interner: Rodeo,
|
||||||
|
/// # type_table: TypeTable,
|
||||||
|
/// # }
|
||||||
|
/// # let interner = new_interner();
|
||||||
|
/// # let state = &mut State { interner, type_table: TypeTable{} };
|
||||||
|
/// let mut builder = GreenNodeBuilder::with_interner(&mut state.interner);
|
||||||
|
/// # let input = "";
|
||||||
|
/// # builder.start_node(ROOT);
|
||||||
|
/// # builder.token(IDENT, "x");
|
||||||
|
/// # builder.finish_node();
|
||||||
|
/// let tree = parse(&mut builder, "x");
|
||||||
|
/// # let tree = SyntaxNode::<Lang>::new_root(builder.finish().0);
|
||||||
|
/// let type_table = &state.type_table;
|
||||||
|
/// let ident = tree.children_with_tokens().next().unwrap().into_token().unwrap();
|
||||||
|
/// let typ = type_table.type_of(ident.text_key());
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn text_key(&self) -> Key {
|
||||||
|
self.green().text_key()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the unterlying green tree token of this token.
|
/// Returns the unterlying green tree token of this token.
|
||||||
|
#[inline]
|
||||||
pub fn green(&self) -> &GreenToken {
|
pub fn green(&self) -> &GreenToken {
|
||||||
self.parent
|
self.parent
|
||||||
.green()
|
.green()
|
||||||
|
@ -242,6 +313,7 @@ impl<L: Language, D> SyntaxToken<L, D> {
|
||||||
|
|
||||||
/// Returns the next token in the tree.
|
/// Returns the next token in the tree.
|
||||||
/// This is not necessary a direct sibling of this token, but will always be further right in the tree.
|
/// This is not necessary a direct sibling of this token, but will always be further right in the tree.
|
||||||
|
#[inline]
|
||||||
pub fn next_token(&self) -> Option<&SyntaxToken<L, D>> {
|
pub fn next_token(&self) -> Option<&SyntaxToken<L, D>> {
|
||||||
match self.next_sibling_or_token() {
|
match self.next_sibling_or_token() {
|
||||||
Some(element) => element.first_token(),
|
Some(element) => element.first_token(),
|
||||||
|
@ -255,6 +327,7 @@ impl<L: Language, D> SyntaxToken<L, D> {
|
||||||
|
|
||||||
/// Returns the previous token in the tree.
|
/// Returns the previous token in the tree.
|
||||||
/// This is not necessary a direct sibling of this token, but will always be further left in the tree.
|
/// This is not necessary a direct sibling of this token, but will always be further left in the tree.
|
||||||
|
#[inline]
|
||||||
pub fn prev_token(&self) -> Option<&SyntaxToken<L, D>> {
|
pub fn prev_token(&self) -> Option<&SyntaxToken<L, D>> {
|
||||||
match self.prev_sibling_or_token() {
|
match self.prev_sibling_or_token() {
|
||||||
Some(element) => element.last_token(),
|
Some(element) => element.last_token(),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
mod basic;
|
mod basic;
|
||||||
mod regressions;
|
mod regressions;
|
||||||
mod sendsync;
|
mod sendsync;
|
||||||
#[cfg(feature = "serde1")]
|
#[cfg(feature = "serialize")]
|
||||||
mod serde;
|
mod serde;
|
||||||
|
|
||||||
use cstree::{GreenNode, GreenNodeBuilder, Language, NodeCache, SyntaxKind};
|
use cstree::{GreenNode, GreenNodeBuilder, Language, NodeCache, SyntaxKind};
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
use crate::{build_recursive, build_tree_with_cache, ResolvedNode};
|
use crate::{build_recursive, build_tree_with_cache, ResolvedNode};
|
||||||
|
|
||||||
use super::{Element, SyntaxNode};
|
use super::{Element, SyntaxNode};
|
||||||
use cstree::{interning::IntoResolver, GreenNodeBuilder, NodeCache, NodeOrToken};
|
use cstree::{
|
||||||
|
interning::{new_interner, IntoResolver},
|
||||||
|
GreenNodeBuilder, NodeCache, NodeOrToken,
|
||||||
|
};
|
||||||
use serde_test::Token;
|
use serde_test::Token;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
type Rodeo = lasso::Rodeo<lasso::Spur, fxhash::FxBuildHasher>;
|
|
||||||
|
|
||||||
/// Macro for generating a list of `serde_test::Token`s using a simpler DSL.
|
/// Macro for generating a list of `serde_test::Token`s using a simpler DSL.
|
||||||
macro_rules! event_tokens {
|
macro_rules! event_tokens {
|
||||||
($($name:ident($($token:tt)*)),*) => {
|
($($name:ident($($token:tt)*)),*) => {
|
||||||
|
@ -237,7 +238,7 @@ fn attach_data(node: &SyntaxNode<String>) {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_tree_with_data_with_resolver() {
|
fn serialize_tree_with_data_with_resolver() {
|
||||||
let mut interner = Rodeo::with_hasher(Default::default());
|
let mut interner = new_interner();
|
||||||
let mut cache = NodeCache::with_interner(&mut interner);
|
let mut cache = NodeCache::with_interner(&mut interner);
|
||||||
|
|
||||||
let root = three_level_tree();
|
let root = three_level_tree();
|
||||||
|
@ -255,7 +256,7 @@ fn serialize_tree_with_data_with_resolver() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_tree_with_resolver() {
|
fn serialize_tree_with_resolver() {
|
||||||
let mut interner = Rodeo::with_hasher(Default::default());
|
let mut interner = new_interner();
|
||||||
let mut cache = NodeCache::with_interner(&mut interner);
|
let mut cache = NodeCache::with_interner(&mut interner);
|
||||||
|
|
||||||
let root = three_level_tree();
|
let root = three_level_tree();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue