Skip to content

Commit

Permalink
syntax: unify all MacResult's into a single trait.
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
huonw committed Apr 16, 2014
1 parent 168b2d1 commit 99dd591
Show file tree
Hide file tree
Showing 18 changed files with 245 additions and 174 deletions.
10 changes: 5 additions & 5 deletions src/libfourcc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}
};

Expand All @@ -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 {
Expand Down
12 changes: 6 additions & 6 deletions src/libhexfloat/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
}
};

Expand All @@ -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);
}
_ => ()
}
Expand All @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax/ext/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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);
Expand Down Expand Up @@ -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()),
Expand Down
144 changes: 106 additions & 38 deletions src/libsyntax/ext/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand All @@ -78,7 +78,7 @@ pub trait IdentMacroExpander {
sp: Span,
ident: ast::Ident,
token_tree: Vec<ast::TokenTree> )
-> MacResult;
-> ~MacResult;
}

impl IdentMacroExpander for BasicIdentMacroExpander {
Expand All @@ -87,62 +87,130 @@ impl IdentMacroExpander for BasicIdentMacroExpander {
sp: Span,
ident: ast::Ident,
token_tree: Vec<ast::TokenTree> )
-> MacResult {
-> ~MacResult {
(self.expander)(cx, sp, ident, token_tree)
}
}

pub type IdentMacroExpanderFn =
fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree> ) -> MacResult;
fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree> ) -> ~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<MacroDef> {
None
}
/// Create an expression.
fn make_expr(&self) -> Option<@ast::Expr> {
None
}
/// Create zero or more items.
fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
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)))
}
}

/// A convenience type for macros that return a single expression.
pub struct MacExpr {
e: @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<SmallVector<@ast::Item>> {
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)))
}
}

pub enum MacResult {
MRExpr(@ast::Expr),
MRItem(@ast::Item),
MRAny(~AnyMacro:),
MRDef(MacroDef),
/// Fill-in macro expansion result, to allow compilation to continue
/// after hitting errors.
pub struct DummyResult {
expr_only: bool,
span: Span
}
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 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<SmallVector<@ast::Item>> {
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)))
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax/ext/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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)
}
4 changes: 2 additions & 2 deletions src/libsyntax/ext/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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)
}
6 changes: 3 additions & 3 deletions src/libsyntax/ext/concat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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())))
}
Loading

5 comments on commit 99dd591

@bors
Copy link
Contributor

@bors bors commented on 99dd591 Apr 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saw approval from sfackler
at huonw@99dd591

@bors
Copy link
Contributor

@bors bors commented on 99dd591 Apr 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merging huonw/rust/macro-expander-trait = 99dd591 into auto

@bors
Copy link
Contributor

@bors bors commented on 99dd591 Apr 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

huonw/rust/macro-expander-trait = 99dd591 merged ok, testing candidate = 61f788c

@bors
Copy link
Contributor

@bors bors commented on 99dd591 Apr 16, 2014

@bors
Copy link
Contributor

@bors bors commented on 99dd591 Apr 16, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fast-forwarding master to auto = 61f788c

Please sign in to comment.