aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax')
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/algo.rs130
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs13
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs5
-rw-r--r--crates/ra_syntax/src/lib.rs32
-rw-r--r--crates/ra_syntax/src/parsing/reparsing.rs13
-rw-r--r--crates/ra_syntax/src/syntax_node.rs492
-rw-r--r--crates/ra_syntax/src/syntax_text.rs178
-rw-r--r--crates/ra_syntax/src/validation.rs6
9 files changed, 164 insertions, 707 deletions
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index a5565de33..97b6b047f 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -10,7 +10,7 @@ repository = "https://github.com/rust-analyzer/rust-analyzer"
10[dependencies] 10[dependencies]
11unicode-xid = "0.1.0" 11unicode-xid = "0.1.0"
12itertools = "0.8.0" 12itertools = "0.8.0"
13rowan = "0.5.6" 13rowan = "0.6.0-pre.1"
14 14
15# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 15# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
16# to reduce number of compilations 16# to reduce number of compilations
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index f47e11e66..45f624810 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -1,18 +1,12 @@
1pub mod visit; 1pub mod visit;
2 2
3use itertools::Itertools; 3use std::ops::RangeInclusive;
4
5use crate::{AstNode, Direction, SyntaxElement, SyntaxNode, SyntaxToken, TextRange, TextUnit};
6 4
7pub use rowan::TokenAtOffset; 5use itertools::Itertools;
8 6
9pub fn find_token_at_offset(node: &SyntaxNode, offset: TextUnit) -> TokenAtOffset<SyntaxToken> { 7use crate::{
10 match node.0.token_at_offset(offset) { 8 AstNode, Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxNodePtr, TextRange, TextUnit,
11 TokenAtOffset::None => TokenAtOffset::None, 9};
12 TokenAtOffset::Single(n) => TokenAtOffset::Single(SyntaxToken(n)),
13 TokenAtOffset::Between(l, r) => TokenAtOffset::Between(SyntaxToken(l), SyntaxToken(r)),
14 }
15}
16 10
17/// Returns ancestors of the node at the offset, sorted by length. This should 11/// Returns ancestors of the node at the offset, sorted by length. This should
18/// do the right thing at an edge, e.g. when searching for expressions at `{ 12/// do the right thing at an edge, e.g. when searching for expressions at `{
@@ -23,7 +17,7 @@ pub fn ancestors_at_offset(
23 node: &SyntaxNode, 17 node: &SyntaxNode,
24 offset: TextUnit, 18 offset: TextUnit,
25) -> impl Iterator<Item = SyntaxNode> { 19) -> impl Iterator<Item = SyntaxNode> {
26 find_token_at_offset(node, offset) 20 node.token_at_offset(offset)
27 .map(|token| token.parent().ancestors()) 21 .map(|token| token.parent().ancestors())
28 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len()) 22 .kmerge_by(|node1, node2| node1.text_range().len() < node2.text_range().len())
29} 23}
@@ -44,20 +38,118 @@ pub fn find_node_at_offset<N: AstNode>(syntax: &SyntaxNode, offset: TextUnit) ->
44/// Finds the first sibling in the given direction which is not `trivia` 38/// Finds the first sibling in the given direction which is not `trivia`
45pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> { 39pub fn non_trivia_sibling(element: SyntaxElement, direction: Direction) -> Option<SyntaxElement> {
46 return match element { 40 return match element {
47 SyntaxElement::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia), 41 NodeOrToken::Node(node) => node.siblings_with_tokens(direction).skip(1).find(not_trivia),
48 SyntaxElement::Token(token) => { 42 NodeOrToken::Token(token) => token.siblings_with_tokens(direction).skip(1).find(not_trivia),
49 token.siblings_with_tokens(direction).skip(1).find(not_trivia)
50 }
51 }; 43 };
52 44
53 fn not_trivia(element: &SyntaxElement) -> bool { 45 fn not_trivia(element: &SyntaxElement) -> bool {
54 match element { 46 match element {
55 SyntaxElement::Node(_) => true, 47 NodeOrToken::Node(_) => true,
56 SyntaxElement::Token(token) => !token.kind().is_trivia(), 48 NodeOrToken::Token(token) => !token.kind().is_trivia(),
57 } 49 }
58 } 50 }
59} 51}
60 52
61pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement { 53pub fn find_covering_element(root: &SyntaxNode, range: TextRange) -> SyntaxElement {
62 SyntaxElement::new(root.0.covering_node(range)) 54 root.covering_element(range)
55}
56
57#[derive(Debug, PartialEq, Eq, Clone, Copy)]
58pub enum InsertPosition<T> {
59 First,
60 Last,
61 Before(T),
62 After(T),
63}
64
65/// Adds specified children (tokens or nodes) to the current node at the
66/// specific position.
67///
68/// This is a type-unsafe low-level editing API, if you need to use it,
69/// prefer to create a type-safe abstraction on top of it instead.
70pub fn insert_children(
71 parent: &SyntaxNode,
72 position: InsertPosition<SyntaxElement>,
73 to_insert: impl Iterator<Item = SyntaxElement>,
74) -> SyntaxNode {
75 let mut delta = TextUnit::default();
76 let to_insert = to_insert.map(|element| {
77 delta += element.text_range().len();
78 to_green_element(element)
79 });
80
81 let old_children = parent.green().children();
82
83 let new_children = match &position {
84 InsertPosition::First => {
85 to_insert.chain(old_children.iter().cloned()).collect::<Box<[_]>>()
86 }
87 InsertPosition::Last => old_children.iter().cloned().chain(to_insert).collect::<Box<[_]>>(),
88 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => {
89 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 };
90 let split_at = position_of_child(parent, anchor.clone()) + take_anchor;
91 let (before, after) = old_children.split_at(split_at);
92 before
93 .iter()
94 .cloned()
95 .chain(to_insert)
96 .chain(after.iter().cloned())
97 .collect::<Box<[_]>>()
98 }
99 };
100
101 with_children(parent, new_children)
102}
103
104/// Replaces all nodes in `to_delete` with nodes from `to_insert`
105///
106/// This is a type-unsafe low-level editing API, if you need to use it,
107/// prefer to create a type-safe abstraction on top of it instead.
108pub fn replace_children(
109 parent: &SyntaxNode,
110 to_delete: RangeInclusive<SyntaxElement>,
111 to_insert: impl Iterator<Item = SyntaxElement>,
112) -> SyntaxNode {
113 let start = position_of_child(parent, to_delete.start().clone());
114 let end = position_of_child(parent, to_delete.end().clone());
115 let old_children = parent.green().children();
116
117 let new_children = old_children[..start]
118 .iter()
119 .cloned()
120 .chain(to_insert.map(to_green_element))
121 .chain(old_children[end + 1..].iter().cloned())
122 .collect::<Box<[_]>>();
123 with_children(parent, new_children)
124}
125
126fn with_children(
127 parent: &SyntaxNode,
128 new_children: Box<[NodeOrToken<rowan::GreenNode, rowan::GreenToken>]>,
129) -> SyntaxNode {
130 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>();
131 let new_node =
132 rowan::GreenNode::new(rowan::cursor::SyntaxKind(parent.kind() as u16), new_children);
133 let new_root_node = parent.replace_with(new_node);
134 let new_root_node = SyntaxNode::new_root(new_root_node);
135
136 // FIXME: use a more elegant way to re-fetch the node (#1185), make
137 // `range` private afterwards
138 let mut ptr = SyntaxNodePtr::new(parent);
139 ptr.range = TextRange::offset_len(ptr.range().start(), len);
140 ptr.to_node(&new_root_node)
141}
142
143fn position_of_child(parent: &SyntaxNode, child: SyntaxElement) -> usize {
144 parent
145 .children_with_tokens()
146 .position(|it| it == child)
147 .expect("element is not a child of current element")
148}
149
150fn to_green_element(element: SyntaxElement) -> NodeOrToken<rowan::GreenNode, rowan::GreenToken> {
151 match element {
152 NodeOrToken::Node(it) => it.green().clone().into(),
153 NodeOrToken::Token(it) => it.green().clone().into(),
154 }
63} 155}
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs
index 139bd3ec0..f9190d877 100644
--- a/crates/ra_syntax/src/ast/expr_extensions.rs
+++ b/crates/ra_syntax/src/ast/expr_extensions.rs
@@ -2,7 +2,7 @@
2 2
3use crate::{ 3use crate::{
4 ast::{self, child_opt, children, AstChildren, AstNode}, 4 ast::{self, child_opt, children, AstChildren, AstNode},
5 SmolStr, SyntaxElement, 5 SmolStr,
6 SyntaxKind::*, 6 SyntaxKind::*,
7 SyntaxToken, T, 7 SyntaxToken, T,
8}; 8};
@@ -229,14 +229,11 @@ pub enum LiteralKind {
229 229
230impl ast::Literal { 230impl ast::Literal {
231 pub fn token(&self) -> SyntaxToken { 231 pub fn token(&self) -> SyntaxToken {
232 let elem = self 232 self.syntax()
233 .syntax()
234 .children_with_tokens() 233 .children_with_tokens()
235 .find(|e| e.kind() != ATTR && !e.kind().is_trivia()); 234 .find(|e| e.kind() != ATTR && !e.kind().is_trivia())
236 match elem { 235 .and_then(|e| e.into_token())
237 Some(SyntaxElement::Token(token)) => token, 236 .unwrap()
238 _ => unreachable!(),
239 }
240 } 237 }
241 238
242 pub fn kind(&self) -> LiteralKind { 239 pub fn kind(&self) -> LiteralKind {
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index 753fc42c6..d4873b39a 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -24,10 +24,7 @@ impl ast::NameRef {
24} 24}
25 25
26fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { 26fn text_of_first_token(node: &SyntaxNode) -> &SmolStr {
27 match node.0.green().children().first() { 27 node.green().children().first().and_then(|it| it.as_token()).unwrap().text()
28 Some(rowan::GreenElement::Token(it)) => it.text(),
29 _ => panic!(),
30 }
31} 28}
32 29
33impl ast::Attr { 30impl ast::Attr {
diff --git a/crates/ra_syntax/src/lib.rs b/crates/ra_syntax/src/lib.rs
index 8af04c136..7f69b86e1 100644
--- a/crates/ra_syntax/src/lib.rs
+++ b/crates/ra_syntax/src/lib.rs
@@ -20,7 +20,6 @@
20//! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md> 20//! [Swift]: <https://github.com/apple/swift/blob/13d593df6f359d0cb2fc81cfaac273297c539455/lib/Syntax/README.md>
21 21
22mod syntax_node; 22mod syntax_node;
23mod syntax_text;
24mod syntax_error; 23mod syntax_error;
25mod parsing; 24mod parsing;
26mod validation; 25mod validation;
@@ -38,19 +37,17 @@ use ra_text_edit::AtomTextEdit;
38use crate::syntax_node::GreenNode; 37use crate::syntax_node::GreenNode;
39 38
40pub use crate::{ 39pub use crate::{
40 algo::InsertPosition,
41 ast::{AstNode, AstToken}, 41 ast::{AstNode, AstToken},
42 parsing::{classify_literal, tokenize, Token}, 42 parsing::{classify_literal, tokenize, Token},
43 ptr::{AstPtr, SyntaxNodePtr}, 43 ptr::{AstPtr, SyntaxNodePtr},
44 syntax_error::{Location, SyntaxError, SyntaxErrorKind}, 44 syntax_error::{Location, SyntaxError, SyntaxErrorKind},
45 syntax_node::{ 45 syntax_node::{
46 Direction, InsertPosition, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder, 46 Direction, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxToken, SyntaxTreeBuilder,
47 WalkEvent,
48 }, 47 },
49 syntax_text::SyntaxText,
50}; 48};
51pub use ra_parser::SyntaxKind; 49pub use ra_parser::{SyntaxKind, T};
52pub use ra_parser::T; 50pub use rowan::{SmolStr, SyntaxText, TextRange, TextUnit, TokenAtOffset, WalkEvent};
53pub use rowan::{SmolStr, TextRange, TextUnit};
54 51
55/// `Parse` is the result of the parsing: a syntax tree and a collection of 52/// `Parse` is the result of the parsing: a syntax tree and a collection of
56/// errors. 53/// errors.
@@ -76,7 +73,7 @@ impl<T> Parse<T> {
76 } 73 }
77 74
78 pub fn syntax_node(&self) -> SyntaxNode { 75 pub fn syntax_node(&self) -> SyntaxNode {
79 SyntaxNode::new(self.green.clone()) 76 SyntaxNode::new_root(self.green.clone())
80 } 77 }
81} 78}
82 79
@@ -146,18 +143,17 @@ impl Parse<SourceFile> {
146pub use crate::ast::SourceFile; 143pub use crate::ast::SourceFile;
147 144
148impl SourceFile { 145impl SourceFile {
149 fn new(green: GreenNode) -> SourceFile { 146 pub fn parse(text: &str) -> Parse<SourceFile> {
150 let root = SyntaxNode::new(green); 147 let (green, mut errors) = parsing::parse_text(text);
148 let root = SyntaxNode::new_root(green.clone());
149
151 if cfg!(debug_assertions) { 150 if cfg!(debug_assertions) {
152 validation::validate_block_structure(&root); 151 validation::validate_block_structure(&root);
153 } 152 }
154 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
155 SourceFile::cast(root).unwrap()
156 }
157 153
158 pub fn parse(text: &str) -> Parse<SourceFile> { 154 errors.extend(validation::validate(&root));
159 let (green, mut errors) = parsing::parse_text(text); 155
160 errors.extend(validation::validate(&SourceFile::new(green.clone()))); 156 assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
161 Parse { green, errors: Arc::new(errors), _ty: PhantomData } 157 Parse { green, errors: Arc::new(errors), _ty: PhantomData }
162 } 158 }
163} 159}
@@ -267,8 +263,8 @@ fn api_walkthrough() {
267 match event { 263 match event {
268 WalkEvent::Enter(node) => { 264 WalkEvent::Enter(node) => {
269 let text = match &node { 265 let text = match &node {
270 SyntaxElement::Node(it) => it.text().to_string(), 266 NodeOrToken::Node(it) => it.text().to_string(),
271 SyntaxElement::Token(it) => it.text().to_string(), 267 NodeOrToken::Token(it) => it.text().to_string(),
272 }; 268 };
273 buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent); 269 buf += &format!("{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
274 indent += 2; 270 indent += 2;
diff --git a/crates/ra_syntax/src/parsing/reparsing.rs b/crates/ra_syntax/src/parsing/reparsing.rs
index 2f388bdfe..65b8aa10d 100644
--- a/crates/ra_syntax/src/parsing/reparsing.rs
+++ b/crates/ra_syntax/src/parsing/reparsing.rs
@@ -16,7 +16,7 @@ use crate::{
16 text_token_source::TextTokenSource, 16 text_token_source::TextTokenSource,
17 text_tree_sink::TextTreeSink, 17 text_tree_sink::TextTreeSink,
18 }, 18 },
19 syntax_node::{GreenNode, GreenToken, SyntaxElement, SyntaxNode}, 19 syntax_node::{GreenNode, GreenToken, NodeOrToken, SyntaxElement, SyntaxNode},
20 SyntaxError, 20 SyntaxError,
21 SyntaxKind::*, 21 SyntaxKind::*,
22 TextRange, TextUnit, T, 22 TextRange, TextUnit, T,
@@ -70,7 +70,8 @@ fn reparse_token<'node>(
70 } 70 }
71 } 71 }
72 72
73 let new_token = GreenToken::new(rowan::SyntaxKind(token.kind().into()), text.into()); 73 let new_token =
74 GreenToken::new(rowan::cursor::SyntaxKind(token.kind().into()), text.into());
74 Some((token.replace_with(new_token), token.text_range())) 75 Some((token.replace_with(new_token), token.text_range()))
75 } 76 }
76 _ => None, 77 _ => None,
@@ -98,8 +99,8 @@ fn get_text_after_edit(element: SyntaxElement, edit: &AtomTextEdit) -> String {
98 let edit = 99 let edit =
99 AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone()); 100 AtomTextEdit::replace(edit.delete - element.text_range().start(), edit.insert.clone());
100 let text = match element { 101 let text = match element {
101 SyntaxElement::Token(token) => token.text().to_string(), 102 NodeOrToken::Token(token) => token.text().to_string(),
102 SyntaxElement::Node(node) => node.text().to_string(), 103 NodeOrToken::Node(node) => node.text().to_string(),
103 }; 104 };
104 edit.apply(text) 105 edit.apply(text)
105} 106}
@@ -114,8 +115,8 @@ fn is_contextual_kw(text: &str) -> bool {
114fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> { 115fn find_reparsable_node(node: &SyntaxNode, range: TextRange) -> Option<(SyntaxNode, Reparser)> {
115 let node = algo::find_covering_element(node, range); 116 let node = algo::find_covering_element(node, range);
116 let mut ancestors = match node { 117 let mut ancestors = match node {
117 SyntaxElement::Token(it) => it.parent().ancestors(), 118 NodeOrToken::Token(it) => it.parent().ancestors(),
118 SyntaxElement::Node(it) => it.ancestors(), 119 NodeOrToken::Node(it) => it.ancestors(),
119 }; 120 };
120 ancestors.find_map(|node| { 121 ancestors.find_map(|node| {
121 let first_child = node.first_child_or_token().map(|it| it.kind()); 122 let first_child = node.first_child_or_token().map(|it| it.kind());
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index c42045d77..b2f5b8c64 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -6,487 +6,37 @@
6//! The *real* implementation is in the (language-agnostic) `rowan` crate, this 6//! The *real* implementation is in the (language-agnostic) `rowan` crate, this
7//! modules just wraps its API. 7//! modules just wraps its API.
8 8
9use std::{fmt, iter::successors, ops::RangeInclusive};
10
11use ra_parser::ParseError; 9use ra_parser::ParseError;
12use rowan::GreenNodeBuilder; 10use rowan::{GreenNodeBuilder, Language};
13 11
14use crate::{ 12use crate::{
15 syntax_error::{SyntaxError, SyntaxErrorKind}, 13 syntax_error::{SyntaxError, SyntaxErrorKind},
16 AstNode, Parse, SmolStr, SourceFile, SyntaxKind, SyntaxNodePtr, SyntaxText, TextRange, 14 Parse, SmolStr, SyntaxKind, TextUnit,
17 TextUnit,
18}; 15};
19 16
20pub use rowan::WalkEvent;
21pub(crate) use rowan::{GreenNode, GreenToken}; 17pub(crate) use rowan::{GreenNode, GreenToken};
22 18
23#[derive(Debug, PartialEq, Eq, Clone, Copy)] 19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24pub enum InsertPosition<T> { 20pub enum RustLanguage {}
25 First, 21impl Language for RustLanguage {
26 Last, 22 type Kind = SyntaxKind;
27 Before(T),
28 After(T),
29}
30
31#[derive(PartialEq, Eq, Hash, Clone)]
32pub struct SyntaxNode(pub(crate) rowan::cursor::SyntaxNode);
33 23
34impl fmt::Debug for SyntaxNode { 24 fn kind_from_raw(raw: rowan::cursor::SyntaxKind) -> SyntaxKind {
35 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 25 SyntaxKind::from(raw.0)
36 if f.alternate() {
37 let mut level = 0;
38 for event in self.preorder_with_tokens() {
39 match event {
40 WalkEvent::Enter(element) => {
41 for _ in 0..level {
42 write!(f, " ")?;
43 }
44 match element {
45 SyntaxElement::Node(node) => writeln!(f, "{:?}", node)?,
46 SyntaxElement::Token(token) => writeln!(f, "{:?}", token)?,
47 }
48 level += 1;
49 }
50 WalkEvent::Leave(_) => level -= 1,
51 }
52 }
53 assert_eq!(level, 0);
54 Ok(())
55 } else {
56 write!(f, "{:?}@{:?}", self.kind(), self.text_range())
57 }
58 } 26 }
59}
60 27
61impl fmt::Display for SyntaxNode { 28 fn kind_to_raw(kind: SyntaxKind) -> rowan::cursor::SyntaxKind {
62 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 29 rowan::cursor::SyntaxKind(kind.into())
63 fmt::Display::fmt(&self.text(), fmt)
64 } 30 }
65} 31}
66 32
67#[derive(Debug, Clone, Copy, PartialEq, Eq)] 33pub type SyntaxNode = rowan::SyntaxNode<RustLanguage>;
68pub enum Direction { 34pub type SyntaxToken = rowan::SyntaxToken<RustLanguage>;
69 Next, 35pub type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
70 Prev, 36pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<RustLanguage>;
71} 37pub type SyntaxElementChildren = rowan::SyntaxElementChildren<RustLanguage>;
72
73impl SyntaxNode {
74 pub(crate) fn new(green: GreenNode) -> SyntaxNode {
75 let inner = rowan::cursor::SyntaxNode::new_root(green);
76 SyntaxNode(inner)
77 }
78
79 pub fn kind(&self) -> SyntaxKind {
80 self.0.kind().0.into()
81 }
82
83 pub fn text_range(&self) -> TextRange {
84 self.0.text_range()
85 }
86
87 pub fn text(&self) -> SyntaxText {
88 SyntaxText::new(self.clone())
89 }
90
91 pub fn parent(&self) -> Option<SyntaxNode> {
92 self.0.parent().map(SyntaxNode)
93 }
94
95 pub fn first_child(&self) -> Option<SyntaxNode> {
96 self.0.first_child().map(SyntaxNode)
97 }
98
99 pub fn first_child_or_token(&self) -> Option<SyntaxElement> {
100 self.0.first_child_or_token().map(SyntaxElement::new)
101 }
102
103 pub fn last_child(&self) -> Option<SyntaxNode> {
104 self.0.last_child().map(SyntaxNode)
105 }
106
107 pub fn last_child_or_token(&self) -> Option<SyntaxElement> {
108 self.0.last_child_or_token().map(SyntaxElement::new)
109 }
110
111 pub fn next_sibling(&self) -> Option<SyntaxNode> {
112 self.0.next_sibling().map(SyntaxNode)
113 }
114
115 pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> {
116 self.0.next_sibling_or_token().map(SyntaxElement::new)
117 }
118
119 pub fn prev_sibling(&self) -> Option<SyntaxNode> {
120 self.0.prev_sibling().map(SyntaxNode)
121 }
122
123 pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> {
124 self.0.prev_sibling_or_token().map(SyntaxElement::new)
125 }
126
127 pub fn children(&self) -> SyntaxNodeChildren {
128 SyntaxNodeChildren(self.0.children())
129 }
130
131 pub fn children_with_tokens(&self) -> SyntaxElementChildren {
132 SyntaxElementChildren(self.0.children_with_tokens())
133 }
134
135 pub fn first_token(&self) -> Option<SyntaxToken> {
136 self.0.first_token().map(SyntaxToken)
137 }
138
139 pub fn last_token(&self) -> Option<SyntaxToken> {
140 self.0.last_token().map(SyntaxToken)
141 }
142 38
143 pub fn ancestors(&self) -> impl Iterator<Item = SyntaxNode> { 39pub use rowan::{Direction, NodeOrToken};
144 successors(Some(self.clone()), |node| node.parent())
145 }
146
147 pub fn descendants(&self) -> impl Iterator<Item = SyntaxNode> {
148 self.preorder().filter_map(|event| match event {
149 WalkEvent::Enter(node) => Some(node),
150 WalkEvent::Leave(_) => None,
151 })
152 }
153
154 pub fn descendants_with_tokens(&self) -> impl Iterator<Item = SyntaxElement> {
155 self.preorder_with_tokens().filter_map(|event| match event {
156 WalkEvent::Enter(it) => Some(it),
157 WalkEvent::Leave(_) => None,
158 })
159 }
160
161 pub fn siblings(&self, direction: Direction) -> impl Iterator<Item = SyntaxNode> {
162 successors(Some(self.clone()), move |node| match direction {
163 Direction::Next => node.next_sibling(),
164 Direction::Prev => node.prev_sibling(),
165 })
166 }
167
168 pub fn siblings_with_tokens(
169 &self,
170 direction: Direction,
171 ) -> impl Iterator<Item = SyntaxElement> {
172 let me: SyntaxElement = self.clone().into();
173 successors(Some(me), move |el| match direction {
174 Direction::Next => el.next_sibling_or_token(),
175 Direction::Prev => el.prev_sibling_or_token(),
176 })
177 }
178
179 pub fn preorder(&self) -> impl Iterator<Item = WalkEvent<SyntaxNode>> {
180 self.0.preorder().map(|event| match event {
181 WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxNode(n)),
182 WalkEvent::Leave(n) => WalkEvent::Leave(SyntaxNode(n)),
183 })
184 }
185
186 pub fn preorder_with_tokens(&self) -> impl Iterator<Item = WalkEvent<SyntaxElement>> {
187 self.0.preorder_with_tokens().map(|event| match event {
188 WalkEvent::Enter(n) => WalkEvent::Enter(SyntaxElement::new(n)),
189 WalkEvent::Leave(n) => WalkEvent::Leave(SyntaxElement::new(n)),
190 })
191 }
192
193 pub(crate) fn replace_with(&self, replacement: GreenNode) -> GreenNode {
194 self.0.replace_with(replacement)
195 }
196
197 /// Adds specified children (tokens or nodes) to the current node at the
198 /// specific position.
199 ///
200 /// This is a type-unsafe low-level editing API, if you need to use it,
201 /// prefer to create a type-safe abstraction on top of it instead.
202 pub fn insert_children(
203 &self,
204 position: InsertPosition<SyntaxElement>,
205 to_insert: impl Iterator<Item = SyntaxElement>,
206 ) -> SyntaxNode {
207 let mut delta = TextUnit::default();
208 let to_insert = to_insert.map(|element| {
209 delta += element.text_len();
210 to_green_element(element)
211 });
212
213 let old_children = self.0.green().children();
214
215 let new_children = match &position {
216 InsertPosition::First => {
217 to_insert.chain(old_children.iter().cloned()).collect::<Box<[_]>>()
218 }
219 InsertPosition::Last => {
220 old_children.iter().cloned().chain(to_insert).collect::<Box<[_]>>()
221 }
222 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => {
223 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 };
224 let split_at = self.position_of_child(anchor.clone()) + take_anchor;
225 let (before, after) = old_children.split_at(split_at);
226 before
227 .iter()
228 .cloned()
229 .chain(to_insert)
230 .chain(after.iter().cloned())
231 .collect::<Box<[_]>>()
232 }
233 };
234
235 self.with_children(new_children)
236 }
237
238 /// Replaces all nodes in `to_delete` with nodes from `to_insert`
239 ///
240 /// This is a type-unsafe low-level editing API, if you need to use it,
241 /// prefer to create a type-safe abstraction on top of it instead.
242 pub fn replace_children(
243 &self,
244 to_delete: RangeInclusive<SyntaxElement>,
245 to_insert: impl Iterator<Item = SyntaxElement>,
246 ) -> SyntaxNode {
247 let start = self.position_of_child(to_delete.start().clone());
248 let end = self.position_of_child(to_delete.end().clone());
249 let old_children = self.0.green().children();
250
251 let new_children = old_children[..start]
252 .iter()
253 .cloned()
254 .chain(to_insert.map(to_green_element))
255 .chain(old_children[end + 1..].iter().cloned())
256 .collect::<Box<[_]>>();
257 self.with_children(new_children)
258 }
259
260 fn with_children(&self, new_children: Box<[rowan::GreenElement]>) -> SyntaxNode {
261 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>();
262 let new_node = GreenNode::new(rowan::SyntaxKind(self.kind() as u16), new_children);
263 let new_file_node = self.replace_with(new_node);
264 let file = SourceFile::new(new_file_node);
265
266 // FIXME: use a more elegant way to re-fetch the node (#1185), make
267 // `range` private afterwards
268 let mut ptr = SyntaxNodePtr::new(self);
269 ptr.range = TextRange::offset_len(ptr.range().start(), len);
270 ptr.to_node(file.syntax()).to_owned()
271 }
272
273 fn position_of_child(&self, child: SyntaxElement) -> usize {
274 self.children_with_tokens()
275 .position(|it| it == child)
276 .expect("element is not a child of current element")
277 }
278}
279
280fn to_green_element(element: SyntaxElement) -> rowan::GreenElement {
281 match element {
282 SyntaxElement::Node(node) => node.0.green().clone().into(),
283 SyntaxElement::Token(tok) => {
284 GreenToken::new(rowan::SyntaxKind(tok.kind() as u16), tok.text().clone()).into()
285 }
286 }
287}
288
289#[derive(Clone, PartialEq, Eq, Hash)]
290pub struct SyntaxToken(pub(crate) rowan::cursor::SyntaxToken);
291
292impl fmt::Debug for SyntaxToken {
293 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
294 write!(fmt, "{:?}@{:?}", self.kind(), self.text_range())?;
295 if self.text().len() < 25 {
296 return write!(fmt, " {:?}", self.text());
297 }
298 let text = self.text().as_str();
299 for idx in 21..25 {
300 if text.is_char_boundary(idx) {
301 let text = format!("{} ...", &text[..idx]);
302 return write!(fmt, " {:?}", text);
303 }
304 }
305 unreachable!()
306 }
307}
308
309impl fmt::Display for SyntaxToken {
310 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
311 fmt::Display::fmt(self.text(), fmt)
312 }
313}
314
315impl SyntaxToken {
316 pub fn kind(&self) -> SyntaxKind {
317 self.0.kind().0.into()
318 }
319
320 pub fn text(&self) -> &SmolStr {
321 self.0.text()
322 }
323
324 pub fn text_range(&self) -> TextRange {
325 self.0.text_range()
326 }
327
328 pub fn parent(&self) -> SyntaxNode {
329 SyntaxNode(self.0.parent())
330 }
331
332 pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> {
333 self.0.next_sibling_or_token().map(SyntaxElement::new)
334 }
335
336 pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> {
337 self.0.prev_sibling_or_token().map(SyntaxElement::new)
338 }
339
340 pub fn siblings_with_tokens(
341 &self,
342 direction: Direction,
343 ) -> impl Iterator<Item = SyntaxElement> {
344 let me: SyntaxElement = self.clone().into();
345 successors(Some(me), move |el| match direction {
346 Direction::Next => el.next_sibling_or_token(),
347 Direction::Prev => el.prev_sibling_or_token(),
348 })
349 }
350
351 pub fn next_token(&self) -> Option<SyntaxToken> {
352 self.0.next_token().map(SyntaxToken)
353 }
354
355 pub fn prev_token(&self) -> Option<SyntaxToken> {
356 self.0.prev_token().map(SyntaxToken)
357 }
358
359 pub(crate) fn replace_with(&self, new_token: GreenToken) -> GreenNode {
360 self.0.replace_with(new_token)
361 }
362}
363
364#[derive(Debug, PartialEq, Eq, Hash, Clone)]
365pub enum SyntaxElement {
366 Node(SyntaxNode),
367 Token(SyntaxToken),
368}
369
370impl From<SyntaxNode> for SyntaxElement {
371 fn from(node: SyntaxNode) -> Self {
372 SyntaxElement::Node(node)
373 }
374}
375
376impl From<SyntaxToken> for SyntaxElement {
377 fn from(token: SyntaxToken) -> Self {
378 SyntaxElement::Token(token)
379 }
380}
381
382impl fmt::Display for SyntaxElement {
383 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
384 match self {
385 SyntaxElement::Node(it) => fmt::Display::fmt(it, fmt),
386 SyntaxElement::Token(it) => fmt::Display::fmt(it, fmt),
387 }
388 }
389}
390
391impl SyntaxElement {
392 pub(crate) fn new(el: rowan::cursor::SyntaxElement) -> Self {
393 match el {
394 rowan::cursor::SyntaxElement::Node(it) => SyntaxElement::Node(SyntaxNode(it)),
395 rowan::cursor::SyntaxElement::Token(it) => SyntaxElement::Token(SyntaxToken(it)),
396 }
397 }
398
399 pub fn kind(&self) -> SyntaxKind {
400 match self {
401 SyntaxElement::Node(it) => it.kind(),
402 SyntaxElement::Token(it) => it.kind(),
403 }
404 }
405
406 pub fn as_node(&self) -> Option<&SyntaxNode> {
407 match self {
408 SyntaxElement::Node(node) => Some(node),
409 SyntaxElement::Token(_) => None,
410 }
411 }
412
413 pub fn into_node(self) -> Option<SyntaxNode> {
414 match self {
415 SyntaxElement::Node(node) => Some(node),
416 SyntaxElement::Token(_) => None,
417 }
418 }
419
420 pub fn as_token(&self) -> Option<&SyntaxToken> {
421 match self {
422 SyntaxElement::Node(_) => None,
423 SyntaxElement::Token(token) => Some(token),
424 }
425 }
426
427 pub fn into_token(self) -> Option<SyntaxToken> {
428 match self {
429 SyntaxElement::Node(_) => None,
430 SyntaxElement::Token(token) => Some(token),
431 }
432 }
433
434 pub fn next_sibling_or_token(&self) -> Option<SyntaxElement> {
435 match self {
436 SyntaxElement::Node(it) => it.next_sibling_or_token(),
437 SyntaxElement::Token(it) => it.next_sibling_or_token(),
438 }
439 }
440
441 pub fn prev_sibling_or_token(&self) -> Option<SyntaxElement> {
442 match self {
443 SyntaxElement::Node(it) => it.prev_sibling_or_token(),
444 SyntaxElement::Token(it) => it.prev_sibling_or_token(),
445 }
446 }
447
448 pub fn ancestors(&self) -> impl Iterator<Item = SyntaxNode> {
449 match self {
450 SyntaxElement::Node(it) => it.clone(),
451 SyntaxElement::Token(it) => it.parent(),
452 }
453 .ancestors()
454 }
455
456 pub fn text_range(&self) -> TextRange {
457 match self {
458 SyntaxElement::Node(it) => it.text_range(),
459 SyntaxElement::Token(it) => it.text_range(),
460 }
461 }
462
463 fn text_len(&self) -> TextUnit {
464 match self {
465 SyntaxElement::Node(node) => node.0.green().text_len(),
466 SyntaxElement::Token(token) => TextUnit::of_str(token.0.text()),
467 }
468 }
469}
470
471#[derive(Clone, Debug)]
472pub struct SyntaxNodeChildren(rowan::cursor::SyntaxNodeChildren);
473
474impl Iterator for SyntaxNodeChildren {
475 type Item = SyntaxNode;
476 fn next(&mut self) -> Option<SyntaxNode> {
477 self.0.next().map(SyntaxNode)
478 }
479}
480
481#[derive(Clone, Debug)]
482pub struct SyntaxElementChildren(rowan::cursor::SyntaxElementChildren);
483
484impl Iterator for SyntaxElementChildren {
485 type Item = SyntaxElement;
486 fn next(&mut self) -> Option<SyntaxElement> {
487 self.0.next().map(SyntaxElement::new)
488 }
489}
490 40
491pub struct SyntaxTreeBuilder { 41pub struct SyntaxTreeBuilder {
492 errors: Vec<SyntaxError>, 42 errors: Vec<SyntaxError>,
@@ -507,19 +57,21 @@ impl SyntaxTreeBuilder {
507 57
508 pub fn finish(self) -> Parse<SyntaxNode> { 58 pub fn finish(self) -> Parse<SyntaxNode> {
509 let (green, errors) = self.finish_raw(); 59 let (green, errors) = self.finish_raw();
510 let node = SyntaxNode::new(green); 60 let node = SyntaxNode::new_root(green);
511 if cfg!(debug_assertions) { 61 if cfg!(debug_assertions) {
512 crate::validation::validate_block_structure(&node); 62 crate::validation::validate_block_structure(&node);
513 } 63 }
514 Parse::new(node.0.green().clone(), errors) 64 Parse::new(node.green().clone(), errors)
515 } 65 }
516 66
517 pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) { 67 pub fn token(&mut self, kind: SyntaxKind, text: SmolStr) {
518 self.inner.token(rowan::SyntaxKind(kind.into()), text) 68 let kind = RustLanguage::kind_to_raw(kind);
69 self.inner.token(kind, text)
519 } 70 }
520 71
521 pub fn start_node(&mut self, kind: SyntaxKind) { 72 pub fn start_node(&mut self, kind: SyntaxKind) {
522 self.inner.start_node(rowan::SyntaxKind(kind.into())) 73 let kind = RustLanguage::kind_to_raw(kind);
74 self.inner.start_node(kind)
523 } 75 }
524 76
525 pub fn finish_node(&mut self) { 77 pub fn finish_node(&mut self) {
diff --git a/crates/ra_syntax/src/syntax_text.rs b/crates/ra_syntax/src/syntax_text.rs
deleted file mode 100644
index 652cb7a1e..000000000
--- a/crates/ra_syntax/src/syntax_text.rs
+++ /dev/null
@@ -1,178 +0,0 @@
1use std::{
2 fmt,
3 ops::{self, Bound},
4};
5
6use crate::{SmolStr, SyntaxElement, SyntaxNode, TextRange, TextUnit};
7
8#[derive(Clone)]
9pub struct SyntaxText {
10 node: SyntaxNode,
11 range: TextRange,
12}
13
14impl SyntaxText {
15 pub(crate) fn new(node: SyntaxNode) -> SyntaxText {
16 let range = node.text_range();
17 SyntaxText { node, range }
18 }
19
20 pub fn try_fold_chunks<T, F, E>(&self, init: T, mut f: F) -> Result<T, E>
21 where
22 F: FnMut(T, &str) -> Result<T, E>,
23 {
24 self.node.descendants_with_tokens().try_fold(init, move |acc, element| {
25 let res = match element {
26 SyntaxElement::Token(token) => {
27 let range = match self.range.intersection(&token.text_range()) {
28 None => return Ok(acc),
29 Some(it) => it,
30 };
31 let slice = if range == token.text_range() {
32 token.text()
33 } else {
34 let range = range - token.text_range().start();
35 &token.text()[range]
36 };
37 f(acc, slice)?
38 }
39 SyntaxElement::Node(_) => acc,
40 };
41 Ok(res)
42 })
43 }
44
45 pub fn try_for_each_chunk<F: FnMut(&str) -> Result<(), E>, E>(
46 &self,
47 mut f: F,
48 ) -> Result<(), E> {
49 self.try_fold_chunks((), move |(), chunk| f(chunk))
50 }
51
52 pub fn for_each_chunk<F: FnMut(&str)>(&self, mut f: F) {
53 enum Void {}
54 match self.try_for_each_chunk(|chunk| Ok::<(), Void>(f(chunk))) {
55 Ok(()) => (),
56 Err(void) => match void {},
57 }
58 }
59
60 pub fn to_smol_string(&self) -> SmolStr {
61 self.to_string().into()
62 }
63
64 pub fn contains_char(&self, c: char) -> bool {
65 self.try_for_each_chunk(|chunk| if chunk.contains(c) { Err(()) } else { Ok(()) }).is_err()
66 }
67
68 pub fn find_char(&self, c: char) -> Option<TextUnit> {
69 let mut acc: TextUnit = 0.into();
70 let res = self.try_for_each_chunk(|chunk| {
71 if let Some(pos) = chunk.find(c) {
72 let pos: TextUnit = (pos as u32).into();
73 return Err(acc + pos);
74 }
75 acc += TextUnit::of_str(chunk);
76 Ok(())
77 });
78 found(res)
79 }
80
81 pub fn len(&self) -> TextUnit {
82 self.range.len()
83 }
84
85 pub fn is_empty(&self) -> bool {
86 self.range.is_empty()
87 }
88
89 pub fn slice(&self, range: impl ops::RangeBounds<TextUnit>) -> SyntaxText {
90 let start = match range.start_bound() {
91 Bound::Included(&b) => b,
92 Bound::Excluded(_) => panic!("utf-aware slicing can't work this way"),
93 Bound::Unbounded => 0.into(),
94 };
95 let end = match range.end_bound() {
96 Bound::Included(_) => panic!("utf-aware slicing can't work this way"),
97 Bound::Excluded(&b) => b,
98 Bound::Unbounded => self.len(),
99 };
100 assert!(start <= end);
101 let len = end - start;
102 let start = self.range.start() + start;
103 let end = start + len;
104 assert!(
105 start <= end,
106 "invalid slice, range: {:?}, slice: {:?}",
107 self.range,
108 (range.start_bound(), range.end_bound()),
109 );
110 let range = TextRange::from_to(start, end);
111 assert!(
112 range.is_subrange(&self.range),
113 "invalid slice, range: {:?}, slice: {:?}",
114 self.range,
115 range,
116 );
117 SyntaxText { node: self.node.clone(), range }
118 }
119
120 pub fn char_at(&self, offset: impl Into<TextUnit>) -> Option<char> {
121 let offset = offset.into();
122 let mut start: TextUnit = 0.into();
123 let res = self.try_for_each_chunk(|chunk| {
124 let end = start + TextUnit::of_str(chunk);
125 if start <= offset && offset < end {
126 let off: usize = u32::from(offset - start) as usize;
127 return Err(chunk[off..].chars().next().unwrap());
128 }
129 start = end;
130 Ok(())
131 });
132 found(res)
133 }
134}
135
136fn found<T>(res: Result<(), T>) -> Option<T> {
137 match res {
138 Ok(()) => None,
139 Err(it) => Some(it),
140 }
141}
142
143impl fmt::Debug for SyntaxText {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 fmt::Debug::fmt(&self.to_string(), f)
146 }
147}
148
149impl fmt::Display for SyntaxText {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 self.try_for_each_chunk(|chunk| fmt::Display::fmt(chunk, f))
152 }
153}
154
155impl From<SyntaxText> for String {
156 fn from(text: SyntaxText) -> String {
157 text.to_string()
158 }
159}
160
161impl PartialEq<str> for SyntaxText {
162 fn eq(&self, mut rhs: &str) -> bool {
163 self.try_for_each_chunk(|chunk| {
164 if !rhs.starts_with(chunk) {
165 return Err(());
166 }
167 rhs = &rhs[chunk.len()..];
168 Ok(())
169 })
170 .is_ok()
171 }
172}
173
174impl PartialEq<&'_ str> for SyntaxText {
175 fn eq(&self, rhs: &&str) -> bool {
176 self == *rhs
177 }
178}
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 19bdafef2..e03c02d1b 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -5,16 +5,16 @@ mod field_expr;
5 5
6use crate::{ 6use crate::{
7 algo::visit::{visitor_ctx, VisitorCtx}, 7 algo::visit::{visitor_ctx, VisitorCtx},
8 ast, AstNode, SourceFile, SyntaxError, 8 ast, SyntaxError,
9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, STRING}, 9 SyntaxKind::{BYTE, BYTE_STRING, CHAR, STRING},
10 SyntaxNode, TextUnit, T, 10 SyntaxNode, TextUnit, T,
11}; 11};
12 12
13pub(crate) use unescape::EscapeError; 13pub(crate) use unescape::EscapeError;
14 14
15pub(crate) fn validate(file: &SourceFile) -> Vec<SyntaxError> { 15pub(crate) fn validate(root: &SyntaxNode) -> Vec<SyntaxError> {
16 let mut errors = Vec::new(); 16 let mut errors = Vec::new();
17 for node in file.syntax().descendants() { 17 for node in root.descendants() {
18 let _ = visitor_ctx(&mut errors) 18 let _ = visitor_ctx(&mut errors)
19 .visit::<ast::Literal, _>(validate_literal) 19 .visit::<ast::Literal, _>(validate_literal)
20 .visit::<ast::Block, _>(block::validate_block_node) 20 .visit::<ast::Block, _>(block::validate_block_node)