Skip to content

Commit 99dd591

Browse files
committed
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).
1 parent 168b2d1 commit 99dd591

18 files changed

+245
-174
lines changed

src/libfourcc/lib.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ use syntax::ast::Name;
5757
use syntax::attr::contains;
5858
use syntax::codemap::{Span, mk_sp};
5959
use syntax::ext::base;
60-
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MRExpr};
60+
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
6161
use syntax::ext::build::AstBuilder;
6262
use syntax::parse;
6363
use syntax::parse::token;
@@ -73,7 +73,7 @@ pub fn macro_registrar(register: |Name, SyntaxExtension|) {
7373
None));
7474
}
7575

76-
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
76+
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult {
7777
let (expr, endian) = parse_tts(cx, tts);
7878

7979
let little = match endian {
@@ -101,12 +101,12 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ->
101101
}
102102
_ => {
103103
cx.span_err(expr.span, "unsupported literal in fourcc!");
104-
return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
104+
return base::DummyResult::expr(sp)
105105
}
106106
},
107107
_ => {
108108
cx.span_err(expr.span, "non-literal in fourcc!");
109-
return MRExpr(cx.expr_lit(sp, ast::LitUint(0u64, ast::TyU32)));
109+
return base::DummyResult::expr(sp)
110110
}
111111
};
112112

@@ -126,7 +126,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ->
126126
};
127127
}
128128
let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
129-
MRExpr(e)
129+
MacExpr::new(e)
130130
}
131131

132132
struct Ident {

src/libhexfloat/lib.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ use syntax::ast;
5353
use syntax::ast::Name;
5454
use syntax::codemap::{Span, mk_sp};
5555
use syntax::ext::base;
56-
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MRExpr};
56+
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
5757
use syntax::ext::build::AstBuilder;
5858
use syntax::parse;
5959
use syntax::parse::token;
@@ -97,7 +97,7 @@ fn hex_float_lit_err(s: &str) -> Option<(uint, ~str)> {
9797
}
9898
}
9999

100-
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
100+
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult {
101101
let (expr, ty_lit) = parse_tts(cx, tts);
102102

103103
let ty = match ty_lit {
@@ -121,12 +121,12 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ->
121121
}
122122
_ => {
123123
cx.span_err(expr.span, "unsupported literal in hexfloat!");
124-
return base::MacResult::dummy_expr(sp);
124+
return base::DummyResult::expr(sp);
125125
}
126126
},
127127
_ => {
128128
cx.span_err(expr.span, "non-literal in hexfloat!");
129-
return base::MacResult::dummy_expr(sp);
129+
return base::DummyResult::expr(sp);
130130
}
131131
};
132132

@@ -137,7 +137,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ->
137137
let pos = expr.span.lo + syntax::codemap::Pos::from_uint(err_pos + 1);
138138
let span = syntax::codemap::mk_sp(pos,pos);
139139
cx.span_err(span, format!("invalid hex float literal in hexfloat!: {}", err_str));
140-
return base::MacResult::dummy_expr(sp);
140+
return base::DummyResult::expr(sp);
141141
}
142142
_ => ()
143143
}
@@ -147,7 +147,7 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ->
147147
None => ast::LitFloatUnsuffixed(s),
148148
Some (ty) => ast::LitFloat(s, ty)
149149
};
150-
MRExpr(cx.expr_lit(sp, lit))
150+
MacExpr::new(cx.expr_lit(sp, lit))
151151
}
152152

153153
struct Ident {

src/libsyntax/ext/asm.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ impl State {
4545
static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
4646

4747
pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
48-
-> base::MacResult {
48+
-> ~base::MacResult {
4949
let mut p = parse::new_parser_from_tts(cx.parse_sess(),
5050
cx.cfg(),
5151
tts.iter()
@@ -72,7 +72,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
7272
"inline assembly must be a string literal.") {
7373
Some((s, st)) => (s, st),
7474
// let compilation continue
75-
None => return MacResult::dummy_expr(sp),
75+
None => return DummyResult::expr(sp),
7676
};
7777
asm = s;
7878
asm_str_style = Some(style);
@@ -210,7 +210,7 @@ pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
210210
inputs.push((token::intern_and_get_ident(i.to_str()), out));
211211
}
212212

213-
MRExpr(@ast::Expr {
213+
MacExpr::new(@ast::Expr {
214214
id: ast::DUMMY_NODE_ID,
215215
node: ast::ExprInlineAsm(ast::InlineAsm {
216216
asm: token::intern_and_get_ident(asm.get()),

src/libsyntax/ext/base.rs

+106-38
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,19 @@ pub trait MacroExpander {
5050
ecx: &mut ExtCtxt,
5151
span: Span,
5252
token_tree: &[ast::TokenTree])
53-
-> MacResult;
53+
-> ~MacResult;
5454
}
5555

5656
pub type MacroExpanderFn =
5757
fn(ecx: &mut ExtCtxt, span: codemap::Span, token_tree: &[ast::TokenTree])
58-
-> MacResult;
58+
-> ~MacResult;
5959

6060
impl MacroExpander for BasicMacroExpander {
6161
fn expand(&self,
6262
ecx: &mut ExtCtxt,
6363
span: Span,
6464
token_tree: &[ast::TokenTree])
65-
-> MacResult {
65+
-> ~MacResult {
6666
(self.expander)(ecx, span, token_tree)
6767
}
6868
}
@@ -78,7 +78,7 @@ pub trait IdentMacroExpander {
7878
sp: Span,
7979
ident: ast::Ident,
8080
token_tree: Vec<ast::TokenTree> )
81-
-> MacResult;
81+
-> ~MacResult;
8282
}
8383

8484
impl IdentMacroExpander for BasicIdentMacroExpander {
@@ -87,62 +87,130 @@ impl IdentMacroExpander for BasicIdentMacroExpander {
8787
sp: Span,
8888
ident: ast::Ident,
8989
token_tree: Vec<ast::TokenTree> )
90-
-> MacResult {
90+
-> ~MacResult {
9191
(self.expander)(cx, sp, ident, token_tree)
9292
}
9393
}
9494

9595
pub type IdentMacroExpanderFn =
96-
fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree> ) -> MacResult;
96+
fn(&mut ExtCtxt, Span, ast::Ident, Vec<ast::TokenTree> ) -> ~MacResult;
9797

9898
pub type MacroCrateRegistrationFun =
9999
fn(|ast::Name, SyntaxExtension|);
100100

101-
pub trait AnyMacro {
102-
fn make_expr(&self) -> @ast::Expr;
103-
fn make_items(&self) -> SmallVector<@ast::Item>;
104-
fn make_stmt(&self) -> @ast::Stmt;
101+
/// The result of a macro expansion. The return values of the various
102+
/// methods are spliced into the AST at the callsite of the macro (or
103+
/// just into the compiler's internal macro table, for `make_def`).
104+
pub trait MacResult {
105+
/// Define a new macro.
106+
fn make_def(&self) -> Option<MacroDef> {
107+
None
108+
}
109+
/// Create an expression.
110+
fn make_expr(&self) -> Option<@ast::Expr> {
111+
None
112+
}
113+
/// Create zero or more items.
114+
fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
115+
None
116+
}
117+
118+
/// Create a statement.
119+
///
120+
/// By default this attempts to create an expression statement,
121+
/// returning None if that fails.
122+
fn make_stmt(&self) -> Option<@ast::Stmt> {
123+
self.make_expr()
124+
.map(|e| @codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID)))
125+
}
105126
}
106127

128+
/// A convenience type for macros that return a single expression.
129+
pub struct MacExpr {
130+
e: @ast::Expr
131+
}
132+
impl MacExpr {
133+
pub fn new(e: @ast::Expr) -> ~MacResult {
134+
~MacExpr { e: e } as ~MacResult
135+
}
136+
}
137+
impl MacResult for MacExpr {
138+
fn make_expr(&self) -> Option<@ast::Expr> {
139+
Some(self.e)
140+
}
141+
}
142+
/// A convenience type for macros that return a single item.
143+
pub struct MacItem {
144+
i: @ast::Item
145+
}
146+
impl MacItem {
147+
pub fn new(i: @ast::Item) -> ~MacResult {
148+
~MacItem { i: i } as ~MacResult
149+
}
150+
}
151+
impl MacResult for MacItem {
152+
fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
153+
Some(SmallVector::one(self.i))
154+
}
155+
fn make_stmt(&self) -> Option<@ast::Stmt> {
156+
Some(@codemap::respan(
157+
self.i.span,
158+
ast::StmtDecl(
159+
@codemap::respan(self.i.span, ast::DeclItem(self.i)),
160+
ast::DUMMY_NODE_ID)))
161+
}
162+
}
107163

108-
pub enum MacResult {
109-
MRExpr(@ast::Expr),
110-
MRItem(@ast::Item),
111-
MRAny(~AnyMacro:),
112-
MRDef(MacroDef),
164+
/// Fill-in macro expansion result, to allow compilation to continue
165+
/// after hitting errors.
166+
pub struct DummyResult {
167+
expr_only: bool,
168+
span: Span
113169
}
114-
impl MacResult {
115-
/// Create an empty expression MacResult; useful for satisfying
116-
/// type signatures after emitting a non-fatal error (which stop
117-
/// compilation well before the validity (or otherwise)) of the
118-
/// expression are checked.
119-
pub fn raw_dummy_expr(sp: codemap::Span) -> @ast::Expr {
170+
171+
impl DummyResult {
172+
/// Create a default MacResult that can be anything.
173+
///
174+
/// Use this as a return value after hitting any errors and
175+
/// calling `span_err`.
176+
pub fn any(sp: Span) -> ~MacResult {
177+
~DummyResult { expr_only: false, span: sp } as ~MacResult
178+
}
179+
180+
/// Create a default MacResult that can only be an expression.
181+
///
182+
/// Use this for macros that must expand to an expression, so even
183+
/// if an error is encountered internally, the user will recieve
184+
/// an error that they also used it in the wrong place.
185+
pub fn expr(sp: Span) -> ~MacResult {
186+
~DummyResult { expr_only: true, span: sp } as ~MacResult
187+
}
188+
189+
/// A plain dummy expression.
190+
pub fn raw_expr(sp: Span) -> @ast::Expr {
120191
@ast::Expr {
121192
id: ast::DUMMY_NODE_ID,
122193
node: ast::ExprLit(@codemap::respan(sp, ast::LitNil)),
123194
span: sp,
124195
}
125196
}
126-
pub fn dummy_expr(sp: codemap::Span) -> MacResult {
127-
MRExpr(MacResult::raw_dummy_expr(sp))
128-
}
129-
pub fn dummy_any(sp: codemap::Span) -> MacResult {
130-
MRAny(~DummyMacResult { sp: sp })
131-
}
132-
}
133-
struct DummyMacResult {
134-
sp: codemap::Span
135197
}
136-
impl AnyMacro for DummyMacResult {
137-
fn make_expr(&self) -> @ast::Expr {
138-
MacResult::raw_dummy_expr(self.sp)
198+
199+
impl MacResult for DummyResult {
200+
fn make_expr(&self) -> Option<@ast::Expr> {
201+
Some(DummyResult::raw_expr(self.span))
139202
}
140-
fn make_items(&self) -> SmallVector<@ast::Item> {
141-
SmallVector::zero()
203+
fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
204+
if self.expr_only {
205+
None
206+
} else {
207+
Some(SmallVector::zero())
208+
}
142209
}
143-
fn make_stmt(&self) -> @ast::Stmt {
144-
@codemap::respan(self.sp,
145-
ast::StmtExpr(MacResult::raw_dummy_expr(self.sp), ast::DUMMY_NODE_ID))
210+
fn make_stmt(&self) -> Option<@ast::Stmt> {
211+
Some(@codemap::respan(self.span,
212+
ast::StmtExpr(DummyResult::raw_expr(self.span),
213+
ast::DUMMY_NODE_ID)))
146214
}
147215
}
148216

src/libsyntax/ext/bytes.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ use ext::build::AstBuilder;
1818

1919
use std::char;
2020

21-
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
21+
pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult {
2222
// Gather all argument expressions
2323
let exprs = match get_exprs_from_tts(cx, sp, tts) {
24-
None => return MacResult::dummy_expr(sp),
24+
None => return DummyResult::expr(sp),
2525
Some(e) => e,
2626
};
2727
let mut bytes = Vec::new();
@@ -74,5 +74,5 @@ pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) ->
7474
}
7575

7676
let e = cx.expr_vec_slice(sp, bytes);
77-
MRExpr(e)
77+
MacExpr::new(e)
7878
}

src/libsyntax/ext/cfg.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use parse::token::InternedString;
2626
use parse::token;
2727
use parse;
2828

29-
pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult {
29+
pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> ~base::MacResult {
3030
let mut p = parse::new_parser_from_tts(cx.parse_sess(),
3131
cx.cfg(),
3232
tts.iter()
@@ -47,5 +47,5 @@ pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::M
4747
let matches_cfg = attr::test_cfg(cx.cfg().as_slice(),
4848
in_cfg.iter().map(|&x| x));
4949
let e = cx.expr_bool(sp, matches_cfg);
50-
MRExpr(e)
50+
MacExpr::new(e)
5151
}

src/libsyntax/ext/concat.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ use std::strbuf::StrBuf;
1919

2020
pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
2121
sp: codemap::Span,
22-
tts: &[ast::TokenTree]) -> base::MacResult {
22+
tts: &[ast::TokenTree]) -> ~base::MacResult {
2323
let es = match base::get_exprs_from_tts(cx, sp, tts) {
2424
Some(e) => e,
25-
None => return base::MacResult::dummy_expr(sp)
25+
None => return base::DummyResult::expr(sp)
2626
};
2727
let mut accumulator = StrBuf::new();
2828
for e in es.move_iter() {
@@ -57,7 +57,7 @@ pub fn expand_syntax_ext(cx: &mut base::ExtCtxt,
5757
}
5858
}
5959
}
60-
base::MRExpr(cx.expr_str(
60+
base::MacExpr::new(cx.expr_str(
6161
sp,
6262
token::intern_and_get_ident(accumulator.into_owned())))
6363
}

0 commit comments

Comments
 (0)