mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
Move to rowan for syntax tree impl
This commit is contained in:
parent
cd9c5f4ab2
commit
a261a1836b
13 changed files with 169 additions and 551 deletions
14
Cargo.lock
generated
14
Cargo.lock
generated
|
@ -602,9 +602,8 @@ dependencies = [
|
||||||
"drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"smol_str 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rowan 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"test_utils 0.1.0",
|
"test_utils 0.1.0",
|
||||||
"text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 2.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -713,6 +712,16 @@ dependencies = [
|
||||||
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.79 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rowan"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"smol_str 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"text_unit 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
@ -1230,6 +1239,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum relative-path 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e614f96449605730b4f7ad2c019e88c1652d730634b4eba07b810801856635e3"
|
"checksum relative-path 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e614f96449605730b4f7ad2c019e88c1652d730634b4eba07b810801856635e3"
|
||||||
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
|
||||||
"checksum ron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fa11b7a38511d46ff1959ae46ebb60bd8a746f17bdd0206b4c8de7559ac47b"
|
"checksum ron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9fa11b7a38511d46ff1959ae46ebb60bd8a746f17bdd0206b4c8de7559ac47b"
|
||||||
|
"checksum rowan 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4a1a7366ece9deee5e7df8316a136d585d5c5042854c2297f7f1aee3014c9130"
|
||||||
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395"
|
||||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||||
"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
|
"checksum ryu 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7153dd96dade874ab973e098cb62fcdbb89a03682e46b144fd09550998d4a4a7"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [ "crates/*" ]
|
members = [ "crates/*" ]
|
||||||
|
exclude = [ "crates/rowan"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
debug = true
|
debug = true
|
||||||
|
|
|
@ -6,11 +6,10 @@ license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
unicode-xid = "0.1.0"
|
unicode-xid = "0.1.0"
|
||||||
text_unit = "0.1.4"
|
|
||||||
itertools = "0.7.8"
|
itertools = "0.7.8"
|
||||||
drop_bomb = "0.1.4"
|
drop_bomb = "0.1.4"
|
||||||
parking_lot = "0.6.0"
|
parking_lot = "0.6.0"
|
||||||
smol_str = "0.1.6"
|
rowan = "0.1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
test_utils = { path = "../test_utils" }
|
test_utils = { path = "../test_utils" }
|
||||||
|
|
|
@ -3,10 +3,9 @@ mod generated;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use smol_str::SmolStr;
|
|
||||||
|
|
||||||
use {
|
use {
|
||||||
SyntaxNodeRef, SyntaxKind::*,
|
SmolStr, SyntaxNodeRef, SyntaxKind::*,
|
||||||
yellow::{RefRoot, SyntaxNodeChildren},
|
yellow::{RefRoot, SyntaxNodeChildren},
|
||||||
};
|
};
|
||||||
pub use self::generated::*;
|
pub use self::generated::*;
|
||||||
|
@ -76,7 +75,7 @@ impl<'a> Attr<'a> {
|
||||||
let tt = self.value()?;
|
let tt = self.value()?;
|
||||||
let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
|
let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
|
||||||
if attr.kind() == IDENT {
|
if attr.kind() == IDENT {
|
||||||
Some(attr.leaf_text().unwrap())
|
Some(attr.leaf_text().unwrap().clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -87,7 +86,7 @@ impl<'a> Attr<'a> {
|
||||||
let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?;
|
let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?;
|
||||||
let args = TokenTree::cast(args)?;
|
let args = TokenTree::cast(args)?;
|
||||||
if attr.kind() == IDENT {
|
if attr.kind() == IDENT {
|
||||||
Some((attr.leaf_text().unwrap(), args))
|
Some((attr.leaf_text().unwrap().clone(), args))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -96,7 +95,7 @@ impl<'a> Attr<'a> {
|
||||||
|
|
||||||
impl<'a> Lifetime<'a> {
|
impl<'a> Lifetime<'a> {
|
||||||
pub fn text(&self) -> SmolStr {
|
pub fn text(&self) -> SmolStr {
|
||||||
self.syntax().leaf_text().unwrap()
|
self.syntax().leaf_text().unwrap().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +103,7 @@ impl<'a> Name<'a> {
|
||||||
pub fn text(&self) -> SmolStr {
|
pub fn text(&self) -> SmolStr {
|
||||||
let ident = self.syntax().first_child()
|
let ident = self.syntax().first_child()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ident.leaf_text().unwrap()
|
ident.leaf_text().unwrap().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +111,7 @@ impl<'a> NameRef<'a> {
|
||||||
pub fn text(&self) -> SmolStr {
|
pub fn text(&self) -> SmolStr {
|
||||||
let ident = self.syntax().first_child()
|
let ident = self.syntax().first_child()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
ident.leaf_text().unwrap()
|
ident.leaf_text().unwrap().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,8 +24,7 @@ extern crate itertools;
|
||||||
extern crate unicode_xid;
|
extern crate unicode_xid;
|
||||||
extern crate drop_bomb;
|
extern crate drop_bomb;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
extern crate smol_str;
|
extern crate rowan;
|
||||||
extern crate text_unit;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -48,8 +47,7 @@ pub mod utils;
|
||||||
pub mod text_utils;
|
pub mod text_utils;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
text_unit::{TextRange, TextUnit},
|
rowan::{SmolStr, TextRange, TextUnit},
|
||||||
smol_str::SmolStr,
|
|
||||||
ast::AstNode,
|
ast::AstNode,
|
||||||
lexer::{tokenize, Token},
|
lexer::{tokenize, Token},
|
||||||
syntax_kinds::SyntaxKind,
|
syntax_kinds::SyntaxKind,
|
||||||
|
@ -58,7 +56,7 @@ pub use {
|
||||||
};
|
};
|
||||||
|
|
||||||
use {
|
use {
|
||||||
yellow::{GreenNode, SyntaxRoot},
|
yellow::{GreenNode},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Hash)]
|
#[derive(Clone, Debug, Hash)]
|
||||||
|
@ -68,8 +66,7 @@ pub struct File {
|
||||||
|
|
||||||
impl File {
|
impl File {
|
||||||
fn new(green: GreenNode, errors: Vec<SyntaxError>) -> File {
|
fn new(green: GreenNode, errors: Vec<SyntaxError>) -> File {
|
||||||
let root = SyntaxRoot::new(green, errors);
|
let root = SyntaxNode::new(green, errors);
|
||||||
let root = SyntaxNode::new_owned(root);
|
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
utils::validate_block_structure(root.borrowed());
|
utils::validate_block_structure(root.borrowed());
|
||||||
}
|
}
|
||||||
|
@ -100,6 +97,6 @@ impl File {
|
||||||
self.root.borrowed()
|
self.root.borrowed()
|
||||||
}
|
}
|
||||||
pub fn errors(&self) -> Vec<SyntaxError> {
|
pub fn errors(&self) -> Vec<SyntaxError> {
|
||||||
self.syntax().root.syntax_root().errors.clone()
|
self.root.root_data().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use algo;
|
use algo;
|
||||||
use grammar;
|
use grammar;
|
||||||
use lexer::{tokenize, Token};
|
use lexer::{tokenize, Token};
|
||||||
use text_unit::{TextRange, TextUnit};
|
use yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError};
|
||||||
use yellow::{self, SyntaxNodeRef, GreenNode, SyntaxError};
|
|
||||||
use parser_impl;
|
use parser_impl;
|
||||||
use parser_api::Parser;
|
use parser_api::Parser;
|
||||||
use {
|
use {
|
||||||
|
TextUnit, TextRange,
|
||||||
SyntaxKind::*,
|
SyntaxKind::*,
|
||||||
};
|
};
|
||||||
use text_utils::replace_range;
|
use text_utils::replace_range;
|
||||||
|
@ -65,7 +65,7 @@ fn reparse_leaf<'node>(
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let green = GreenNode::new_leaf(node.kind(), &text);
|
let green = GreenNode::new_leaf(node.kind(), text.into());
|
||||||
let new_errors = vec![];
|
let new_errors = vec![];
|
||||||
Some((node, green, new_errors))
|
Some((node, green, new_errors))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use {
|
use {
|
||||||
algo::walk::{preorder, walk, WalkEvent},
|
algo::walk::{preorder, walk, WalkEvent},
|
||||||
SyntaxKind, File, SyntaxNodeRef, TreeRoot,
|
SyntaxKind, File, SyntaxNodeRef
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Parse a file and create a string representation of the resulting parse tree.
|
/// Parse a file and create a string representation of the resulting parse tree.
|
||||||
pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
|
pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
|
||||||
let mut errors: Vec<_> = syntax.root.syntax_root().errors.iter().cloned().collect();
|
let mut errors: Vec<_> = syntax.root_data().iter().cloned().collect();
|
||||||
errors.sort_by_key(|e| e.offset);
|
errors.sort_by_key(|e| e.offset);
|
||||||
let mut err_pos = 0;
|
let mut err_pos = 0;
|
||||||
let mut level = 0;
|
let mut level = 0;
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
use rowan::GreenNodeBuilder;
|
||||||
use {
|
use {
|
||||||
parser_impl::Sink,
|
parser_impl::Sink,
|
||||||
yellow::{GreenNode, SyntaxError},
|
yellow::{GreenNode, SyntaxError, RaTypes},
|
||||||
SyntaxKind, TextRange, TextUnit,
|
SyntaxKind, TextRange, TextUnit,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct GreenBuilder<'a> {
|
pub(crate) struct GreenBuilder<'a> {
|
||||||
text: &'a str,
|
text: &'a str,
|
||||||
parents: Vec<(SyntaxKind, usize)>,
|
|
||||||
children: Vec<GreenNode>,
|
|
||||||
pos: TextUnit,
|
pos: TextUnit,
|
||||||
errors: Vec<SyntaxError>,
|
errors: Vec<SyntaxError>,
|
||||||
|
inner: GreenNodeBuilder<RaTypes>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Sink<'a> for GreenBuilder<'a> {
|
impl<'a> Sink<'a> for GreenBuilder<'a> {
|
||||||
|
@ -18,35 +18,25 @@ impl<'a> Sink<'a> for GreenBuilder<'a> {
|
||||||
fn new(text: &'a str) -> Self {
|
fn new(text: &'a str) -> Self {
|
||||||
GreenBuilder {
|
GreenBuilder {
|
||||||
text,
|
text,
|
||||||
parents: Vec::new(),
|
|
||||||
children: Vec::new(),
|
|
||||||
pos: 0.into(),
|
pos: 0.into(),
|
||||||
errors: Vec::new(),
|
errors: Vec::new(),
|
||||||
|
inner: GreenNodeBuilder::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
|
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
|
||||||
let range = TextRange::offset_len(self.pos, len);
|
let range = TextRange::offset_len(self.pos, len);
|
||||||
self.pos += len;
|
self.pos += len;
|
||||||
let text = &self.text[range];
|
let text = self.text[range].into();
|
||||||
self.children.push(
|
self.inner.leaf(kind, text);
|
||||||
GreenNode::new_leaf(kind, text)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_internal(&mut self, kind: SyntaxKind) {
|
fn start_internal(&mut self, kind: SyntaxKind) {
|
||||||
let len = self.children.len();
|
self.inner.start_internal(kind)
|
||||||
self.parents.push((kind, len));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_internal(&mut self) {
|
fn finish_internal(&mut self) {
|
||||||
let (kind, first_child) = self.parents.pop().unwrap();
|
self.inner.finish_internal();
|
||||||
let children: Vec<_> = self.children
|
|
||||||
.drain(first_child..)
|
|
||||||
.collect();
|
|
||||||
self.children.push(
|
|
||||||
GreenNode::new_branch(kind, children.into_boxed_slice())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&mut self, message: String) {
|
fn error(&mut self, message: String) {
|
||||||
|
@ -56,9 +46,7 @@ impl<'a> Sink<'a> for GreenBuilder<'a> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(mut self) -> (GreenNode, Vec<SyntaxError>) {
|
fn finish(self) -> (GreenNode, Vec<SyntaxError>) {
|
||||||
assert_eq!(self.children.len(), 1);
|
(self.inner.finish(), self.errors)
|
||||||
let root = self.children.pop().unwrap();
|
|
||||||
(root, self.errors)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use smol_str::SmolStr;
|
|
||||||
|
|
||||||
use {SyntaxKind, TextUnit};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub(crate) enum GreenNode {
|
|
||||||
Leaf {
|
|
||||||
kind: SyntaxKind,
|
|
||||||
text: SmolStr,
|
|
||||||
},
|
|
||||||
Branch(Arc<GreenBranch>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GreenNode {
|
|
||||||
pub(crate) fn new_leaf(kind: SyntaxKind, text: &str) -> GreenNode {
|
|
||||||
GreenNode::Leaf { kind, text: SmolStr::new(text) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn new_branch(kind: SyntaxKind, children: Box<[GreenNode]>) -> GreenNode {
|
|
||||||
GreenNode::Branch(Arc::new(GreenBranch::new(kind, children)))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> SyntaxKind {
|
|
||||||
match self {
|
|
||||||
GreenNode::Leaf { kind, .. } => *kind,
|
|
||||||
GreenNode::Branch(b) => b.kind(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn text_len(&self) -> TextUnit {
|
|
||||||
match self {
|
|
||||||
GreenNode::Leaf { text, .. } => TextUnit::from(text.len() as u32),
|
|
||||||
GreenNode::Branch(b) => b.text_len(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn children(&self) -> &[GreenNode] {
|
|
||||||
match self {
|
|
||||||
GreenNode::Leaf { .. } => &[],
|
|
||||||
GreenNode::Branch(b) => b.children(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn leaf_text_ref(&self) -> Option<&SmolStr> {
|
|
||||||
match self {
|
|
||||||
GreenNode::Leaf { text, .. } => Some(text),
|
|
||||||
GreenNode::Branch(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub(crate) struct GreenBranch {
|
|
||||||
text_len: TextUnit,
|
|
||||||
kind: SyntaxKind,
|
|
||||||
children: Box<[GreenNode]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl GreenBranch {
|
|
||||||
fn new(kind: SyntaxKind, children: Box<[GreenNode]>) -> GreenBranch {
|
|
||||||
let text_len = children.iter().map(|x| x.text_len()).sum::<TextUnit>();
|
|
||||||
GreenBranch {
|
|
||||||
text_len,
|
|
||||||
kind,
|
|
||||||
children,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> SyntaxKind {
|
|
||||||
self.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn text_len(&self) -> TextUnit {
|
|
||||||
self.text_len
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn children(&self) -> &[GreenNode] {
|
|
||||||
&*self.children
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sizes() {
|
|
||||||
use std::mem::size_of;
|
|
||||||
println!("GreenBranch = {}", size_of::<GreenBranch>());
|
|
||||||
println!("GreenNode = {}", size_of::<GreenNode>());
|
|
||||||
println!("SmolStr = {}", size_of::<SmolStr>());
|
|
||||||
}
|
|
|
@ -1,100 +1,142 @@
|
||||||
mod builder;
|
mod builder;
|
||||||
mod green;
|
|
||||||
mod red;
|
|
||||||
mod syntax;
|
|
||||||
mod syntax_text;
|
mod syntax_text;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
sync::Arc,
|
fmt,
|
||||||
ptr,
|
hash::{Hash, Hasher},
|
||||||
};
|
|
||||||
pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxError, SyntaxNodeChildren};
|
|
||||||
pub(crate) use self::{
|
|
||||||
builder::GreenBuilder,
|
|
||||||
green::GreenNode,
|
|
||||||
red::RedNode,
|
|
||||||
syntax_text::SyntaxText,
|
|
||||||
};
|
};
|
||||||
|
use rowan::Types;
|
||||||
|
use {SyntaxKind, TextUnit, TextRange, SmolStr};
|
||||||
|
use self::syntax_text::SyntaxText;
|
||||||
|
|
||||||
|
pub use rowan::{TreeRoot};
|
||||||
|
pub(crate) use self::builder::GreenBuilder;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub enum RaTypes {}
|
||||||
|
impl Types for RaTypes {
|
||||||
|
type Kind = SyntaxKind;
|
||||||
|
type RootData = Vec<SyntaxError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type OwnedRoot = ::rowan::OwnedRoot<RaTypes>;
|
||||||
|
pub type RefRoot<'a> = ::rowan::RefRoot<'a, RaTypes>;
|
||||||
|
|
||||||
|
pub type GreenNode = ::rowan::GreenNode<RaTypes>;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||||
|
pub struct SyntaxError {
|
||||||
|
pub msg: String,
|
||||||
|
pub offset: TextUnit,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(
|
||||||
|
::rowan::SyntaxNode<RaTypes, R>,
|
||||||
|
);
|
||||||
|
pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;
|
||||||
|
|
||||||
|
impl<R1, R2> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2>
|
||||||
|
where
|
||||||
|
R1: TreeRoot<RaTypes>,
|
||||||
|
R2: TreeRoot<RaTypes>,
|
||||||
|
{
|
||||||
|
fn eq(&self, other: &SyntaxNode<R1>) -> bool {
|
||||||
|
self.0 == other.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: TreeRoot<RaTypes>> Eq for SyntaxNode<R> {}
|
||||||
|
impl<R: TreeRoot<RaTypes>> Hash for SyntaxNode<R> {
|
||||||
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
|
self.0.hash(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyntaxNode<OwnedRoot> {
|
||||||
|
pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxNode {
|
||||||
|
SyntaxNode(::rowan::SyntaxNode::new(green, errors))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'a> SyntaxNode<RefRoot<'a>> {
|
||||||
|
pub fn leaf_text(self) -> Option<&'a SmolStr> {
|
||||||
|
self.0.leaf_text()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: TreeRoot<RaTypes>> SyntaxNode<R> {
|
||||||
|
pub(crate) fn root_data(&self) -> &Vec<SyntaxError> {
|
||||||
|
self.0.root_data()
|
||||||
|
}
|
||||||
|
pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
|
||||||
|
self.0.replace_with(replacement)
|
||||||
|
}
|
||||||
|
pub fn borrowed<'a>(&'a self) -> SyntaxNode<RefRoot<'a>> {
|
||||||
|
SyntaxNode(self.0.borrowed())
|
||||||
|
}
|
||||||
|
pub fn owned(&self) -> SyntaxNode<OwnedRoot> {
|
||||||
|
SyntaxNode(self.0.owned())
|
||||||
|
}
|
||||||
|
pub fn kind(&self) -> SyntaxKind {
|
||||||
|
self.0.kind()
|
||||||
|
}
|
||||||
|
pub fn range(&self) -> TextRange {
|
||||||
|
self.0.range()
|
||||||
|
}
|
||||||
|
pub fn text(&self) -> SyntaxText {
|
||||||
|
SyntaxText::new(self.borrowed())
|
||||||
|
}
|
||||||
|
pub fn is_leaf(&self) -> bool {
|
||||||
|
self.0.is_leaf()
|
||||||
|
}
|
||||||
|
pub fn parent(&self) -> Option<SyntaxNode<R>> {
|
||||||
|
self.0.parent().map(SyntaxNode)
|
||||||
|
}
|
||||||
|
pub fn first_child(&self) -> Option<SyntaxNode<R>> {
|
||||||
|
self.0.first_child().map(SyntaxNode)
|
||||||
|
}
|
||||||
|
pub fn last_child(&self) -> Option<SyntaxNode<R>> {
|
||||||
|
self.0.last_child().map(SyntaxNode)
|
||||||
|
}
|
||||||
|
pub fn next_sibling(&self) -> Option<SyntaxNode<R>> {
|
||||||
|
self.0.next_sibling().map(SyntaxNode)
|
||||||
|
}
|
||||||
|
pub fn prev_sibling(&self) -> Option<SyntaxNode<R>> {
|
||||||
|
self.0.prev_sibling().map(SyntaxNode)
|
||||||
|
}
|
||||||
|
pub fn children(&self) -> SyntaxNodeChildren<R> {
|
||||||
|
SyntaxNodeChildren(self.0.children())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: TreeRoot<RaTypes>> fmt::Debug for SyntaxNode<R> {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(fmt, "{:?}@{:?}", self.kind(), self.range())?;
|
||||||
|
if has_short_text(self.kind()) {
|
||||||
|
write!(fmt, " \"{}\"", self.text())?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SyntaxRoot {
|
pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>(
|
||||||
red: RedNode,
|
::rowan::SyntaxNodeChildren<RaTypes, R>
|
||||||
pub(crate) errors: Vec<SyntaxError>,
|
);
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TreeRoot: Clone + Send + Sync {
|
impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> {
|
||||||
fn borrowed(&self) -> RefRoot;
|
type Item = SyntaxNode<R>;
|
||||||
fn owned(&self) -> OwnedRoot;
|
|
||||||
|
|
||||||
#[doc(hidden)]
|
fn next(&mut self) -> Option<SyntaxNode<R>> {
|
||||||
fn syntax_root(&self) -> &SyntaxRoot;
|
self.0.next().map(SyntaxNode)
|
||||||
}
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct OwnedRoot(Arc<SyntaxRoot>);
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct RefRoot<'a>(&'a OwnedRoot); // TODO: shared_from_this instead of double indirection
|
|
||||||
|
|
||||||
impl<'a> RefRoot<'a> {
|
|
||||||
fn syntax_root(&self) -> &'a SyntaxRoot {
|
|
||||||
self.0.syntax_root()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TreeRoot for OwnedRoot {
|
|
||||||
fn borrowed(&self) -> RefRoot {
|
|
||||||
RefRoot(&self)
|
|
||||||
}
|
|
||||||
fn owned(&self) -> OwnedRoot {
|
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn syntax_root(&self) -> &SyntaxRoot {
|
fn has_short_text(kind: SyntaxKind) -> bool {
|
||||||
&*self.0
|
use SyntaxKind::*;
|
||||||
|
match kind {
|
||||||
|
IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TreeRoot for RefRoot<'a> {
|
|
||||||
fn borrowed(&self) -> RefRoot {
|
|
||||||
*self
|
|
||||||
}
|
|
||||||
fn owned(&self) -> OwnedRoot {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
|
||||||
fn syntax_root(&self) -> &SyntaxRoot {
|
|
||||||
self.0.syntax_root()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyntaxRoot {
|
|
||||||
pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
|
|
||||||
SyntaxRoot {
|
|
||||||
red: RedNode::new_root(green),
|
|
||||||
errors,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
|
|
||||||
pub(crate) struct RedPtr(ptr::NonNull<RedNode>);
|
|
||||||
|
|
||||||
unsafe impl Send for RedPtr {}
|
|
||||||
|
|
||||||
unsafe impl Sync for RedPtr {}
|
|
||||||
|
|
||||||
impl RedPtr {
|
|
||||||
fn new(red: &RedNode) -> RedPtr {
|
|
||||||
RedPtr(red.into())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe fn get<'a>(self, _root: &'a SyntaxRoot) -> &'a RedNode {
|
|
||||||
&*self.0.as_ptr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn assert_send_sync() {
|
|
||||||
fn f<T: Send + Sync>() {}
|
|
||||||
f::<GreenNode>();
|
|
||||||
f::<RedNode>();
|
|
||||||
f::<SyntaxNode>();
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
use parking_lot::RwLock;
|
|
||||||
use {yellow::{GreenNode, RedPtr}, TextUnit};
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct RedNode {
|
|
||||||
green: GreenNode,
|
|
||||||
parent: Option<ParentData>,
|
|
||||||
children: RwLock<Box<[RedChild]>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum RedChild {
|
|
||||||
Zigot(TextUnit),
|
|
||||||
Child(RedNode)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RedChild {
|
|
||||||
fn set(&mut self, node: RedNode) -> &RedNode {
|
|
||||||
match self {
|
|
||||||
RedChild::Child(node) => return node,
|
|
||||||
RedChild::Zigot(_) => {
|
|
||||||
*self = RedChild::Child(node);
|
|
||||||
match self {
|
|
||||||
RedChild::Child(node) => return node,
|
|
||||||
RedChild::Zigot(_) => unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ParentData {
|
|
||||||
parent: RedPtr,
|
|
||||||
start_offset: TextUnit,
|
|
||||||
index_in_parent: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RedNode {
|
|
||||||
pub fn new_root(green: GreenNode) -> RedNode {
|
|
||||||
RedNode::new(green, None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_child(
|
|
||||||
green: GreenNode,
|
|
||||||
parent: RedPtr,
|
|
||||||
start_offset: TextUnit,
|
|
||||||
index_in_parent: usize,
|
|
||||||
) -> RedNode {
|
|
||||||
let parent_data = ParentData {
|
|
||||||
parent,
|
|
||||||
start_offset,
|
|
||||||
index_in_parent,
|
|
||||||
};
|
|
||||||
RedNode::new(green, Some(parent_data))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new(green: GreenNode, parent: Option<ParentData>) -> RedNode {
|
|
||||||
let mut start_offset = parent.as_ref().map(|it| it.start_offset).unwrap_or(0.into());
|
|
||||||
let children = green.children()
|
|
||||||
.iter()
|
|
||||||
.map(|child| {
|
|
||||||
let off = start_offset;
|
|
||||||
start_offset += child.text_len();
|
|
||||||
RedChild::Zigot(off)
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_boxed_slice();
|
|
||||||
RedNode {
|
|
||||||
green,
|
|
||||||
parent,
|
|
||||||
children: RwLock::new(children),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn green(&self) -> &GreenNode {
|
|
||||||
&self.green
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn start_offset(&self) -> TextUnit {
|
|
||||||
match &self.parent {
|
|
||||||
None => 0.into(),
|
|
||||||
Some(p) => p.start_offset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn n_children(&self) -> usize {
|
|
||||||
self.green.children().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn get_child(&self, idx: usize) -> Option<RedPtr> {
|
|
||||||
if idx >= self.n_children() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let start_offset = match &self.children.read()[idx] {
|
|
||||||
RedChild::Child(child) => return Some(RedPtr::new(child)),
|
|
||||||
RedChild::Zigot(start_offset) => *start_offset,
|
|
||||||
};
|
|
||||||
let green_children = self.green.children();
|
|
||||||
let child =
|
|
||||||
RedNode::new_child(green_children[idx].clone(), RedPtr::new(self), start_offset, idx);
|
|
||||||
let mut children = self.children.write();
|
|
||||||
let child = children[idx].set(child);
|
|
||||||
Some(RedPtr::new(child))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn parent(&self) -> Option<RedPtr> {
|
|
||||||
Some(self.parent.as_ref()?.parent)
|
|
||||||
}
|
|
||||||
pub(crate) fn index_in_parent(&self) -> Option<usize> {
|
|
||||||
Some(self.parent.as_ref()?.index_in_parent)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,215 +0,0 @@
|
||||||
use std::{
|
|
||||||
fmt, sync::Arc,
|
|
||||||
hash::{Hasher, Hash},
|
|
||||||
ops::Range,
|
|
||||||
};
|
|
||||||
|
|
||||||
use smol_str::SmolStr;
|
|
||||||
|
|
||||||
use {
|
|
||||||
yellow::{GreenNode, RedNode, TreeRoot, SyntaxRoot, RedPtr, RefRoot, OwnedRoot, SyntaxText},
|
|
||||||
SyntaxKind::{self, *},
|
|
||||||
TextRange, TextUnit,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct SyntaxNode<R: TreeRoot = OwnedRoot> {
|
|
||||||
pub(crate) root: R,
|
|
||||||
// Guaranteed to not dangle, because `root` holds a
|
|
||||||
// strong reference to red's ancestor
|
|
||||||
red: RedPtr,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl<R: TreeRoot> Send for SyntaxNode<R> {}
|
|
||||||
unsafe impl<R: TreeRoot> Sync for SyntaxNode<R> {}
|
|
||||||
|
|
||||||
impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> {
|
|
||||||
fn eq(&self, other: &SyntaxNode<R1>) -> bool {
|
|
||||||
self.red == other.red
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: TreeRoot> Eq for SyntaxNode<R> {}
|
|
||||||
impl<R: TreeRoot> Hash for SyntaxNode<R> {
|
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
|
||||||
self.red.hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn syntax_node_ref_is_copy() {
|
|
||||||
fn assert_copy<T: Copy>(){}
|
|
||||||
assert_copy::<SyntaxNodeRef>()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
|
||||||
pub struct SyntaxError {
|
|
||||||
pub msg: String,
|
|
||||||
pub offset: TextUnit,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SyntaxNode<OwnedRoot> {
|
|
||||||
pub(crate) fn new_owned(root: SyntaxRoot) -> Self {
|
|
||||||
let root = OwnedRoot(Arc::new(root));
|
|
||||||
let red = RedPtr::new(&root.syntax_root().red);
|
|
||||||
SyntaxNode { root, red }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> SyntaxNode<RefRoot<'a>> {
|
|
||||||
pub(crate) fn leaf_text_ref(self) -> Option<&'a SmolStr> {
|
|
||||||
let red = unsafe { self.red.get(self.root.syntax_root()) };
|
|
||||||
red.green().leaf_text_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: TreeRoot> SyntaxNode<R> {
|
|
||||||
pub fn borrowed<'a>(&'a self) -> SyntaxNodeRef<'a> {
|
|
||||||
SyntaxNode {
|
|
||||||
root: self.root.borrowed(),
|
|
||||||
red: self.red,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn owned(&self) -> SyntaxNode {
|
|
||||||
SyntaxNode {
|
|
||||||
root: self.root.owned(),
|
|
||||||
red: self.red,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn kind(&self) -> SyntaxKind {
|
|
||||||
self.red().green().kind()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn range(&self) -> TextRange {
|
|
||||||
let red = self.red();
|
|
||||||
TextRange::offset_len(red.start_offset(), red.green().text_len())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn text(&self) -> SyntaxText {
|
|
||||||
SyntaxText::new(self.borrowed())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn children(&self) -> SyntaxNodeChildren<R> {
|
|
||||||
SyntaxNodeChildren {
|
|
||||||
parent: self.clone(),
|
|
||||||
iter: (0..self.red().n_children())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parent(&self) -> Option<SyntaxNode<R>> {
|
|
||||||
let parent = self.red().parent()?;
|
|
||||||
Some(SyntaxNode {
|
|
||||||
root: self.root.clone(),
|
|
||||||
red: parent,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn first_child(&self) -> Option<SyntaxNode<R>> {
|
|
||||||
let red = self.red().get_child(0)?;
|
|
||||||
Some(SyntaxNode { root: self.root.clone(), red })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn last_child(&self) -> Option<SyntaxNode<R>> {
|
|
||||||
let n = self.red().n_children();
|
|
||||||
let n = n.checked_sub(1)?;
|
|
||||||
let red = self.red().get_child(n)?;
|
|
||||||
Some(SyntaxNode { root: self.root.clone(), red })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next_sibling(&self) -> Option<SyntaxNode<R>> {
|
|
||||||
let red = self.red();
|
|
||||||
let parent = self.parent()?;
|
|
||||||
let next_sibling_idx = red.index_in_parent()? + 1;
|
|
||||||
let sibling_red = parent.red().get_child(next_sibling_idx)?;
|
|
||||||
Some(SyntaxNode {
|
|
||||||
root: self.root.clone(),
|
|
||||||
red: sibling_red,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prev_sibling(&self) -> Option<SyntaxNode<R>> {
|
|
||||||
let red = self.red();
|
|
||||||
let parent = self.parent()?;
|
|
||||||
let prev_sibling_idx = red.index_in_parent()?.checked_sub(1)?;
|
|
||||||
let sibling_red = parent.red().get_child(prev_sibling_idx)?;
|
|
||||||
Some(SyntaxNode {
|
|
||||||
root: self.root.clone(),
|
|
||||||
red: sibling_red,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_leaf(&self) -> bool {
|
|
||||||
self.first_child().is_none()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn leaf_text(&self) -> Option<SmolStr> {
|
|
||||||
self.borrowed().leaf_text_ref().map(|it| it.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn replace_with(&self, green: GreenNode) -> GreenNode {
|
|
||||||
assert_eq!(self.kind(), green.kind());
|
|
||||||
match self.parent() {
|
|
||||||
None => green,
|
|
||||||
Some(parent) => {
|
|
||||||
let children: Vec<_> = parent.children().map(|child| {
|
|
||||||
if child == *self {
|
|
||||||
green.clone()
|
|
||||||
} else {
|
|
||||||
child.red().green().clone()
|
|
||||||
}
|
|
||||||
}).collect();
|
|
||||||
let new_parent = GreenNode::new_branch(
|
|
||||||
parent.kind(),
|
|
||||||
children.into_boxed_slice(),
|
|
||||||
);
|
|
||||||
parent.replace_with(new_parent)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn red(&self) -> &RedNode {
|
|
||||||
unsafe { self.red.get(self.root.syntax_root()) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: TreeRoot> fmt::Debug for SyntaxNode<R> {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(fmt, "{:?}@{:?}", self.kind(), self.range())?;
|
|
||||||
if has_short_text(self.kind()) {
|
|
||||||
write!(fmt, " \"{}\"", self.text())?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SyntaxNodeChildren<R: TreeRoot> {
|
|
||||||
parent: SyntaxNode<R>,
|
|
||||||
iter: Range<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: TreeRoot> Iterator for SyntaxNodeChildren<R> {
|
|
||||||
type Item = SyntaxNode<R>;
|
|
||||||
|
|
||||||
fn next(&mut self) -> Option<SyntaxNode<R>> {
|
|
||||||
self.iter.next().map(|i| {
|
|
||||||
let red = self.parent.red();
|
|
||||||
SyntaxNode {
|
|
||||||
root: self.parent.root.clone(),
|
|
||||||
red: red.get_child(i).unwrap(),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_short_text(kind: SyntaxKind) -> bool {
|
|
||||||
match kind {
|
|
||||||
IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -25,7 +25,7 @@ impl<'a> SyntaxText<'a> {
|
||||||
let range = self.range;
|
let range = self.range;
|
||||||
preorder(self.node)
|
preorder(self.node)
|
||||||
.filter_map(move |node| {
|
.filter_map(move |node| {
|
||||||
let text = node.leaf_text_ref()?;
|
let text = node.leaf_text()?;
|
||||||
let range = intersect(range, node.range())?;
|
let range = intersect(range, node.range())?;
|
||||||
let range = range - node.range().start();
|
let range = range - node.range().start();
|
||||||
Some(&text[range])
|
Some(&text[range])
|
||||||
|
|
Loading…
Reference in a new issue