mirror of
https://github.com/RGBCube/cstree
synced 2025-07-31 11:07:47 +00:00
Compare commits
5 commits
fb8cc54104
...
a102fdf1d4
Author | SHA1 | Date | |
---|---|---|---|
a102fdf1d4 | |||
35c2799059 | |||
c35e88c3da | |||
a8ebf29808 | |||
27c40cbf01 |
10 changed files with 107 additions and 29 deletions
|
@ -114,7 +114,7 @@ fn print(indent: usize, element: SyntaxElementRef<'_>, resolver: &impl Resolver)
|
|||
print!("{:indent$}", "", indent = indent);
|
||||
match element {
|
||||
NodeOrToken::Node(node) => {
|
||||
println!("- {:?}", kind);
|
||||
println!("- {kind:?}");
|
||||
for child in node.children_with_tokens() {
|
||||
print(indent + 2, child, resolver);
|
||||
}
|
||||
|
|
|
@ -392,7 +392,7 @@ nan
|
|||
let root = parse.root();
|
||||
let resolver = &parse.resolver;
|
||||
let res = root.sexps().map(|it| it.eval(resolver)).collect::<Vec<_>>();
|
||||
eprintln!("{:?}", res);
|
||||
eprintln!("{res:?}");
|
||||
assert_eq!(res, vec![Some(92), Some(92), None, None, Some(92),])
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ const DEFAULT_STRING_CAPACITY: usize = 512;
|
|||
|
||||
/// Default memory in bytes that the interner will initially allocate space for.
|
||||
/// Value recommended by the author of `lasso`.
|
||||
const DEFAULT_BYTE_CAPACITY: NonZeroUsize = unsafe { NonZeroUsize::new_unchecked(4096) };
|
||||
const DEFAULT_BYTE_CAPACITY: NonZeroUsize = NonZeroUsize::new(4096).unwrap();
|
||||
|
||||
macro_rules! impl_traits {
|
||||
(for $interner:ty $(, if #[cfg(feature = $feature:literal)])?) => {
|
||||
|
|
|
@ -292,7 +292,7 @@ impl<'a, S: Syntax, D> SyntaxElementRef<'a, S, D> {
|
|||
|
||||
/// Returns an iterator along the chain of parents of this node.
|
||||
#[inline]
|
||||
pub fn ancestors(&self) -> impl Iterator<Item = &'a SyntaxNode<S, D>> {
|
||||
pub fn ancestors(&self) -> impl Iterator<Item = &'a SyntaxNode<S, D>> + use<'a, S, D> {
|
||||
match self {
|
||||
NodeOrToken::Node(it) => it.ancestors(),
|
||||
NodeOrToken::Token(it) => it.parent().ancestors(),
|
||||
|
|
|
@ -66,12 +66,21 @@ impl ExactSizeIterator for Iter<'_> {
|
|||
impl FusedIterator for Iter<'_> {}
|
||||
|
||||
/// An iterator over the child nodes of a [`SyntaxNode`].
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct SyntaxNodeChildren<'n, S: Syntax, D: 'static = ()> {
|
||||
inner: Iter<'n>,
|
||||
parent: &'n SyntaxNode<S, D>,
|
||||
}
|
||||
|
||||
impl<S: Syntax, D> Clone for SyntaxNodeChildren<'_, S, D> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
parent: self.parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'n, S: Syntax, D> SyntaxNodeChildren<'n, S, D> {
|
||||
#[inline]
|
||||
pub(super) fn new(parent: &'n SyntaxNode<S, D>) -> Self {
|
||||
|
@ -118,12 +127,21 @@ impl<S: Syntax, D> ExactSizeIterator for SyntaxNodeChildren<'_, S, D> {
|
|||
impl<S: Syntax, D> FusedIterator for SyntaxNodeChildren<'_, S, D> {}
|
||||
|
||||
/// An iterator over the children of a [`SyntaxNode`].
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct SyntaxElementChildren<'n, S: Syntax, D: 'static = ()> {
|
||||
inner: Iter<'n>,
|
||||
parent: &'n SyntaxNode<S, D>,
|
||||
}
|
||||
|
||||
impl<S: Syntax, D> Clone for SyntaxElementChildren<'_, S, D> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
inner: self.inner.clone(),
|
||||
parent: self.parent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'n, S: Syntax, D> SyntaxElementChildren<'n, S, D> {
|
||||
#[inline]
|
||||
pub(super) fn new(parent: &'n SyntaxNode<S, D>) -> Self {
|
||||
|
@ -166,3 +184,35 @@ impl<S: Syntax, D> ExactSizeIterator for SyntaxElementChildren<'_, S, D> {
|
|||
}
|
||||
}
|
||||
impl<S: Syntax, D> FusedIterator for SyntaxElementChildren<'_, S, D> {}
|
||||
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
struct DummyKind;
|
||||
|
||||
impl Syntax for DummyKind {
|
||||
fn from_raw(_: crate::RawSyntaxKind) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn into_raw(self) -> crate::RawSyntaxKind {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
fn static_text(self) -> Option<&'static str> {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
struct NotClone;
|
||||
|
||||
fn assert_clone<C: Clone>() {}
|
||||
|
||||
fn test_impls_clone() {
|
||||
assert_clone::<SyntaxNodeChildren<DummyKind, NotClone>>();
|
||||
assert_clone::<SyntaxElementChildren<DummyKind, NotClone>>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -851,9 +851,7 @@ impl<S: Syntax, D> SyntaxNode<S, D> {
|
|||
let range = self.text_range();
|
||||
assert!(
|
||||
range.start() <= offset && offset <= range.end(),
|
||||
"Bad offset: range {:?} offset {:?}",
|
||||
range,
|
||||
offset
|
||||
"Bad offset: range {range:?} offset {offset:?}"
|
||||
);
|
||||
if range.is_empty() {
|
||||
return TokenAtOffset::None;
|
||||
|
@ -940,7 +938,7 @@ impl GreenNode {
|
|||
&self,
|
||||
start_index: usize,
|
||||
mut offset: TextSize,
|
||||
) -> impl Iterator<Item = (GreenElementRef, (usize, TextSize))> {
|
||||
) -> impl Iterator<Item = (GreenElementRef<'_>, (usize, TextSize))> {
|
||||
self.children()
|
||||
.skip(start_index)
|
||||
.enumerate()
|
||||
|
@ -956,7 +954,7 @@ impl GreenNode {
|
|||
&self,
|
||||
end_index: usize,
|
||||
mut offset: TextSize,
|
||||
) -> impl Iterator<Item = (GreenElementRef, (usize, TextSize))> {
|
||||
) -> impl Iterator<Item = (GreenElementRef<'_>, (usize, TextSize))> {
|
||||
self.children()
|
||||
.take(end_index)
|
||||
.rev()
|
||||
|
|
|
@ -713,7 +713,7 @@ impl<'a, S: Syntax, D> ResolvedElementRef<'a, S, D> {
|
|||
|
||||
/// Returns an iterator along the chain of parents of this node.
|
||||
#[inline]
|
||||
pub fn ancestors(&self) -> impl Iterator<Item = &'a ResolvedNode<S, D>> {
|
||||
pub fn ancestors(&self) -> impl Iterator<Item = &'a ResolvedNode<S, D>> + use<'a, S, D> {
|
||||
match self {
|
||||
NodeOrToken::Node(it) => it.ancestors(),
|
||||
NodeOrToken::Token(it) => it.parent().ancestors(),
|
||||
|
|
|
@ -40,13 +40,20 @@ use crate::{
|
|||
/// let sub = text.slice(2.into()..5.into());
|
||||
/// assert_eq!(sub, "748");
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct SyntaxText<'n, 'i, I: ?Sized, S: Syntax, D: 'static = ()> {
|
||||
node: &'n SyntaxNode<S, D>,
|
||||
range: TextRange,
|
||||
resolver: &'i I,
|
||||
}
|
||||
|
||||
impl<I: ?Sized, S: Syntax, D> Clone for SyntaxText<'_, '_, I, S, D> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<I: ?Sized, S: Syntax, D> Copy for SyntaxText<'_, '_, I, S, D> {}
|
||||
|
||||
impl<'n, 'i, I: Resolver<TokenKey> + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I, S, D> {
|
||||
pub(crate) fn new(node: &'n SyntaxNode<S, D>, resolver: &'i I) -> Self {
|
||||
let range = node.text_range();
|
||||
|
@ -84,6 +91,18 @@ impl<'n, 'i, I: Resolver<TokenKey> + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I,
|
|||
found(res)
|
||||
}
|
||||
|
||||
/// If `self.contains_char(c)`, returns `Some(pos)`, where `pos` is the byte position of the
|
||||
/// last appearance of `c`. Otherwise, returns `None`.
|
||||
pub fn rfind_char(&self, c: char) -> Option<TextSize> {
|
||||
let mut acc: TextSize = 0.into();
|
||||
let mut res = None;
|
||||
self.for_each_chunk(|chunk| {
|
||||
res = chunk.rfind(c).map(|pos| acc + TextSize::from(pos as u32)).or(res);
|
||||
acc += TextSize::of(chunk);
|
||||
});
|
||||
res
|
||||
}
|
||||
|
||||
/// If `offset < self.len()`, returns `Some(c)`, where `c` is the first `char` at or after
|
||||
/// `offset` (in bytes). Otherwise, returns `None`.
|
||||
pub fn char_at(&self, offset: TextSize) -> Option<char> {
|
||||
|
@ -143,7 +162,7 @@ impl<'n, 'i, I: Resolver<TokenKey> + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I,
|
|||
/// See also [`fold_chunks`](SyntaxText::fold_chunks) for folds that always succeed.
|
||||
pub fn try_fold_chunks<T, F, E>(&self, init: T, mut f: F) -> Result<T, E>
|
||||
where
|
||||
F: FnMut(T, &str) -> Result<T, E>,
|
||||
F: FnMut(T, &'i str) -> Result<T, E>,
|
||||
{
|
||||
self.tokens_with_ranges().try_fold(init, move |acc, (token, range)| {
|
||||
f(acc, &token.resolve_text(self.resolver)[range])
|
||||
|
@ -188,7 +207,7 @@ impl<'n, 'i, I: Resolver<TokenKey> + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I,
|
|||
self.fold_chunks((), |(), chunk| f(chunk))
|
||||
}
|
||||
|
||||
fn tokens_with_ranges(&self) -> impl Iterator<Item = (&SyntaxToken<S, D>, TextRange)> {
|
||||
fn tokens_with_ranges(&self) -> impl Iterator<Item = (&'n SyntaxToken<S, D>, TextRange)> + use<'i, 'n, I, S, D> {
|
||||
let text_range = self.range;
|
||||
self.node
|
||||
.descendants_with_tokens()
|
||||
|
@ -201,11 +220,9 @@ impl<'n, 'i, I: Resolver<TokenKey> + ?Sized, S: Syntax, D> SyntaxText<'n, 'i, I,
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn found<T>(res: Result<(), T>) -> Option<T> {
|
||||
match res {
|
||||
Ok(()) => None,
|
||||
Err(it) => Some(it),
|
||||
}
|
||||
res.err()
|
||||
}
|
||||
|
||||
impl<I: Resolver<TokenKey> + ?Sized, S: Syntax, D> fmt::Debug for SyntaxText<'_, '_, I, S, D> {
|
||||
|
@ -378,7 +395,7 @@ mod private {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{build::GreenNodeBuilder, RawSyntaxKind};
|
||||
use crate::{build::GreenNodeBuilder, interning::TokenInterner, RawSyntaxKind};
|
||||
|
||||
use super::*;
|
||||
|
||||
|
@ -429,9 +446,9 @@ mod tests {
|
|||
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);
|
||||
assert_eq!(expected, actual, "`{t1}` (SyntaxText) `{t2}` (SyntaxText)");
|
||||
let actual = t1 == t2.to_string().as_str();
|
||||
assert_eq!(expected, actual, "`{}` (SyntaxText) `{}` (&str)", t1, t2);
|
||||
assert_eq!(expected, actual, "`{t1}` (SyntaxText) `{t2}` (&str)");
|
||||
}
|
||||
fn check(t1: &[&str], t2: &[&str]) {
|
||||
do_check(t1, t2);
|
||||
|
@ -450,4 +467,17 @@ mod tests {
|
|||
check(&["{", "abc", "}"], &["{", "123", "}", "{"]);
|
||||
check(&["{", "abc", "}ab"], &["{", "abc", "}", "ab"]);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod impl_asserts {
|
||||
use super::*;
|
||||
|
||||
struct NotClone;
|
||||
|
||||
fn assert_copy<C: Copy>() {}
|
||||
|
||||
fn test_impls_copy() {
|
||||
assert_copy::<SyntaxText<TokenInterner, SyntaxKind, NotClone>>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,13 +58,13 @@ impl<S: Syntax, D> SyntaxToken<S, D> {
|
|||
write!(target, "{:?}@{:?}", self.kind(), self.text_range())?;
|
||||
let text = self.resolve_text(resolver);
|
||||
if text.len() < 25 {
|
||||
return write!(target, " {:?}", text);
|
||||
return write!(target, " {text:?}");
|
||||
}
|
||||
|
||||
for idx in 21..25 {
|
||||
if text.is_char_boundary(idx) {
|
||||
let text = format!("{} ...", &text[..idx]);
|
||||
return write!(target, " {:?}", text);
|
||||
return write!(target, " {text:?}");
|
||||
}
|
||||
}
|
||||
unreachable!()
|
||||
|
|
|
@ -149,18 +149,18 @@ fn inline_resolver() {
|
|||
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\"");
|
||||
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}").as_str(), node2.text());
|
||||
assert_eq!(format!("{node2:?}"), "SyntaxKind(6)@9..18");
|
||||
assert_eq!(
|
||||
format!("{:#?}", node2),
|
||||
format!("{node2:#?}"),
|
||||
r#"SyntaxKind(6)@9..18
|
||||
SyntaxKind(7)@9..12 "2.0"
|
||||
SyntaxKind(8)@12..15 "2.1"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue