diff options
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander.rs')
-rw-r--r-- | crates/ra_mbe/src/mbe_expander.rs | 61 |
1 files changed, 49 insertions, 12 deletions
diff --git a/crates/ra_mbe/src/mbe_expander.rs b/crates/ra_mbe/src/mbe_expander.rs index 8f8a79855..4b007647c 100644 --- a/crates/ra_mbe/src/mbe_expander.rs +++ b/crates/ra_mbe/src/mbe_expander.rs | |||
@@ -81,9 +81,25 @@ struct Bindings { | |||
81 | enum Binding { | 81 | enum Binding { |
82 | Simple(tt::TokenTree), | 82 | Simple(tt::TokenTree), |
83 | Nested(Vec<Binding>), | 83 | Nested(Vec<Binding>), |
84 | Empty, | ||
84 | } | 85 | } |
85 | 86 | ||
86 | impl Bindings { | 87 | impl Bindings { |
88 | fn push_optional(&mut self, name: &SmolStr) { | ||
89 | // FIXME: Do we have a better way to represent an empty token ? | ||
90 | // Insert an empty subtree for empty token | ||
91 | self.inner.insert( | ||
92 | name.clone(), | ||
93 | Binding::Simple( | ||
94 | tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(), | ||
95 | ), | ||
96 | ); | ||
97 | } | ||
98 | |||
99 | fn push_empty(&mut self, name: &SmolStr) { | ||
100 | self.inner.insert(name.clone(), Binding::Empty); | ||
101 | } | ||
102 | |||
87 | fn contains(&self, name: &SmolStr) -> bool { | 103 | fn contains(&self, name: &SmolStr) -> bool { |
88 | self.inner.contains_key(name) | 104 | self.inner.contains_key(name) |
89 | } | 105 | } |
@@ -100,6 +116,12 @@ impl Bindings { | |||
100 | "could not find nested binding `{}`", | 116 | "could not find nested binding `{}`", |
101 | name | 117 | name |
102 | )))?, | 118 | )))?, |
119 | Binding::Empty => { | ||
120 | return Err(ExpandError::BindingError(format!( | ||
121 | "could not find empty binding `{}`", | ||
122 | name | ||
123 | ))) | ||
124 | } | ||
103 | }; | 125 | }; |
104 | } | 126 | } |
105 | match b { | 127 | match b { |
@@ -108,6 +130,10 @@ impl Bindings { | |||
108 | "expected simple binding, found nested binding `{}`", | 130 | "expected simple binding, found nested binding `{}`", |
109 | name | 131 | name |
110 | ))), | 132 | ))), |
133 | Binding::Empty => Err(ExpandError::BindingError(format!( | ||
134 | "expected simple binding, found empty binding `{}`", | ||
135 | name | ||
136 | ))), | ||
111 | } | 137 | } |
112 | } | 138 | } |
113 | 139 | ||
@@ -140,6 +166,24 @@ impl Bindings { | |||
140 | } | 166 | } |
141 | } | 167 | } |
142 | 168 | ||
169 | fn collect_vars(subtree: &crate::Subtree) -> Vec<SmolStr> { | ||
170 | let mut res = vec![]; | ||
171 | |||
172 | for tkn in subtree.token_trees.iter() { | ||
173 | match tkn { | ||
174 | crate::TokenTree::Leaf(crate::Leaf::Var(crate::Var { text, .. })) => { | ||
175 | res.push(text.clone()); | ||
176 | } | ||
177 | crate::TokenTree::Subtree(subtree) => { | ||
178 | res.extend(collect_vars(subtree)); | ||
179 | } | ||
180 | _ => {} | ||
181 | } | ||
182 | } | ||
183 | |||
184 | res | ||
185 | } | ||
186 | |||
143 | fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, ExpandError> { | 187 | fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, ExpandError> { |
144 | let mut res = Bindings::default(); | 188 | let mut res = Bindings::default(); |
145 | for pat in pattern.token_trees.iter() { | 189 | for pat in pattern.token_trees.iter() { |
@@ -217,18 +261,7 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
217 | let vis = vis.clone(); | 261 | let vis = vis.clone(); |
218 | res.inner.insert(text.clone(), Binding::Simple(vis.into())); | 262 | res.inner.insert(text.clone(), Binding::Simple(vis.into())); |
219 | } else { | 263 | } else { |
220 | // FIXME: Do we have a better way to represent an empty token ? | 264 | res.push_optional(&text); |
221 | // Insert an empty subtree for empty token | ||
222 | res.inner.insert( | ||
223 | text.clone(), | ||
224 | Binding::Simple( | ||
225 | tt::Subtree { | ||
226 | delimiter: tt::Delimiter::None, | ||
227 | token_trees: vec![], | ||
228 | } | ||
229 | .into(), | ||
230 | ), | ||
231 | ); | ||
232 | } | 265 | } |
233 | } | 266 | } |
234 | 267 | ||
@@ -295,6 +328,10 @@ fn match_lhs(pattern: &crate::Subtree, input: &mut TtCursor) -> Result<Bindings, | |||
295 | crate::RepeatKind::OneOrMore if counter == 0 => { | 328 | crate::RepeatKind::OneOrMore if counter == 0 => { |
296 | return Err(ExpandError::UnexpectedToken); | 329 | return Err(ExpandError::UnexpectedToken); |
297 | } | 330 | } |
331 | _ if counter == 0 => { | ||
332 | // Collect all empty variables in subtrees | ||
333 | collect_vars(subtree).iter().for_each(|s| res.push_empty(s)); | ||
334 | } | ||
298 | _ => {} | 335 | _ => {} |
299 | } | 336 | } |
300 | } | 337 | } |