85: start moving syntax tree to a separate crate r=matklad a=matklad

WIP

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2018-10-02 14:14:56 +00:00
commit 7ffc114dab
13 changed files with 169 additions and 551 deletions

14
Cargo.lock generated
View File

@ -602,9 +602,8 @@ dependencies = [
"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)",
"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",
"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)",
"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)",
]
[[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]]
name = "rustc-demangle"
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 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 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_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"

View File

@ -1,5 +1,6 @@
[workspace]
members = [ "crates/*" ]
exclude = [ "crates/rowan"]
[profile.release]
debug = true

View File

@ -6,11 +6,10 @@ license = "MIT OR Apache-2.0"
[dependencies]
unicode-xid = "0.1.0"
text_unit = "0.1.4"
itertools = "0.7.8"
drop_bomb = "0.1.4"
parking_lot = "0.6.0"
smol_str = "0.1.6"
rowan = "0.1.0"
[dev-dependencies]
test_utils = { path = "../test_utils" }

View File

@ -3,10 +3,9 @@
use std::marker::PhantomData;
use itertools::Itertools;
use smol_str::SmolStr;
use {
SyntaxNodeRef, SyntaxKind::*,
SmolStr, SyntaxNodeRef, SyntaxKind::*,
yellow::{RefRoot, SyntaxNodeChildren},
};
pub use self::generated::*;
@ -76,7 +75,7 @@ pub fn as_atom(&self) -> Option<SmolStr> {
let tt = self.value()?;
let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
if attr.kind() == IDENT {
Some(attr.leaf_text().unwrap())
Some(attr.leaf_text().unwrap().clone())
} else {
None
}
@ -87,7 +86,7 @@ pub fn as_call(&self) -> Option<(SmolStr, TokenTree<'a>)> {
let (_bra, attr, args, _ket) = tt.syntax().children().collect_tuple()?;
let args = TokenTree::cast(args)?;
if attr.kind() == IDENT {
Some((attr.leaf_text().unwrap(), args))
Some((attr.leaf_text().unwrap().clone(), args))
} else {
None
}
@ -96,7 +95,7 @@ pub fn as_call(&self) -> Option<(SmolStr, TokenTree<'a>)> {
impl<'a> Lifetime<'a> {
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 {
let ident = self.syntax().first_child()
.unwrap();
ident.leaf_text().unwrap()
ident.leaf_text().unwrap().clone()
}
}
@ -112,7 +111,7 @@ impl<'a> NameRef<'a> {
pub fn text(&self) -> SmolStr {
let ident = self.syntax().first_child()
.unwrap();
ident.leaf_text().unwrap()
ident.leaf_text().unwrap().clone()
}
}

View File

@ -24,8 +24,7 @@
extern crate unicode_xid;
extern crate drop_bomb;
extern crate parking_lot;
extern crate smol_str;
extern crate text_unit;
extern crate rowan;
#[cfg(test)]
#[macro_use]
@ -48,8 +47,7 @@
pub mod text_utils;
pub use {
text_unit::{TextRange, TextUnit},
smol_str::SmolStr,
rowan::{SmolStr, TextRange, TextUnit},
ast::AstNode,
lexer::{tokenize, Token},
syntax_kinds::SyntaxKind,
@ -58,7 +56,7 @@
};
use {
yellow::{GreenNode, SyntaxRoot},
yellow::{GreenNode},
};
#[derive(Clone, Debug, Hash)]
@ -68,8 +66,7 @@ pub struct File {
impl File {
fn new(green: GreenNode, errors: Vec<SyntaxError>) -> File {
let root = SyntaxRoot::new(green, errors);
let root = SyntaxNode::new_owned(root);
let root = SyntaxNode::new(green, errors);
if cfg!(debug_assertions) {
utils::validate_block_structure(root.borrowed());
}
@ -100,6 +97,6 @@ pub fn syntax(&self) -> SyntaxNodeRef {
self.root.borrowed()
}
pub fn errors(&self) -> Vec<SyntaxError> {
self.syntax().root.syntax_root().errors.clone()
self.root.root_data().clone()
}
}

View File

@ -1,11 +1,11 @@
use algo;
use grammar;
use lexer::{tokenize, Token};
use text_unit::{TextRange, TextUnit};
use yellow::{self, SyntaxNodeRef, GreenNode, SyntaxError};
use yellow::{self, GreenNode, SyntaxNodeRef, SyntaxError};
use parser_impl;
use parser_api::Parser;
use {
TextUnit, TextRange,
SyntaxKind::*,
};
use text_utils::replace_range;
@ -65,7 +65,7 @@ fn reparse_leaf<'node>(
return None;
}
let green = GreenNode::new_leaf(node.kind(), &text);
let green = GreenNode::new_leaf(node.kind(), text.into());
let new_errors = vec![];
Some((node, green, new_errors))
}

View File

@ -1,12 +1,12 @@
use std::fmt::Write;
use {
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.
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);
let mut err_pos = 0;
let mut level = 0;

View File

@ -1,15 +1,15 @@
use rowan::GreenNodeBuilder;
use {
parser_impl::Sink,
yellow::{GreenNode, SyntaxError},
yellow::{GreenNode, SyntaxError, RaTypes},
SyntaxKind, TextRange, TextUnit,
};
pub(crate) struct GreenBuilder<'a> {
text: &'a str,
parents: Vec<(SyntaxKind, usize)>,
children: Vec<GreenNode>,
pos: TextUnit,
errors: Vec<SyntaxError>,
inner: GreenNodeBuilder<RaTypes>,
}
impl<'a> Sink<'a> for GreenBuilder<'a> {
@ -18,35 +18,25 @@ impl<'a> Sink<'a> for GreenBuilder<'a> {
fn new(text: &'a str) -> Self {
GreenBuilder {
text,
parents: Vec::new(),
children: Vec::new(),
pos: 0.into(),
errors: Vec::new(),
inner: GreenNodeBuilder::new(),
}
}
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
let range = TextRange::offset_len(self.pos, len);
self.pos += len;
let text = &self.text[range];
self.children.push(
GreenNode::new_leaf(kind, text)
);
let text = self.text[range].into();
self.inner.leaf(kind, text);
}
fn start_internal(&mut self, kind: SyntaxKind) {
let len = self.children.len();
self.parents.push((kind, len));
self.inner.start_internal(kind)
}
fn finish_internal(&mut self) {
let (kind, first_child) = self.parents.pop().unwrap();
let children: Vec<_> = self.children
.drain(first_child..)
.collect();
self.children.push(
GreenNode::new_branch(kind, children.into_boxed_slice())
);
self.inner.finish_internal();
}
fn error(&mut self, message: String) {
@ -56,9 +46,7 @@ fn error(&mut self, message: String) {
})
}
fn finish(mut self) -> (GreenNode, Vec<SyntaxError>) {
assert_eq!(self.children.len(), 1);
let root = self.children.pop().unwrap();
(root, self.errors)
fn finish(self) -> (GreenNode, Vec<SyntaxError>) {
(self.inner.finish(), self.errors)
}
}

View File

@ -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>());
}

View File

@ -1,100 +1,142 @@
mod builder;
mod green;
mod red;
mod syntax;
mod syntax_text;
use std::{
sync::Arc,
ptr,
};
pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxError, SyntaxNodeChildren};
pub(crate) use self::{
builder::GreenBuilder,
green::GreenNode,
red::RedNode,
syntax_text::SyntaxText,
fmt,
hash::{Hash, Hasher},
};
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)]
pub struct SyntaxRoot {
red: RedNode,
pub(crate) errors: Vec<SyntaxError>,
}
pub struct SyntaxNodeChildren<R: TreeRoot<RaTypes>>(
::rowan::SyntaxNodeChildren<RaTypes, R>
);
pub trait TreeRoot: Clone + Send + Sync {
fn borrowed(&self) -> RefRoot;
fn owned(&self) -> OwnedRoot;
impl<R: TreeRoot<RaTypes>> Iterator for SyntaxNodeChildren<R> {
type Item = SyntaxNode<R>;
#[doc(hidden)]
fn syntax_root(&self) -> &SyntaxRoot;
}
#[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()
fn next(&mut self) -> Option<SyntaxNode<R>> {
self.0.next().map(SyntaxNode)
}
}
impl TreeRoot for OwnedRoot {
fn borrowed(&self) -> RefRoot {
RefRoot(&self)
}
fn owned(&self) -> OwnedRoot {
self.clone()
}
fn syntax_root(&self) -> &SyntaxRoot {
&*self.0
fn has_short_text(kind: SyntaxKind) -> bool {
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>();
}

View File

@ -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)
}
}

View File

@ -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,
}
}

View File

@ -25,7 +25,7 @@ pub fn chunks(&self) -> impl Iterator<Item=&'a str> {
let range = self.range;
preorder(self.node)
.filter_map(move |node| {
let text = node.leaf_text_ref()?;
let text = node.leaf_text()?;
let range = intersect(range, node.range())?;
let range = range - node.range().start();
Some(&text[range])