about summary refs log tree commit diff
path: root/src/libsyntax/ast_util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsyntax/ast_util.rs')
-rw-r--r--src/libsyntax/ast_util.rs134
1 files changed, 93 insertions, 41 deletions
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index bb6d13b2831..eaacb054ca1 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -15,6 +15,7 @@ use codemap::{span, spanned};
 use parse::token;
 use visit;
 use opt_vec;
+use core::hashmap::HashMap;
 
 use core::to_bytes;
 
@@ -577,22 +578,61 @@ pub enum Privacy {
 // HYGIENE FUNCTIONS
 
 /// Construct an identifier with the given repr and an empty context:
-pub fn mk_ident(repr: uint) -> ident { ident {repr: repr, ctxt: 0}}
+pub fn new_ident(repr: uint) -> ident { ident {repr: repr, ctxt: 0}}
 
 /// Extend a syntax context with a given mark
-pub fn mk_mark (m:Mrk,ctxt:SyntaxContext,table:&mut SCTable)
+pub fn new_mark (m:Mrk, tail:SyntaxContext,table:&mut SCTable)
     -> SyntaxContext {
-    idx_push(table,Mark(m,ctxt))
+    let key = (tail,m);
+    // FIXME #5074 : can't use more natural style because we're missing
+    // flow-sensitivity. Results in two lookups on a hash table hit.
+    // also applies to new_rename, below.
+    // let try_lookup = table.mark_memo.find(&key);
+    match table.mark_memo.contains_key(&key) {
+        false => {
+            let new_idx = idx_push(&mut table.table,Mark(m,tail));
+            table.mark_memo.insert(key,new_idx);
+            new_idx
+        }
+        true => {
+            match table.mark_memo.find(&key) {
+                None => fail!(~"internal error: key disappeared 2013042901"),
+                Some(idxptr) => {*idxptr}
+            }
+        }
+    }
 }
 
 /// Extend a syntax context with a given rename
-pub fn mk_rename (id:ident, to:Name, tail:SyntaxContext, table: &mut SCTable)
+pub fn new_rename (id:ident, to:Name, tail:SyntaxContext, table: &mut SCTable)
     -> SyntaxContext {
-    idx_push(table,Rename(id,to,tail))
+    let key = (tail,id,to);
+    // FIXME #5074
+    //let try_lookup = table.rename_memo.find(&key);
+    match table.rename_memo.contains_key(&key) {
+        false => {
+            let new_idx = idx_push(&mut table.table,Rename(id,to,tail));
+            table.rename_memo.insert(key,new_idx);
+            new_idx
+        }
+        true => {
+            match table.rename_memo.find(&key) {
+                None => fail!(~"internal error: key disappeared 2013042902"),
+                Some(idxptr) => {*idxptr}
+            }
+        }
+    }
 }
 
 /// Make a fresh syntax context table with EmptyCtxt in slot zero
-pub fn mk_sctable() -> SCTable { ~[EmptyCtxt] }
+/// and IllegalCtxt in slot one.
+pub fn new_sctable() -> SCTable {
+    SCTable {
+        table: ~[EmptyCtxt,IllegalCtxt],
+        mark_memo: HashMap::new(),
+        rename_memo: HashMap::new()
+    }
+}
 
 /// Add a value to the end of a vec, return its index
 fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
@@ -601,8 +641,8 @@ fn idx_push<T>(vec: &mut ~[T], val: T) -> uint {
 }
 
 /// Resolve a syntax object to a name, per MTWT.
-pub fn resolve (id : ident, table : &SCTable) -> Name {
-    match table[id.ctxt] {
+pub fn resolve (id : ident, table : &mut SCTable) -> Name {
+    match table.table[id.ctxt] {
         EmptyCtxt => id.repr,
         // ignore marks here:
         Mark(_,subctxt) => resolve (ident{repr:id.repr, ctxt: subctxt},table),
@@ -619,6 +659,7 @@ pub fn resolve (id : ident, table : &SCTable) -> Name {
                 resolvedthis
             }
         }
+        IllegalCtxt() => fail!(~"expected resolvable context, got IllegalCtxt")
     }
 }
 
@@ -629,7 +670,7 @@ pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
     let mut result = ~[];
     let mut loopvar = ctxt;
     loop {
-        match table[loopvar] {
+        match table.table[loopvar] {
             EmptyCtxt => {return result;},
             Mark(mark,tl) => {
                 xorPush(&mut result,mark);
@@ -644,6 +685,7 @@ pub fn marksof(ctxt: SyntaxContext, stopname: Name, table: &SCTable) -> ~[Mrk] {
                     loopvar = tl;
                 }
             }
+            IllegalCtxt => fail!(~"expected resolvable context, got IllegalCtxt")
         }
     }
 }
@@ -713,15 +755,15 @@ mod test {
         -> SyntaxContext {
         tscs.foldr(tail, |tsc : &TestSC,tail : SyntaxContext|
                   {match *tsc {
-                      M(mrk) => mk_mark(mrk,tail,table),
-                      R(ident,name) => mk_rename(ident,name,tail,table)}})
+                      M(mrk) => new_mark(mrk,tail,table),
+                      R(ident,name) => new_rename(ident,name,tail,table)}})
     }
 
     // gather a SyntaxContext back into a vector of TestSCs
     fn refold_test_sc(mut sc: SyntaxContext, table : &SCTable) -> ~[TestSC] {
         let mut result = ~[];
         loop {
-            match table[sc] {
+            match table.table[sc] {
                 EmptyCtxt => {return result;},
                 Mark(mrk,tail) => {
                     result.push(M(mrk));
@@ -733,40 +775,41 @@ mod test {
                     sc = tail;
                     loop;
                 }
+                IllegalCtxt => fail!("expected resolvable context, got IllegalCtxt")
             }
         }
     }
 
     #[test] fn test_unfold_refold(){
-        let mut t = mk_sctable();
+        let mut t = new_sctable();
 
         let test_sc = ~[M(3),R(id(101,0),14),M(9)];
-        assert_eq!(unfold_test_sc(copy test_sc,empty_ctxt,&mut t),3);
-        assert_eq!(t[1],Mark(9,0));
-        assert_eq!(t[2],Rename(id(101,0),14,1));
-        assert_eq!(t[3],Mark(3,2));
-        assert_eq!(refold_test_sc(3,&t),test_sc);
+        assert_eq!(unfold_test_sc(copy test_sc,empty_ctxt,&mut t),4);
+        assert_eq!(t.table[2],Mark(9,0));
+        assert_eq!(t.table[3],Rename(id(101,0),14,2));
+        assert_eq!(t.table[4],Mark(3,3));
+        assert_eq!(refold_test_sc(4,&t),test_sc);
     }
 
     // extend a syntax context with a sequence of marks given
     // in a vector. v[0] will be the outermost mark.
     fn unfold_marks(mrks:~[Mrk],tail:SyntaxContext,table: &mut SCTable) -> SyntaxContext {
         mrks.foldr(tail, |mrk:&Mrk,tail:SyntaxContext|
-                   {mk_mark(*mrk,tail,table)})
+                   {new_mark(*mrk,tail,table)})
     }
 
     #[test] fn unfold_marks_test() {
-        let mut t = ~[EmptyCtxt];
+        let mut t = new_sctable();
 
-        assert_eq!(unfold_marks(~[3,7],empty_ctxt,&mut t),2);
-        assert_eq!(t[1],Mark(7,0));
-        assert_eq!(t[2],Mark(3,1));
+        assert_eq!(unfold_marks(~[3,7],empty_ctxt,&mut t),3);
+        assert_eq!(t.table[2],Mark(7,0));
+        assert_eq!(t.table[3],Mark(3,2));
     }
 
     #[test] fn test_marksof () {
         let stopname = 242;
         let name1 = 243;
-        let mut t = mk_sctable();
+        let mut t = new_sctable();
         assert_eq!(marksof (empty_ctxt,stopname,&t),~[]);
         // FIXME #5074: ANF'd to dodge nested calls
         { let ans = unfold_marks(~[4,98],empty_ctxt,&mut t);
@@ -780,13 +823,13 @@ mod test {
         // rename where stop doesn't match:
         { let chain = ~[M(9),
                         R(id(name1,
-                             mk_mark (4, empty_ctxt,&mut t)),
+                             new_mark (4, empty_ctxt,&mut t)),
                           100101102),
                         M(14)];
          let ans = unfold_test_sc(chain,empty_ctxt,&mut t);
          assert_eq! (marksof (ans, stopname, &t), ~[9,14]);}
         // rename where stop does match
-        { let name1sc = mk_mark(4, empty_ctxt, &mut t);
+        { let name1sc = new_mark(4, empty_ctxt, &mut t);
          let chain = ~[M(9),
                        R(id(name1, name1sc),
                          stopname),
@@ -798,30 +841,30 @@ mod test {
 
     #[test] fn resolve_tests () {
         let a = 40;
-        let mut t = mk_sctable();
+        let mut t = new_sctable();
         // - ctxt is MT
-        assert_eq!(resolve(id(a,empty_ctxt),&t),a);
+        assert_eq!(resolve(id(a,empty_ctxt),&mut t),a);
         // - simple ignored marks
         { let sc = unfold_marks(~[1,2,3],empty_ctxt,&mut t);
-         assert_eq!(resolve(id(a,sc),&t),a);}
+         assert_eq!(resolve(id(a,sc),&mut t),a);}
         // - orthogonal rename where names don't match
         { let sc = unfold_test_sc(~[R(id(50,empty_ctxt),51),M(12)],empty_ctxt,&mut t);
-         assert_eq!(resolve(id(a,sc),&t),a);}
+         assert_eq!(resolve(id(a,sc),&mut t),a);}
         // - rename where names do match, but marks don't
-        { let sc1 = mk_mark(1,empty_ctxt,&mut t);
+        { let sc1 = new_mark(1,empty_ctxt,&mut t);
          let sc = unfold_test_sc(~[R(id(a,sc1),50),
                                    M(1),
                                    M(2)],
                                  empty_ctxt,&mut t);
-        assert_eq!(resolve(id(a,sc),&t), a);}
+        assert_eq!(resolve(id(a,sc),&mut t), a);}
         // - rename where names and marks match
         { let sc1 = unfold_test_sc(~[M(1),M(2)],empty_ctxt,&mut t);
          let sc = unfold_test_sc(~[R(id(a,sc1),50),M(1),M(2)],empty_ctxt,&mut t);
-         assert_eq!(resolve(id(a,sc),&t), 50); }
+         assert_eq!(resolve(id(a,sc),&mut t), 50); }
         // - rename where names and marks match by literal sharing
         { let sc1 = unfold_test_sc(~[M(1),M(2)],empty_ctxt,&mut t);
          let sc = unfold_test_sc(~[R(id(a,sc1),50)],sc1,&mut t);
-         assert_eq!(resolve(id(a,sc),&t), 50); }
+         assert_eq!(resolve(id(a,sc),&mut t), 50); }
         // - two renames of the same var.. can only happen if you use
         // local-expand to prevent the inner binding from being renamed
         // during the rename-pass caused by the first:
@@ -829,20 +872,29 @@ mod test {
         { let sc = unfold_test_sc(~[R(id(a,empty_ctxt),50),
                                     R(id(a,empty_ctxt),51)],
                                   empty_ctxt,&mut t);
-         assert_eq!(resolve(id(a,sc),&t), 51); }
+         assert_eq!(resolve(id(a,sc),&mut t), 51); }
         // the simplest double-rename:
-        { let a_to_a50 = mk_rename(id(a,empty_ctxt),50,empty_ctxt,&mut t);
-         let a50_to_a51 = mk_rename(id(a,a_to_a50),51,a_to_a50,&mut t);
-         assert_eq!(resolve(id(a,a50_to_a51),&t),51);
+        { let a_to_a50 = new_rename(id(a,empty_ctxt),50,empty_ctxt,&mut t);
+         let a50_to_a51 = new_rename(id(a,a_to_a50),51,a_to_a50,&mut t);
+         assert_eq!(resolve(id(a,a50_to_a51),&mut t),51);
          // mark on the outside doesn't stop rename:
-         let sc = mk_mark(9,a50_to_a51,&mut t);
-         assert_eq!(resolve(id(a,sc),&t),51);
+         let sc = new_mark(9,a50_to_a51,&mut t);
+         assert_eq!(resolve(id(a,sc),&mut t),51);
          // but mark on the inside does:
          let a50_to_a51_b = unfold_test_sc(~[R(id(a,a_to_a50),51),
                                               M(9)],
                                            a_to_a50,
                                            &mut t);
-         assert_eq!(resolve(id(a,a50_to_a51_b),&t),50);}
+         assert_eq!(resolve(id(a,a50_to_a51_b),&mut t),50);}
+    }
+
+    #[test] fn hashing_tests () {
+        let mut t = new_sctable();
+        assert_eq!(new_mark(12,empty_ctxt,&mut t),2);
+        assert_eq!(new_mark(13,empty_ctxt,&mut t),3);
+        // using the same one again should result in the same index:
+        assert_eq!(new_mark(12,empty_ctxt,&mut t),2);
+        // I'm assuming that the rename table will behave the same....
     }
 
 }