From 99dd5911a1026da0a374b697e4a0407a631eb388 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 15 Apr 2014 22:00:14 +1000 Subject: [PATCH] syntax: unify all MacResult's into a single trait. There's now one unified way to return things from a macro, instead of being able to choose the `AnyMacro` trait or the `MRItem`/`MRExpr` variants of the `MacResult` enum. This does simplify the logic handling the expansions, but the biggest value of this is it makes macros in (for example) type position easier to implement, as there's this single thing to modify. By my measurements (using `-Z time-passes` on libstd and librustc etc.), this appears to have little-to-no impact on expansion speed. There are presumably larger costs than the small number of extra allocations and virtual calls this adds (notably, all `macro_rules!`-defined macros have not changed in behaviour, since they had to use the `AnyMacro` trait anyway). --- src/libfourcc/lib.rs | 10 +- src/libhexfloat/lib.rs | 12 +- src/libsyntax/ext/asm.rs | 6 +- src/libsyntax/ext/base.rs | 146 ++++++++++++++++++------- src/libsyntax/ext/bytes.rs | 6 +- src/libsyntax/ext/cfg.rs | 4 +- src/libsyntax/ext/concat.rs | 6 +- src/libsyntax/ext/concat_idents.rs | 8 +- src/libsyntax/ext/env.rs | 20 ++-- src/libsyntax/ext/expand.rs | 64 +++++------ src/libsyntax/ext/fmt.rs | 4 +- src/libsyntax/ext/format.rs | 10 +- src/libsyntax/ext/log_syntax.rs | 4 +- src/libsyntax/ext/quote.rs | 24 ++-- src/libsyntax/ext/source_util.rs | 44 ++++---- src/libsyntax/ext/trace_macros.rs | 4 +- src/libsyntax/ext/tt/macro_rules.rs | 45 +++++--- src/test/auxiliary/macro_crate_test.rs | 4 +- 18 files changed, 246 insertions(+), 175 deletions(-) diff --git a/src/libfourcc/lib.rs b/src/libfourcc/lib.rs index 267b0592d76..50cdd6cedc2 100644 --- a/src/libfourcc/lib.rs +++ b/src/libfourcc/lib.rs @@ -57,7 +57,7 @@ use syntax::ast::Name; use syntax::attr::contains; use syntax::codemap::{Span, mk_sp}; use syntax::ext::base; -use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MRExpr}; +use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr}; use syntax::ext::build::AstBuilder; use syntax::parse; use syntax::parse::token; @@ -73,7 +73,7 @@ pub fn macro_registrar(register: |Name, SyntaxExtension|) { None)); } -pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { +pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult { let (expr, endian) = parse_tts(cx, tts); let little = match endian { @@ -101,12 +101,12 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> } _ => { cx.span_err(expr.span, "unsupported literal in fourcc!"); - return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32))); + return base::DummyResult::expr(sp) } }, _ => { cx.span_err(expr.span, "non-literal in fourcc!"); - return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32))); + return base::DummyResult::expr(sp) } }; @@ -126,7 +126,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> }; } let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32)); - MRExpr(e) + MacExpr::new(e) } struct Ident { diff --git a/src/libhexfloat/lib.rs b/src/libhexfloat/lib.rs index 9f2f417080f..e65b84091e5 100644 --- a/src/libhexfloat/lib.rs +++ b/src/libhexfloat/lib.rs @@ -53,7 +53,7 @@ use syntax::ast; use syntax::ast::Name; use syntax::codemap::{Span, mk_sp}; use syntax::ext::base; -use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MRExpr}; +use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr}; use syntax::ext::build::AstBuilder; use syntax::parse; use syntax::parse::token; @@ -97,7 +97,7 @@ fn hex_float_lit_err(s: &str) -> Option<(uint, ~str)> { } } -pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { +pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult { let (expr, ty_lit) = parse_tts(cx, tts); let ty = match ty_lit { @@ -121,12 +121,12 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> } _ => { cx.span_err(expr.span, "unsupported literal in hexfloat!"); - return base::MacResult::dummy_expr(sp); + return base::DummyResult::expr(sp); } }, _ => { cx.span_err(expr.span, "non-literal in hexfloat!"); - return base::MacResult::dummy_expr(sp); + return base::DummyResult::expr(sp); } }; @@ -137,7 +137,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> let pos = expr.span.lo + syntax::codemap::Pos::from_uint(err_pos + 1); let span = syntax::codemap::mk_sp(pos,pos); cx.span_err(span, format!("invalid hex float literal in hexfloat!: {}", err_str)); - return base::MacResult::dummy_expr(sp); + return base::DummyResult::expr(sp); } _ => () } @@ -147,7 +147,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> None => ast::LitFloatUnsuffixed(s), Some (ty) => ast::LitFloat(s, ty) }; - MRExpr(cx.expr_lit(sp, lit)) + MacExpr::new(cx.expr_lit(sp, lit)) } struct Ident { diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index 9371f817ac8..efefe885acb 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -45,7 +45,7 @@ impl State { static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"]; pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { let mut p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.iter() @@ -72,7 +72,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) "inline assembly must be a string literal.") { Some((s, st)) => (s, st), // let compilation continue - None => return MacResult::dummy_expr(sp), + None => return DummyResult::expr(sp), }; asm = s; asm_str_style = Some(style); @@ -210,7 +210,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) inputs.push((token::intern_and_get_ident(i.to_str()), out)); } - MRExpr(@ast::Expr { + MacExpr::new(@ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprInlineAsm(ast::InlineAsm { asm: token::intern_and_get_ident(asm.get()), diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 3bf1ed95f38..90bde60621d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -50,19 +50,19 @@ pub trait MacroExpander { ecx: &mut ExtCtxt, span: Span, token_tree: &[ast::TokenTree]) - -> MacResult; + -> ~MacResult; } pub type MacroExpanderFn = fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree]) - -> MacResult; + -> ~MacResult; impl MacroExpander for BasicMacroExpander { fn expand(&self, ecx: &mut ExtCtxt, span: Span, token_tree: &[ast::TokenTree]) - -> MacResult { + -> ~MacResult { (self.expander)(ecx, span, token_tree) } } @@ -78,7 +78,7 @@ pub trait IdentMacroExpander { sp: Span, ident: ast::Ident, token_tree: Vec ) - -> MacResult; + -> ~MacResult; } impl IdentMacroExpander for BasicIdentMacroExpander { @@ -87,62 +87,130 @@ impl IdentMacroExpander for BasicIdentMacroExpander { sp: Span, ident: ast::Ident, token_tree: Vec ) - -> MacResult { + -> ~MacResult { (self.expander)(cx, sp, ident, token_tree) } } pub type IdentMacroExpanderFn = - fn(&mut ExtCtxt, Span, ast::Ident, Vec ) -> MacResult; + fn(&mut ExtCtxt, Span, ast::Ident, Vec ) -> ~MacResult; pub type MacroCrateRegistrationFun = fn(|ast::Name, SyntaxExtension|); -pub trait AnyMacro { - fn make_expr(&self) -> @ast::Expr; - fn make_items(&self) -> SmallVector<@ast::Item>; - fn make_stmt(&self) -> @ast::Stmt; +/// 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`). +pub trait MacResult { + /// Define a new macro. + fn make_def(&self) -> Option { + None + } + /// Create an expression. + fn make_expr(&self) -> Option<@ast::Expr> { + None + } + /// Create zero or more items. + fn make_items(&self) -> Option> { + None + } + + /// Create a statement. + /// + /// By default this attempts to create an expression statement, + /// returning None if that fails. + fn make_stmt(&self) -> Option<@ast::Stmt> { + self.make_expr() + .map(|e| @codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID))) + } } - -pub enum MacResult { - MRExpr(@ast::Expr), - MRItem(@ast::Item), - MRAny(~AnyMacro:), - MRDef(MacroDef), +/// A convenience type for macros that return a single expression. +pub struct MacExpr { + e: @ast::Expr } -impl MacResult { - /// Create an empty expression MacResult; useful for satisfying - /// type signatures after emitting a non-fatal error (which stop - /// compilation well before the validity (or otherwise)) of the - /// expression are checked. - pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr { +impl MacExpr { + pub fn new(e: @ast::Expr) -> ~MacResult { + ~MacExpr { e: e } as ~MacResult + } +} +impl MacResult for MacExpr { + fn make_expr(&self) -> Option<@ast::Expr> { + Some(self.e) + } +} +/// A convenience type for macros that return a single item. +pub struct MacItem { + i: @ast::Item +} +impl MacItem { + pub fn new(i: @ast::Item) -> ~MacResult { + ~MacItem { i: i } as ~MacResult + } +} +impl MacResult for MacItem { + fn make_items(&self) -> Option> { + Some(SmallVector::one(self.i)) + } + fn make_stmt(&self) -> Option<@ast::Stmt> { + Some(@codemap::respan( + self.i.span, + ast::StmtDecl( + @codemap::respan(self.i.span, ast::DeclItem(self.i)), + ast::DUMMY_NODE_ID))) + } +} + +/// Fill-in macro expansion result, to allow compilation to continue +/// after hitting errors. +pub struct DummyResult { + expr_only: bool, + span: Span +} + +impl DummyResult { + /// Create a default MacResult that can be anything. + /// + /// Use this as a return value after hitting any errors and + /// calling `span_err`. + pub fn any(sp: Span) -> ~MacResult { + ~DummyResult { expr_only: false, span: sp } as ~MacResult + } + + /// Create a default MacResult that can only be an expression. + /// + /// Use this for macros that must expand to an expression, so even + /// if an error is encountered internally, the user will recieve + /// an error that they also used it in the wrong place. + pub fn expr(sp: Span) -> ~MacResult { + ~DummyResult { expr_only: true, span: sp } as ~MacResult + } + + /// A plain dummy expression. + pub fn raw_expr(sp: Span) -> @ast::Expr { @ast::Expr { id: ast::DUMMY_NODE_ID, node: ast::ExprLit(@codemap::respan(sp, ast::LitNil)), span: sp, } } - pub fn dummy_expr(sp: codemap::Span) -> MacResult { - MRExpr(MacResult::raw_dummy_expr(sp)) - } - pub fn dummy_any(sp: codemap::Span) -> MacResult { - MRAny(~DummyMacResult { sp: sp }) - } } -struct DummyMacResult { - sp: codemap::Span -} -impl AnyMacro for DummyMacResult { - fn make_expr(&self) -> @ast::Expr { - MacResult::raw_dummy_expr(self.sp) + +impl MacResult for DummyResult { + fn make_expr(&self) -> Option<@ast::Expr> { + Some(DummyResult::raw_expr(self.span)) } - fn make_items(&self) -> SmallVector<@ast::Item> { - SmallVector::zero() + fn make_items(&self) -> Option> { + if self.expr_only { + None + } else { + Some(SmallVector::zero()) + } } - fn make_stmt(&self) -> @ast::Stmt { - @codemap::respan(self.sp, - ast::StmtExpr(MacResult::raw_dummy_expr(self.sp), ast::DUMMY_NODE_ID)) + fn make_stmt(&self) -> Option<@ast::Stmt> { + Some(@codemap::respan(self.span, + ast::StmtExpr(DummyResult::raw_expr(self.span), + ast::DUMMY_NODE_ID))) } } diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index ba6ad4888e2..f4680b27084 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -18,10 +18,10 @@ use ext::build::AstBuilder; use std::char; -pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { +pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult { // Gather all argument expressions let exprs = match get_exprs_from_tts(cx, sp, tts) { - None => return MacResult::dummy_expr(sp), + None => return DummyResult::expr(sp), Some(e) => e, }; let mut bytes = Vec::new(); @@ -74,5 +74,5 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> } let e = cx.expr_vec_slice(sp, bytes); - MRExpr(e) + MacExpr::new(e) } diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index d83a386554e..8cd899738bf 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -26,7 +26,7 @@ use parse::token::InternedString; use parse::token; use parse; -pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { +pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult { let mut p = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(), tts.iter() @@ -47,5 +47,5 @@ pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::M let matches_cfg = attr::test_cfg(cx.cfg().as_slice(), in_cfg.iter().map(|&x| x)); let e = cx.expr_bool(sp, matches_cfg); - MRExpr(e) + MacExpr::new(e) } diff --git a/src/libsyntax/ext/concat.rs b/src/libsyntax/ext/concat.rs index 1db65e3b9e4..123271c5b5e 100644 --- a/src/libsyntax/ext/concat.rs +++ b/src/libsyntax/ext/concat.rs @@ -19,10 +19,10 @@ use std::strbuf::StrBuf; pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, sp: codemap::Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { let es = match base::get_exprs_from_tts(cx, sp, tts) { Some(e) => e, - None => return base::MacResult::dummy_expr(sp) + None => return base::DummyResult::expr(sp) }; let mut accumulator = StrBuf::new(); for e in es.move_iter() { @@ -57,7 +57,7 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, } } } - base::MRExpr(cx.expr_str( + base::MacExpr::new(cx.expr_str( sp, token::intern_and_get_ident(accumulator.into_owned()))) } diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index a5faa693982..9513c15c3d0 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -19,7 +19,7 @@ use parse::token::{str_to_ident}; use std::strbuf::StrBuf; pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { let mut res_str = StrBuf::new(); for (i, e) in tts.iter().enumerate() { if i & 1 == 1 { @@ -27,7 +27,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ast::TTTok(_, token::COMMA) => (), _ => { cx.span_err(sp, "concat_idents! expecting comma."); - return MacResult::dummy_expr(sp); + return DummyResult::expr(sp); } } } else { @@ -37,7 +37,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } _ => { cx.span_err(sp, "concat_idents! requires ident args."); - return MacResult::dummy_expr(sp); + return DummyResult::expr(sp); } } } @@ -61,5 +61,5 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ), span: sp, }; - MRExpr(e) + MacExpr::new(e) } diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index ecf63c8257d..7229f5c1df9 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -24,9 +24,9 @@ use parse::token; use std::os; pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { - None => return MacResult::dummy_expr(sp), + None => return DummyResult::expr(sp), Some(v) => v }; @@ -56,24 +56,24 @@ pub fn expand_option_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) s)))) } }; - MRExpr(e) + MacExpr::new(e) } pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { let exprs = match get_exprs_from_tts(cx, sp, tts) { Some(ref exprs) if exprs.len() == 0 => { cx.span_err(sp, "env! takes 1 or 2 arguments"); - return MacResult::dummy_expr(sp); + return DummyResult::expr(sp); } - None => return MacResult::dummy_expr(sp), + None => return DummyResult::expr(sp), Some(exprs) => exprs }; let var = match expr_to_str(cx, *exprs.get(0), "expected string literal") { - None => return MacResult::dummy_expr(sp), + None => return DummyResult::expr(sp), Some((v, _style)) => v }; let msg = match exprs.len() { @@ -84,13 +84,13 @@ pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } 2 => { match expr_to_str(cx, *exprs.get(1), "expected string literal") { - None => return MacResult::dummy_expr(sp), + None => return DummyResult::expr(sp), Some((s, _style)) => s } } _ => { cx.span_err(sp, "env! takes 1 or 2 arguments"); - return MacResult::dummy_expr(sp); + return DummyResult::expr(sp); } }; @@ -101,5 +101,5 @@ pub fn expand_env(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) } Some(s) => cx.expr_str(sp, token::intern_and_get_ident(s)) }; - MRExpr(e) + MacExpr::new(e) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1cff1d0f295..d73cb3856f9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -52,7 +52,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { format!("expected macro name without module \ separators")); // let compilation continue - return MacResult::raw_dummy_expr(e.span); + return DummyResult::raw_expr(e.span); } let extname = pth.segments.get(0).identifier; let extnamestr = token::get_ident(extname); @@ -65,7 +65,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { extnamestr.get())); // let compilation continue - return MacResult::raw_dummy_expr(e.span); + return DummyResult::raw_expr(e.span); } Some(&NormalTT(ref expandfun, exp_span)) => { fld.cx.bt_push(ExpnInfo { @@ -88,10 +88,9 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { let expanded = match expandfun.expand(fld.cx, mac_span.call_site, - marked_before.as_slice()) { - MRExpr(e) => e, - MRAny(any_macro) => any_macro.make_expr(), - _ => { + marked_before.as_slice()).make_expr() { + Some(e) => e, + None => { fld.cx.span_err( pth.span, format!( @@ -99,7 +98,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { extnamestr.get() ) ); - return MacResult::raw_dummy_expr(e.span); + return DummyResult::raw_expr(e.span); } }; @@ -112,7 +111,7 @@ pub fn expand_expr(e: @ast::Expr, fld: &mut MacroExpander) -> @ast::Expr { format!("'{}' is not a tt-style macro", extnamestr.get()) ); - return MacResult::raw_dummy_expr(e.span); + return DummyResult::raw_expr(e.span); } }; @@ -430,25 +429,8 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander) } }; - let items = match expanded { - MRItem(it) => { - mark_item(it,fm).move_iter() - .flat_map(|i| fld.fold_item(i).move_iter()) - .collect() - } - MRExpr(_) => { - fld.cx.span_err(pth.span, - format!("expr macro in item position: {}", - extnamestr.get())); - return SmallVector::zero(); - } - MRAny(any_macro) => { - any_macro.make_items().move_iter() - .flat_map(|i| mark_item(i, fm).move_iter()) - .flat_map(|i| fld.fold_item(i).move_iter()) - .collect() - } - MRDef(MacroDef { name, ext }) => { + let items = match expanded.make_def() { + Some(MacroDef { name, ext }) => { // yikes... no idea how to apply the mark to this. I'm afraid // we're going to have to wait-and-see on this one. fld.extsbox.insert(intern(name), ext); @@ -458,6 +440,22 @@ pub fn expand_item_mac(it: @ast::Item, fld: &mut MacroExpander) SmallVector::zero() } } + None => { + match expanded.make_items() { + Some(items) => { + items.move_iter() + .flat_map(|i| mark_item(i, fm).move_iter()) + .flat_map(|i| fld.fold_item(i).move_iter()) + .collect() + } + None => { + fld.cx.span_err(pth.span, + format!("expr macro in item position: {}", + extnamestr.get())); + return SmallVector::zero(); + } + } + } }; fld.cx.bt_pop(); return items; @@ -593,15 +591,9 @@ pub fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<@Stmt> { let expanded = match expandfun.expand(fld.cx, mac_span.call_site, - marked_tts.as_slice()) { - MRExpr(e) => { - @codemap::Spanned { - node: StmtExpr(e, ast::DUMMY_NODE_ID), - span: e.span, - } - } - MRAny(any_macro) => any_macro.make_stmt(), - _ => { + marked_tts.as_slice()).make_stmt() { + Some(stmt) => stmt, + None => { fld.cx.span_err(pth.span, format!("non-stmt macro in stmt pos: {}", extnamestr)); diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 411bf921dd2..41c74ce9ae5 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -16,11 +16,11 @@ use ext::base; use ext::build::AstBuilder; pub fn expand_syntax_ext(ecx: &mut base::ExtCtxt, sp: Span, - _tts: &[ast::TokenTree]) -> base::MacResult { + _tts: &[ast::TokenTree]) -> ~base::MacResult { ecx.span_err(sp, "`fmt!` is deprecated, use `format!` instead"); ecx.parse_sess.span_diagnostic.span_note(sp, "see http://static.rust-lang.org/doc/master/std/fmt/index.html \ for documentation"); - base::MRExpr(ecx.expr_uint(sp, 2)) + base::MacExpr::new(ecx.expr_uint(sp, 2)) } diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index cc0f26dcc2f..86c7ae28ac2 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -806,14 +806,14 @@ impl<'a, 'b> Context<'a, 'b> { } pub fn expand_args(ecx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { match parse_args(ecx, sp, tts) { (extra, Some((efmt, args, order, names))) => { - MRExpr(expand_preparsed_format_args(ecx, sp, extra, efmt, args, + MacExpr::new(expand_preparsed_format_args(ecx, sp, extra, efmt, args, order, names)) } - (_, None) => MRExpr(ecx.expr_uint(sp, 2)) + (_, None) => MacExpr::new(ecx.expr_uint(sp, 2)) } } @@ -845,7 +845,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, efmt, "format argument must be a string literal.") { Some((fmt, _)) => fmt, - None => return MacResult::raw_dummy_expr(sp) + None => return DummyResult::raw_expr(sp) }; let mut parser = parse::Parser::new(fmt.get()); @@ -863,7 +863,7 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span, match parser.errors.shift() { Some(error) => { cx.ecx.span_err(efmt.span, "invalid format string: " + error); - return MacResult::raw_dummy_expr(sp); + return DummyResult::raw_expr(sp); } None => {} } diff --git a/src/libsyntax/ext/log_syntax.rs b/src/libsyntax/ext/log_syntax.rs index c9e444a9b8c..666bc486fbf 100644 --- a/src/libsyntax/ext/log_syntax.rs +++ b/src/libsyntax/ext/log_syntax.rs @@ -18,12 +18,12 @@ use std::rc::Rc; pub fn expand_syntax_ext(cx: &mut base::ExtCtxt, sp: codemap::Span, tt: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { cx.print_backtrace(); println!("{}", print::pprust::tt_to_str(&ast::TTDelim( Rc::new(tt.iter().map(|x| (*x).clone()).collect())))); // any so that `log_syntax` can be invoked as an expression and item. - base::MacResult::dummy_any(sp) + base::DummyResult::any(sp) } diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index 6f8656f494d..7664d089149 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -289,53 +289,53 @@ pub mod rt { pub fn expand_quote_tokens(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { let (cx_expr, expr) = expand_tts(cx, sp, tts); let expanded = expand_wrapper(cx, sp, cx_expr, expr); - base::MRExpr(expanded) + base::MacExpr::new(expanded) } pub fn expand_quote_expr(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { let expanded = expand_parse_call(cx, sp, "parse_expr", Vec::new(), tts); - base::MRExpr(expanded) + base::MacExpr::new(expanded) } pub fn expand_quote_item(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { let e_attrs = cx.expr_vec_ng(sp); let expanded = expand_parse_call(cx, sp, "parse_item", vec!(e_attrs), tts); - base::MRExpr(expanded) + base::MacExpr::new(expanded) } pub fn expand_quote_pat(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { let e_refutable = cx.expr_lit(sp, ast::LitBool(true)); let expanded = expand_parse_call(cx, sp, "parse_pat", vec!(e_refutable), tts); - base::MRExpr(expanded) + base::MacExpr::new(expanded) } pub fn expand_quote_ty(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { let e_param_colons = cx.expr_lit(sp, ast::LitBool(false)); let expanded = expand_parse_call(cx, sp, "parse_ty", vec!(e_param_colons), tts); - base::MRExpr(expanded) + base::MacExpr::new(expanded) } pub fn expand_quote_stmt(cx: &mut ExtCtxt, sp: Span, - tts: &[ast::TokenTree]) -> base::MacResult { + tts: &[ast::TokenTree]) -> ~base::MacResult { let e_attrs = cx.expr_vec_ng(sp); let expanded = expand_parse_call(cx, sp, "parse_stmt", vec!(e_attrs), tts); - base::MRExpr(expanded) + base::MacExpr::new(expanded) } fn ids_ext(strs: Vec<~str> ) -> Vec { diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 008532bcafe..7f1d8172255 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -29,63 +29,63 @@ use std::str; /* line!(): expands to the current line number */ pub fn expand_line(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { base::check_zero_tts(cx, sp, tts, "line!"); let topmost = topmost_expn_info(cx.backtrace().unwrap()); let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo); - base::MRExpr(cx.expr_uint(topmost.call_site, loc.line)) + base::MacExpr::new(cx.expr_uint(topmost.call_site, loc.line)) } /* col!(): expands to the current column number */ pub fn expand_col(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { base::check_zero_tts(cx, sp, tts, "col!"); let topmost = topmost_expn_info(cx.backtrace().unwrap()); let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo); - base::MRExpr(cx.expr_uint(topmost.call_site, loc.col.to_uint())) + base::MacExpr::new(cx.expr_uint(topmost.call_site, loc.col.to_uint())) } /* file!(): expands to the current filename */ /* The filemap (`loc.file`) contains a bunch more information we could spit * out if we wanted. */ pub fn expand_file(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { base::check_zero_tts(cx, sp, tts, "file!"); let topmost = topmost_expn_info(cx.backtrace().unwrap()); let loc = cx.codemap().lookup_char_pos(topmost.call_site.lo); let filename = token::intern_and_get_ident(loc.file.name); - base::MRExpr(cx.expr_str(topmost.call_site, filename)) + base::MacExpr::new(cx.expr_str(topmost.call_site, filename)) } pub fn expand_stringify(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { let s = pprust::tts_to_str(tts); - base::MRExpr(cx.expr_str(sp, token::intern_and_get_ident(s))) + base::MacExpr::new(cx.expr_str(sp, token::intern_and_get_ident(s))) } pub fn expand_mod(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { base::check_zero_tts(cx, sp, tts, "module_path!"); let string = cx.mod_path() .iter() .map(|x| token::get_ident(*x).get().to_str()) .collect::>() .connect("::"); - base::MRExpr(cx.expr_str(sp, token::intern_and_get_ident(string))) + base::MacExpr::new(cx.expr_str(sp, token::intern_and_get_ident(string))) } // include! : parse the given file as an expr // This is generally a bad idea because it's going to behave // unhygienically. pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { let file = match get_single_str_from_tts(cx, sp, tts, "include!") { Some(f) => f, - None => return MacResult::dummy_expr(sp), + None => return DummyResult::expr(sp), }; // The file will be added to the code map by the parser let mut p = @@ -95,21 +95,21 @@ pub fn expand_include(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) sp, &Path::new(file)), sp); - base::MRExpr(p.parse_expr()) + base::MacExpr::new(p.parse_expr()) } // include_str! : read the given file, insert it as a literal string expr pub fn expand_include_str(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { Some(f) => f, - None => return MacResult::dummy_expr(sp) + None => return DummyResult::expr(sp) }; let file = res_rel_file(cx, sp, &Path::new(file)); let bytes = match File::open(&file).read_to_end() { Err(e) => { cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - return MacResult::dummy_expr(sp); + return DummyResult::expr(sp); } Ok(bytes) => bytes, }; @@ -121,31 +121,31 @@ 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.to_owned()); - base::MRExpr(cx.expr_str(sp, interned)) + base::MacExpr::new(cx.expr_str(sp, interned)) } None => { cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display())); - return MacResult::dummy_expr(sp); + return DummyResult::expr(sp); } } } pub fn expand_include_bin(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) - -> base::MacResult + -> ~base::MacResult { let file = match get_single_str_from_tts(cx, sp, tts, "include_bin!") { Some(f) => f, - None => return MacResult::dummy_expr(sp) + None => return DummyResult::expr(sp) }; let file = res_rel_file(cx, sp, &Path::new(file)); match File::open(&file).read_to_end() { Err(e) => { cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - return MacResult::dummy_expr(sp); + return DummyResult::expr(sp); } Ok(bytes) => { let bytes = bytes.iter().map(|x| *x).collect(); - base::MRExpr(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) + base::MacExpr::new(cx.expr_lit(sp, ast::LitBinary(Rc::new(bytes)))) } } } diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 173cf4c9ad9..d428251604c 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -17,7 +17,7 @@ use parse::token::{keywords, is_keyword}; pub fn expand_trace_macros(cx: &mut ExtCtxt, sp: Span, tt: &[ast::TokenTree]) - -> base::MacResult { + -> ~base::MacResult { match tt { [ast::TTTok(_, ref tok)] if is_keyword(keywords::True, tok) => { cx.set_trace_macros(true); @@ -28,5 +28,5 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt, _ => cx.span_err(sp, "trace_macros! accepts only `true` or `false`"), } - base::MacResult::dummy_any(sp) + base::DummyResult::any(sp) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index d4a883a63eb..279544d106e 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -12,7 +12,7 @@ use ast::{Ident, Matcher_, Matcher, MatchTok, MatchNonterminal, MatchSeq}; use ast::{TTDelim}; use ast; use codemap::{Span, Spanned, DUMMY_SP}; -use ext::base::{AnyMacro, ExtCtxt, MacResult, MRAny, MRDef, MacroDef}; +use ext::base::{ExtCtxt, MacResult, MacroDef}; use ext::base::{NormalTT, MacroExpander}; use ext::base; use ext::tt::macro_parser::{Success, Error, Failure}; @@ -57,13 +57,13 @@ impl<'a> ParserAnyMacro<'a> { } } -impl<'a> AnyMacro for ParserAnyMacro<'a> { - fn make_expr(&self) -> @ast::Expr { +impl<'a> MacResult for ParserAnyMacro<'a> { + fn make_expr(&self) -> Option<@ast::Expr> { let ret = self.parser.borrow_mut().parse_expr(); self.ensure_complete_parse(true); - ret + Some(ret) } - fn make_items(&self) -> SmallVector<@ast::Item> { + fn make_items(&self) -> Option> { let mut ret = SmallVector::zero(); loop { let mut parser = self.parser.borrow_mut(); @@ -74,13 +74,13 @@ impl<'a> AnyMacro for ParserAnyMacro<'a> { } } self.ensure_complete_parse(false); - ret + Some(ret) } - fn make_stmt(&self) -> @ast::Stmt { + fn make_stmt(&self) -> Option<@ast::Stmt> { let attrs = self.parser.borrow_mut().parse_outer_attributes(); let ret = self.parser.borrow_mut().parse_stmt(attrs); self.ensure_complete_parse(true); - ret + Some(ret) } } @@ -95,7 +95,7 @@ impl MacroExpander for MacroRulesMacroExpander { cx: &mut ExtCtxt, sp: Span, arg: &[ast::TokenTree]) - -> MacResult { + -> ~MacResult { generic_extension(cx, sp, self.name, @@ -105,6 +105,15 @@ impl MacroExpander for MacroRulesMacroExpander { } } +struct MacroRulesDefiner { + def: RefCell> +} +impl MacResult for MacroRulesDefiner { + fn make_def(&self) -> Option { + Some(self.def.borrow_mut().take().expect("MacroRulesDefiner expanded twice")) + } +} + // Given `lhses` and `rhses`, this is the new macro we create fn generic_extension(cx: &ExtCtxt, sp: Span, @@ -112,7 +121,7 @@ fn generic_extension(cx: &ExtCtxt, arg: &[ast::TokenTree], lhses: &[Rc], rhses: &[Rc]) - -> MacResult { + -> ~MacResult { if cx.trace_macros() { println!("{}! \\{ {} \\}", token::get_ident(name), @@ -160,9 +169,9 @@ fn generic_extension(cx: &ExtCtxt, let p = Parser(cx.parse_sess(), cx.cfg(), ~trncbr); // Let the context choose how to interpret the result. // Weird, but useful for X-macros. - return MRAny(~ParserAnyMacro { + return ~ParserAnyMacro { parser: RefCell::new(p), - }) + } as ~MacResult } Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo { best_fail_spot = sp; @@ -184,7 +193,7 @@ pub fn add_new_extension(cx: &mut ExtCtxt, sp: Span, name: Ident, arg: Vec ) - -> base::MacResult { + -> ~base::MacResult { // these spans won't matter, anyways fn ms(m: Matcher_) -> Matcher { Spanned { @@ -236,8 +245,10 @@ pub fn add_new_extension(cx: &mut ExtCtxt, rhses: rhses, }; - return MRDef(MacroDef { - name: token::get_ident(name).to_str(), - ext: NormalTT(exp, Some(sp)) - }); + ~MacroRulesDefiner { + def: RefCell::new(Some(MacroDef { + name: token::get_ident(name).to_str(), + ext: NormalTT(exp, Some(sp)) + })) + } as ~MacResult } diff --git a/src/test/auxiliary/macro_crate_test.rs b/src/test/auxiliary/macro_crate_test.rs index 5864f839352..070bb6dfcb7 100644 --- a/src/test/auxiliary/macro_crate_test.rs +++ b/src/test/auxiliary/macro_crate_test.rs @@ -35,11 +35,11 @@ pub fn macro_registrar(register: |Name, SyntaxExtension|) { register(token::intern("into_foo"), ItemModifier(expand_into_foo)); } -fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> MacResult { +fn expand_make_a_1(cx: &mut ExtCtxt, sp: Span, tts: &[TokenTree]) -> ~MacResult { if !tts.is_empty() { cx.span_fatal(sp, "make_a_1 takes no arguments"); } - MRExpr(quote_expr!(cx, 1i)) + MacExpr::new(quote_expr!(cx, 1i)) } fn expand_into_foo(cx: &mut ExtCtxt, sp: Span, attr: @MetaItem, it: @Item)