]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ext/quote.rs
Imported Upstream version 1.7.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
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
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
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.
336pub fn parse_expr_panic(parser: &mut Parser) -> P<Expr> {
337 panictry!(parser.parse_expr())
338}
339
340pub fn parse_item_panic(parser: &mut Parser) -> Option<P<Item>> {
341 panictry!(parser.parse_item())
342}
343
344pub fn parse_pat_panic(parser: &mut Parser) -> P<Pat> {
345 panictry!(parser.parse_pat())
346}
347
348pub fn parse_arm_panic(parser: &mut Parser) -> Arm {
349 panictry!(parser.parse_arm())
350}
351
352pub fn parse_ty_panic(parser: &mut Parser) -> P<Ty> {
353 panictry!(parser.parse_ty())
354}
355
356pub fn parse_stmt_panic(parser: &mut Parser) -> Option<P<Stmt>> {
357 panictry!(parser.parse_stmt())
358}
359
360pub fn parse_attribute_panic(parser: &mut Parser, permit_inner: bool) -> ast::Attribute {
361 panictry!(parser.parse_attribute(permit_inner))
362}
363
364pub fn parse_arg_panic(parser: &mut Parser) -> Arg {
365 panictry!(parser.parse_arg())
366}
367
368pub fn parse_block_panic(parser: &mut Parser) -> P<Block> {
369 panictry!(parser.parse_block())
370}
371
372pub fn parse_meta_item_panic(parser: &mut Parser) -> P<ast::MetaItem> {
373 panictry!(parser.parse_meta_item())
374}
375
376pub fn parse_path_panic(parser: &mut Parser, mode: PathParsingMode) -> ast::Path {
377 panictry!(parser.parse_path(mode))
378}
379
1a4d82fc
JJ
380pub 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
389pub 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
397pub 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
405pub 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
413pub 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
421pub 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
429pub 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 437pub 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
447pub 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
455pub 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
463pub 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
471pub 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
480pub 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 496fn ids_ext(strs: Vec<String> ) -> Vec<ast::Ident> {
c34b1796 497 strs.iter().map(|str| str_to_ident(&(*str))).collect()
223e47cc
LB
498}
499
1a4d82fc 500fn 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 505fn 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
514fn 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
522fn 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
527fn 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
532fn 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
537fn 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 542fn 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
558fn 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 568fn 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 700fn 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
792fn 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
814fn 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 855fn 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 863fn 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
877fn 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
895fn 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}