diff options
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r-- | crates/ra_syntax/src/ast/extensions.rs | 73 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 43 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/traits.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 3 |
4 files changed, 68 insertions, 53 deletions
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs index 8c5ece65d..cefc00402 100644 --- a/crates/ra_syntax/src/ast/extensions.rs +++ b/crates/ra_syntax/src/ast/extensions.rs | |||
@@ -1,10 +1,8 @@ | |||
1 | //! Various extension methods to ast Nodes, which are hard to code-generate. | 1 | //! Various extension methods to ast Nodes, which are hard to code-generate. |
2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. | 2 | //! Extensions for various expressions live in a sibling `expr_extensions` module. |
3 | 3 | ||
4 | use itertools::Itertools; | ||
5 | |||
6 | use crate::{ | 4 | use crate::{ |
7 | ast::{self, child_opt, children, AstChildren, AstNode, SyntaxNode}, | 5 | ast::{self, child_opt, children, AstChildren, AstNode, AttrInput, SyntaxNode}, |
8 | SmolStr, SyntaxElement, | 6 | SmolStr, SyntaxElement, |
9 | SyntaxKind::*, | 7 | SyntaxKind::*, |
10 | SyntaxToken, T, | 8 | SyntaxToken, T, |
@@ -38,62 +36,37 @@ fn text_of_first_token(node: &SyntaxNode) -> &SmolStr { | |||
38 | } | 36 | } |
39 | 37 | ||
40 | impl ast::Attr { | 38 | impl ast::Attr { |
41 | pub fn is_inner(&self) -> bool { | 39 | pub fn as_simple_atom(&self) -> Option<SmolStr> { |
42 | let tt = match self.value() { | 40 | match self.input() { |
43 | None => return false, | 41 | None => self.simple_name(), |
44 | Some(tt) => tt, | 42 | Some(_) => None, |
45 | }; | ||
46 | |||
47 | let prev = match tt.syntax().prev_sibling() { | ||
48 | None => return false, | ||
49 | Some(prev) => prev, | ||
50 | }; | ||
51 | |||
52 | prev.kind() == T![!] | ||
53 | } | ||
54 | |||
55 | pub fn as_atom(&self) -> Option<SmolStr> { | ||
56 | let tt = self.value()?; | ||
57 | let (_bra, attr, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | ||
58 | if attr.kind() == IDENT { | ||
59 | Some(attr.as_token()?.text().clone()) | ||
60 | } else { | ||
61 | None | ||
62 | } | 43 | } |
63 | } | 44 | } |
64 | 45 | ||
65 | pub fn as_call(&self) -> Option<(SmolStr, ast::TokenTree)> { | 46 | pub fn as_simple_call(&self) -> Option<(SmolStr, ast::TokenTree)> { |
66 | let tt = self.value()?; | 47 | match self.input() { |
67 | let (_bra, attr, args, _ket) = tt.syntax().children_with_tokens().collect_tuple()?; | 48 | Some(AttrInput::TokenTree(tt)) => Some((self.simple_name()?, tt)), |
68 | let args = ast::TokenTree::cast(args.as_node()?.clone())?; | 49 | _ => None, |
69 | if attr.kind() == IDENT { | ||
70 | Some((attr.as_token()?.text().clone(), args)) | ||
71 | } else { | ||
72 | None | ||
73 | } | 50 | } |
74 | } | 51 | } |
75 | 52 | ||
76 | pub fn as_named(&self) -> Option<SmolStr> { | 53 | pub fn as_simple_key_value(&self) -> Option<(SmolStr, SmolStr)> { |
77 | let tt = self.value()?; | 54 | match self.input() { |
78 | let attr = tt.syntax().children_with_tokens().nth(1)?; | 55 | Some(AttrInput::Literal(lit)) => { |
79 | if attr.kind() == IDENT { | 56 | let key = self.simple_name()?; |
80 | Some(attr.as_token()?.text().clone()) | 57 | // FIXME: escape? raw string? |
81 | } else { | 58 | let value = lit.syntax().first_token()?.text().trim_matches('"').into(); |
82 | None | 59 | Some((key, value)) |
60 | } | ||
61 | _ => None, | ||
83 | } | 62 | } |
84 | } | 63 | } |
85 | 64 | ||
86 | pub fn as_key_value(&self) -> Option<(SmolStr, SmolStr)> { | 65 | pub fn simple_name(&self) -> Option<SmolStr> { |
87 | let tt = self.value()?; | 66 | let path = self.path()?; |
88 | let tt_node = tt.syntax(); | 67 | match (path.segment(), path.qualifier()) { |
89 | let attr = tt_node.children_with_tokens().nth(1)?; | 68 | (Some(segment), None) => Some(segment.syntax().first_token()?.text().clone()), |
90 | if attr.kind() == IDENT { | 69 | _ => None, |
91 | let key = attr.as_token()?.text().clone(); | ||
92 | let val_node = tt_node.children_with_tokens().find(|t| t.kind() == STRING)?; | ||
93 | let val = val_node.as_token()?.text().trim_start_matches('"').trim_end_matches('"'); | ||
94 | Some((key, SmolStr::new(val))) | ||
95 | } else { | ||
96 | None | ||
97 | } | 70 | } |
98 | } | 71 | } |
99 | } | 72 | } |
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index dc1f8c82c..aaf03ce3f 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs | |||
@@ -166,11 +166,52 @@ impl AstNode for Attr { | |||
166 | } | 166 | } |
167 | } | 167 | } |
168 | impl Attr { | 168 | impl Attr { |
169 | pub fn value(&self) -> Option<TokenTree> { | 169 | pub fn path(&self) -> Option<Path> { |
170 | AstChildren::new(&self.syntax).next() | ||
171 | } | ||
172 | pub fn input(&self) -> Option<AttrInput> { | ||
170 | AstChildren::new(&self.syntax).next() | 173 | AstChildren::new(&self.syntax).next() |
171 | } | 174 | } |
172 | } | 175 | } |
173 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 176 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
177 | pub enum AttrInput { | ||
178 | Literal(Literal), | ||
179 | TokenTree(TokenTree), | ||
180 | } | ||
181 | impl From<Literal> for AttrInput { | ||
182 | fn from(node: Literal) -> AttrInput { | ||
183 | AttrInput::Literal(node) | ||
184 | } | ||
185 | } | ||
186 | impl From<TokenTree> for AttrInput { | ||
187 | fn from(node: TokenTree) -> AttrInput { | ||
188 | AttrInput::TokenTree(node) | ||
189 | } | ||
190 | } | ||
191 | impl AstNode for AttrInput { | ||
192 | fn can_cast(kind: SyntaxKind) -> bool { | ||
193 | match kind { | ||
194 | LITERAL | TOKEN_TREE => true, | ||
195 | _ => false, | ||
196 | } | ||
197 | } | ||
198 | fn cast(syntax: SyntaxNode) -> Option<Self> { | ||
199 | let res = match syntax.kind() { | ||
200 | LITERAL => AttrInput::Literal(Literal { syntax }), | ||
201 | TOKEN_TREE => AttrInput::TokenTree(TokenTree { syntax }), | ||
202 | _ => return None, | ||
203 | }; | ||
204 | Some(res) | ||
205 | } | ||
206 | fn syntax(&self) -> &SyntaxNode { | ||
207 | match self { | ||
208 | AttrInput::Literal(it) => &it.syntax, | ||
209 | AttrInput::TokenTree(it) => &it.syntax, | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | impl AttrInput {} | ||
214 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
174 | pub struct AwaitExpr { | 215 | pub struct AwaitExpr { |
175 | pub(crate) syntax: SyntaxNode, | 216 | pub(crate) syntax: SyntaxNode, |
176 | } | 217 | } |
diff --git a/crates/ra_syntax/src/ast/traits.rs b/crates/ra_syntax/src/ast/traits.rs index c3e676d4c..f275a4955 100644 --- a/crates/ra_syntax/src/ast/traits.rs +++ b/crates/ra_syntax/src/ast/traits.rs | |||
@@ -99,7 +99,7 @@ pub trait AttrsOwner: AstNode { | |||
99 | children(self) | 99 | children(self) |
100 | } | 100 | } |
101 | fn has_atom_attr(&self, atom: &str) -> bool { | 101 | fn has_atom_attr(&self, atom: &str) -> bool { |
102 | self.attrs().filter_map(|x| x.as_atom()).any(|x| x == atom) | 102 | self.attrs().filter_map(|x| x.as_simple_atom()).any(|x| x == atom) |
103 | } | 103 | } |
104 | } | 104 | } |
105 | 105 | ||
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 5f395501a..30328f59f 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron | |||
@@ -576,7 +576,8 @@ Grammar( | |||
576 | traits: [ "NameOwner", "AttrsOwner","DocCommentsOwner" ], | 576 | traits: [ "NameOwner", "AttrsOwner","DocCommentsOwner" ], |
577 | options: [ "TokenTree", "Path" ], | 577 | options: [ "TokenTree", "Path" ], |
578 | ), | 578 | ), |
579 | "Attr": ( options: [ ["value", "TokenTree"] ] ), | 579 | "AttrInput": ( enum: [ "Literal", "TokenTree" ] ), |
580 | "Attr": ( options: [ "Path", [ "input", "AttrInput" ] ] ), | ||
580 | "TokenTree": (), | 581 | "TokenTree": (), |
581 | "TypeParamList": ( | 582 | "TypeParamList": ( |
582 | collections: [ | 583 | collections: [ |