]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ext/quote.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / libsyntax / ext / quote.rs
CommitLineData
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 11use ast::{self, Arg, Arm, Block, Expr, Item, Pat, Stmt, TokenTree, Ty};
1a4d82fc 12use codemap::Span;
970d7e83 13use ext::base::ExtCtxt;
223e47cc 14use ext::base;
970d7e83 15use ext::build::AstBuilder;
92a42be0 16use parse::parser::{Parser, PathParsingMode};
223e47cc
LB
17use parse::token::*;
18use parse::token;
1a4d82fc 19use 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
28pub 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.
364pub fn parse_expr_panic(parser: &mut Parser) -> P<Expr> {
365 panictry!(parser.parse_expr())
366}
367
368pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> {
369 panictry!(parser.parse_item())
370}
371
372pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> {
373 panictry!(parser.parse_pat())
374}
375
376pub fn parse_arm_panic(parser: &mut Parser) -> Arm {
377 panictry!(parser.parse_arm())
378}
379
380pub fn parse_ty_panic(parser: &mut Parser) -> P<Ty> {
381 panictry!(parser.parse_ty())
382}
383
7453a54e 384pub fn parse_stmt_panic(parser: &mut Parser) -> Option<Stmt> {
92a42be0
SL
385 panictry!(parser.parse_stmt())
386}
387
388pub fn parse_attribute_panic(parser: &mut Parser, permit_inner: bool) -> ast::Attribute {
389 panictry!(parser.parse_attribute(permit_inner))
390}
391
392pub fn parse_arg_panic(parser: &mut Parser) -> Arg {
393 panictry!(parser.parse_arg())
394}
395
396pub fn parse_block_panic(parser: &mut Parser) -> P<Block> {
397 panictry!(parser.parse_block())
398}
399
400pub fn parse_meta_item_panic(parser: &mut Parser) -> P<ast::MetaItem> {
401 panictry!(parser.parse_meta_item())
402}
403
404pub fn parse_path_panic(parser: &mut Parser, mode: PathParsingMode) -> ast::Path {
405 panictry!(parser.parse_path(mode))
406}
407
1a4d82fc
JJ
408pub 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
417pub 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
425pub 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
433pub 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
441pub 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
449pub 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
457pub 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 465pub 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
475pub 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
483pub 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
491pub 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
499pub 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
508pub 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 524fn ids_ext(strs: Vec<String> ) -> Vec<ast::Ident> {
c34b1796 525 strs.iter().map(|str| str_to_ident(&(*str))).collect()
223e47cc
LB
526}
527
1a4d82fc 528fn 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 533fn 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
542fn 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
550fn 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
555fn 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
560fn 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 565fn 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
581fn 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 591fn 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 723fn 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
822fn 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 844fn 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 885fn 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 893fn 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
907fn 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
925fn 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}