Improves handling of statement macros.

Statement macros are now treated somewhat like item macros, in that a
statement macro can now expand into a series of statements, rather than
just a single statement.

This allows statement macros to be nested inside other kinds of macros and
expand properly, where previously the expansion would only work when no
nesting was present.

See: src/test/run-pass/macro-stmt_macro_in_expr_macro.rs
     src/test/run-pass/macro-nested_stmt_macro.rs

This changes the interface of the MacResult trait.  make_stmt has become
make_stmts and now returns a vector, rather than a single item.  Plugin
writers who were implementing MacResult will have breakage, as well as
anyone using MacEager::stmt.

See: src/libsyntax/ext/base.rs

This also causes a minor difference in behavior to the diagnostics
produced by certain malformed macros.

See: src/test/compile-fail/macro-incomplete-parse.rs
This commit is contained in:
Christopher Chambers
2015-04-07 08:21:18 -05:00
parent de51bbec15
commit 19343860aa
6 changed files with 138 additions and 45 deletions

View File

@@ -208,10 +208,11 @@ impl<F> IdentMacroExpander for F
}
// Use a macro because forwarding to a simple function has type system issues
macro_rules! make_stmt_default {
macro_rules! make_stmts_default {
($me:expr) => {
$me.make_expr().map(|e| {
P(codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID)))
SmallVector::one(P(codemap::respan(
e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID))))
})
}
}
@@ -238,12 +239,12 @@ pub trait MacResult {
None
}
/// Create a statement.
/// Create zero or more statements.
///
/// By default this attempts to create an expression statement,
/// returning None if that fails.
fn make_stmt(self: Box<Self>) -> Option<P<ast::Stmt>> {
make_stmt_default!(self)
fn make_stmts(self: Box<Self>) -> Option<SmallVector<P<ast::Stmt>>> {
make_stmts_default!(self)
}
}
@@ -276,7 +277,7 @@ make_MacEager! {
pat: P<ast::Pat>,
items: SmallVector<P<ast::Item>>,
impl_items: SmallVector<P<ast::ImplItem>>,
stmt: P<ast::Stmt>,
stmts: SmallVector<P<ast::Stmt>>,
}
impl MacResult for MacEager {
@@ -292,10 +293,10 @@ impl MacResult for MacEager {
self.impl_items
}
fn make_stmt(self: Box<Self>) -> Option<P<ast::Stmt>> {
match self.stmt {
None => make_stmt_default!(self),
s => s,
fn make_stmts(self: Box<Self>) -> Option<SmallVector<P<ast::Stmt>>> {
match self.stmts.as_ref().map_or(0, |s| s.len()) {
0 => make_stmts_default!(self),
_ => self.stmts,
}
}
@@ -384,10 +385,11 @@ impl MacResult for DummyResult {
Some(SmallVector::zero())
}
}
fn make_stmt(self: Box<DummyResult>) -> Option<P<ast::Stmt>> {
Some(P(codemap::respan(self.span,
ast::StmtExpr(DummyResult::raw_expr(self.span),
ast::DUMMY_NODE_ID))))
fn make_stmts(self: Box<DummyResult>) -> Option<SmallVector<P<ast::Stmt>>> {
Some(SmallVector::one(P(
codemap::respan(self.span,
ast::StmtExpr(DummyResult::raw_expr(self.span),
ast::DUMMY_NODE_ID)))))
}
}