From f66a3f7bba378d4a308e02a860a11ab5f9f8e4ad Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Fri, 27 Feb 2015 11:14:42 -0800 Subject: [PATCH] Replace MacExpr / MacPat / MacItems with MacEager MacEager is a MacResult implementation for the common case where you've already built each form of AST that you might return. Fixes #17637. Based on #18814. This is a [breaking-change] for syntax extensions: * MacExpr::new becomes MacEager::expr. * MacPat::new becomes MacEager::pat. * MacItems::new becomes MacEager::items. It takes a SmallVector directly, not an iterator. --- src/doc/trpl/plugins.md | 8 +- src/libsyntax/diagnostics/plugin.rs | 11 +- src/libsyntax/ext/asm.rs | 2 +- src/libsyntax/ext/base.rs | 116 +++++++++++------- src/libsyntax/ext/cfg.rs | 2 +- src/libsyntax/ext/concat.rs | 2 +- src/libsyntax/ext/concat_idents.rs | 2 +- src/libsyntax/ext/env.rs | 4 +- src/libsyntax/ext/format.rs | 2 +- src/libsyntax/ext/quote.rs | 16 +-- src/libsyntax/ext/source_util.rs | 14 +-- .../issue_16723_multiple_items_syntax_ext.rs | 7 +- src/test/auxiliary/macro_crate_test.rs | 6 +- src/test/auxiliary/plugin_args.rs | 4 +- src/test/auxiliary/roman_numerals.rs | 4 +- .../syntax_extension_with_dll_deps_2.rs | 2 +- 16 files changed, 113 insertions(+), 89 deletions(-) diff --git a/src/doc/trpl/plugins.md b/src/doc/trpl/plugins.md index f609a0a918a..a093b97eefb 100644 --- a/src/doc/trpl/plugins.md +++ b/src/doc/trpl/plugins.md @@ -71,8 +71,8 @@ extern crate rustc; use syntax::codemap::Span; use syntax::parse::token; use syntax::ast::{TokenTree, TtToken}; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacExpr}; -use syntax::ext::build::AstBuilder; // trait for expr_uint +use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; +use syntax::ext::build::AstBuilder; // trait for expr_usize use rustc::plugin::Registry; fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) @@ -107,7 +107,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) } } - MacExpr::new(cx.expr_uint(sp, total)) + MacEager::expr(cx.expr_usize(sp, total)) } #[plugin_registrar] @@ -183,7 +183,7 @@ with [`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions). The example above produced an integer literal using -[`AstBuilder::expr_uint`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_uint). +[`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize). As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of [quasiquote macros](../syntax/ext/quote/index.html). They are undocumented and very rough around the edges. However, the implementation may be a good diff --git a/src/libsyntax/diagnostics/plugin.rs b/src/libsyntax/diagnostics/plugin.rs index b3afc3fc4dd..59fe3658437 100644 --- a/src/libsyntax/diagnostics/plugin.rs +++ b/src/libsyntax/diagnostics/plugin.rs @@ -14,10 +14,11 @@ use ast; use ast::{Ident, Name, TokenTree}; use codemap::Span; -use ext::base::{ExtCtxt, MacExpr, MacResult, MacItems}; +use ext::base::{ExtCtxt, MacEager, MacResult}; use ext::build::AstBuilder; use parse::token; use ptr::P; +use util::small_vector::SmallVector; thread_local! { static REGISTERED_DIAGNOSTICS: RefCell>> = { @@ -73,7 +74,7 @@ pub fn expand_diagnostic_used<'cx>(ecx: &'cx mut ExtCtxt, )); } }); - MacExpr::new(quote_expr!(ecx, ())) + MacEager::expr(quote_expr!(ecx, ())) } pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, @@ -101,7 +102,7 @@ pub fn expand_register_diagnostic<'cx>(ecx: &'cx mut ExtCtxt, let sym = Ident::new(token::gensym(&( "__register_diagnostic_".to_string() + &token::get_ident(*code) ))); - MacItems::new(vec![quote_item!(ecx, mod $sym {}).unwrap()].into_iter()) + MacEager::items(SmallVector::many(vec![quote_item!(ecx, mod $sym {}).unwrap()])) } pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, @@ -126,7 +127,7 @@ pub fn expand_build_diagnostic_array<'cx>(ecx: &'cx mut ExtCtxt, (descriptions.len(), ecx.expr_vec(span, descriptions)) }); - MacItems::new(vec![quote_item!(ecx, + MacEager::items(SmallVector::many(vec![quote_item!(ecx, pub static $name: [(&'static str, &'static str); $count] = $expr; - ).unwrap()].into_iter()) + ).unwrap()])) } diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index 009bfef8623..ae48084947e 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -217,7 +217,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) }, }); - MacExpr::new(P(ast::Expr { + MacEager::expr(P(ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprInlineAsm(ast::InlineAsm { asm: token::intern_and_get_ident(&asm), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2ef90f04f75..e5d1fe2388c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -28,6 +28,7 @@ use std::collections::HashMap; use std::rc::Rc; +use std::default::Default; pub trait ItemDecorator { fn expand(&self, @@ -226,9 +227,17 @@ fn expand<'cx>(&self, } } +// Use a macro because forwarding to a simple function has type system issues +macro_rules! make_stmt_default { + ($me:expr) => { + $me.make_expr().map(|e| { + P(codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID))) + }) + } +} + /// The result of a macro expansion. The return values of the various -/// methods are spliced into the AST at the callsite of the macro (or -/// just into the compiler's internal macro table, for `make_def`). +/// methods are spliced into the AST at the callsite of the macro. pub trait MacResult { /// Create an expression. fn make_expr(self: Box) -> Option> { @@ -254,63 +263,76 @@ fn make_pat(self: Box) -> Option> { /// By default this attempts to create an expression statement, /// returning None if that fails. fn make_stmt(self: Box) -> Option> { - self.make_expr() - .map(|e| P(codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID)))) + make_stmt_default!(self) } } -/// A convenience type for macros that return a single expression. -pub struct MacExpr { - e: P -} -impl MacExpr { - pub fn new(e: P) -> Box { - box MacExpr { e: e } as Box - } -} -impl MacResult for MacExpr { - fn make_expr(self: Box) -> Option> { - Some(self.e) - } - fn make_pat(self: Box) -> Option> { - match self.e.node { - ast::ExprLit(_) => Some(P(ast::Pat { - id: ast::DUMMY_NODE_ID, - span: self.e.span, - node: ast::PatLit(self.e) - })), - _ => None +macro_rules! make_MacEager { + ( $( $fld:ident: $t:ty, )* ) => { + /// `MacResult` implementation for the common case where you've already + /// built each form of AST that you might return. + #[derive(Default)] + pub struct MacEager { + $( + pub $fld: Option<$t>, + )* + } + + impl MacEager { + $( + pub fn $fld(v: $t) -> Box { + box MacEager { + $fld: Some(v), + ..Default::default() + } as Box + } + )* } } } -/// A convenience type for macros that return a single pattern. -pub struct MacPat { - p: P + +make_MacEager! { + expr: P, + pat: P, + items: SmallVector>, + methods: SmallVector>, + stmt: P, } -impl MacPat { - pub fn new(p: P) -> Box { - box MacPat { p: p } as Box + +impl MacResult for MacEager { + fn make_expr(self: Box) -> Option> { + self.expr } -} -impl MacResult for MacPat { - fn make_pat(self: Box) -> Option> { - Some(self.p) + + fn make_items(self: Box) -> Option>> { + self.items } -} -/// A type for macros that return multiple items. -pub struct MacItems { - items: SmallVector> -} -impl MacItems { - pub fn new>>(it: I) -> Box { - box MacItems { items: it.collect() } as Box + fn make_methods(self: Box) -> Option>> { + self.methods } -} -impl MacResult for MacItems { - fn make_items(self: Box) -> Option>> { - Some(self.items) + fn make_stmt(self: Box) -> Option> { + match self.stmt { + None => make_stmt_default!(self), + s => s, + } + } + + fn make_pat(self: Box) -> Option> { + if let Some(p) = self.pat { + return Some(p); + } + if let Some(e) = self.expr { + if let ast::ExprLit(_) = e.node { + return Some(P(ast::Pat { + id: ast::DUMMY_NODE_ID, + span: e.span, + node: ast::PatLit(e), + })); + } + } + None } } diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index 7216602071b..6a2209bf0ae 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -35,5 +35,5 @@ pub fn expand_cfg<'cx>(cx: &mut ExtCtxt, } let matches_cfg = attr::cfg_matches(&cx.parse_sess.span_diagnostic, &cx.cfg, &*cfg); - MacExpr::new(cx.expr_bool(sp, matches_cfg)) + MacEager::expr(cx.expr_bool(sp, matches_cfg)) } diff --git a/src/libsyntax/ext/concat.rs b/src/libsyntax/ext/concat.rs index 84f786e9780..754c73a9d78 100644 --- a/src/libsyntax/ext/concat.rs +++ b/src/libsyntax/ext/concat.rs @@ -60,7 +60,7 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, } } } - base::MacExpr::new(cx.expr_str( + base::MacEager::expr(cx.expr_str( sp, token::intern_and_get_ident(&accumulator[..]))) } diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 2303eb9645b..e350ce61017 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -67,5 +67,5 @@ pub fn expand_syntax_ext<'cx>(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree] ), span: sp, }); - MacExpr::new(e) + MacEager::expr(e) } diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index 93f8ee5042b..f72303985e7 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -59,7 +59,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT &s[..])))) } }; - MacExpr::new(e) + MacEager::expr(e) } pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) @@ -108,5 +108,5 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } Ok(s) => cx.expr_str(sp, token::intern_and_get_ident(&s)) }; - MacExpr::new(e) + MacEager::expr(e) } diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index 91262556abd..0eaca9af4f0 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -633,7 +633,7 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt, sp: Span, match parse_args(ecx, sp, tts) { Some((efmt, args, order, names)) => { - MacExpr::new(expand_preparsed_format_args(ecx, sp, efmt, + MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, order, names)) } None => DummyResult::expr(sp) diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 554529b5cb2..544fb15dcde 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -402,7 +402,7 @@ pub fn expand_quote_tokens<'cx>(cx: &'cx mut ExtCtxt, -> Box { let (cx_expr, expr) = expand_tts(cx, sp, tts); let expanded = expand_wrapper(cx, sp, cx_expr, expr); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt, @@ -410,7 +410,7 @@ pub fn expand_quote_expr<'cx>(cx: &'cx mut ExtCtxt, tts: &[ast::TokenTree]) -> Box { let expanded = expand_parse_call(cx, sp, "parse_expr", Vec::new(), tts); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt, @@ -419,7 +419,7 @@ pub fn expand_quote_item<'cx>(cx: &mut ExtCtxt, -> Box { let expanded = expand_parse_call(cx, sp, "parse_item_with_outer_attributes", vec!(), tts); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt, @@ -427,7 +427,7 @@ pub fn expand_quote_pat<'cx>(cx: &'cx mut ExtCtxt, tts: &[ast::TokenTree]) -> Box { let expanded = expand_parse_call(cx, sp, "parse_pat", vec!(), tts); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } pub fn expand_quote_arm(cx: &mut ExtCtxt, @@ -435,7 +435,7 @@ pub fn expand_quote_arm(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Box { let expanded = expand_parse_call(cx, sp, "parse_arm", vec!(), tts); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } pub fn expand_quote_ty(cx: &mut ExtCtxt, @@ -443,7 +443,7 @@ pub fn expand_quote_ty(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Box { let expanded = expand_parse_call(cx, sp, "parse_ty", vec!(), tts); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } pub fn expand_quote_method(cx: &mut ExtCtxt, @@ -452,7 +452,7 @@ pub fn expand_quote_method(cx: &mut ExtCtxt, -> Box { let expanded = expand_parse_call(cx, sp, "parse_method_with_outer_attributes", vec!(), tts); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } pub fn expand_quote_stmt(cx: &mut ExtCtxt, @@ -462,7 +462,7 @@ pub fn expand_quote_stmt(cx: &mut ExtCtxt, let e_attrs = cx.expr_vec_ng(sp); let expanded = expand_parse_call(cx, sp, "parse_stmt", vec!(e_attrs), tts); - base::MacExpr::new(expanded) + base::MacEager::expr(expanded) } fn ids_ext(strs: Vec ) -> Vec { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index af43f5a1501..ba3743cdb33 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -35,7 +35,7 @@ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let topmost = cx.original_span_in_file(); let loc = cx.codemap().lookup_char_pos(topmost.lo); - base::MacExpr::new(cx.expr_u32(topmost, loc.line as u32)) + base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32)) } /* column!(): expands to the current column number */ @@ -46,7 +46,7 @@ pub fn expand_column(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let topmost = cx.original_span_in_file(); let loc = cx.codemap().lookup_char_pos(topmost.lo); - base::MacExpr::new(cx.expr_u32(topmost, loc.col.to_usize() as u32)) + base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32)) } /// file!(): expands to the current filename */ @@ -59,13 +59,13 @@ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let topmost = cx.original_span_in_file(); let loc = cx.codemap().lookup_char_pos(topmost.lo); let filename = token::intern_and_get_ident(&loc.file.name); - base::MacExpr::new(cx.expr_str(topmost, filename)) + base::MacEager::expr(cx.expr_str(topmost, filename)) } pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> Box { let s = pprust::tts_to_string(tts); - base::MacExpr::new(cx.expr_str(sp, + base::MacEager::expr(cx.expr_str(sp, token::intern_and_get_ident(&s[..]))) } @@ -77,7 +77,7 @@ pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) .map(|x| token::get_ident(*x).to_string()) .collect::>() .connect("::"); - base::MacExpr::new(cx.expr_str( + base::MacEager::expr(cx.expr_str( sp, token::intern_and_get_ident(&string[..]))) } @@ -155,7 +155,7 @@ pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let interned = token::intern_and_get_ident(&src[..]); cx.codemap().new_filemap(filename, src); - base::MacExpr::new(cx.expr_str(sp, interned)) + base::MacEager::expr(cx.expr_str(sp, interned)) } Err(_) => { cx.span_err(sp, @@ -181,7 +181,7 @@ pub fn expand_include_bytes(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } Ok(bytes) => { let bytes = bytes.iter().cloned().collect(); - base::MacExpr::new(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) + base::MacEager::expr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) } } } diff --git a/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs b/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs index bb57b4a98bb..f5a9063e1de 100644 --- a/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs +++ b/src/test/auxiliary/issue_16723_multiple_items_syntax_ext.rs @@ -19,7 +19,8 @@ use syntax::ast; use syntax::codemap; -use syntax::ext::base::{ExtCtxt, MacResult, MacItems}; +use syntax::ext::base::{ExtCtxt, MacResult, MacEager}; +use syntax::util::small_vector::SmallVector; use rustc::plugin::Registry; #[plugin_registrar] @@ -28,8 +29,8 @@ pub fn plugin_registrar(reg: &mut Registry) { } fn expand(cx: &mut ExtCtxt, _: codemap::Span, _: &[ast::TokenTree]) -> Box { - MacItems::new(vec![ + MacEager::items(SmallVector::many(vec![ quote_item!(cx, struct Struct1;).unwrap(), quote_item!(cx, struct Struct2;).unwrap() - ].into_iter()) + ])) } diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs index d545a42ae19..01bfbd3dbce 100644 --- a/src/test/auxiliary/macro_crate_test.rs +++ b/src/test/auxiliary/macro_crate_test.rs @@ -47,7 +47,7 @@ fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) if !tts.is_empty() { cx.span_fatal(sp, "make_a_1 takes no arguments"); } - MacExpr::new(quote_expr!(cx, 1)) + MacEager::expr(quote_expr!(cx, 1)) } // See Issue #15750 @@ -57,7 +57,7 @@ fn expand_identity(cx: &mut ExtCtxt, _span: Span, tts: &[TokenTree]) let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.to_vec()); let expr = parser.parse_expr(); - MacExpr::new(quote_expr!(&mut *cx, $expr)) + MacEager::expr(quote_expr!(&mut *cx, $expr)) } fn expand_into_foo(cx: &mut ExtCtxt, sp: Span, attr: &MetaItem, it: P) @@ -114,7 +114,7 @@ fn expand_forged_ident(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box(&self, let args = self.args.iter().map(|i| pprust::meta_item_to_string(&*i)) .collect::>().connect(", "); let interned = token::intern_and_get_ident(&args[..]); - MacExpr::new(ecx.expr_str(sp, interned)) + MacEager::expr(ecx.expr_str(sp, interned)) } } diff --git a/src/test/auxiliary/roman_numerals.rs b/src/test/auxiliary/roman_numerals.rs index e05aa16ba5f..e5c42111105 100644 --- a/src/test/auxiliary/roman_numerals.rs +++ b/src/test/auxiliary/roman_numerals.rs @@ -19,7 +19,7 @@ use syntax::codemap::Span; use syntax::parse::token; use syntax::ast::{TokenTree, TtToken}; -use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacExpr}; +use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager}; use syntax::ext::build::AstBuilder; // trait for expr_usize use rustc::plugin::Registry; @@ -61,7 +61,7 @@ fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree]) } } - MacExpr::new(cx.expr_usize(sp, total)) + MacEager::expr(cx.expr_usize(sp, total)) } #[plugin_registrar] diff --git a/src/test/auxiliary/syntax_extension_with_dll_deps_2.rs b/src/test/auxiliary/syntax_extension_with_dll_deps_2.rs index 7a24dd76f32..07f3b863af8 100644 --- a/src/test/auxiliary/syntax_extension_with_dll_deps_2.rs +++ b/src/test/auxiliary/syntax_extension_with_dll_deps_2.rs @@ -30,5 +30,5 @@ pub fn plugin_registrar(reg: &mut Registry) { fn expand_foo(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> Box { let answer = other::the_answer(); - MacExpr::new(quote_expr!(cx, $answer)) + MacEager::expr(quote_expr!(cx, $answer)) } -- GitLab