diff options
-rw-r--r-- | crates/libeditor/src/extend_selection.rs | 7 | ||||
-rw-r--r-- | crates/libeditor/src/lib.rs | 14 | ||||
-rw-r--r-- | crates/libeditor/src/symbols.rs | 67 | ||||
-rw-r--r-- | crates/libeditor/tests/test.rs | 25 | ||||
-rw-r--r-- | crates/libsyntax2/src/algo/mod.rs | 1 | ||||
-rw-r--r-- | crates/libsyntax2/src/algo/visit.rs | 52 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/generated.rs | 80 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/generated.rs.tera | 8 | ||||
-rw-r--r-- | crates/libsyntax2/src/ast/mod.rs | 9 | ||||
-rw-r--r-- | crates/libsyntax2/src/grammar.ron | 28 | ||||
-rw-r--r-- | crates/libsyntax2/src/yellow/syntax.rs | 6 |
11 files changed, 211 insertions, 86 deletions
diff --git a/crates/libeditor/src/extend_selection.rs b/crates/libeditor/src/extend_selection.rs index 16d4bc084..ed7d9b3f7 100644 --- a/crates/libeditor/src/extend_selection.rs +++ b/crates/libeditor/src/extend_selection.rs | |||
@@ -1,11 +1,16 @@ | |||
1 | use libsyntax2::{ | 1 | use libsyntax2::{ |
2 | ast, AstNode, | ||
2 | TextRange, SyntaxNodeRef, | 3 | TextRange, SyntaxNodeRef, |
3 | SyntaxKind::WHITESPACE, | 4 | SyntaxKind::WHITESPACE, |
4 | algo::{find_leaf_at_offset, find_covering_node, ancestors}, | 5 | algo::{find_leaf_at_offset, find_covering_node, ancestors}, |
5 | }; | 6 | }; |
6 | 7 | ||
8 | pub fn extend_selection(file: &ast::File, range: TextRange) -> Option<TextRange> { | ||
9 | let syntax = file.syntax(); | ||
10 | extend(syntax.as_ref(), range) | ||
11 | } | ||
7 | 12 | ||
8 | pub(crate) fn extend_selection(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> { | 13 | pub(crate) fn extend(root: SyntaxNodeRef, range: TextRange) -> Option<TextRange> { |
9 | if range.is_empty() { | 14 | if range.is_empty() { |
10 | let offset = range.start(); | 15 | let offset = range.start(); |
11 | let mut leaves = find_leaf_at_offset(root, offset); | 16 | let mut leaves = find_leaf_at_offset(root, offset); |
diff --git a/crates/libeditor/src/lib.rs b/crates/libeditor/src/lib.rs index 293fafae7..4ea344b17 100644 --- a/crates/libeditor/src/lib.rs +++ b/crates/libeditor/src/lib.rs | |||
@@ -2,16 +2,21 @@ extern crate libsyntax2; | |||
2 | extern crate superslice; | 2 | extern crate superslice; |
3 | 3 | ||
4 | mod extend_selection; | 4 | mod extend_selection; |
5 | mod symbols; | ||
5 | mod line_index; | 6 | mod line_index; |
6 | 7 | ||
7 | use libsyntax2::{ | 8 | use libsyntax2::{ |
8 | ast, | 9 | ast::{self, NameOwner}, |
9 | SyntaxNodeRef, AstNode, | 10 | SyntaxNodeRef, AstNode, |
10 | algo::walk, | 11 | algo::walk, |
11 | SyntaxKind::*, | 12 | SyntaxKind::*, |
12 | }; | 13 | }; |
13 | pub use libsyntax2::{File, TextRange, TextUnit}; | 14 | pub use libsyntax2::{File, TextRange, TextUnit}; |
14 | pub use self::line_index::{LineIndex, LineCol}; | 15 | pub use self::{ |
16 | line_index::{LineIndex, LineCol}, | ||
17 | extend_selection::extend_selection, | ||
18 | symbols::{FileSymbol, file_symbols} | ||
19 | }; | ||
15 | 20 | ||
16 | #[derive(Debug)] | 21 | #[derive(Debug)] |
17 | pub struct HighlightedRange { | 22 | pub struct HighlightedRange { |
@@ -108,11 +113,6 @@ pub fn symbols(file: &ast::File) -> Vec<Symbol> { | |||
108 | res // NLL :-( | 113 | res // NLL :-( |
109 | } | 114 | } |
110 | 115 | ||
111 | pub fn extend_selection(file: &ast::File, range: TextRange) -> Option<TextRange> { | ||
112 | let syntax = file.syntax(); | ||
113 | extend_selection::extend_selection(syntax.as_ref(), range) | ||
114 | } | ||
115 | |||
116 | pub fn runnables(file: &ast::File) -> Vec<Runnable> { | 116 | pub fn runnables(file: &ast::File) -> Vec<Runnable> { |
117 | file | 117 | file |
118 | .functions() | 118 | .functions() |
diff --git a/crates/libeditor/src/symbols.rs b/crates/libeditor/src/symbols.rs new file mode 100644 index 000000000..3faf96868 --- /dev/null +++ b/crates/libeditor/src/symbols.rs | |||
@@ -0,0 +1,67 @@ | |||
1 | use libsyntax2::{ | ||
2 | SyntaxKind, SyntaxNodeRef, SyntaxRoot, AstNode, | ||
3 | ast::{self, NameOwner}, | ||
4 | algo::{ | ||
5 | visit::{visitor, Visitor}, | ||
6 | walk::{walk, WalkEvent}, | ||
7 | }, | ||
8 | }; | ||
9 | use TextRange; | ||
10 | |||
11 | #[derive(Debug)] | ||
12 | pub struct FileSymbol { | ||
13 | pub parent: Option<usize>, | ||
14 | pub name: String, | ||
15 | pub name_range: TextRange, | ||
16 | pub node_range: TextRange, | ||
17 | pub kind: SyntaxKind, | ||
18 | } | ||
19 | |||
20 | |||
21 | pub fn file_symbols(file: &ast::File) -> Vec<FileSymbol> { | ||
22 | let mut res = Vec::new(); | ||
23 | let mut stack = Vec::new(); | ||
24 | let syntax = file.syntax(); | ||
25 | |||
26 | for event in walk(syntax.as_ref()) { | ||
27 | match event { | ||
28 | WalkEvent::Enter(node) => { | ||
29 | match to_symbol(node) { | ||
30 | Some(mut symbol) => { | ||
31 | symbol.parent = stack.last().map(|&n| n); | ||
32 | stack.push(res.len()); | ||
33 | res.push(symbol); | ||
34 | } | ||
35 | None => (), | ||
36 | } | ||
37 | } | ||
38 | WalkEvent::Exit(node) => { | ||
39 | if to_symbol(node).is_some() { | ||
40 | stack.pop().unwrap(); | ||
41 | } | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | res | ||
46 | } | ||
47 | |||
48 | fn to_symbol(node: SyntaxNodeRef) -> Option<FileSymbol> { | ||
49 | fn decl<'a, N: NameOwner<&'a SyntaxRoot>>(node: N) -> Option<FileSymbol> { | ||
50 | let name = node.name()?; | ||
51 | Some(FileSymbol { | ||
52 | parent: None, | ||
53 | name: name.text(), | ||
54 | name_range: name.syntax().range(), | ||
55 | node_range: node.syntax().range(), | ||
56 | kind: node.syntax().kind(), | ||
57 | }) | ||
58 | } | ||
59 | |||
60 | visitor() | ||
61 | .visit(decl::<ast::Function<_>>) | ||
62 | .visit(decl::<ast::Struct<_>>) | ||
63 | .visit(decl::<ast::Enum<_>>) | ||
64 | .visit(decl::<ast::Trait<_>>) | ||
65 | .visit(decl::<ast::Module<_>>) | ||
66 | .accept(node)? | ||
67 | } | ||
diff --git a/crates/libeditor/tests/test.rs b/crates/libeditor/tests/test.rs index d617f4b99..ba7181ab8 100644 --- a/crates/libeditor/tests/test.rs +++ b/crates/libeditor/tests/test.rs | |||
@@ -3,7 +3,7 @@ extern crate itertools; | |||
3 | 3 | ||
4 | use std::fmt; | 4 | use std::fmt; |
5 | use itertools::Itertools; | 5 | use itertools::Itertools; |
6 | use libeditor::{File, highlight, runnables, extend_selection, TextRange}; | 6 | use libeditor::{File, highlight, runnables, extend_selection, TextRange, file_symbols}; |
7 | 7 | ||
8 | #[test] | 8 | #[test] |
9 | fn test_extend_selection() { | 9 | fn test_extend_selection() { |
@@ -58,6 +58,29 @@ fn test_foo() {} | |||
58 | ) | 58 | ) |
59 | } | 59 | } |
60 | 60 | ||
61 | #[test] | ||
62 | fn symbols() { | ||
63 | let file = file(r#" | ||
64 | struct Foo { | ||
65 | x: i32 | ||
66 | } | ||
67 | |||
68 | mod m { | ||
69 | fn bar() {} | ||
70 | } | ||
71 | |||
72 | enum E { X, Y(i32) } | ||
73 | "#); | ||
74 | let symbols = file_symbols(&file); | ||
75 | dbg_eq( | ||
76 | &symbols, | ||
77 | r#"[FileSymbol { parent: None, name: "Foo", name_range: [8; 11), node_range: [1; 26), kind: STRUCT }, | ||
78 | FileSymbol { parent: None, name: "m", name_range: [32; 33), node_range: [28; 53), kind: MODULE }, | ||
79 | FileSymbol { parent: Some(1), name: "bar", name_range: [43; 46), node_range: [40; 51), kind: FUNCTION }, | ||
80 | FileSymbol { parent: None, name: "E", name_range: [60; 61), node_range: [55; 75), kind: ENUM }]"#, | ||
81 | ) | ||
82 | } | ||
83 | |||
61 | fn file(text: &str) -> File { | 84 | fn file(text: &str) -> File { |
62 | File::parse(text) | 85 | File::parse(text) |
63 | } | 86 | } |
diff --git a/crates/libsyntax2/src/algo/mod.rs b/crates/libsyntax2/src/algo/mod.rs index d2de70fd4..263b58d97 100644 --- a/crates/libsyntax2/src/algo/mod.rs +++ b/crates/libsyntax2/src/algo/mod.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | pub mod walk; | 1 | pub mod walk; |
2 | pub mod visit; | ||
2 | 3 | ||
3 | use {SyntaxNodeRef, TextUnit, TextRange}; | 4 | use {SyntaxNodeRef, TextUnit, TextRange}; |
4 | 5 | ||
diff --git a/crates/libsyntax2/src/algo/visit.rs b/crates/libsyntax2/src/algo/visit.rs new file mode 100644 index 000000000..dc5afa5a9 --- /dev/null +++ b/crates/libsyntax2/src/algo/visit.rs | |||
@@ -0,0 +1,52 @@ | |||
1 | use std::marker::PhantomData; | ||
2 | use {SyntaxNodeRef, AstNode, SyntaxRoot}; | ||
3 | |||
4 | |||
5 | pub fn visitor<'a, T>() -> impl Visitor<'a, Output=T> { | ||
6 | EmptyVisitor { ph: PhantomData } | ||
7 | } | ||
8 | |||
9 | pub trait Visitor<'a>: Sized { | ||
10 | type Output; | ||
11 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output>; | ||
12 | fn visit<N, F>(self, f: F) -> Vis<Self, N, F> | ||
13 | where N: AstNode<&'a SyntaxRoot>, | ||
14 | F: FnOnce(N) -> Self::Output, | ||
15 | { | ||
16 | Vis { inner: self, f, ph: PhantomData } | ||
17 | } | ||
18 | } | ||
19 | |||
20 | #[derive(Debug)] | ||
21 | struct EmptyVisitor<T> { | ||
22 | ph: PhantomData<fn() -> T> | ||
23 | } | ||
24 | |||
25 | impl<'a, T> Visitor<'a> for EmptyVisitor<T> { | ||
26 | type Output = T; | ||
27 | |||
28 | fn accept(self, _node: SyntaxNodeRef<'a>) -> Option<T> { | ||
29 | None | ||
30 | } | ||
31 | } | ||
32 | |||
33 | #[derive(Debug)] | ||
34 | pub struct Vis<V, N, F> { | ||
35 | inner: V, | ||
36 | f: F, | ||
37 | ph: PhantomData<fn(N)>, | ||
38 | } | ||
39 | |||
40 | impl<'a, V, N, F> Visitor<'a> for Vis<V, N, F> | ||
41 | where | ||
42 | V: Visitor<'a>, | ||
43 | N: AstNode<&'a SyntaxRoot>, | ||
44 | F: FnOnce(N) -> <V as Visitor<'a>>::Output, | ||
45 | { | ||
46 | type Output = <V as Visitor<'a>>::Output; | ||
47 | |||
48 | fn accept(self, node: SyntaxNodeRef<'a>) -> Option<Self::Output> { | ||
49 | let Vis { inner, f, .. } = self; | ||
50 | inner.accept(node).or_else(|| N::cast(node).map(f)) | ||
51 | } | ||
52 | } | ||
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs index 7a2a9c7d4..a4b116941 100644 --- a/crates/libsyntax2/src/ast/generated.rs +++ b/crates/libsyntax2/src/ast/generated.rs | |||
@@ -1,9 +1,11 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use { | 2 | use { |
3 | ast, | ||
3 | SyntaxNode, SyntaxRoot, TreeRoot, AstNode, | 4 | SyntaxNode, SyntaxRoot, TreeRoot, AstNode, |
4 | SyntaxKind::*, | 5 | SyntaxKind::*, |
5 | }; | 6 | }; |
6 | 7 | ||
8 | // ConstItem | ||
7 | #[derive(Debug, Clone, Copy)] | 9 | #[derive(Debug, Clone, Copy)] |
8 | pub struct ConstItem<R: TreeRoot = Arc<SyntaxRoot>> { | 10 | pub struct ConstItem<R: TreeRoot = Arc<SyntaxRoot>> { |
9 | syntax: SyntaxNode<R>, | 11 | syntax: SyntaxNode<R>, |
@@ -19,15 +21,10 @@ impl<R: TreeRoot> AstNode<R> for ConstItem<R> { | |||
19 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 21 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
20 | } | 22 | } |
21 | 23 | ||
22 | impl<R: TreeRoot> ConstItem<R> { | 24 | impl<R: TreeRoot> ast::NameOwner<R> for ConstItem<R> {} |
23 | pub fn name(&self) -> Option<Name<R>> { | 25 | impl<R: TreeRoot> ConstItem<R> {} |
24 | self.syntax() | ||
25 | .children() | ||
26 | .filter_map(Name::cast) | ||
27 | .next() | ||
28 | } | ||
29 | } | ||
30 | 26 | ||
27 | // Enum | ||
31 | #[derive(Debug, Clone, Copy)] | 28 | #[derive(Debug, Clone, Copy)] |
32 | pub struct Enum<R: TreeRoot = Arc<SyntaxRoot>> { | 29 | pub struct Enum<R: TreeRoot = Arc<SyntaxRoot>> { |
33 | syntax: SyntaxNode<R>, | 30 | syntax: SyntaxNode<R>, |
@@ -43,15 +40,10 @@ impl<R: TreeRoot> AstNode<R> for Enum<R> { | |||
43 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 40 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
44 | } | 41 | } |
45 | 42 | ||
46 | impl<R: TreeRoot> Enum<R> { | 43 | impl<R: TreeRoot> ast::NameOwner<R> for Enum<R> {} |
47 | pub fn name(&self) -> Option<Name<R>> { | 44 | impl<R: TreeRoot> Enum<R> {} |
48 | self.syntax() | ||
49 | .children() | ||
50 | .filter_map(Name::cast) | ||
51 | .next() | ||
52 | } | ||
53 | } | ||
54 | 45 | ||
46 | // File | ||
55 | #[derive(Debug, Clone, Copy)] | 47 | #[derive(Debug, Clone, Copy)] |
56 | pub struct File<R: TreeRoot = Arc<SyntaxRoot>> { | 48 | pub struct File<R: TreeRoot = Arc<SyntaxRoot>> { |
57 | syntax: SyntaxNode<R>, | 49 | syntax: SyntaxNode<R>, |
@@ -75,6 +67,7 @@ impl<R: TreeRoot> File<R> { | |||
75 | } | 67 | } |
76 | } | 68 | } |
77 | 69 | ||
70 | // Function | ||
78 | #[derive(Debug, Clone, Copy)] | 71 | #[derive(Debug, Clone, Copy)] |
79 | pub struct Function<R: TreeRoot = Arc<SyntaxRoot>> { | 72 | pub struct Function<R: TreeRoot = Arc<SyntaxRoot>> { |
80 | syntax: SyntaxNode<R>, | 73 | syntax: SyntaxNode<R>, |
@@ -90,15 +83,10 @@ impl<R: TreeRoot> AstNode<R> for Function<R> { | |||
90 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 83 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
91 | } | 84 | } |
92 | 85 | ||
93 | impl<R: TreeRoot> Function<R> { | 86 | impl<R: TreeRoot> ast::NameOwner<R> for Function<R> {} |
94 | pub fn name(&self) -> Option<Name<R>> { | 87 | impl<R: TreeRoot> Function<R> {} |
95 | self.syntax() | ||
96 | .children() | ||
97 | .filter_map(Name::cast) | ||
98 | .next() | ||
99 | } | ||
100 | } | ||
101 | 88 | ||
89 | // Module | ||
102 | #[derive(Debug, Clone, Copy)] | 90 | #[derive(Debug, Clone, Copy)] |
103 | pub struct Module<R: TreeRoot = Arc<SyntaxRoot>> { | 91 | pub struct Module<R: TreeRoot = Arc<SyntaxRoot>> { |
104 | syntax: SyntaxNode<R>, | 92 | syntax: SyntaxNode<R>, |
@@ -114,15 +102,10 @@ impl<R: TreeRoot> AstNode<R> for Module<R> { | |||
114 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 102 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
115 | } | 103 | } |
116 | 104 | ||
117 | impl<R: TreeRoot> Module<R> { | 105 | impl<R: TreeRoot> ast::NameOwner<R> for Module<R> {} |
118 | pub fn name(&self) -> Option<Name<R>> { | 106 | impl<R: TreeRoot> Module<R> {} |
119 | self.syntax() | ||
120 | .children() | ||
121 | .filter_map(Name::cast) | ||
122 | .next() | ||
123 | } | ||
124 | } | ||
125 | 107 | ||
108 | // Name | ||
126 | #[derive(Debug, Clone, Copy)] | 109 | #[derive(Debug, Clone, Copy)] |
127 | pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> { | 110 | pub struct Name<R: TreeRoot = Arc<SyntaxRoot>> { |
128 | syntax: SyntaxNode<R>, | 111 | syntax: SyntaxNode<R>, |
@@ -140,6 +123,7 @@ impl<R: TreeRoot> AstNode<R> for Name<R> { | |||
140 | 123 | ||
141 | impl<R: TreeRoot> Name<R> {} | 124 | impl<R: TreeRoot> Name<R> {} |
142 | 125 | ||
126 | // StaticItem | ||
143 | #[derive(Debug, Clone, Copy)] | 127 | #[derive(Debug, Clone, Copy)] |
144 | pub struct StaticItem<R: TreeRoot = Arc<SyntaxRoot>> { | 128 | pub struct StaticItem<R: TreeRoot = Arc<SyntaxRoot>> { |
145 | syntax: SyntaxNode<R>, | 129 | syntax: SyntaxNode<R>, |
@@ -155,15 +139,10 @@ impl<R: TreeRoot> AstNode<R> for StaticItem<R> { | |||
155 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 139 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
156 | } | 140 | } |
157 | 141 | ||
158 | impl<R: TreeRoot> StaticItem<R> { | 142 | impl<R: TreeRoot> ast::NameOwner<R> for StaticItem<R> {} |
159 | pub fn name(&self) -> Option<Name<R>> { | 143 | impl<R: TreeRoot> StaticItem<R> {} |
160 | self.syntax() | ||
161 | .children() | ||
162 | .filter_map(Name::cast) | ||
163 | .next() | ||
164 | } | ||
165 | } | ||
166 | 144 | ||
145 | // Struct | ||
167 | #[derive(Debug, Clone, Copy)] | 146 | #[derive(Debug, Clone, Copy)] |
168 | pub struct Struct<R: TreeRoot = Arc<SyntaxRoot>> { | 147 | pub struct Struct<R: TreeRoot = Arc<SyntaxRoot>> { |
169 | syntax: SyntaxNode<R>, | 148 | syntax: SyntaxNode<R>, |
@@ -179,15 +158,10 @@ impl<R: TreeRoot> AstNode<R> for Struct<R> { | |||
179 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 158 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
180 | } | 159 | } |
181 | 160 | ||
182 | impl<R: TreeRoot> Struct<R> { | 161 | impl<R: TreeRoot> ast::NameOwner<R> for Struct<R> {} |
183 | pub fn name(&self) -> Option<Name<R>> { | 162 | impl<R: TreeRoot> Struct<R> {} |
184 | self.syntax() | ||
185 | .children() | ||
186 | .filter_map(Name::cast) | ||
187 | .next() | ||
188 | } | ||
189 | } | ||
190 | 163 | ||
164 | // Trait | ||
191 | #[derive(Debug, Clone, Copy)] | 165 | #[derive(Debug, Clone, Copy)] |
192 | pub struct Trait<R: TreeRoot = Arc<SyntaxRoot>> { | 166 | pub struct Trait<R: TreeRoot = Arc<SyntaxRoot>> { |
193 | syntax: SyntaxNode<R>, | 167 | syntax: SyntaxNode<R>, |
@@ -203,12 +177,6 @@ impl<R: TreeRoot> AstNode<R> for Trait<R> { | |||
203 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 177 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
204 | } | 178 | } |
205 | 179 | ||
206 | impl<R: TreeRoot> Trait<R> { | 180 | impl<R: TreeRoot> ast::NameOwner<R> for Trait<R> {} |
207 | pub fn name(&self) -> Option<Name<R>> { | 181 | impl<R: TreeRoot> Trait<R> {} |
208 | self.syntax() | ||
209 | .children() | ||
210 | .filter_map(Name::cast) | ||
211 | .next() | ||
212 | } | ||
213 | } | ||
214 | 182 | ||
diff --git a/crates/libsyntax2/src/ast/generated.rs.tera b/crates/libsyntax2/src/ast/generated.rs.tera index 86b8b05d1..3d79b5543 100644 --- a/crates/libsyntax2/src/ast/generated.rs.tera +++ b/crates/libsyntax2/src/ast/generated.rs.tera | |||
@@ -1,9 +1,11 @@ | |||
1 | use std::sync::Arc; | 1 | use std::sync::Arc; |
2 | use { | 2 | use { |
3 | ast, | ||
3 | SyntaxNode, SyntaxRoot, TreeRoot, AstNode, | 4 | SyntaxNode, SyntaxRoot, TreeRoot, AstNode, |
4 | SyntaxKind::*, | 5 | SyntaxKind::*, |
5 | }; | 6 | }; |
6 | {% for node, methods in ast %} | 7 | {% for node, methods in ast %} |
8 | // {{ node }} | ||
7 | #[derive(Debug, Clone, Copy)] | 9 | #[derive(Debug, Clone, Copy)] |
8 | pub struct {{ node }}<R: TreeRoot = Arc<SyntaxRoot>> { | 10 | pub struct {{ node }}<R: TreeRoot = Arc<SyntaxRoot>> { |
9 | syntax: SyntaxNode<R>, | 11 | syntax: SyntaxNode<R>, |
@@ -19,6 +21,12 @@ impl<R: TreeRoot> AstNode<R> for {{ node }}<R> { | |||
19 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } | 21 | fn syntax(&self) -> &SyntaxNode<R> { &self.syntax } |
20 | } | 22 | } |
21 | 23 | ||
24 | {% if methods.traits -%} | ||
25 | {%- for t in methods.traits -%} | ||
26 | impl<R: TreeRoot> ast::{{ t }}<R> for {{ node }}<R> {} | ||
27 | {% endfor -%} | ||
28 | {%- endif -%} | ||
29 | |||
22 | impl<R: TreeRoot> {{ node }}<R> { | 30 | impl<R: TreeRoot> {{ node }}<R> { |
23 | {%- if methods.collections -%} | 31 | {%- if methods.collections -%} |
24 | {%- for m in methods.collections -%} | 32 | {%- for m in methods.collections -%} |
diff --git a/crates/libsyntax2/src/ast/mod.rs b/crates/libsyntax2/src/ast/mod.rs index 7d3cdb93d..56bc099fe 100644 --- a/crates/libsyntax2/src/ast/mod.rs +++ b/crates/libsyntax2/src/ast/mod.rs | |||
@@ -12,6 +12,15 @@ pub trait AstNode<R: TreeRoot>: Sized { | |||
12 | fn syntax(&self) -> &SyntaxNode<R>; | 12 | fn syntax(&self) -> &SyntaxNode<R>; |
13 | } | 13 | } |
14 | 14 | ||
15 | pub trait NameOwner<R: TreeRoot>: AstNode<R> { | ||
16 | fn name(&self) -> Option<Name<R>> { | ||
17 | self.syntax() | ||
18 | .children() | ||
19 | .filter_map(Name::cast) | ||
20 | .next() | ||
21 | } | ||
22 | } | ||
23 | |||
15 | impl File<Arc<SyntaxRoot>> { | 24 | impl File<Arc<SyntaxRoot>> { |
16 | pub fn parse(text: &str) -> Self { | 25 | pub fn parse(text: &str) -> Self { |
17 | File::cast(::parse(text)).unwrap() | 26 | File::cast(::parse(text)).unwrap() |
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron index c9470d4fa..3fe8fdf0b 100644 --- a/crates/libsyntax2/src/grammar.ron +++ b/crates/libsyntax2/src/grammar.ron | |||
@@ -220,39 +220,25 @@ Grammar( | |||
220 | ] | 220 | ] |
221 | ), | 221 | ), |
222 | "Function": ( | 222 | "Function": ( |
223 | options: [ | 223 | traits: ["NameOwner"] |
224 | ["name", "Name"] | ||
225 | ] | ||
226 | ), | 224 | ), |
227 | "Struct": ( | 225 | "Struct": ( |
228 | options: [ | 226 | traits: ["NameOwner"] |
229 | ["name", "Name"] | ||
230 | ] | ||
231 | ), | 227 | ), |
232 | "Enum": ( | 228 | "Enum": ( |
233 | options: [ | 229 | traits: ["NameOwner"] |
234 | ["name", "Name"] | ||
235 | ] | ||
236 | ), | 230 | ), |
237 | "Trait": ( | 231 | "Trait": ( |
238 | options: [ | 232 | traits: ["NameOwner"] |
239 | ["name", "Name"] | ||
240 | ] | ||
241 | ), | 233 | ), |
242 | "Module": ( | 234 | "Module": ( |
243 | options: [ | 235 | traits: ["NameOwner"] |
244 | ["name", "Name"] | ||
245 | ] | ||
246 | ), | 236 | ), |
247 | "ConstItem": ( | 237 | "ConstItem": ( |
248 | options: [ | 238 | traits: ["NameOwner"] |
249 | ["name", "Name"] | ||
250 | ] | ||
251 | ), | 239 | ), |
252 | "StaticItem": ( | 240 | "StaticItem": ( |
253 | options: [ | 241 | traits: ["NameOwner"] |
254 | ["name", "Name"] | ||
255 | ] | ||
256 | ), | 242 | ), |
257 | "Name": (), | 243 | "Name": (), |
258 | }, | 244 | }, |
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs index 6e33310f1..a22275ed9 100644 --- a/crates/libsyntax2/src/yellow/syntax.rs +++ b/crates/libsyntax2/src/yellow/syntax.rs | |||
@@ -28,6 +28,12 @@ impl<R: TreeRoot> Eq for SyntaxNode<R> {} | |||
28 | 28 | ||
29 | pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>; | 29 | pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>; |
30 | 30 | ||
31 | #[test] | ||
32 | fn syntax_node_ref_is_copy() { | ||
33 | fn assert_copy<T: Copy>(){} | ||
34 | assert_copy::<SyntaxNodeRef>() | ||
35 | } | ||
36 | |||
31 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | 37 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] |
32 | pub struct SyntaxError { | 38 | pub struct SyntaxError { |
33 | pub msg: String, | 39 | pub msg: String, |