aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2019-09-30 09:46:08 +0100
committerGitHub <[email protected]>2019-09-30 09:46:08 +0100
commit733f1d8b709788225bd06f8c0aee1819db92620b (patch)
treed17395e4c3f7965c5cf9bdd50ef940e52eef1155 /crates/ra_syntax/src
parentc913b48928107710d6ec87a455b1ae6891297c2b (diff)
parentf7e12559cb26b59a9a2ecee4deecaf6fe9100d16 (diff)
Merge #1934
1934: Parse Path and AttrInput in Attr r=matklad a=uHOOCCOOHu [Syntax reference](https://doc.rust-lang.org/reference/attributes.html#attributes) Co-authored-by: uHOOCCOOHu <[email protected]>
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs73
-rw-r--r--crates/ra_syntax/src/ast/generated.rs43
-rw-r--r--crates/ra_syntax/src/ast/traits.rs2
-rw-r--r--crates/ra_syntax/src/grammar.ron3
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
4use itertools::Itertools;
5
6use crate::{ 4use 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
40impl ast::Attr { 38impl 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}
168impl Attr { 168impl 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)]
177pub enum AttrInput {
178 Literal(Literal),
179 TokenTree(TokenTree),
180}
181impl From<Literal> for AttrInput {
182 fn from(node: Literal) -> AttrInput {
183 AttrInput::Literal(node)
184 }
185}
186impl From<TokenTree> for AttrInput {
187 fn from(node: TokenTree) -> AttrInput {
188 AttrInput::TokenTree(node)
189 }
190}
191impl 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}
213impl AttrInput {}
214#[derive(Debug, Clone, PartialEq, Eq, Hash)]
174pub struct AwaitExpr { 215pub 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: [