Merge #85
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:
commit
7ffc114dab
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)",
|
||||
"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"
|
||||
|
@ -1,5 +1,6 @@
|
||||
[workspace]
|
||||
members = [ "crates/*" ]
|
||||
exclude = [ "crates/rowan"]
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
@ -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" }
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
@ -340,4 +340,4 @@ enum Foo {
|
||||
}
|
||||
", "Clone");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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 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>();
|
||||
}
|
||||
|
@ -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 @@ 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])
|
||||
|
Loading…
Reference in New Issue
Block a user