Improves semicolon expansion efficiency, corrects bt_pop placement.

Implements pop() on SmallVector, and uses it to expand the final semicolon
in a statement macro expansion more efficiently.

Corrects the placement of the call to fld.cx.bt_pop().  It must run
unconditionally to reverse the corresponding push.
This commit is contained in:
Christopher Chambers 2015-04-10 21:50:23 -05:00
parent 19343860aa
commit b16cfacbcc
2 changed files with 51 additions and 16 deletions

View File

@ -758,25 +758,23 @@ fn expand_stmt(stmt: P<Stmt>, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
|stmts, mark| stmts.move_map(|m| mark_stmt(m, mark)),
fld);
let fully_expanded = match maybe_new_items {
let mut fully_expanded = match maybe_new_items {
Some(stmts) => {
// Keep going, outside-in.
let new_items = stmts.into_iter().flat_map(|s| {
stmts.into_iter().flat_map(|s| {
fld.fold_stmt(s).into_iter()
}).collect();
fld.cx.bt_pop();
new_items
}).collect()
}
None => SmallVector::zero()
};
fld.cx.bt_pop();
// If this is a macro invocation with a semicolon, then apply that
// semicolon to the final statement produced by expansion.
if style == MacStmtWithSemicolon && fully_expanded.len() > 0 {
let last_index = fully_expanded.len() - 1;
fully_expanded.into_iter().enumerate().map(|(i, stmt)|
if i == last_index {
stmt.map(|Spanned {node, span}| {
if style == MacStmtWithSemicolon && !fully_expanded.is_empty() {
match fully_expanded.pop() {
Some(stmt) => {
let new_stmt = stmt.map(|Spanned {node, span}| {
Spanned {
node: match node {
StmtExpr(e, stmt_id) => StmtSemi(e, stmt_id),
@ -784,13 +782,14 @@ fn expand_stmt(stmt: P<Stmt>, fld: &mut MacroExpander) -> SmallVector<P<Stmt>> {
},
span: span
}
})
} else {
stmt
}).collect()
} else {
fully_expanded
});
fully_expanded.push(new_stmt);
}
None => (),
}
}
fully_expanded
}
// expand a non-macro stmt. this is essentially the fallthrough for

View File

@ -69,6 +69,42 @@ impl<T> SmallVector<T> {
}
}
pub fn pop(&mut self) -> Option<T> {
match self.repr {
Zero => None,
One(..) => {
let one = mem::replace(&mut self.repr, Zero);
match one {
One(v1) => Some(v1),
_ => unreachable!()
}
}
Many(..) => {
let mut many = mem::replace(&mut self.repr, Zero);
let item =
match many {
Many(ref mut vs) if vs.len() == 1 => {
// self.repr is already Zero
vs.pop()
},
Many(ref mut vs) if vs.len() == 2 => {
let item = vs.pop();
mem::replace(&mut self.repr, One(vs.pop().unwrap()));
item
},
Many(ref mut vs) if vs.len() > 2 => {
let item = vs.pop();
let rest = mem::replace(vs, vec!());
mem::replace(&mut self.repr, Many(rest));
item
},
_ => unreachable!()
};
item
}
}
}
pub fn push(&mut self, v: T) {
match self.repr {
Zero => self.repr = One(v),