From: Kyle Mayes Date: Wed, 11 Nov 2015 20:19:01 +0000 (-0500) Subject: libsyntax: Add more quasiquoting macros X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=8c88308c68691b795815a776d41b3aa11717c146;p=rust.git libsyntax: Add more quasiquoting macros --- diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3f925c9d7ba..3e854cd72ba 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -512,6 +512,18 @@ fn builtin_normal_expander(f: MacroExpanderFn) -> SyntaxExtension { syntax_expanders.insert(intern("quote_attr"), builtin_normal_expander( ext::quote::expand_quote_attr)); + syntax_expanders.insert(intern("quote_arg"), + builtin_normal_expander( + ext::quote::expand_quote_arg)); + syntax_expanders.insert(intern("quote_block"), + builtin_normal_expander( + ext::quote::expand_quote_block)); + syntax_expanders.insert(intern("quote_meta_item"), + builtin_normal_expander( + ext::quote::expand_quote_meta_item)); + syntax_expanders.insert(intern("quote_path"), + builtin_normal_expander( + ext::quote::expand_quote_path)); } syntax_expanders.insert(intern("line"), diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 5e1d2339164..dc4a061ce78 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -158,6 +158,18 @@ fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { } } + impl ToTokens for ast::Arg { + fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtArg(self.clone())))] + } + } + + impl ToTokens for P { + fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { + vec![TokenTree::Token(DUMMY_SP, token::Interpolated(token::NtBlock(self.clone())))] + } + } + macro_rules! impl_to_tokens_slice { ($t: ty, $sep: expr) => { impl ToTokens for [$t] { @@ -177,6 +189,7 @@ fn to_tokens(&self, cx: &ExtCtxt) -> Vec { impl_to_tokens_slice! { ast::Ty, [TokenTree::Token(DUMMY_SP, token::Comma)] } impl_to_tokens_slice! { P, [] } + impl_to_tokens_slice! { ast::Arg, [TokenTree::Token(DUMMY_SP, token::Comma)] } impl ToTokens for P { fn to_tokens(&self, _cx: &ExtCtxt) -> Vec { @@ -383,6 +396,39 @@ pub fn expand_quote_attr(cx: &mut ExtCtxt, base::MacEager::expr(expanded) } +pub fn expand_quote_arg(cx: &mut ExtCtxt, + sp: Span, + tts: &[TokenTree]) + -> Box { + let expanded = expand_parse_call(cx, sp, "parse_arg_panic", vec!(), tts); + base::MacEager::expr(expanded) +} + +pub fn expand_quote_block(cx: &mut ExtCtxt, + sp: Span, + tts: &[TokenTree]) + -> Box { + let expanded = expand_parse_call(cx, sp, "parse_block_panic", vec!(), tts); + base::MacEager::expr(expanded) +} + +pub fn expand_quote_meta_item(cx: &mut ExtCtxt, + sp: Span, + tts: &[TokenTree]) + -> Box { + let expanded = expand_parse_call(cx, sp, "parse_meta_item_panic", vec!(), tts); + base::MacEager::expr(expanded) +} + +pub fn expand_quote_path(cx: &mut ExtCtxt, + sp: Span, + tts: &[TokenTree]) + -> Box { + let mode = mk_parser_path(cx, sp, "LifetimeAndTypesWithoutColons"); + let expanded = expand_parse_call(cx, sp, "parse_path_panic", vec!(mode), tts); + base::MacEager::expr(expanded) +} + pub fn expand_quote_matcher(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) @@ -440,6 +486,11 @@ fn mk_token_path(cx: &ExtCtxt, sp: Span, name: &str) -> P { cx.expr_path(cx.path_global(sp, idents)) } +fn mk_parser_path(cx: &ExtCtxt, sp: Span, name: &str) -> P { + let idents = vec!(id_ext("syntax"), id_ext("parse"), id_ext("parser"), id_ext(name)); + cx.expr_path(cx.path_global(sp, idents)) +} + fn mk_binop(cx: &ExtCtxt, sp: Span, bop: token::BinOpToken) -> P { let name = match bop { token::Plus => "Plus", diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 284bf46cc3f..66ee5aa12ca 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -684,6 +684,7 @@ pub fn noop_fold_interpolated(nt: token::Nonterminal, fld: &mut T) token::NtGenerics(generics) => token::NtGenerics(fld.fold_generics(generics)), token::NtWhereClause(where_clause) => token::NtWhereClause(fld.fold_where_clause(where_clause)), + token::NtArg(arg) => token::NtArg(fld.fold_arg(arg)), } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fde1058a785..f5e4114464f 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -393,6 +393,22 @@ pub fn parse_attribute_panic(&mut self, permit_inner: bool) -> ast::Attribute { panictry!(self.parse_attribute(permit_inner)) } + pub fn parse_arg_panic(&mut self) -> Arg { + panictry!(self.parse_arg()) + } + + pub fn parse_block_panic(&mut self) -> P { + panictry!(self.parse_block()) + } + + pub fn parse_meta_item_panic(&mut self) -> P { + panictry!(self.parse_meta_item()) + } + + pub fn parse_path_panic(&mut self, mode: PathParsingMode) -> ast::Path { + panictry!(self.parse_path(mode)) + } + /// Convert a token to a string using self's reader pub fn token_to_string(token: &token::Token) -> String { pprust::token_to_string(token) @@ -1455,6 +1471,8 @@ pub fn is_named_argument(&mut self) -> bool { /// This version of parse arg doesn't necessarily require /// identifier names. pub fn parse_arg_general(&mut self, require_name: bool) -> PResult { + maybe_whole!(no_clone self, NtArg); + let pat = if require_name || self.is_named_argument() { debug!("parse_arg_general parse_pat (require_name:{})", require_name); diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index ba24dc3c0a7..5e4449af604 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -381,12 +381,13 @@ pub enum Nonterminal { NtMeta(P), NtPath(Box), NtTT(P), // needs P'ed to break a circularity - // These is not exposed to macros, but is used by quasiquote. + // These are not exposed to macros, but are used by quasiquote. NtArm(ast::Arm), NtImplItem(P), NtTraitItem(P), NtGenerics(ast::Generics), NtWhereClause(ast::WhereClause), + NtArg(ast::Arg), } impl fmt::Debug for Nonterminal { @@ -407,6 +408,7 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { NtTraitItem(..) => f.pad("NtTraitItem(..)"), NtGenerics(..) => f.pad("NtGenerics(..)"), NtWhereClause(..) => f.pad("NtWhereClause(..)"), + NtArg(..) => f.pad("NtArg(..)"), } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index fad0b7869f0..5b8f5c0aef6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -305,6 +305,7 @@ pub fn token_to_string(tok: &Token) -> String { token::NtTraitItem(ref e) => trait_item_to_string(&**e), token::NtGenerics(ref e) => generics_to_string(&*e), token::NtWhereClause(ref e) => where_clause_to_string(&*e), + token::NtArg(ref e) => arg_to_string(&*e), } } } diff --git a/src/test/compile-fail-fulldeps/gated-quote.rs b/src/test/compile-fail-fulldeps/gated-quote.rs index 6a5cd88a591..cd801fbcd88 100644 --- a/src/test/compile-fail-fulldeps/gated-quote.rs +++ b/src/test/compile-fail-fulldeps/gated-quote.rs @@ -37,14 +37,18 @@ fn name_of(&self, st: &str) -> ast::Name { loop { } } pub fn main() { let ecx = &ParseSess; - let x = quote_tokens!(ecx, 3); //~ ERROR macro undefined: 'quote_tokens!' - let x = quote_expr!(ecx, 3); //~ ERROR macro undefined: 'quote_expr!' - let x = quote_ty!(ecx, 3); //~ ERROR macro undefined: 'quote_ty!' - let x = quote_method!(ecx, 3); //~ ERROR macro undefined: 'quote_method!' - let x = quote_item!(ecx, 3); //~ ERROR macro undefined: 'quote_item!' - let x = quote_pat!(ecx, 3); //~ ERROR macro undefined: 'quote_pat!' - let x = quote_arm!(ecx, 3); //~ ERROR macro undefined: 'quote_arm!' - let x = quote_stmt!(ecx, 3); //~ ERROR macro undefined: 'quote_stmt!' - let x = quote_matcher!(ecx, 3); //~ ERROR macro undefined: 'quote_matcher!' - let x = quote_attr!(ecx, 3); //~ ERROR macro undefined: 'quote_attr!' + let x = quote_tokens!(ecx, 3); //~ ERROR macro undefined: 'quote_tokens!' + let x = quote_expr!(ecx, 3); //~ ERROR macro undefined: 'quote_expr!' + let x = quote_ty!(ecx, 3); //~ ERROR macro undefined: 'quote_ty!' + let x = quote_method!(ecx, 3); //~ ERROR macro undefined: 'quote_method!' + let x = quote_item!(ecx, 3); //~ ERROR macro undefined: 'quote_item!' + let x = quote_pat!(ecx, 3); //~ ERROR macro undefined: 'quote_pat!' + let x = quote_arm!(ecx, 3); //~ ERROR macro undefined: 'quote_arm!' + let x = quote_stmt!(ecx, 3); //~ ERROR macro undefined: 'quote_stmt!' + let x = quote_matcher!(ecx, 3); //~ ERROR macro undefined: 'quote_matcher!' + let x = quote_attr!(ecx, 3); //~ ERROR macro undefined: 'quote_attr!' + let x = quote_arg!(ecx, 3); //~ ERROR macro undefined: 'quote_arg!' + let x = quote_block!(ecx, 3); //~ ERROR macro undefined: 'quote_block!' + let x = quote_meta_item!(ecx, 3); //~ ERROR macro undefined: 'quote_meta_item!' + let x = quote_path!(ecx, 3); //~ ERROR macro undefined: 'quote_path!' } diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index ba713bb98f8..edaa88452c4 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -63,4 +63,41 @@ macro_rules! check { let attr = quote_attr!(cx, #![cfg(foo = "bar")]); check!(attribute_to_string, attr, quote_attr!(cx, $attr); r#"#![cfg(foo = "bar")]"#); + + // quote_arg! + + let arg = quote_arg!(cx, foo: i32); + check!(arg_to_string, arg, quote_arg!(cx, $arg); "foo: i32"); + + let function = quote_item!(cx, fn f($arg) { }).unwrap(); + check!(item_to_string, function; "fn f(foo: i32) { }"); + + let args = vec![arg, quote_arg!(cx, bar: u32)]; + let args = &args[..]; + let function = quote_item!(cx, fn f($args) { }).unwrap(); + check!(item_to_string, function; "fn f(foo: i32, bar: u32) { }"); + + // quote_block! + + let block = quote_block!(cx, { $stmt let y = 40u32; }); + check!(block_to_string, block, *quote_block!(cx, $block); "{ let x = 20u16; let y = 40u32; }"); + + let function = quote_item!(cx, fn f() $block).unwrap(); + check!(item_to_string, function; "fn f() { let x = 20u16; let y = 40u32; }"); + + // quote_path! + + let path = quote_path!(cx, ::syntax::ptr::P); + check!(path_to_string, path, quote_path!(cx, $path); "::syntax::ptr::P"); + + let ty = quote_ty!(cx, $path); + check!(ty_to_string, ty; "::syntax::ptr::P"); + + // quote_meta_item! + + let meta = quote_meta_item!(cx, cfg(foo = "bar")); + check!(meta_item_to_string, meta, *quote_meta_item!(cx, $meta); r#"cfg(foo = "bar")"#); + + let attr = quote_attr!(cx, #![$meta]); + check!(attribute_to_string, attr; r#"#![cfg(foo = "bar")]"#); }