]>
Commit | Line | Data |
---|---|---|
c34b1796 | 1 | // Copyright 2015 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
9cc50fc6 | 11 | use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, TokenTree, Ty}; |
1a4d82fc | 12 | use codemap::Span; |
970d7e83 | 13 | use ext::base::ExtCtxt; |
223e47cc | 14 | use ext::base; |
970d7e83 | 15 | use ext::build::AstBuilder; |
92a42be0 | 16 | use parse::parser::{Parser, PathParsingMode}; |
223e47cc LB |
17 | use parse::token::*; |
18 | use parse::token; | |
1a4d82fc | 19 | use ptr::P; |
223e47cc | 20 | |
1a4d82fc JJ |
21 | /// Quasiquoting works via token trees. |
22 | /// | |
23 | /// This is registered as a set of expression syntax extension called quote! | |
24 | /// that lifts its argument token-tree to an AST representing the | |
25 | /// construction of the same token tree, with token::SubstNt interpreted | |
26 | /// as antiquotes (splices). | |
223e47cc LB |
27 | |
28 | pub mod rt { | |
29 | use ast; | |
1a4d82fc | 30 | use codemap::Spanned; |
970d7e83 | 31 | use ext::base::ExtCtxt; |
d9579d0f | 32 | use parse::{self, token, classify}; |
1a4d82fc | 33 | use ptr::P; |
d9579d0f | 34 | use std::rc::Rc; |
1a4d82fc | 35 | |
9cc50fc6 | 36 | use ast::TokenTree; |
223e47cc | 37 | |
223e47cc | 38 | pub use parse::new_parser_from_tts; |
d9579d0f | 39 | pub use codemap::{BytePos, Span, dummy_spanned, DUMMY_SP}; |
223e47cc | 40 | |
223e47cc | 41 | pub trait ToTokens { |
d9579d0f | 42 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree>; |
223e47cc LB |
43 | } |
44 | ||
1a4d82fc JJ |
45 | impl ToTokens for TokenTree { |
46 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
47 | vec!(self.clone()) | |
223e47cc LB |
48 | } |
49 | } | |
50 | ||
1a4d82fc JJ |
51 | impl<T: ToTokens> ToTokens for Vec<T> { |
52 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
62682a34 | 53 | self.iter().flat_map(|t| t.to_tokens(cx)).collect() |
223e47cc LB |
54 | } |
55 | } | |
56 | ||
1a4d82fc JJ |
57 | impl<T: ToTokens> ToTokens for Spanned<T> { |
58 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
59 | // FIXME: use the span? | |
60 | self.node.to_tokens(cx) | |
223e47cc LB |
61 | } |
62 | } | |
63 | ||
1a4d82fc JJ |
64 | impl<T: ToTokens> ToTokens for Option<T> { |
65 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 SL |
66 | match *self { |
67 | Some(ref t) => t.to_tokens(cx), | |
68 | None => Vec::new(), | |
1a4d82fc | 69 | } |
223e47cc LB |
70 | } |
71 | } | |
72 | ||
d9579d0f AL |
73 | impl ToTokens for ast::Ident { |
74 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 75 | vec![TokenTree::Token(DUMMY_SP, token::Ident(*self, token::Plain))] |
d9579d0f AL |
76 | } |
77 | } | |
223e47cc | 78 | |
d9579d0f AL |
79 | impl ToTokens for ast::Path { |
80 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 SL |
81 | vec![TokenTree::Token(DUMMY_SP, |
82 | token::Interpolated(token::NtPath(Box::new(self.clone()))))] | |
d9579d0f AL |
83 | } |
84 | } | |
223e47cc | 85 | |
d9579d0f AL |
86 | impl ToTokens for ast::Ty { |
87 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 88 | vec![TokenTree::Token(self.span, token::Interpolated(token::NtTy(P(self.clone()))))] |
223e47cc LB |
89 | } |
90 | } | |
91 | ||
d9579d0f AL |
92 | impl ToTokens for ast::Block { |
93 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 94 | vec![TokenTree::Token(self.span, token::Interpolated(token::NtBlock(P(self.clone()))))] |
d9579d0f AL |
95 | } |
96 | } | |
223e47cc | 97 | |
d9579d0f AL |
98 | impl ToTokens for ast::Generics { |
99 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 100 | vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtGenerics(self.clone())))] |
d9579d0f | 101 | } |
223e47cc LB |
102 | } |
103 | ||
d9579d0f AL |
104 | impl ToTokens for ast::WhereClause { |
105 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 SL |
106 | vec![TokenTree::Token(DUMMY_SP, |
107 | token::Interpolated(token::NtWhereClause(self.clone())))] | |
d9579d0f | 108 | } |
223e47cc LB |
109 | } |
110 | ||
d9579d0f AL |
111 | impl ToTokens for P<ast::Item> { |
112 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 113 | vec![TokenTree::Token(self.span, token::Interpolated(token::NtItem(self.clone())))] |
d9579d0f | 114 | } |
223e47cc LB |
115 | } |
116 | ||
d9579d0f AL |
117 | impl ToTokens for P<ast::ImplItem> { |
118 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 119 | vec![TokenTree::Token(self.span, token::Interpolated(token::NtImplItem(self.clone())))] |
d9579d0f | 120 | } |
223e47cc LB |
121 | } |
122 | ||
d9579d0f AL |
123 | impl ToTokens for P<ast::TraitItem> { |
124 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 125 | vec![TokenTree::Token(self.span, token::Interpolated(token::NtTraitItem(self.clone())))] |
d9579d0f | 126 | } |
223e47cc LB |
127 | } |
128 | ||
d9579d0f AL |
129 | impl ToTokens for P<ast::Stmt> { |
130 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
131 | let mut tts = vec![ | |
92a42be0 | 132 | TokenTree::Token(self.span, token::Interpolated(token::NtStmt(self.clone()))) |
d9579d0f | 133 | ]; |
223e47cc | 134 | |
d9579d0f AL |
135 | // Some statements require a trailing semicolon. |
136 | if classify::stmt_ends_with_semi(&self.node) { | |
92a42be0 | 137 | tts.push(TokenTree::Token(self.span, token::Semi)); |
1a4d82fc | 138 | } |
223e47cc | 139 | |
d9579d0f | 140 | tts |
223e47cc LB |
141 | } |
142 | } | |
143 | ||
d9579d0f AL |
144 | impl ToTokens for P<ast::Expr> { |
145 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 146 | vec![TokenTree::Token(self.span, token::Interpolated(token::NtExpr(self.clone())))] |
223e47cc LB |
147 | } |
148 | } | |
149 | ||
d9579d0f AL |
150 | impl ToTokens for P<ast::Pat> { |
151 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 152 | vec![TokenTree::Token(self.span, token::Interpolated(token::NtPat(self.clone())))] |
223e47cc LB |
153 | } |
154 | } | |
d9579d0f AL |
155 | |
156 | impl ToTokens for ast::Arm { | |
157 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 SL |
158 | vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArm(self.clone())))] |
159 | } | |
160 | } | |
161 | ||
162 | impl ToTokens for ast::Arg { | |
163 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
164 | vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))] | |
165 | } | |
166 | } | |
167 | ||
168 | impl ToTokens for P<ast::Block> { | |
169 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
170 | vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))] | |
223e47cc LB |
171 | } |
172 | } | |
173 | ||
d9579d0f AL |
174 | macro_rules! impl_to_tokens_slice { |
175 | ($t: ty, $sep: expr) => { | |
176 | impl ToTokens for [$t] { | |
177 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
178 | let mut v = vec![]; | |
179 | for (i, x) in self.iter().enumerate() { | |
180 | if i > 0 { | |
92a42be0 | 181 | v.extend_from_slice(&$sep); |
d9579d0f AL |
182 | } |
183 | v.extend(x.to_tokens(cx)); | |
184 | } | |
185 | v | |
186 | } | |
187 | } | |
188 | }; | |
223e47cc | 189 | } |
d9579d0f | 190 | |
92a42be0 | 191 | impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] } |
d9579d0f | 192 | impl_to_tokens_slice! { P<ast::Item>, [] } |
92a42be0 | 193 | impl_to_tokens_slice! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] } |
d9579d0f AL |
194 | |
195 | impl ToTokens for P<ast::MetaItem> { | |
196 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 197 | vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtMeta(self.clone())))] |
223e47cc LB |
198 | } |
199 | } | |
200 | ||
d9579d0f AL |
201 | impl ToTokens for ast::Attribute { |
202 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
203 | let mut r = vec![]; | |
204 | // FIXME: The spans could be better | |
92a42be0 | 205 | r.push(TokenTree::Token(self.span, token::Pound)); |
b039eaaf | 206 | if self.node.style == ast::AttrStyle::Inner { |
92a42be0 | 207 | r.push(TokenTree::Token(self.span, token::Not)); |
d9579d0f | 208 | } |
92a42be0 | 209 | r.push(TokenTree::Delimited(self.span, Rc::new(ast::Delimited { |
d9579d0f AL |
210 | delim: token::Bracket, |
211 | open_span: self.span, | |
212 | tts: self.node.value.to_tokens(cx), | |
213 | close_span: self.span, | |
214 | }))); | |
215 | r | |
223e47cc LB |
216 | } |
217 | } | |
d9579d0f AL |
218 | |
219 | impl ToTokens for str { | |
220 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
221 | let lit = ast::LitStr( | |
222 | token::intern_and_get_ident(self), ast::CookedStr); | |
223 | dummy_spanned(lit).to_tokens(cx) | |
223e47cc LB |
224 | } |
225 | } | |
226 | ||
d9579d0f AL |
227 | impl ToTokens for () { |
228 | fn to_tokens(&self, _cx: &ExtCtxt) -> Vec<TokenTree> { | |
92a42be0 | 229 | vec![TokenTree::Delimited(DUMMY_SP, Rc::new(ast::Delimited { |
d9579d0f AL |
230 | delim: token::Paren, |
231 | open_span: DUMMY_SP, | |
232 | tts: vec![], | |
233 | close_span: DUMMY_SP, | |
234 | }))] | |
223e47cc LB |
235 | } |
236 | } | |
d9579d0f AL |
237 | |
238 | impl ToTokens for ast::Lit { | |
239 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
240 | // FIXME: This is wrong | |
241 | P(ast::Expr { | |
242 | id: ast::DUMMY_NODE_ID, | |
243 | node: ast::ExprLit(P(self.clone())), | |
244 | span: DUMMY_SP, | |
92a42be0 | 245 | attrs: None, |
d9579d0f | 246 | }).to_tokens(cx) |
223e47cc LB |
247 | } |
248 | } | |
249 | ||
d9579d0f AL |
250 | impl ToTokens for bool { |
251 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
252 | dummy_spanned(ast::LitBool(*self)).to_tokens(cx) | |
223e47cc LB |
253 | } |
254 | } | |
d9579d0f AL |
255 | |
256 | impl ToTokens for char { | |
257 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
258 | dummy_spanned(ast::LitChar(*self)).to_tokens(cx) | |
223e47cc LB |
259 | } |
260 | } | |
261 | ||
d9579d0f | 262 | macro_rules! impl_to_tokens_int { |
1a4d82fc | 263 | (signed, $t:ty, $tag:expr) => ( |
d9579d0f AL |
264 | impl ToTokens for $t { |
265 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
1a4d82fc JJ |
266 | let lit = ast::LitInt(*self as u64, ast::SignedIntLit($tag, |
267 | ast::Sign::new(*self))); | |
d9579d0f | 268 | dummy_spanned(lit).to_tokens(cx) |
1a4d82fc JJ |
269 | } |
270 | } | |
271 | ); | |
272 | (unsigned, $t:ty, $tag:expr) => ( | |
1a4d82fc JJ |
273 | impl ToTokens for $t { |
274 | fn to_tokens(&self, cx: &ExtCtxt) -> Vec<TokenTree> { | |
d9579d0f AL |
275 | let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag)); |
276 | dummy_spanned(lit).to_tokens(cx) | |
1a4d82fc JJ |
277 | } |
278 | } | |
d9579d0f | 279 | ); |
223e47cc LB |
280 | } |
281 | ||
d9579d0f AL |
282 | impl_to_tokens_int! { signed, isize, ast::TyIs } |
283 | impl_to_tokens_int! { signed, i8, ast::TyI8 } | |
284 | impl_to_tokens_int! { signed, i16, ast::TyI16 } | |
285 | impl_to_tokens_int! { signed, i32, ast::TyI32 } | |
286 | impl_to_tokens_int! { signed, i64, ast::TyI64 } | |
1a4d82fc | 287 | |
d9579d0f AL |
288 | impl_to_tokens_int! { unsigned, usize, ast::TyUs } |
289 | impl_to_tokens_int! { unsigned, u8, ast::TyU8 } | |
290 | impl_to_tokens_int! { unsigned, u16, ast::TyU16 } | |
291 | impl_to_tokens_int! { unsigned, u32, ast::TyU32 } | |
292 | impl_to_tokens_int! { unsigned, u64, ast::TyU64 } | |
223e47cc | 293 | |
1a4d82fc JJ |
294 | pub trait ExtParseUtils { |
295 | fn parse_item(&self, s: String) -> P<ast::Item>; | |
296 | fn parse_expr(&self, s: String) -> P<ast::Expr>; | |
297 | fn parse_stmt(&self, s: String) -> P<ast::Stmt>; | |
92a42be0 | 298 | fn parse_tts(&self, s: String) -> Vec<TokenTree>; |
223e47cc LB |
299 | } |
300 | ||
1a4d82fc | 301 | impl<'a> ExtParseUtils for ExtCtxt<'a> { |
223e47cc | 302 | |
1a4d82fc | 303 | fn parse_item(&self, s: String) -> P<ast::Item> { |
85aaf69f | 304 | parse::parse_item_from_source_str( |
1a4d82fc | 305 | "<quote expansion>".to_string(), |
970d7e83 | 306 | s, |
223e47cc | 307 | self.cfg(), |
85aaf69f | 308 | self.parse_sess()).expect("parse error") |
223e47cc LB |
309 | } |
310 | ||
1a4d82fc JJ |
311 | fn parse_stmt(&self, s: String) -> P<ast::Stmt> { |
312 | parse::parse_stmt_from_source_str("<quote expansion>".to_string(), | |
313 | s, | |
314 | self.cfg(), | |
c34b1796 | 315 | self.parse_sess()).expect("parse error") |
223e47cc LB |
316 | } |
317 | ||
1a4d82fc JJ |
318 | fn parse_expr(&self, s: String) -> P<ast::Expr> { |
319 | parse::parse_expr_from_source_str("<quote expansion>".to_string(), | |
320 | s, | |
321 | self.cfg(), | |
322 | self.parse_sess()) | |
223e47cc LB |
323 | } |
324 | ||
92a42be0 | 325 | fn parse_tts(&self, s: String) -> Vec<TokenTree> { |
1a4d82fc JJ |
326 | parse::parse_tts_from_source_str("<quote expansion>".to_string(), |
327 | s, | |
328 | self.cfg(), | |
329 | self.parse_sess()) | |
223e47cc LB |
330 | } |
331 | } | |
1a4d82fc JJ |
332 | } |
333 | ||
92a42be0 SL |
334 | // These panicking parsing functions are used by the quote_*!() syntax extensions, |
335 | // but shouldn't be used otherwise. | |
336 | pub fn parse_expr_panic(parser: &mut Parser) -> P<Expr> { | |
337 | panictry!(parser.parse_expr()) | |
338 | } | |
339 | ||
340 | pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> { | |
341 | panictry!(parser.parse_item()) | |
342 | } | |
343 | ||
344 | pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> { | |
345 | panictry!(parser.parse_pat()) | |
346 | } | |
347 | ||
348 | pub fn parse_arm_panic(parser: &mut Parser) -> Arm { | |
349 | panictry!(parser.parse_arm()) | |
350 | } | |
351 | ||
352 | pub fn parse_ty_panic(parser: &mut Parser) -> P<Ty> { | |
353 | panictry!(parser.parse_ty()) | |
354 | } | |
355 | ||
356 | pub fn parse_stmt_panic(parser: &mut Parser) -> Option<P<Stmt>> { | |
357 | panictry!(parser.parse_stmt()) | |
358 | } | |
359 | ||
360 | pub fn parse_attribute_panic(parser: &mut Parser, permit_inner: bool) -> ast::Attribute { | |
361 | panictry!(parser.parse_attribute(permit_inner)) | |
362 | } | |
363 | ||
364 | pub fn parse_arg_panic(parser: &mut Parser) -> Arg { | |
365 | panictry!(parser.parse_arg()) | |
366 | } | |
367 | ||
368 | pub fn parse_block_panic(parser: &mut Parser) -> P<Block> { | |
369 | panictry!(parser.parse_block()) | |
370 | } | |
371 | ||
372 | pub fn parse_meta_item_panic(parser: &mut Parser) -> P<ast::MetaItem> { | |
373 | panictry!(parser.parse_meta_item()) | |
374 | } | |
375 | ||
376 | pub fn parse_path_panic(parser: &mut Parser, mode: PathParsingMode) -> ast::Path { | |
377 | panictry!(parser.parse_path(mode)) | |
378 | } | |
379 | ||
1a4d82fc JJ |
380 | pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt, |
381 | sp: Span, | |
92a42be0 | 382 | tts: &[TokenTree]) |
1a4d82fc JJ |
383 | -> Box<base::MacResult+'cx> { |
384 | let (cx_expr, expr) = expand_tts(cx, sp, tts); | |
c34b1796 AL |
385 | let expanded = expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]]); |
386 | base::MacEager::expr(expanded) | |
1a4d82fc JJ |
387 | } |
388 | ||
389 | pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt, | |
390 | sp: Span, | |
92a42be0 | 391 | tts: &[TokenTree]) |
1a4d82fc | 392 | -> Box<base::MacResult+'cx> { |
92a42be0 | 393 | let expanded = expand_parse_call(cx, sp, "parse_expr_panic", vec!(), tts); |
c34b1796 | 394 | base::MacEager::expr(expanded) |
223e47cc LB |
395 | } |
396 | ||
1a4d82fc JJ |
397 | pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt, |
398 | sp: Span, | |
92a42be0 | 399 | tts: &[TokenTree]) |
1a4d82fc | 400 | -> Box<base::MacResult+'cx> { |
92a42be0 | 401 | let expanded = expand_parse_call(cx, sp, "parse_item_panic", vec!(), tts); |
c34b1796 | 402 | base::MacEager::expr(expanded) |
223e47cc LB |
403 | } |
404 | ||
1a4d82fc JJ |
405 | pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt, |
406 | sp: Span, | |
92a42be0 | 407 | tts: &[TokenTree]) |
1a4d82fc | 408 | -> Box<base::MacResult+'cx> { |
92a42be0 | 409 | let expanded = expand_parse_call(cx, sp, "parse_pat_panic", vec!(), tts); |
c34b1796 | 410 | base::MacEager::expr(expanded) |
223e47cc LB |
411 | } |
412 | ||
1a4d82fc JJ |
413 | pub fn expand_quote_arm(cx: &mut ExtCtxt, |
414 | sp: Span, | |
92a42be0 | 415 | tts: &[TokenTree]) |
1a4d82fc | 416 | -> Box<base::MacResult+'static> { |
92a42be0 | 417 | let expanded = expand_parse_call(cx, sp, "parse_arm_panic", vec!(), tts); |
c34b1796 | 418 | base::MacEager::expr(expanded) |
223e47cc LB |
419 | } |
420 | ||
1a4d82fc JJ |
421 | pub fn expand_quote_ty(cx: &mut ExtCtxt, |
422 | sp: Span, | |
92a42be0 | 423 | tts: &[TokenTree]) |
1a4d82fc | 424 | -> Box<base::MacResult+'static> { |
92a42be0 | 425 | let expanded = expand_parse_call(cx, sp, "parse_ty_panic", vec!(), tts); |
c34b1796 | 426 | base::MacEager::expr(expanded) |
223e47cc LB |
427 | } |
428 | ||
c34b1796 AL |
429 | pub fn expand_quote_stmt(cx: &mut ExtCtxt, |
430 | sp: Span, | |
92a42be0 | 431 | tts: &[TokenTree]) |
c34b1796 | 432 | -> Box<base::MacResult+'static> { |
92a42be0 | 433 | let expanded = expand_parse_call(cx, sp, "parse_stmt_panic", vec!(), tts); |
c34b1796 | 434 | base::MacEager::expr(expanded) |
223e47cc LB |
435 | } |
436 | ||
c34b1796 | 437 | pub fn expand_quote_attr(cx: &mut ExtCtxt, |
1a4d82fc | 438 | sp: Span, |
92a42be0 | 439 | tts: &[TokenTree]) |
1a4d82fc | 440 | -> Box<base::MacResult+'static> { |
92a42be0 | 441 | let expanded = expand_parse_call(cx, sp, "parse_attribute_panic", |
c34b1796 AL |
442 | vec!(cx.expr_bool(sp, true)), tts); |
443 | ||
444 | base::MacEager::expr(expanded) | |
445 | } | |
446 | ||
92a42be0 SL |
447 | pub fn expand_quote_arg(cx: &mut ExtCtxt, |
448 | sp: Span, | |
449 | tts: &[TokenTree]) | |
450 | -> Box<base::MacResult+'static> { | |
451 | let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec!(), tts); | |
452 | base::MacEager::expr(expanded) | |
453 | } | |
454 | ||
455 | pub fn expand_quote_block(cx: &mut ExtCtxt, | |
456 | sp: Span, | |
457 | tts: &[TokenTree]) | |
458 | -> Box<base::MacResult+'static> { | |
459 | let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec!(), tts); | |
460 | base::MacEager::expr(expanded) | |
461 | } | |
462 | ||
463 | pub fn expand_quote_meta_item(cx: &mut ExtCtxt, | |
464 | sp: Span, | |
465 | tts: &[TokenTree]) | |
466 | -> Box<base::MacResult+'static> { | |
467 | let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec!(), tts); | |
468 | base::MacEager::expr(expanded) | |
469 | } | |
470 | ||
471 | pub fn expand_quote_path(cx: &mut ExtCtxt, | |
472 | sp: Span, | |
473 | tts: &[TokenTree]) | |
474 | -> Box<base::MacResult+'static> { | |
475 | let mode = mk_parser_path(cx, sp, "LifetimeAndTypesWithoutColons"); | |
476 | let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec!(mode), tts); | |
477 | base::MacEager::expr(expanded) | |
478 | } | |
479 | ||
c34b1796 AL |
480 | pub fn expand_quote_matcher(cx: &mut ExtCtxt, |
481 | sp: Span, | |
92a42be0 | 482 | tts: &[TokenTree]) |
c34b1796 AL |
483 | -> Box<base::MacResult+'static> { |
484 | let (cx_expr, tts) = parse_arguments_to_quote(cx, tts); | |
485 | let mut vector = mk_stmts_let(cx, sp); | |
62682a34 | 486 | vector.extend(statements_mk_tts(cx, &tts[..], true)); |
c34b1796 AL |
487 | let block = cx.expr_block( |
488 | cx.block_all(sp, | |
489 | vector, | |
490 | Some(cx.expr_ident(sp, id_ext("tt"))))); | |
491 | ||
492 | let expanded = expand_wrapper(cx, sp, cx_expr, block, &[&["syntax", "ext", "quote", "rt"]]); | |
493 | base::MacEager::expr(expanded) | |
223e47cc LB |
494 | } |
495 | ||
1a4d82fc | 496 | fn ids_ext(strs: Vec<String> ) -> Vec<ast::Ident> { |
c34b1796 | 497 | strs.iter().map(|str| str_to_ident(&(*str))).collect() |
223e47cc LB |
498 | } |
499 | ||
1a4d82fc | 500 | fn id_ext(str: &str) -> ast::Ident { |
970d7e83 | 501 | str_to_ident(str) |
223e47cc LB |
502 | } |
503 | ||
504 | // Lift an ident to the expr that evaluates to that ident. | |
1a4d82fc | 505 | fn mk_ident(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> { |
c1a9b12d | 506 | let e_str = cx.expr_str(sp, ident.name.as_str()); |
970d7e83 LB |
507 | cx.expr_method_call(sp, |
508 | cx.expr_ident(sp, id_ext("ext_cx")), | |
509 | id_ext("ident_of"), | |
1a4d82fc | 510 | vec!(e_str)) |
223e47cc LB |
511 | } |
512 | ||
1a4d82fc JJ |
513 | // Lift a name to the expr that evaluates to that name |
514 | fn mk_name(cx: &ExtCtxt, sp: Span, ident: ast::Ident) -> P<ast::Expr> { | |
c1a9b12d | 515 | let e_str = cx.expr_str(sp, ident.name.as_str()); |
1a4d82fc JJ |
516 | cx.expr_method_call(sp, |
517 | cx.expr_ident(sp, id_ext("ext_cx")), | |
518 | id_ext("name_of"), | |
519 | vec!(e_str)) | |
223e47cc LB |
520 | } |
521 | ||
92a42be0 SL |
522 | fn mk_tt_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> { |
523 | let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext("TokenTree"), id_ext(name)); | |
524 | cx.expr_path(cx.path_global(sp, idents)) | |
525 | } | |
526 | ||
1a4d82fc JJ |
527 | fn mk_ast_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> { |
528 | let idents = vec!(id_ext("syntax"), id_ext("ast"), id_ext(name)); | |
529 | cx.expr_path(cx.path_global(sp, idents)) | |
530 | } | |
531 | ||
532 | fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> { | |
533 | let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("token"), id_ext(name)); | |
534 | cx.expr_path(cx.path_global(sp, idents)) | |
535 | } | |
536 | ||
92a42be0 SL |
537 | fn mk_parser_path(cx: &ExtCtxt, sp: Span, name: &str) -> P<ast::Expr> { |
538 | let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("parser"), id_ext(name)); | |
539 | cx.expr_path(cx.path_global(sp, idents)) | |
540 | } | |
541 | ||
1a4d82fc | 542 | fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P<ast::Expr> { |
223e47cc | 543 | let name = match bop { |
1a4d82fc JJ |
544 | token::Plus => "Plus", |
545 | token::Minus => "Minus", | |
546 | token::Star => "Star", | |
547 | token::Slash => "Slash", | |
548 | token::Percent => "Percent", | |
549 | token::Caret => "Caret", | |
550 | token::And => "And", | |
551 | token::Or => "Or", | |
552 | token::Shl => "Shl", | |
553 | token::Shr => "Shr" | |
223e47cc | 554 | }; |
1a4d82fc | 555 | mk_token_path(cx, sp, name) |
223e47cc LB |
556 | } |
557 | ||
1a4d82fc JJ |
558 | fn mk_delim(cx: &ExtCtxt, sp: Span, delim: token::DelimToken) -> P<ast::Expr> { |
559 | let name = match delim { | |
560 | token::Paren => "Paren", | |
561 | token::Bracket => "Bracket", | |
562 | token::Brace => "Brace", | |
563 | }; | |
564 | mk_token_path(cx, sp, name) | |
565 | } | |
223e47cc | 566 | |
1a4d82fc | 567 | #[allow(non_upper_case_globals)] |
c34b1796 | 568 | fn expr_mk_token(cx: &ExtCtxt, sp: Span, tok: &token::Token) -> P<ast::Expr> { |
1a4d82fc JJ |
569 | macro_rules! mk_lit { |
570 | ($name: expr, $suffix: expr, $($args: expr),*) => {{ | |
571 | let inner = cx.expr_call(sp, mk_token_path(cx, sp, $name), vec![$($args),*]); | |
572 | let suffix = match $suffix { | |
b039eaaf | 573 | Some(name) => cx.expr_some(sp, mk_name(cx, sp, ast::Ident::with_empty_ctxt(name))), |
1a4d82fc | 574 | None => cx.expr_none(sp) |
223e47cc | 575 | }; |
1a4d82fc JJ |
576 | cx.expr_call(sp, mk_token_path(cx, sp, "Literal"), vec![inner, suffix]) |
577 | }} | |
578 | } | |
579 | match *tok { | |
580 | token::BinOp(binop) => { | |
581 | return cx.expr_call(sp, mk_token_path(cx, sp, "BinOp"), vec!(mk_binop(cx, sp, binop))); | |
582 | } | |
583 | token::BinOpEq(binop) => { | |
584 | return cx.expr_call(sp, mk_token_path(cx, sp, "BinOpEq"), | |
585 | vec!(mk_binop(cx, sp, binop))); | |
223e47cc LB |
586 | } |
587 | ||
1a4d82fc JJ |
588 | token::OpenDelim(delim) => { |
589 | return cx.expr_call(sp, mk_token_path(cx, sp, "OpenDelim"), | |
590 | vec![mk_delim(cx, sp, delim)]); | |
591 | } | |
592 | token::CloseDelim(delim) => { | |
593 | return cx.expr_call(sp, mk_token_path(cx, sp, "CloseDelim"), | |
594 | vec![mk_delim(cx, sp, delim)]); | |
223e47cc LB |
595 | } |
596 | ||
1a4d82fc | 597 | token::Literal(token::Byte(i), suf) => { |
b039eaaf | 598 | let e_byte = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i)); |
1a4d82fc JJ |
599 | return mk_lit!("Byte", suf, e_byte); |
600 | } | |
223e47cc | 601 | |
1a4d82fc | 602 | token::Literal(token::Char(i), suf) => { |
b039eaaf | 603 | let e_char = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i)); |
1a4d82fc | 604 | return mk_lit!("Char", suf, e_char); |
223e47cc LB |
605 | } |
606 | ||
1a4d82fc | 607 | token::Literal(token::Integer(i), suf) => { |
b039eaaf | 608 | let e_int = mk_name(cx, sp, ast::Ident::with_empty_ctxt(i)); |
1a4d82fc JJ |
609 | return mk_lit!("Integer", suf, e_int); |
610 | } | |
223e47cc | 611 | |
1a4d82fc | 612 | token::Literal(token::Float(fident), suf) => { |
b039eaaf | 613 | let e_fident = mk_name(cx, sp, ast::Ident::with_empty_ctxt(fident)); |
1a4d82fc JJ |
614 | return mk_lit!("Float", suf, e_fident); |
615 | } | |
223e47cc | 616 | |
1a4d82fc | 617 | token::Literal(token::Str_(ident), suf) => { |
b039eaaf | 618 | return mk_lit!("Str_", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident))) |
223e47cc LB |
619 | } |
620 | ||
1a4d82fc | 621 | token::Literal(token::StrRaw(ident, n), suf) => { |
b039eaaf SL |
622 | return mk_lit!("StrRaw", suf, mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)), |
623 | cx.expr_usize(sp, n)) | |
223e47cc LB |
624 | } |
625 | ||
1a4d82fc JJ |
626 | token::Ident(ident, style) => { |
627 | return cx.expr_call(sp, | |
628 | mk_token_path(cx, sp, "Ident"), | |
629 | vec![mk_ident(cx, sp, ident), | |
630 | match style { | |
631 | ModName => mk_token_path(cx, sp, "ModName"), | |
632 | Plain => mk_token_path(cx, sp, "Plain"), | |
633 | }]); | |
223e47cc LB |
634 | } |
635 | ||
1a4d82fc JJ |
636 | token::Lifetime(ident) => { |
637 | return cx.expr_call(sp, | |
638 | mk_token_path(cx, sp, "Lifetime"), | |
639 | vec!(mk_ident(cx, sp, ident))); | |
223e47cc LB |
640 | } |
641 | ||
1a4d82fc JJ |
642 | token::DocComment(ident) => { |
643 | return cx.expr_call(sp, | |
644 | mk_token_path(cx, sp, "DocComment"), | |
b039eaaf | 645 | vec!(mk_name(cx, sp, ast::Ident::with_empty_ctxt(ident)))); |
223e47cc LB |
646 | } |
647 | ||
c34b1796 AL |
648 | token::MatchNt(name, kind, namep, kindp) => { |
649 | return cx.expr_call(sp, | |
650 | mk_token_path(cx, sp, "MatchNt"), | |
651 | vec!(mk_ident(cx, sp, name), | |
652 | mk_ident(cx, sp, kind), | |
653 | match namep { | |
654 | ModName => mk_token_path(cx, sp, "ModName"), | |
655 | Plain => mk_token_path(cx, sp, "Plain"), | |
656 | }, | |
657 | match kindp { | |
658 | ModName => mk_token_path(cx, sp, "ModName"), | |
659 | Plain => mk_token_path(cx, sp, "Plain"), | |
660 | })); | |
661 | } | |
662 | ||
1a4d82fc | 663 | token::Interpolated(_) => panic!("quote! with interpolated token"), |
223e47cc LB |
664 | |
665 | _ => () | |
666 | } | |
667 | ||
970d7e83 | 668 | let name = match *tok { |
1a4d82fc JJ |
669 | token::Eq => "Eq", |
670 | token::Lt => "Lt", | |
671 | token::Le => "Le", | |
672 | token::EqEq => "EqEq", | |
673 | token::Ne => "Ne", | |
674 | token::Ge => "Ge", | |
675 | token::Gt => "Gt", | |
676 | token::AndAnd => "AndAnd", | |
677 | token::OrOr => "OrOr", | |
678 | token::Not => "Not", | |
679 | token::Tilde => "Tilde", | |
680 | token::At => "At", | |
681 | token::Dot => "Dot", | |
682 | token::DotDot => "DotDot", | |
683 | token::Comma => "Comma", | |
684 | token::Semi => "Semi", | |
685 | token::Colon => "Colon", | |
686 | token::ModSep => "ModSep", | |
687 | token::RArrow => "RArrow", | |
688 | token::LArrow => "LArrow", | |
689 | token::FatArrow => "FatArrow", | |
690 | token::Pound => "Pound", | |
691 | token::Dollar => "Dollar", | |
c34b1796 | 692 | token::Question => "Question", |
1a4d82fc JJ |
693 | token::Underscore => "Underscore", |
694 | token::Eof => "Eof", | |
c34b1796 | 695 | _ => panic!("unhandled token in quote!"), |
223e47cc | 696 | }; |
1a4d82fc | 697 | mk_token_path(cx, sp, name) |
223e47cc LB |
698 | } |
699 | ||
92a42be0 | 700 | fn statements_mk_tt(cx: &ExtCtxt, tt: &TokenTree, matcher: bool) -> Vec<P<ast::Stmt>> { |
223e47cc | 701 | match *tt { |
92a42be0 | 702 | TokenTree::Token(sp, SubstNt(ident, _)) => { |
62682a34 | 703 | // tt.extend($ident.to_tokens(ext_cx)) |
223e47cc LB |
704 | |
705 | let e_to_toks = | |
970d7e83 LB |
706 | cx.expr_method_call(sp, |
707 | cx.expr_ident(sp, ident), | |
708 | id_ext("to_tokens"), | |
1a4d82fc JJ |
709 | vec!(cx.expr_ident(sp, id_ext("ext_cx")))); |
710 | let e_to_toks = | |
711 | cx.expr_method_call(sp, e_to_toks, id_ext("into_iter"), vec![]); | |
223e47cc LB |
712 | |
713 | let e_push = | |
970d7e83 LB |
714 | cx.expr_method_call(sp, |
715 | cx.expr_ident(sp, id_ext("tt")), | |
1a4d82fc JJ |
716 | id_ext("extend"), |
717 | vec!(e_to_toks)); | |
223e47cc | 718 | |
1a4d82fc | 719 | vec!(cx.stmt_expr(e_push)) |
223e47cc | 720 | } |
92a42be0 | 721 | ref tt @ TokenTree::Token(_, MatchNt(..)) if !matcher => { |
1a4d82fc | 722 | let mut seq = vec![]; |
85aaf69f | 723 | for i in 0..tt.len() { |
1a4d82fc JJ |
724 | seq.push(tt.get_tt(i)); |
725 | } | |
c34b1796 | 726 | statements_mk_tts(cx, &seq[..], matcher) |
1a4d82fc | 727 | } |
92a42be0 | 728 | TokenTree::Token(sp, ref tok) => { |
1a4d82fc JJ |
729 | let e_sp = cx.expr_ident(sp, id_ext("_sp")); |
730 | let e_tok = cx.expr_call(sp, | |
92a42be0 | 731 | mk_tt_path(cx, sp, "Token"), |
c34b1796 | 732 | vec!(e_sp, expr_mk_token(cx, sp, tok))); |
1a4d82fc JJ |
733 | let e_push = |
734 | cx.expr_method_call(sp, | |
735 | cx.expr_ident(sp, id_ext("tt")), | |
736 | id_ext("push"), | |
737 | vec!(e_tok)); | |
738 | vec!(cx.stmt_expr(e_push)) | |
739 | }, | |
92a42be0 | 740 | TokenTree::Delimited(_, ref delimed) => { |
c34b1796 AL |
741 | statements_mk_tt(cx, &delimed.open_tt(), matcher).into_iter() |
742 | .chain(delimed.tts.iter() | |
62682a34 SL |
743 | .flat_map(|tt| statements_mk_tt(cx, tt, matcher))) |
744 | .chain(statements_mk_tt(cx, &delimed.close_tt(), matcher)) | |
1a4d82fc JJ |
745 | .collect() |
746 | }, | |
92a42be0 | 747 | TokenTree::Sequence(sp, ref seq) => { |
c34b1796 | 748 | if !matcher { |
92a42be0 | 749 | panic!("TokenTree::Sequence in quote!"); |
c34b1796 | 750 | } |
223e47cc | 751 | |
c34b1796 AL |
752 | let e_sp = cx.expr_ident(sp, id_ext("_sp")); |
753 | ||
754 | let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp)); | |
755 | let mut tts_stmts = vec![stmt_let_tt]; | |
62682a34 | 756 | tts_stmts.extend(statements_mk_tts(cx, &seq.tts[..], matcher)); |
c34b1796 AL |
757 | let e_tts = cx.expr_block(cx.block(sp, tts_stmts, |
758 | Some(cx.expr_ident(sp, id_ext("tt"))))); | |
759 | let e_separator = match seq.separator { | |
760 | Some(ref sep) => cx.expr_some(sp, expr_mk_token(cx, sp, sep)), | |
761 | None => cx.expr_none(sp), | |
762 | }; | |
763 | let e_op = match seq.op { | |
764 | ast::ZeroOrMore => mk_ast_path(cx, sp, "ZeroOrMore"), | |
765 | ast::OneOrMore => mk_ast_path(cx, sp, "OneOrMore"), | |
766 | }; | |
767 | let fields = vec![cx.field_imm(sp, id_ext("tts"), e_tts), | |
768 | cx.field_imm(sp, id_ext("separator"), e_separator), | |
769 | cx.field_imm(sp, id_ext("op"), e_op), | |
770 | cx.field_imm(sp, id_ext("num_captures"), | |
771 | cx.expr_usize(sp, seq.num_captures))]; | |
772 | let seq_path = vec![id_ext("syntax"), id_ext("ast"), id_ext("SequenceRepetition")]; | |
773 | let e_seq_struct = cx.expr_struct(sp, cx.path_global(sp, seq_path), fields); | |
774 | let e_rc_new = cx.expr_call_global(sp, vec![id_ext("std"), | |
775 | id_ext("rc"), | |
776 | id_ext("Rc"), | |
777 | id_ext("new")], | |
778 | vec![e_seq_struct]); | |
779 | let e_tok = cx.expr_call(sp, | |
92a42be0 | 780 | mk_tt_path(cx, sp, "Sequence"), |
c34b1796 AL |
781 | vec!(e_sp, e_rc_new)); |
782 | let e_push = | |
783 | cx.expr_method_call(sp, | |
784 | cx.expr_ident(sp, id_ext("tt")), | |
785 | id_ext("push"), | |
786 | vec!(e_tok)); | |
787 | vec!(cx.stmt_expr(e_push)) | |
788 | } | |
223e47cc | 789 | } |
223e47cc LB |
790 | } |
791 | ||
92a42be0 SL |
792 | fn parse_arguments_to_quote(cx: &ExtCtxt, tts: &[TokenTree]) |
793 | -> (P<ast::Expr>, Vec<TokenTree>) { | |
223e47cc | 794 | // NB: It appears that the main parser loses its mind if we consider |
c34b1796 | 795 | // $foo as a SubstNt during the main parse, so we have to re-parse |
223e47cc LB |
796 | // under quote_depth > 0. This is silly and should go away; the _guess_ is |
797 | // it has to do with transition away from supporting old-style macros, so | |
798 | // try removing it when enough of them are gone. | |
799 | ||
1a4d82fc | 800 | let mut p = cx.new_parser_from_tts(tts); |
85aaf69f | 801 | p.quote_depth += 1; |
223e47cc | 802 | |
92a42be0 | 803 | let cx_expr = panictry!(p.parse_expr()); |
9cc50fc6 SL |
804 | if !p.eat(&token::Comma) { |
805 | let _ = p.diagnostic().fatal("expected token `,`"); | |
1a4d82fc | 806 | } |
223e47cc | 807 | |
9346a6ac | 808 | let tts = panictry!(p.parse_all_token_trees()); |
1a4d82fc | 809 | p.abort_if_errors(); |
223e47cc | 810 | |
c34b1796 AL |
811 | (cx_expr, tts) |
812 | } | |
813 | ||
814 | fn mk_stmts_let(cx: &ExtCtxt, sp: Span) -> Vec<P<ast::Stmt>> { | |
223e47cc LB |
815 | // We also bind a single value, sp, to ext_cx.call_site() |
816 | // | |
817 | // This causes every span in a token-tree quote to be attributed to the | |
818 | // call site of the extension using the quote. We can't really do much | |
819 | // better since the source of the quote may well be in a library that | |
820 | // was not even parsed by this compilation run, that the user has no | |
821 | // source code for (eg. in libsyntax, which they're just _using_). | |
822 | // | |
823 | // The old quasiquoter had an elaborate mechanism for denoting input | |
824 | // file locations from which quotes originated; unfortunately this | |
825 | // relied on feeding the source string of the quote back into the | |
826 | // compiler (which we don't really want to do) and, in any case, only | |
827 | // pushed the problem a very small step further back: an error | |
828 | // resulting from a parse of the resulting quote is still attributed to | |
970d7e83 | 829 | // the site the string literal occurred, which was in a source file |
223e47cc LB |
830 | // _other_ than the one the user has control over. For example, an |
831 | // error in a quote from the protocol compiler, invoked in user code | |
1a4d82fc JJ |
832 | // using macro_rules! for example, will be attributed to the macro_rules.rs |
833 | // file in libsyntax, which the user might not even have source to (unless | |
834 | // they happen to have a compiler on hand). Over all, the phase distinction | |
223e47cc LB |
835 | // just makes quotes "hard to attribute". Possibly this could be fixed |
836 | // by recreating some of the original qq machinery in the tt regime | |
837 | // (pushing fake FileMaps onto the parser to account for original sites | |
838 | // of quotes, for example) but at this point it seems not likely to be | |
839 | // worth the hassle. | |
840 | ||
970d7e83 LB |
841 | let e_sp = cx.expr_method_call(sp, |
842 | cx.expr_ident(sp, id_ext("ext_cx")), | |
843 | id_ext("call_site"), | |
1a4d82fc | 844 | Vec::new()); |
223e47cc | 845 | |
970d7e83 | 846 | let stmt_let_sp = cx.stmt_let(sp, false, |
1a4d82fc | 847 | id_ext("_sp"), |
970d7e83 | 848 | e_sp); |
223e47cc | 849 | |
1a4d82fc | 850 | let stmt_let_tt = cx.stmt_let(sp, true, id_ext("tt"), cx.expr_vec_ng(sp)); |
223e47cc | 851 | |
c34b1796 AL |
852 | vec!(stmt_let_sp, stmt_let_tt) |
853 | } | |
854 | ||
92a42be0 | 855 | fn statements_mk_tts(cx: &ExtCtxt, tts: &[TokenTree], matcher: bool) -> Vec<P<ast::Stmt>> { |
c34b1796 AL |
856 | let mut ss = Vec::new(); |
857 | for tt in tts { | |
62682a34 | 858 | ss.extend(statements_mk_tt(cx, tt, matcher)); |
c34b1796 AL |
859 | } |
860 | ss | |
861 | } | |
862 | ||
92a42be0 | 863 | fn expand_tts(cx: &ExtCtxt, sp: Span, tts: &[TokenTree]) |
c34b1796 AL |
864 | -> (P<ast::Expr>, P<ast::Expr>) { |
865 | let (cx_expr, tts) = parse_arguments_to_quote(cx, tts); | |
866 | ||
867 | let mut vector = mk_stmts_let(cx, sp); | |
62682a34 | 868 | vector.extend(statements_mk_tts(cx, &tts[..], false)); |
1a4d82fc JJ |
869 | let block = cx.expr_block( |
870 | cx.block_all(sp, | |
1a4d82fc JJ |
871 | vector, |
872 | Some(cx.expr_ident(sp, id_ext("tt"))))); | |
873 | ||
874 | (cx_expr, block) | |
875 | } | |
876 | ||
877 | fn expand_wrapper(cx: &ExtCtxt, | |
878 | sp: Span, | |
879 | cx_expr: P<ast::Expr>, | |
c34b1796 AL |
880 | expr: P<ast::Expr>, |
881 | imports: &[&[&str]]) -> P<ast::Expr> { | |
1a4d82fc JJ |
882 | // Explicitly borrow to avoid moving from the invoker (#16992) |
883 | let cx_expr_borrow = cx.expr_addr_of(sp, cx.expr_deref(sp, cx_expr)); | |
884 | let stmt_let_ext_cx = cx.stmt_let(sp, false, id_ext("ext_cx"), cx_expr_borrow); | |
885 | ||
c34b1796 AL |
886 | let stmts = imports.iter().map(|path| { |
887 | // make item: `use ...;` | |
85aaf69f SL |
888 | let path = path.iter().map(|s| s.to_string()).collect(); |
889 | cx.stmt_item(sp, cx.item_use_glob(sp, ast::Inherited, ids_ext(path))) | |
62682a34 | 890 | }).chain(Some(stmt_let_ext_cx)).collect(); |
85aaf69f SL |
891 | |
892 | cx.expr_block(cx.block_all(sp, stmts, Some(expr))) | |
223e47cc LB |
893 | } |
894 | ||
1a4d82fc JJ |
895 | fn expand_parse_call(cx: &ExtCtxt, |
896 | sp: Span, | |
970d7e83 | 897 | parse_method: &str, |
1a4d82fc | 898 | arg_exprs: Vec<P<ast::Expr>> , |
92a42be0 | 899 | tts: &[TokenTree]) -> P<ast::Expr> { |
1a4d82fc | 900 | let (cx_expr, tts_expr) = expand_tts(cx, sp, tts); |
223e47cc | 901 | |
85aaf69f | 902 | let cfg_call = || cx.expr_method_call( |
970d7e83 | 903 | sp, cx.expr_ident(sp, id_ext("ext_cx")), |
1a4d82fc | 904 | id_ext("cfg"), Vec::new()); |
223e47cc | 905 | |
85aaf69f | 906 | let parse_sess_call = || cx.expr_method_call( |
970d7e83 | 907 | sp, cx.expr_ident(sp, id_ext("ext_cx")), |
1a4d82fc | 908 | id_ext("parse_sess"), Vec::new()); |
223e47cc LB |
909 | |
910 | let new_parser_call = | |
1a4d82fc JJ |
911 | cx.expr_call(sp, |
912 | cx.expr_ident(sp, id_ext("new_parser_from_tts")), | |
913 | vec!(parse_sess_call(), cfg_call(), tts_expr)); | |
914 | ||
92a42be0 SL |
915 | let path = vec![id_ext("syntax"), id_ext("ext"), id_ext("quote"), id_ext(parse_method)]; |
916 | let mut args = vec![cx.expr_mut_addr_of(sp, new_parser_call)]; | |
917 | args.extend(arg_exprs); | |
918 | let expr = cx.expr_call_global(sp, path, args); | |
1a4d82fc | 919 | |
c34b1796 AL |
920 | if parse_method == "parse_attribute" { |
921 | expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"], | |
922 | &["syntax", "parse", "attr"]]) | |
923 | } else { | |
924 | expand_wrapper(cx, sp, cx_expr, expr, &[&["syntax", "ext", "quote", "rt"]]) | |
925 | } | |
223e47cc | 926 | } |