Owned&Borrowed nodes

HOLLY COW, UNLIKE C++, WE CAN BE GENERIC WRT OWNERSHIP/BORROWING, SO
WE CAN BOTH MAKE SYNTAX NODES OWNED (WHICH IS CONVENIENT) AND
BORROWED (WHICH IS CONVENIENT FOR LOCAL PROCESSING, BC YOU DON'T NEED
TO BUMP REFCOUNTS).
This commit is contained in:
Aleksey Kladov 2018-07-30 03:21:17 +03:00
parent 83acbc06bd
commit ae849cf134
4 changed files with 42 additions and 21 deletions

View File

@ -27,7 +27,7 @@ mod syntax_kinds;
pub use { pub use {
text_unit::{TextRange, TextUnit}, text_unit::{TextRange, TextUnit},
syntax_kinds::SyntaxKind, syntax_kinds::SyntaxKind,
yellow::{SyntaxNode}, yellow::{SyntaxNode, SyntaxNodeRef},
lexer::{tokenize, Token}, lexer::{tokenize, Token},
}; };
@ -48,16 +48,17 @@ pub mod utils {
collections::BTreeSet collections::BTreeSet
}; };
use {SyntaxNode, SyntaxError}; use {SyntaxNode, SyntaxNodeRef, SyntaxError};
/// 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_green(syntax: &SyntaxNode) -> String { pub fn dump_tree_green(syntax: &SyntaxNode) -> String {
let syntax = syntax.borrow();
let mut errors: BTreeSet<_> = syntax.root.errors.iter().cloned().collect(); let mut errors: BTreeSet<_> = syntax.root.errors.iter().cloned().collect();
let mut result = String::new(); let mut result = String::new();
go(syntax, &mut result, 0, &mut errors); go(syntax, &mut result, 0, &mut errors);
return result; return result;
fn go(node: &SyntaxNode, buff: &mut String, level: usize, errors: &mut BTreeSet<SyntaxError>) { fn go(node: SyntaxNodeRef, buff: &mut String, level: usize, errors: &mut BTreeSet<SyntaxError>) {
buff.push_str(&String::from(" ").repeat(level)); buff.push_str(&String::from(" ").repeat(level));
write!(buff, "{:?}\n", node).unwrap(); write!(buff, "{:?}\n", node).unwrap();
let my_errors: Vec<_> = errors.iter().filter(|e| e.offset == node.range().start()) let my_errors: Vec<_> = errors.iter().filter(|e| e.offset == node.range().start())
@ -68,7 +69,7 @@ pub mod utils {
write!(buff, "err: `{}`\n", err.message).unwrap(); write!(buff, "err: `{}`\n", err.message).unwrap();
} }
for child in node.children().iter() { for child in node.children() {
go(child, buff, level + 1, errors) go(child, buff, level + 1, errors)
} }

View File

@ -1,6 +1,6 @@
use { use {
SyntaxKind, TextRange, TextUnit, SyntaxKind, TextRange, TextUnit,
yellow::{SyntaxNode, GreenNode, GreenNodeBuilder, SyntaxError}, yellow::{SyntaxNode, SyntaxRoot, GreenNode, GreenNodeBuilder, SyntaxError},
parser::Sink parser::Sink
}; };
@ -57,7 +57,8 @@ impl Sink for GreenBuilder {
} }
fn finish(self) -> SyntaxNode { fn finish(self) -> SyntaxNode {
SyntaxNode::new(self.root.unwrap(), self.errors) let root = SyntaxRoot::new(self.root.unwrap(), self.errors);
SyntaxNode::new_owned(root)
} }
} }

View File

@ -6,7 +6,7 @@ mod builder;
pub(crate) use self::{ pub(crate) use self::{
green::{GreenNode, GreenNodeBuilder}, green::{GreenNode, GreenNodeBuilder},
red::RedNode, red::RedNode,
syntax::SyntaxError, syntax::{SyntaxError, SyntaxRoot},
builder::GreenBuilder, builder::GreenBuilder,
}; };
pub use self::syntax::SyntaxNode; pub use self::syntax::{SyntaxNode, SyntaxNodeRef};

View File

@ -10,17 +10,28 @@ use {
yellow::{RedNode, GreenNode}, yellow::{RedNode, GreenNode},
}; };
#[derive(Clone)] #[derive(Clone, Copy)]
pub struct SyntaxNode { pub struct SyntaxNode<ROOT: ::std::ops::Deref<Target=SyntaxRoot> + Clone = Arc<SyntaxRoot>> {
pub(crate) root: SyntaxRoot, pub(crate) root: ROOT,
// guaranteed to be alive bc SyntaxRoot holds a strong ref // guaranteed to be alive bc SyntaxRoot holds a strong ref
red: ptr::NonNull<RedNode>, red: ptr::NonNull<RedNode>,
} }
#[derive(Clone)] pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>;
#[derive(Debug)]
pub struct SyntaxRoot { pub struct SyntaxRoot {
red: Arc<RedNode>, red: RedNode,
pub(crate) errors: Arc<Vec<SyntaxError>>, pub(crate) errors: Vec<SyntaxError>,
}
impl SyntaxRoot {
pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
SyntaxRoot {
red: RedNode::new_root(green),
errors,
}
}
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
@ -29,13 +40,21 @@ pub(crate) struct SyntaxError {
pub(crate) offset: TextUnit, pub(crate) offset: TextUnit,
} }
impl SyntaxNode { impl SyntaxNode<Arc<SyntaxRoot>> {
pub(crate) fn new(root: GreenNode, errors: Vec<SyntaxError>) -> SyntaxNode { pub(crate) fn new_owned(root: SyntaxRoot) -> Self {
let red = Arc::new(RedNode::new_root(root)); let root = Arc::new(root);
let red_weak: ptr::NonNull<RedNode> = (&*red).into(); let red_weak = ptr::NonNull::from(&root.red);
let root = SyntaxRoot { red, errors: Arc::new(errors) };
SyntaxNode { root, red: red_weak } SyntaxNode { root, red: red_weak }
} }
}
impl<ROOT: ::std::ops::Deref<Target=SyntaxRoot> + Clone> SyntaxNode<ROOT> {
pub fn borrow<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> {
SyntaxNode {
root: &*self.root,
red: ptr::NonNull::clone(&self.red),
}
}
pub fn kind(&self) -> SyntaxKind { pub fn kind(&self) -> SyntaxKind {
self.red().green().kind() self.red().green().kind()
@ -53,7 +72,7 @@ impl SyntaxNode {
self.red().green().text() self.red().green().text()
} }
pub fn children(&self) -> Vec<SyntaxNode> { pub fn children(&self) -> Vec<SyntaxNode<ROOT>> {
let red = self.red(); let red = self.red();
let n_children = red.n_children(); let n_children = red.n_children();
let mut res = Vec::with_capacity(n_children); let mut res = Vec::with_capacity(n_children);
@ -71,7 +90,7 @@ impl SyntaxNode {
} }
} }
impl fmt::Debug for SyntaxNode { impl<ROOT: ::std::ops::Deref<Target=SyntaxRoot> + Clone> fmt::Debug for SyntaxNode<ROOT> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{:?}@{:?}", self.kind(), self.range())?; write!(fmt, "{:?}@{:?}", self.kind(), self.range())?;
if has_short_text(self.kind()) { if has_short_text(self.kind()) {