diff options
Diffstat (limited to 'crates/ra_mbe/src/mbe_expander/matcher.rs')
-rw-r--r-- | crates/ra_mbe/src/mbe_expander/matcher.rs | 361 |
1 files changed, 242 insertions, 119 deletions
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs index 100a3b0e0..aff953102 100644 --- a/crates/ra_mbe/src/mbe_expander/matcher.rs +++ b/crates/ra_mbe/src/mbe_expander/matcher.rs | |||
@@ -1,11 +1,14 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | mbe_expander::{Binding, Bindings, Fragment}, | 2 | mbe_expander::{Binding, Bindings, Fragment}, |
3 | tt_cursor::TtCursor, | 3 | parser::{parse_pattern, Op, RepeatKind, Separator}, |
4 | subtree_source::SubtreeTokenSource, | ||
5 | tt_iter::TtIter, | ||
4 | ExpandError, | 6 | ExpandError, |
5 | }; | 7 | }; |
6 | 8 | ||
7 | use ra_parser::FragmentKind::*; | 9 | use ra_parser::{FragmentKind::*, TreeSink}; |
8 | use ra_syntax::SmolStr; | 10 | use ra_syntax::{SmolStr, SyntaxKind}; |
11 | use tt::buffer::{Cursor, TokenBuffer}; | ||
9 | 12 | ||
10 | impl Bindings { | 13 | impl Bindings { |
11 | fn push_optional(&mut self, name: &SmolStr) { | 14 | fn push_optional(&mut self, name: &SmolStr) { |
@@ -42,121 +45,247 @@ impl Bindings { | |||
42 | } | 45 | } |
43 | Ok(()) | 46 | Ok(()) |
44 | } | 47 | } |
48 | } | ||
45 | 49 | ||
46 | fn merge(&mut self, nested: Bindings) { | 50 | macro_rules! err { |
47 | self.inner.extend(nested.inner); | 51 | () => { |
48 | } | 52 | ExpandError::BindingError(format!("")) |
53 | }; | ||
54 | ($($tt:tt)*) => { | ||
55 | ExpandError::BindingError(format!($($tt)*)) | ||
56 | }; | ||
49 | } | 57 | } |
50 | 58 | ||
51 | pub(super) fn match_lhs( | 59 | macro_rules! bail { |
52 | pattern: &crate::Subtree, | 60 | ($($tt:tt)*) => { |
53 | input: &mut TtCursor, | 61 | return Err(err!($($tt)*)) |
54 | ) -> Result<Bindings, ExpandError> { | 62 | }; |
63 | } | ||
64 | |||
65 | pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { | ||
66 | assert!(pattern.delimiter == tt::Delimiter::None); | ||
67 | |||
55 | let mut res = Bindings::default(); | 68 | let mut res = Bindings::default(); |
56 | for pat in pattern.token_trees.iter() { | 69 | let mut src = TtIter::new(src); |
57 | match pat { | 70 | |
58 | crate::TokenTree::Leaf(leaf) => match leaf { | 71 | match_subtree(&mut res, pattern, &mut src)?; |
59 | crate::Leaf::Var(crate::Var { text, kind }) => { | 72 | |
60 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; | 73 | if src.len() > 0 { |
61 | match match_meta_var(kind.as_str(), input)? { | 74 | bail!("leftover tokens"); |
62 | Some(fragment) => { | 75 | } |
63 | res.inner.insert(text.clone(), Binding::Fragment(fragment)); | 76 | |
64 | } | 77 | Ok(res) |
65 | None => res.push_optional(text), | 78 | } |
66 | } | 79 | |
80 | fn match_subtree( | ||
81 | bindings: &mut Bindings, | ||
82 | pattern: &tt::Subtree, | ||
83 | src: &mut TtIter, | ||
84 | ) -> Result<(), ExpandError> { | ||
85 | for op in parse_pattern(pattern) { | ||
86 | match op? { | ||
87 | Op::TokenTree(tt::TokenTree::Leaf(lhs)) => { | ||
88 | let rhs = src.expect_leaf().map_err(|()| err!("expected leaf: `{}`", lhs))?; | ||
89 | match (lhs, rhs) { | ||
90 | ( | ||
91 | tt::Leaf::Punct(tt::Punct { char: lhs, .. }), | ||
92 | tt::Leaf::Punct(tt::Punct { char: rhs, .. }), | ||
93 | ) if lhs == rhs => (), | ||
94 | ( | ||
95 | tt::Leaf::Ident(tt::Ident { text: lhs, .. }), | ||
96 | tt::Leaf::Ident(tt::Ident { text: rhs, .. }), | ||
97 | ) if lhs == rhs => (), | ||
98 | ( | ||
99 | tt::Leaf::Literal(tt::Literal { text: lhs, .. }), | ||
100 | tt::Leaf::Literal(tt::Literal { text: rhs, .. }), | ||
101 | ) if lhs == rhs => (), | ||
102 | _ => Err(ExpandError::UnexpectedToken)?, | ||
67 | } | 103 | } |
68 | crate::Leaf::Punct(punct) => { | 104 | } |
69 | if !input.eat_punct().map(|p| p.char == punct.char).unwrap_or(false) { | 105 | Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { |
70 | return Err(ExpandError::UnexpectedToken); | 106 | let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; |
71 | } | 107 | if lhs.delimiter != rhs.delimiter { |
108 | bail!("mismatched delimiter") | ||
72 | } | 109 | } |
73 | crate::Leaf::Ident(ident) => { | 110 | let mut src = TtIter::new(rhs); |
74 | if input.eat_ident().map(|i| &i.text) != Some(&ident.text) { | 111 | match_subtree(bindings, lhs, &mut src)?; |
75 | return Err(ExpandError::UnexpectedToken); | 112 | if src.len() > 0 { |
76 | } | 113 | bail!("leftover tokens"); |
77 | } | 114 | } |
78 | crate::Leaf::Literal(literal) => { | 115 | } |
79 | if input.eat_literal().map(|i| &i.text) != Some(&literal.text) { | 116 | Op::Var { name, kind } => { |
80 | return Err(ExpandError::UnexpectedToken); | 117 | let kind = kind.as_ref().ok_or(ExpandError::UnexpectedToken)?; |
118 | match match_meta_var(kind.as_str(), src)? { | ||
119 | Some(fragment) => { | ||
120 | bindings.inner.insert(name.clone(), Binding::Fragment(fragment)); | ||
81 | } | 121 | } |
122 | None => bindings.push_optional(name), | ||
82 | } | 123 | } |
124 | () | ||
125 | } | ||
126 | Op::Repeat { subtree, kind, separator } => { | ||
127 | match_repeat(bindings, subtree, kind, separator, src)? | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | Ok(()) | ||
132 | } | ||
133 | |||
134 | impl<'a> TtIter<'a> { | ||
135 | fn eat_separator(&mut self, separator: &Separator) -> bool { | ||
136 | let mut fork = self.clone(); | ||
137 | let ok = match separator { | ||
138 | Separator::Ident(lhs) => match fork.expect_ident() { | ||
139 | Ok(rhs) => rhs.text == lhs.text, | ||
140 | _ => false, | ||
83 | }, | 141 | }, |
84 | crate::TokenTree::Repeat(crate::Repeat { subtree, kind, separator }) => { | 142 | Separator::Literal(lhs) => match fork.expect_literal() { |
85 | // Dirty hack to make macro-expansion terminate. | 143 | Ok(rhs) => rhs.text == lhs.text, |
86 | // This should be replaced by a propper macro-by-example implementation | 144 | _ => false, |
87 | let mut limit = 65536; | 145 | }, |
88 | let mut counter = 0; | 146 | Separator::Puncts(lhss) => lhss.iter().all(|lhs| match fork.expect_punct() { |
89 | 147 | Ok(rhs) => rhs.char == lhs.char, | |
90 | let mut memento = input.save(); | 148 | _ => false, |
91 | 149 | }), | |
92 | loop { | 150 | }; |
93 | match match_lhs(subtree, input) { | 151 | if ok { |
94 | Ok(nested) => { | 152 | *self = fork; |
95 | limit -= 1; | 153 | } |
96 | if limit == 0 { | 154 | ok |
97 | log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", subtree, input, kind, separator); | 155 | } |
98 | break; | ||
99 | } | ||
100 | |||
101 | memento = input.save(); | ||
102 | res.push_nested(counter, nested)?; | ||
103 | counter += 1; | ||
104 | if counter == 1 { | ||
105 | if let crate::RepeatKind::ZeroOrOne = kind { | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | if let Some(separator) = separator { | ||
111 | if !input | ||
112 | .eat_seperator() | ||
113 | .map(|sep| sep == *separator) | ||
114 | .unwrap_or(false) | ||
115 | { | ||
116 | input.rollback(memento); | ||
117 | break; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | Err(_) => { | ||
122 | input.rollback(memento); | ||
123 | break; | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | 156 | ||
128 | match kind { | 157 | pub(crate) fn expect_lifetime(&mut self) -> Result<&tt::Ident, ()> { |
129 | crate::RepeatKind::OneOrMore if counter == 0 => { | 158 | let ident = self.expect_ident()?; |
130 | return Err(ExpandError::UnexpectedToken); | 159 | // check if it start from "`" |
131 | } | 160 | if ident.text.chars().next() != Some('\'') { |
132 | _ if counter == 0 => { | 161 | return Err(()); |
133 | // Collect all empty variables in subtrees | 162 | } |
134 | collect_vars(subtree).iter().for_each(|s| res.push_empty(s)); | 163 | Ok(ident) |
135 | } | 164 | } |
136 | _ => {} | 165 | |
166 | pub(crate) fn expect_fragment( | ||
167 | &mut self, | ||
168 | fragment_kind: ra_parser::FragmentKind, | ||
169 | ) -> Result<tt::TokenTree, ()> { | ||
170 | pub(crate) struct OffsetTokenSink<'a> { | ||
171 | pub(crate) cursor: Cursor<'a>, | ||
172 | pub(crate) error: bool, | ||
173 | } | ||
174 | |||
175 | impl<'a> TreeSink for OffsetTokenSink<'a> { | ||
176 | fn token(&mut self, _kind: SyntaxKind, n_tokens: u8) { | ||
177 | for _ in 0..n_tokens { | ||
178 | self.cursor = self.cursor.bump_subtree(); | ||
137 | } | 179 | } |
138 | } | 180 | } |
139 | crate::TokenTree::Subtree(subtree) => { | 181 | fn start_node(&mut self, _kind: SyntaxKind) {} |
140 | let input_subtree = | 182 | fn finish_node(&mut self) {} |
141 | input.eat_subtree().map_err(|_| ExpandError::UnexpectedToken)?; | 183 | fn error(&mut self, _error: ra_parser::ParseError) { |
142 | if subtree.delimiter != input_subtree.delimiter { | 184 | self.error = true; |
143 | return Err(ExpandError::UnexpectedToken); | 185 | } |
186 | } | ||
187 | |||
188 | let buffer = TokenBuffer::new(self.inner.as_slice()); | ||
189 | let mut src = SubtreeTokenSource::new(&buffer); | ||
190 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; | ||
191 | |||
192 | ra_parser::parse_fragment(&mut src, &mut sink, fragment_kind); | ||
193 | |||
194 | if !sink.cursor.is_root() || sink.error { | ||
195 | return Err(()); | ||
196 | } | ||
197 | |||
198 | let mut curr = buffer.begin(); | ||
199 | let mut res = vec![]; | ||
200 | |||
201 | while curr != sink.cursor { | ||
202 | if let Some(token) = curr.token_tree() { | ||
203 | res.push(token); | ||
204 | } | ||
205 | curr = curr.bump(); | ||
206 | } | ||
207 | self.inner = self.inner.as_slice()[res.len()..].iter(); | ||
208 | match res.len() { | ||
209 | 0 => Err(()), | ||
210 | 1 => Ok(res[0].clone()), | ||
211 | _ => Ok(tt::TokenTree::Subtree(tt::Subtree { | ||
212 | delimiter: tt::Delimiter::None, | ||
213 | token_trees: res.into_iter().cloned().collect(), | ||
214 | })), | ||
215 | } | ||
216 | } | ||
217 | |||
218 | pub(crate) fn eat_vis(&mut self) -> Option<tt::TokenTree> { | ||
219 | let mut fork = self.clone(); | ||
220 | match fork.expect_fragment(Visibility) { | ||
221 | Ok(tt) => { | ||
222 | *self = fork; | ||
223 | Some(tt) | ||
224 | } | ||
225 | Err(()) => None, | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | pub(super) fn match_repeat( | ||
231 | bindings: &mut Bindings, | ||
232 | pattern: &tt::Subtree, | ||
233 | kind: RepeatKind, | ||
234 | separator: Option<Separator>, | ||
235 | src: &mut TtIter, | ||
236 | ) -> Result<(), ExpandError> { | ||
237 | // Dirty hack to make macro-expansion terminate. | ||
238 | // This should be replaced by a propper macro-by-example implementation | ||
239 | let mut limit = 65536; | ||
240 | let mut counter = 0; | ||
241 | |||
242 | for i in 0.. { | ||
243 | let mut fork = src.clone(); | ||
244 | |||
245 | if let Some(separator) = &separator { | ||
246 | if i != 0 && !fork.eat_separator(separator) { | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | let mut nested = Bindings::default(); | ||
252 | match match_subtree(&mut nested, pattern, &mut fork) { | ||
253 | Ok(()) => { | ||
254 | limit -= 1; | ||
255 | if limit == 0 { | ||
256 | log::warn!("match_lhs excced in repeat pattern exceed limit => {:#?}\n{:#?}\n{:#?}\n{:#?}", pattern, src, kind, separator); | ||
257 | break; | ||
144 | } | 258 | } |
259 | *src = fork; | ||
145 | 260 | ||
146 | let mut input = TtCursor::new(input_subtree); | 261 | bindings.push_nested(counter, nested)?; |
147 | let bindings = match_lhs(&subtree, &mut input)?; | 262 | counter += 1; |
148 | if !input.is_eof() { | 263 | if counter == 1 { |
149 | return Err(ExpandError::UnexpectedToken); | 264 | if let RepeatKind::ZeroOrOne = kind { |
265 | break; | ||
266 | } | ||
150 | } | 267 | } |
268 | } | ||
269 | Err(_) => break, | ||
270 | } | ||
271 | } | ||
151 | 272 | ||
152 | res.merge(bindings); | 273 | match (kind, counter) { |
274 | (RepeatKind::OneOrMore, 0) => return Err(ExpandError::UnexpectedToken), | ||
275 | (_, 0) => { | ||
276 | // Collect all empty variables in subtrees | ||
277 | let mut vars = Vec::new(); | ||
278 | collect_vars(&mut vars, pattern)?; | ||
279 | for var in vars { | ||
280 | bindings.push_empty(&var) | ||
153 | } | 281 | } |
154 | } | 282 | } |
283 | _ => (), | ||
155 | } | 284 | } |
156 | Ok(res) | 285 | Ok(()) |
157 | } | 286 | } |
158 | 287 | ||
159 | fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, ExpandError> { | 288 | fn match_meta_var(kind: &str, input: &mut TtIter) -> Result<Option<Fragment>, ExpandError> { |
160 | let fragment = match kind { | 289 | let fragment = match kind { |
161 | "path" => Path, | 290 | "path" => Path, |
162 | "expr" => Expr, | 291 | "expr" => Expr, |
@@ -169,17 +298,20 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, | |||
169 | _ => { | 298 | _ => { |
170 | let tt = match kind { | 299 | let tt = match kind { |
171 | "ident" => { | 300 | "ident" => { |
172 | let ident = input.eat_ident().ok_or(ExpandError::UnexpectedToken)?.clone(); | 301 | let ident = input.expect_ident().map_err(|()| err!("expected ident"))?.clone(); |
173 | tt::Leaf::from(ident).into() | 302 | tt::Leaf::from(ident).into() |
174 | } | 303 | } |
175 | "tt" => input.eat().ok_or(ExpandError::UnexpectedToken)?.clone(), | 304 | "tt" => input.next().ok_or_else(|| err!())?.clone(), |
176 | "lifetime" => input.eat_lifetime().ok_or(ExpandError::UnexpectedToken)?.clone(), | 305 | "lifetime" => { |
306 | let ident = input.expect_lifetime().map_err(|()| err!())?; | ||
307 | tt::Leaf::Ident(ident.clone()).into() | ||
308 | } | ||
177 | "literal" => { | 309 | "literal" => { |
178 | let literal = input.eat_literal().ok_or(ExpandError::UnexpectedToken)?.clone(); | 310 | let literal = input.expect_literal().map_err(|()| err!())?.clone(); |
179 | tt::Leaf::from(literal).into() | 311 | tt::Leaf::from(literal).into() |
180 | } | 312 | } |
181 | // `vis` is optional | 313 | // `vis` is optional |
182 | "vis" => match input.try_eat_vis() { | 314 | "vis" => match input.eat_vis() { |
183 | Some(vis) => vis, | 315 | Some(vis) => vis, |
184 | None => return Ok(None), | 316 | None => return Ok(None), |
185 | }, | 317 | }, |
@@ -188,28 +320,19 @@ fn match_meta_var(kind: &str, input: &mut TtCursor) -> Result<Option<Fragment>, | |||
188 | return Ok(Some(Fragment::Tokens(tt))); | 320 | return Ok(Some(Fragment::Tokens(tt))); |
189 | } | 321 | } |
190 | }; | 322 | }; |
191 | let tt = input.eat_fragment(fragment).ok_or(ExpandError::UnexpectedToken)?; | 323 | let tt = input.expect_fragment(fragment).map_err(|()| err!())?; |
192 | let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; | 324 | let fragment = if kind == "expr" { Fragment::Ast(tt) } else { Fragment::Tokens(tt) }; |
193 | Ok(Some(fragment)) | 325 | Ok(Some(fragment)) |
194 | } | 326 | } |
195 | 327 | ||
196 | fn collect_vars(subtree: &crate::Subtree) -> Vec<SmolStr> { | 328 | fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> { |
197 | let mut res = Vec::new(); | 329 | for op in parse_pattern(pattern) { |
198 | 330 | match op? { | |
199 | for tkn in subtree.token_trees.iter() { | 331 | Op::Var { name, .. } => buf.push(name.clone()), |
200 | match tkn { | 332 | Op::TokenTree(tt::TokenTree::Leaf(_)) => (), |
201 | crate::TokenTree::Leaf(crate::Leaf::Var(crate::Var { text, .. })) => { | 333 | Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?, |
202 | res.push(text.clone()); | 334 | Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?, |
203 | } | ||
204 | crate::TokenTree::Subtree(subtree) => { | ||
205 | res.extend(collect_vars(subtree)); | ||
206 | } | ||
207 | crate::TokenTree::Repeat(crate::Repeat { subtree, .. }) => { | ||
208 | res.extend(collect_vars(subtree)); | ||
209 | } | ||
210 | _ => {} | ||
211 | } | 335 | } |
212 | } | 336 | } |
213 | 337 | Ok(()) | |
214 | res | ||
215 | } | 338 | } |