2019-07-04 20:05:17 +00:00
|
|
|
use std::{iter::successors, marker::PhantomData};
|
2019-01-23 14:37:10 +00:00
|
|
|
|
2019-07-18 16:23:05 +00:00
|
|
|
use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};
|
|
|
|
|
2019-01-23 14:37:10 +00:00
|
|
|
/// A pointer to a syntax node inside a file. It can be used to remember a
|
|
|
|
/// specific node across reparses of the same file.
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
|
|
pub struct SyntaxNodePtr {
|
2019-04-21 14:47:55 +00:00
|
|
|
pub(crate) range: TextRange,
|
2019-01-23 14:37:10 +00:00
|
|
|
kind: SyntaxKind,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SyntaxNodePtr {
|
|
|
|
pub fn new(node: &SyntaxNode) -> SyntaxNodePtr {
|
2019-07-20 09:58:27 +00:00
|
|
|
SyntaxNodePtr { range: node.text_range(), kind: node.kind() }
|
2019-01-23 14:37:10 +00:00
|
|
|
}
|
|
|
|
|
2019-09-03 08:04:38 +00:00
|
|
|
pub fn to_node(self, root: &SyntaxNode) -> SyntaxNode {
|
|
|
|
assert!(root.parent().is_none());
|
|
|
|
successors(Some(root.clone()), |node| {
|
2019-07-20 09:58:27 +00:00
|
|
|
node.children().find(|it| self.range.is_subrange(&it.text_range()))
|
2019-01-23 14:37:10 +00:00
|
|
|
})
|
2019-07-20 09:58:27 +00:00
|
|
|
.find(|it| it.text_range() == self.range && it.kind() == self.kind)
|
2019-01-23 14:37:10 +00:00
|
|
|
.unwrap_or_else(|| panic!("can't resolve local ptr to SyntaxNode: {:?}", self))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn range(self) -> TextRange {
|
|
|
|
self.range
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn kind(self) -> SyntaxKind {
|
|
|
|
self.kind
|
|
|
|
}
|
2019-08-12 19:39:11 +00:00
|
|
|
|
|
|
|
pub fn cast<N: AstNode>(self) -> Option<AstPtr<N>> {
|
|
|
|
if !N::can_cast(self.kind()) {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(AstPtr { raw: self, _ty: PhantomData })
|
|
|
|
}
|
2019-01-23 14:37:10 +00:00
|
|
|
}
|
|
|
|
|
2019-01-23 15:26:02 +00:00
|
|
|
/// Like `SyntaxNodePtr`, but remembers the type of node
|
|
|
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub struct AstPtr<N: AstNode> {
|
2019-01-24 10:40:36 +00:00
|
|
|
raw: SyntaxNodePtr,
|
2019-07-18 15:13:32 +00:00
|
|
|
_ty: PhantomData<fn() -> N>,
|
2019-01-23 15:26:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<N: AstNode> Copy for AstPtr<N> {}
|
|
|
|
impl<N: AstNode> Clone for AstPtr<N> {
|
|
|
|
fn clone(&self) -> AstPtr<N> {
|
|
|
|
*self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<N: AstNode> AstPtr<N> {
|
|
|
|
pub fn new(node: &N) -> AstPtr<N> {
|
2019-02-08 11:49:43 +00:00
|
|
|
AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
|
2019-01-23 15:26:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-18 16:23:05 +00:00
|
|
|
pub fn to_node(self, root: &SyntaxNode) -> N {
|
2019-05-13 16:39:06 +00:00
|
|
|
let syntax_node = self.raw.to_node(root);
|
2019-01-23 15:26:02 +00:00
|
|
|
N::cast(syntax_node).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn syntax_node_ptr(self) -> SyntaxNodePtr {
|
2019-01-24 10:40:36 +00:00
|
|
|
self.raw
|
2019-01-23 15:26:02 +00:00
|
|
|
}
|
2019-07-19 12:53:16 +00:00
|
|
|
|
2019-07-19 15:22:00 +00:00
|
|
|
pub fn cast<U: AstNode>(self) -> Option<AstPtr<U>> {
|
|
|
|
if !U::can_cast(self.raw.kind()) {
|
2019-07-19 12:53:16 +00:00
|
|
|
return None;
|
|
|
|
}
|
|
|
|
Some(AstPtr { raw: self.raw, _ty: PhantomData })
|
|
|
|
}
|
2019-01-23 15:26:02 +00:00
|
|
|
}
|
|
|
|
|
2019-03-23 13:28:47 +00:00
|
|
|
impl<N: AstNode> From<AstPtr<N>> for SyntaxNodePtr {
|
|
|
|
fn from(ptr: AstPtr<N>) -> SyntaxNodePtr {
|
|
|
|
ptr.raw
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-23 14:37:10 +00:00
|
|
|
#[test]
|
|
|
|
fn test_local_syntax_ptr() {
|
2019-05-13 16:39:06 +00:00
|
|
|
use crate::{ast, AstNode, SourceFile};
|
2019-01-23 14:37:10 +00:00
|
|
|
|
2019-05-28 14:34:28 +00:00
|
|
|
let file = SourceFile::parse("struct Foo { f: u32, }").ok().unwrap();
|
2019-08-23 12:55:21 +00:00
|
|
|
let field = file.syntax().descendants().find_map(ast::RecordFieldDef::cast).unwrap();
|
2019-01-23 14:37:10 +00:00
|
|
|
let ptr = SyntaxNodePtr::new(field.syntax());
|
2019-05-13 16:39:06 +00:00
|
|
|
let field_syntax = ptr.to_node(file.syntax());
|
2019-07-18 16:23:05 +00:00
|
|
|
assert_eq!(field.syntax(), &field_syntax);
|
2019-01-23 14:37:10 +00:00
|
|
|
}
|