about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorChristopher Chambers <chris.chambers@peanutcode.com>2015-04-10 21:50:23 -0500
committerChristopher Chambers <chris.chambers@peanutcode.com>2015-04-10 21:50:23 -0500
commitb16cfacbccee272ed8a30aec1f5c25e9f845d1a8 (patch)
tree47cefbeacca81d789e8462d3ce82f787fbd13edb /src/libsyntax
parent19343860aa44d1c31a7802df22349f055ed9da16 (diff)
downloadrust-b16cfacbccee272ed8a30aec1f5c25e9f845d1a8.tar.gz
rust-b16cfacbccee272ed8a30aec1f5c25e9f845d1a8.zip
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.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/expand.rs31
-rw-r--r--src/libsyntax/util/small_vector.rs36
2 files changed, 51 insertions, 16 deletions
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b6d1810a3f7..9c1b32aadbd 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -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
diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs
index 1649934f4b1..c4b096d656f 100644
--- a/src/libsyntax/util/small_vector.rs
+++ b/src/libsyntax/util/small_vector.rs
@@ -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),