Skip to content

Commit bb333ca

Browse files
committed
expansion abstraction
1 parent 2c4b6d6 commit bb333ca

File tree

1 file changed

+114
-144
lines changed

1 file changed

+114
-144
lines changed

src/libsyntax/ext/expand.rs

+114-144
Original file line numberDiff line numberDiff line change
@@ -37,92 +37,28 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
3737
// expr_mac should really be expr_ext or something; it's the
3838
// entry-point for all syntax extensions.
3939
ExprMac(ref mac) => {
40-
match (*mac).node {
41-
// it would almost certainly be cleaner to pass the whole
42-
// macro invocation in, rather than pulling it apart and
43-
// marking the tts and the ctxt separately. This also goes
44-
// for the other three macro invocation chunks of code
45-
// in this file.
46-
// Token-tree macros:
47-
MacInvocTT(ref pth, ref tts, _) => {
48-
if pth.segments.len() > 1u {
49-
fld.cx.span_err(pth.span,
50-
"expected macro name without module \
51-
separators");
52-
// let compilation continue
53-
return DummyResult::raw_expr(e.span);
54-
}
55-
let extname = pth.segments.get(0).identifier;
56-
let extnamestr = token::get_ident(extname);
57-
let marked_after = match fld.extsbox.find(&extname.name) {
58-
None => {
59-
fld.cx.span_err(
60-
pth.span,
61-
format!("macro undefined: '{}!'",
62-
extnamestr.get()).as_slice());
63-
64-
// let compilation continue
65-
return DummyResult::raw_expr(e.span);
66-
}
67-
Some(&NormalTT(ref expandfun, exp_span)) => {
68-
fld.cx.bt_push(ExpnInfo {
69-
call_site: e.span,
70-
callee: NameAndSpan {
71-
name: extnamestr.get().to_string(),
72-
format: MacroBang,
73-
span: exp_span,
74-
},
75-
});
76-
let fm = fresh_mark();
77-
// mark before:
78-
let marked_before = mark_tts(tts.as_slice(), fm);
79-
80-
// The span that we pass to the expanders we want to
81-
// be the root of the call stack. That's the most
82-
// relevant span and it's the actual invocation of
83-
// the macro.
84-
let mac_span = original_span(fld.cx);
85-
86-
let expanded = match expandfun.expand(fld.cx,
87-
mac_span.call_site,
88-
marked_before.as_slice()).make_expr() {
89-
Some(e) => e,
90-
None => {
91-
fld.cx.span_err(
92-
pth.span,
93-
format!("non-expression macro in expression position: {}",
94-
extnamestr.get().as_slice()
95-
).as_slice());
96-
return DummyResult::raw_expr(e.span);
97-
}
98-
};
40+
let expanded_expr = match expand_mac_invoc(mac,&e.span,
41+
|r|{r.make_expr()},
42+
|expr,fm|{mark_expr(expr,fm)},
43+
fld) {
44+
Some(expr) => expr,
45+
None => {
46+
return DummyResult::raw_expr(e.span);
47+
}
48+
};
9949

100-
// mark after:
101-
mark_expr(expanded,fm)
102-
}
103-
_ => {
104-
fld.cx.span_err(
105-
pth.span,
106-
format!("'{}' is not a tt-style macro",
107-
extnamestr.get()).as_slice());
108-
return DummyResult::raw_expr(e.span);
109-
}
110-
};
50+
// Keep going, outside-in.
51+
//
52+
// FIXME(pcwalton): Is it necessary to clone the
53+
// node here?
54+
let fully_expanded =
55+
fld.fold_expr(expanded_expr).node.clone();
56+
fld.cx.bt_pop();
11157

112-
// Keep going, outside-in.
113-
//
114-
// FIXME(pcwalton): Is it necessary to clone the
115-
// node here?
116-
let fully_expanded =
117-
fld.fold_expr(marked_after).node.clone();
118-
fld.cx.bt_pop();
119-
120-
box(GC) ast::Expr {
121-
id: ast::DUMMY_NODE_ID,
122-
node: fully_expanded,
123-
span: e.span,
124-
}
125-
}
58+
box(GC) ast::Expr {
59+
id: ast::DUMMY_NODE_ID,
60+
node: fully_expanded,
61+
span: e.span,
12662
}
12763
}
12864

@@ -246,6 +182,88 @@ pub fn expand_expr(e: Gc<ast::Expr>, fld: &mut MacroExpander) -> Gc<ast::Expr> {
246182
}
247183
}
248184

185+
/// Expand a (not-ident-style) macro invocation. Returns the result
186+
/// of expansion and the mark which must be applied to the result.
187+
/// Our current interface doesn't allow us to apply the mark to the
188+
/// result until after calling make_expr, make_items, etc.
189+
fn expand_mac_invoc<T>(mac: &ast::Mac, span: &codemap::Span,
190+
parse_thunk: |Box<MacResult>|->Option<T>,
191+
mark_thunk: |T,Mrk|->T,
192+
fld: &mut MacroExpander)
193+
-> Option<T> {
194+
match (*mac).node {
195+
// it would almost certainly be cleaner to pass the whole
196+
// macro invocation in, rather than pulling it apart and
197+
// marking the tts and the ctxt separately. This also goes
198+
// for the other three macro invocation chunks of code
199+
// in this file.
200+
// Token-tree macros:
201+
MacInvocTT(ref pth, ref tts, _) => {
202+
if pth.segments.len() > 1u {
203+
fld.cx.span_err(pth.span,
204+
"expected macro name without module \
205+
separators");
206+
// let compilation continue
207+
return None;
208+
}
209+
let extname = pth.segments.get(0).identifier;
210+
let extnamestr = token::get_ident(extname);
211+
match fld.extsbox.find(&extname.name) {
212+
None => {
213+
fld.cx.span_err(
214+
pth.span,
215+
format!("macro undefined: '{}!'",
216+
extnamestr.get()).as_slice());
217+
218+
// let compilation continue
219+
None
220+
}
221+
Some(&NormalTT(ref expandfun, exp_span)) => {
222+
fld.cx.bt_push(ExpnInfo {
223+
call_site: *span,
224+
callee: NameAndSpan {
225+
name: extnamestr.get().to_string(),
226+
format: MacroBang,
227+
span: exp_span,
228+
},
229+
});
230+
let fm = fresh_mark();
231+
let marked_before = mark_tts(tts.as_slice(), fm);
232+
233+
// The span that we pass to the expanders we want to
234+
// be the root of the call stack. That's the most
235+
// relevant span and it's the actual invocation of
236+
// the macro.
237+
let mac_span = original_span(fld.cx);
238+
239+
let expanded = expandfun.expand(fld.cx,
240+
mac_span.call_site,
241+
marked_before.as_slice());
242+
let parsed = match parse_thunk(expanded) {
243+
Some(e) => e,
244+
None => {
245+
fld.cx.span_err(
246+
pth.span,
247+
format!("non-expression macro in expression position: {}",
248+
extnamestr.get().as_slice()
249+
).as_slice());
250+
return None;
251+
}
252+
};
253+
Some(mark_thunk(parsed,fm))
254+
}
255+
_ => {
256+
fld.cx.span_err(
257+
pth.span,
258+
format!("'{}' is not a tt-style macro",
259+
extnamestr.get()).as_slice());
260+
None
261+
}
262+
}
263+
}
264+
}
265+
}
266+
249267
/// Rename loop label and expand its loop body
250268
///
251269
/// The renaming procedure for loop is different in the sense that the loop
@@ -543,75 +561,27 @@ fn expand_item_mac(it: Gc<ast::Item>, fld: &mut MacroExpander)
543561
return items;
544562
}
545563

546-
// expand a stmt
564+
/// Expand a stmt
565+
//
566+
// I don't understand why this returns a vector... it looks like someone got
567+
// half done adding machinery to allow macros to expand into multiple statements.
547568
fn expand_stmt(s: &Stmt, fld: &mut MacroExpander) -> SmallVector<Gc<Stmt>> {
548-
// why the copying here and not in expand_expr?
549-
// looks like classic changed-in-only-one-place
550-
let (pth, tts, semi) = match s.node {
551-
StmtMac(ref mac, semi) => {
552-
match mac.node {
553-
MacInvocTT(ref pth, ref tts, _) => {
554-
(pth, (*tts).clone(), semi)
555-
}
556-
}
557-
}
569+
let (mac, semi) = match s.node {
570+
StmtMac(ref mac, semi) => (mac, semi),
558571
_ => return expand_non_macro_stmt(s, fld)
559572
};
560-
if pth.segments.len() > 1u {
561-
fld.cx.span_err(pth.span, "expected macro name without module separators");
562-
return SmallVector::zero();
563-
}
564-
let extname = pth.segments.get(0).identifier;
565-
let extnamestr = token::get_ident(extname);
566-
let marked_after = match fld.extsbox.find(&extname.name) {
573+
let expanded_stmt = match expand_mac_invoc(mac,s.span,
574+
|r|{r.make_stmt()},
575+
|sts,mrk|{mark_stmt(sts,mrk)},
576+
fld) {
577+
Some(stmt) => stmt,
567578
None => {
568-
fld.cx.span_err(pth.span,
569-
format!("macro undefined: '{}!'",
570-
extnamestr).as_slice());
571-
return SmallVector::zero();
572-
}
573-
574-
Some(&NormalTT(ref expandfun, exp_span)) => {
575-
fld.cx.bt_push(ExpnInfo {
576-
call_site: s.span,
577-
callee: NameAndSpan {
578-
name: extnamestr.get().to_string(),
579-
format: MacroBang,
580-
span: exp_span,
581-
}
582-
});
583-
let fm = fresh_mark();
584-
// mark before expansion:
585-
let marked_tts = mark_tts(tts.as_slice(), fm);
586-
587-
// See the comment in expand_expr for why we want the original span,
588-
// not the current mac.span.
589-
let mac_span = original_span(fld.cx);
590-
591-
let expanded = match expandfun.expand(fld.cx,
592-
mac_span.call_site,
593-
marked_tts.as_slice()).make_stmt() {
594-
Some(stmt) => stmt,
595-
None => {
596-
fld.cx.span_err(pth.span,
597-
format!("non-statement macro in statement position: {}",
598-
extnamestr).as_slice());
599-
return SmallVector::zero();
600-
}
601-
};
602-
603-
mark_stmt(&*expanded,fm)
604-
}
605-
606-
_ => {
607-
fld.cx.span_err(pth.span, format!("'{}' is not a tt-style macro",
608-
extnamestr).as_slice());
609579
return SmallVector::zero();
610580
}
611581
};
612582

613583
// Keep going, outside-in.
614-
let fully_expanded = fld.fold_stmt(&*marked_after);
584+
let fully_expanded = fld.fold_stmt(&*expanded_stmt);
615585
fld.cx.bt_pop();
616586
let fully_expanded: SmallVector<Gc<Stmt>> = fully_expanded.move_iter()
617587
.map(|s| box(GC) Spanned { span: s.span, node: s.node.clone() })

0 commit comments

Comments
 (0)