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