(index<- )        ./libsyntax/ext/mtwt.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
   1  // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
   2  // file at the top-level directory of this distribution and at
   3  // http://rust-lang.org/COPYRIGHT.
   4  //
   5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
   6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
   7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
   8  // option. This file may not be copied, modified, or distributed
   9  // except according to those terms.
  10  
  11  //! Machinery for hygienic macros, as described in the MTWT[1] paper.
  12  //!
  13  //! [1] Matthew Flatt, Ryan Culpepper, David Darais, and Robert Bruce Findler.
  14  //! 2012. *Macros that work together: Compile-time bindings, partial expansion,
  15  //! and definition contexts*. J. Funct. Program. 22, 2 (March 2012), 181-216.
  16  //! DOI=10.1017/S0956796812000093 http://dx.doi.org/10.1017/S0956796812000093
  17  
  18  use ast::{Ident, Mrk, Name, SyntaxContext};
  19  
  20  use std::cell::RefCell;
  21  use std::rc::Rc;
  22  
  23  use collections::HashMap;
  24  
  25  // the SCTable contains a table of SyntaxContext_'s. It
  26  // represents a flattened tree structure, to avoid having
  27  // managed pointers everywhere (that caused an ICE).
  28  // the mark_memo and rename_memo fields are side-tables
  29  // that ensure that adding the same mark to the same context
  30  // gives you back the same context as before. This shouldn't
  31  // change the semantics--everything here is immutable--but
  32  // it should cut down on memory use *a lot*; applying a mark
  33  // to a tree containing 50 identifiers would otherwise generate
  34  pub struct SCTable {
  35      table: RefCell<Vec<SyntaxContext_>>,
  36      mark_memo: RefCell<HashMap<(SyntaxContext,Mrk),SyntaxContext>>,
  37      rename_memo: RefCell<HashMap<(SyntaxContext,Ident,Name),SyntaxContext>>,
  38  }
  39  
  40  #[deriving(Eq, Encodable, Decodable, Hash)]
  41  pub enum SyntaxContext_ {
  42      EmptyCtxt,
  43      Mark (Mrk,SyntaxContext),
  44      // flattening the name and syntaxcontext into the rename...
  45      // HIDDEN INVARIANTS:
  46      // 1) the first name in a Rename node
  47      // can only be a programmer-supplied name.
  48      // 2) Every Rename node with a given Name in the
  49      // "to" slot must have the same name and context
  50      // in the "from" slot. In essence, they're all
  51      // pointers to a single "rename" event node.
  52      Rename (Ident,Name,SyntaxContext),
  53      // actually, IllegalCtxt may not be necessary.
  54      IllegalCtxt
  55  }
  56  
  57  /// Extend a syntax context with a given mark
  58  pub fn new_mark(mMrk, tailSyntaxContext) -> SyntaxContext {
  59      with_sctable(|table| new_mark_internal(m, tail, table))
  60  }
  61  
  62  // Extend a syntax context with a given mark and table
  63  fn new_mark_internal(mMrk, tailSyntaxContext, table: &SCTable) -> SyntaxContext {
  64      let key = (tail, m);
  65      let new_ctxt = |_&(SyntaxContext, Mrk)|
  66                     idx_push(&mut *table.table.borrow_mut(), Mark(m, tail));
  67  
  68      *table.mark_memo.borrow_mut().find_or_insert_with(key, new_ctxt)
  69  }
  70  
  71  /// Extend a syntax context with a given rename
  72  pub fn new_rename(idIdent, to:Name,
  73                    tailSyntaxContext) -> SyntaxContext {
  74      with_sctable(|table| new_rename_internal(id, to, tail, table))
  75  }
  76  
  77  // Extend a syntax context with a given rename and sctable
  78  fn new_rename_internal(idIdent,
  79                         toName,
  80                         tailSyntaxContext,
  81                         table: &SCTable) -> SyntaxContext {
  82      let key = (tail,id,to);
  83      let new_ctxt = |_&(SyntaxContext, Ident, Mrk)|
  84                     idx_push(&mut *table.table.borrow_mut(), Rename(id, to, tail));
  85  
  86      *table.rename_memo.borrow_mut().find_or_insert_with(key, new_ctxt)
  87  }
  88  
  89  /// Fetch the SCTable from TLS, create one if it doesn't yet exist.
  90  pub fn with_sctable<T>(op: |&SCTable-> T) -> T {
  91      local_data_key!(sctable_key: Rc<SCTable>)
  92  
  93      match sctable_key.get() {
  94          Some(ts) => op(&**ts),
  95          None => {
  96              let ts = Rc::new(new_sctable_internal());
  97              sctable_key.replace(Some(ts.clone()));
  98              op(&*ts)
  99          }
 100      }
 101  }
 102  
 103  // Make a fresh syntax context table with EmptyCtxt in slot zero
 104  // and IllegalCtxt in slot one.
 105  fn new_sctable_internal() -> SCTable {
 106      SCTable {
 107          table: RefCell::new(vec!(EmptyCtxt, IllegalCtxt)),
 108          mark_memo: RefCell::new(HashMap::new()),
 109          rename_memo: RefCell::new(HashMap::new()),
 110      }
 111  }
 112  
 113  /// Print out an SCTable for debugging
 114  pub fn display_sctable(table: &SCTable) {
 115      error!("SC table:");
 116      for (idx,val) in table.table.borrow().iter().enumerate() {
 117          error!("{:4u} : {:?}",idx,val);
 118      }
 119  }
 120  
 121  /// Clear the tables from TLD to reclaim memory.
 122  pub fn clear_tables() {
 123      with_sctable(|table| {
 124          *table.table.borrow_mut() = Vec::new();
 125          *table.mark_memo.borrow_mut() = HashMap::new();
 126          *table.rename_memo.borrow_mut() = HashMap::new();
 127      });
 128      with_resolve_table_mut(|table| *table = HashMap::new());
 129  }
 130  
 131  // Add a value to the end of a vec, return its index
 132  fn idx_push<T>(vec: &mut Vec<T> , valT) -> u32 {
 133      vec.push(val);
 134      (vec.len() - 1) as u32
 135  }
 136  
 137  /// Resolve a syntax object to a name, per MTWT.
 138  pub fn resolve(idIdent) -> Name {
 139      with_sctable(|sctable| {
 140          with_resolve_table_mut(|resolve_table| {
 141              resolve_internal(id, sctable, resolve_table)
 142          })
 143      })
 144  }
 145  
 146  type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
 147  
 148  // okay, I admit, putting this in TLS is not so nice:
 149  // fetch the SCTable from TLS, create one if it doesn't yet exist.
 150  fn with_resolve_table_mut<T>(op: |&mut ResolveTable-> T) -> T {
 151      local_data_key!(resolve_table_key: Rc<RefCell<ResolveTable>>)
 152  
 153      match resolve_table_key.get() {
 154          Some(ts) => op(&mut *ts.borrow_mut()),
 155          None => {
 156              let ts = Rc::new(RefCell::new(HashMap::new()));
 157              resolve_table_key.replace(Some(ts.clone()));
 158              op(&mut *ts.borrow_mut())
 159          }
 160      }
 161  }
 162  
 163  // Resolve a syntax object to a name, per MTWT.
 164  // adding memorization to possibly resolve 500+ seconds in resolve for librustc (!)
 165  fn resolve_internal(idIdent,
 166                      table: &SCTable,
 167                      resolve_table: &mut ResolveTable) -> Name {
 168      let key = (id.name, id.ctxt);
 169  
 170      match resolve_table.find(&key) {
 171          Some(&name) => return name,
 172          None => {}
 173      }
 174  
 175      let resolved = {
 176          let result = *table.table.borrow().get(id.ctxt as uint);
 177          match result {
 178              EmptyCtxt => id.name,
 179              // ignore marks here:
 180              Mark(_,subctxt) =>
 181                  resolve_internal(Ident{name:id.name, ctxt: subctxt},
 182                                   table, resolve_table),
 183              // do the rename if necessary:
 184              Rename(Ident{name, ctxt}, toname, subctxt) => {
 185                  let resolvedfrom =
 186                      resolve_internal(Ident{name:name, ctxt:ctxt},
 187                                       table, resolve_table);
 188                  let resolvedthis =
 189                      resolve_internal(Ident{name:id.name, ctxt:subctxt},
 190                                       table, resolve_table);
 191                  if (resolvedthis == resolvedfrom)
 192                      && (marksof_internal(ctxt, resolvedthis, table)
 193                          == marksof_internal(subctxt, resolvedthis, table)) {
 194                      toname
 195                  } else {
 196                      resolvedthis
 197                  }
 198              }
 199              IllegalCtxt => fail!("expected resolvable context, got IllegalCtxt")
 200          }
 201      };
 202      resolve_table.insert(key, resolved);
 203      resolved
 204  }
 205  
 206  /// Compute the marks associated with a syntax context.
 207  pub fn marksof(ctxtSyntaxContext, stopnameName) -> Vec<Mrk> {
 208      with_sctable(|table| marksof_internal(ctxt, stopname, table))
 209  }
 210  
 211  // the internal function for computing marks
 212  // it's not clear to me whether it's better to use a [] mutable
 213  // vector or a cons-list for this.
 214  fn marksof_internal(ctxtSyntaxContext,
 215                      stopnameName,
 216                      table: &SCTable) -> Vec<Mrk> {
 217      let mut result = Vec::new();
 218      let mut loopvar = ctxt;
 219      loop {
 220          let table_entry = *table.table.borrow().get(loopvar as uint);
 221          match table_entry {
 222              EmptyCtxt => {
 223                  return result;
 224              },
 225              Mark(mark, tl) => {
 226                  xorPush(&mut result, mark);
 227                  loopvar = tl;
 228              },
 229              Rename(_,name,tl) => {
 230                  // see MTWT for details on the purpose of the stopname.
 231                  // short version: it prevents duplication of effort.
 232                  if name == stopname {
 233                      return result;
 234                  } else {
 235                      loopvar = tl;
 236                  }
 237              }
 238              IllegalCtxt => fail!("expected resolvable context, got IllegalCtxt")
 239          }
 240      }
 241  }
 242  
 243  /// Return the outer mark for a context with a mark at the outside.
 244  /// FAILS when outside is not a mark.
 245  pub fn outer_mark(ctxtSyntaxContext) -> Mrk {
 246      with_sctable(|sctable| {
 247          match *sctable.table.borrow().get(ctxt as uint) {
 248              Mark(mrk, _) => mrk,
 249              _ => fail!("can't retrieve outer mark when outside is not a mark")
 250          }
 251      })
 252  }
 253  
 254  // Push a name... unless it matches the one on top, in which
 255  // case pop and discard (so two of the same marks cancel)
 256  fn xorPush(marks: &mut Vec<Mrk>, markMrk) {
 257      if (marks.len() > 0) && (*marks.last().unwrap() == mark) {
 258          marks.pop().unwrap();
 259      } else {
 260          marks.push(mark);
 261      }
 262  }
 263  
 264  #[cfg(test)]
 265  mod tests {
 266      use ast::*;
 267      use super::{resolve, xorPush, new_mark_internal, new_sctable_internal};
 268      use super::{new_rename_internal, marksof_internal, resolve_internal};
 269      use super::{SCTable, EmptyCtxt, Mark, Rename, IllegalCtxt};
 270      use collections::HashMap;
 271  
 272      #[test] fn xorpush_test () {
 273          let mut s = Vec::new();
 274          xorPush(&mut s, 14);
 275          assert_eq!(s.clone(), vec!(14));
 276          xorPush(&mut s, 14);
 277          assert_eq!(s.clone(), Vec::new());
 278          xorPush(&mut s, 14);
 279          assert_eq!(s.clone(), vec!(14));
 280          xorPush(&mut s, 15);
 281          assert_eq!(s.clone(), vec!(14, 15));
 282          xorPush(&mut s, 16);
 283          assert_eq!(s.clone(), vec!(14, 15, 16));
 284          xorPush(&mut s, 16);
 285          assert_eq!(s.clone(), vec!(14, 15));
 286          xorPush(&mut s, 15);
 287          assert_eq!(s.clone(), vec!(14));
 288      }
 289  
 290      fn id(n: Name, s: SyntaxContext) -> Ident {
 291          Ident {name: n, ctxt: s}
 292      }
 293  
 294      // because of the SCTable, I now need a tidy way of
 295      // creating syntax objects. Sigh.
 296      #[deriving(Clone, Eq, Show)]
 297      enum TestSC {
 298          M(Mrk),
 299          R(Ident,Name)
 300      }
 301  
 302      // unfold a vector of TestSC values into a SCTable,
 303      // returning the resulting index
 304      fn unfold_test_sc(tscs : Vec<TestSC> , tail: SyntaxContext, table: &SCTable)
 305          -> SyntaxContext {
 306          tscs.iter().rev().fold(tail, |tail : SyntaxContext, tsc : &TestSC|
 307                    {match *tsc {
 308                        M(mrk) => new_mark_internal(mrk,tail,table),
 309                        R(ident,name) => new_rename_internal(ident,name,tail,table)}})
 310      }
 311  
 312      // gather a SyntaxContext back into a vector of TestSCs
 313      fn refold_test_sc(mut sc: SyntaxContext, table : &SCTable) -> Vec<TestSC> {
 314          let mut result = Vec::new();
 315          loop {
 316              let table = table.table.borrow();
 317              match *table.get(sc as uint) {
 318                  EmptyCtxt => {return result;},
 319                  Mark(mrk,tail) => {
 320                      result.push(M(mrk));
 321                      sc = tail;
 322                      continue;
 323                  },
 324                  Rename(id,name,tail) => {
 325                      result.push(R(id,name));
 326                      sc = tail;
 327                      continue;
 328                  }
 329                  IllegalCtxt => fail!("expected resolvable context, got IllegalCtxt")
 330              }
 331          }
 332      }
 333  
 334      #[test] fn test_unfold_refold(){
 335          let mut t = new_sctable_internal();
 336  
 337          let test_sc = vec!(M(3),R(id(101,0),14),M(9));
 338          assert_eq!(unfold_test_sc(test_sc.clone(),EMPTY_CTXT,&mut t),4);
 339          {
 340              let table = t.table.borrow();
 341              assert!(*table.get(2) == Mark(9,0));
 342              assert!(*table.get(3) == Rename(id(101,0),14,2));
 343              assert!(*table.get(4) == Mark(3,3));
 344          }
 345          assert_eq!(refold_test_sc(4,&t),test_sc);
 346      }
 347  
 348      // extend a syntax context with a sequence of marks given
 349      // in a vector. v[0] will be the outermost mark.
 350      fn unfold_marks(mrks: Vec<Mrk> , tail: SyntaxContext, table: &SCTable)
 351                      -> SyntaxContext {
 352          mrks.iter().rev().fold(tail, |tail:SyntaxContext, mrk:&Mrk|
 353                     {new_mark_internal(*mrk,tail,table)})
 354      }
 355  
 356      #[test] fn unfold_marks_test() {
 357          let mut t = new_sctable_internal();
 358  
 359          assert_eq!(unfold_marks(vec!(3,7),EMPTY_CTXT,&mut t),3);
 360          {
 361              let table = t.table.borrow();
 362              assert!(*table.get(2) == Mark(7,0));
 363              assert!(*table.get(3) == Mark(3,2));
 364          }
 365      }
 366  
 367      #[test] fn test_marksof () {
 368          let stopname = 242;
 369          let name1 = 243;
 370          let mut t = new_sctable_internal();
 371          assert_eq!(marksof_internal (EMPTY_CTXT,stopname,&t),Vec::new());
 372          // FIXME #5074: ANF'd to dodge nested calls
 373          { let ans = unfold_marks(vec!(4,98),EMPTY_CTXT,&mut t);
 374           assert_eq! (marksof_internal (ans,stopname,&t),vec!(4,98));}
 375          // does xoring work?
 376          { let ans = unfold_marks(vec!(5,5,16),EMPTY_CTXT,&mut t);
 377           assert_eq! (marksof_internal (ans,stopname,&t), vec!(16));}
 378          // does nested xoring work?
 379          { let ans = unfold_marks(vec!(5,10,10,5,16),EMPTY_CTXT,&mut t);
 380           assert_eq! (marksof_internal (ans, stopname,&t), vec!(16));}
 381          // rename where stop doesn't match:
 382          { let chain = vec!(M(9),
 383                          R(id(name1,
 384                               new_mark_internal (4, EMPTY_CTXT,&mut t)),
 385                            100101102),
 386                          M(14));
 387           let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
 388           assert_eq! (marksof_internal (ans, stopname, &t), vec!(9,14));}
 389          // rename where stop does match
 390          { let name1sc = new_mark_internal(4, EMPTY_CTXT, &mut t);
 391           let chain = vec!(M(9),
 392                         R(id(name1, name1sc),
 393                           stopname),
 394                         M(14));
 395           let ans = unfold_test_sc(chain,EMPTY_CTXT,&mut t);
 396           assert_eq! (marksof_internal (ans, stopname, &t), vec!(9)); }
 397      }
 398  
 399  
 400      #[test] fn resolve_tests () {
 401          let a = 40;
 402          let mut t = new_sctable_internal();
 403          let mut rt = HashMap::new();
 404          // - ctxt is MT
 405          assert_eq!(resolve_internal(id(a,EMPTY_CTXT),&mut t, &mut rt),a);
 406          // - simple ignored marks
 407          { let sc = unfold_marks(vec!(1,2,3),EMPTY_CTXT,&mut t);
 408           assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
 409          // - orthogonal rename where names don't match
 410          { let sc = unfold_test_sc(vec!(R(id(50,EMPTY_CTXT),51),M(12)),EMPTY_CTXT,&mut t);
 411           assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),a);}
 412          // - rename where names do match, but marks don't
 413          { let sc1 = new_mark_internal(1,EMPTY_CTXT,&mut t);
 414           let sc = unfold_test_sc(vec!(R(id(a,sc1),50),
 415                                     M(1),
 416                                     M(2)),
 417                                   EMPTY_CTXT,&mut t);
 418          assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), a);}
 419          // - rename where names and marks match
 420          { let sc1 = unfold_test_sc(vec!(M(1),M(2)),EMPTY_CTXT,&mut t);
 421           let sc = unfold_test_sc(vec!(R(id(a,sc1),50),M(1),M(2)),EMPTY_CTXT,&mut t);
 422           assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
 423          // - rename where names and marks match by literal sharing
 424          { let sc1 = unfold_test_sc(vec!(M(1),M(2)),EMPTY_CTXT,&mut t);
 425           let sc = unfold_test_sc(vec!(R(id(a,sc1),50)),sc1,&mut t);
 426           assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 50); }
 427          // - two renames of the same var.. can only happen if you use
 428          // local-expand to prevent the inner binding from being renamed
 429          // during the rename-pass caused by the first:
 430          println!("about to run bad test");
 431          { let sc = unfold_test_sc(vec!(R(id(a,EMPTY_CTXT),50),
 432                                      R(id(a,EMPTY_CTXT),51)),
 433                                    EMPTY_CTXT,&mut t);
 434           assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt), 51); }
 435          // the simplest double-rename:
 436          { let a_to_a50 = new_rename_internal(id(a,EMPTY_CTXT),50,EMPTY_CTXT,&mut t);
 437           let a50_to_a51 = new_rename_internal(id(a,a_to_a50),51,a_to_a50,&mut t);
 438           assert_eq!(resolve_internal(id(a,a50_to_a51),&mut t, &mut rt),51);
 439           // mark on the outside doesn't stop rename:
 440           let sc = new_mark_internal(9,a50_to_a51,&mut t);
 441           assert_eq!(resolve_internal(id(a,sc),&mut t, &mut rt),51);
 442           // but mark on the inside does:
 443           let a50_to_a51_b = unfold_test_sc(vec!(R(id(a,a_to_a50),51),
 444                                                M(9)),
 445                                             a_to_a50,
 446                                             &mut t);
 447           assert_eq!(resolve_internal(id(a,a50_to_a51_b),&mut t, &mut rt),50);}
 448      }
 449  
 450      #[test] fn mtwt_resolve_test(){
 451          let a = 40;
 452          assert_eq!(resolve(id(a,EMPTY_CTXT)),a);
 453      }
 454  
 455  
 456      #[test] fn hashing_tests () {
 457          let mut t = new_sctable_internal();
 458          assert_eq!(new_mark_internal(12,EMPTY_CTXT,&mut t),2);
 459          assert_eq!(new_mark_internal(13,EMPTY_CTXT,&mut t),3);
 460          // using the same one again should result in the same index:
 461          assert_eq!(new_mark_internal(12,EMPTY_CTXT,&mut t),2);
 462          // I'm assuming that the rename table will behave the same....
 463      }
 464  
 465      #[test] fn resolve_table_hashing_tests() {
 466          let mut t = new_sctable_internal();
 467          let mut rt = HashMap::new();
 468          assert_eq!(rt.len(),0);
 469          resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
 470          assert_eq!(rt.len(),1);
 471          resolve_internal(id(39,EMPTY_CTXT),&mut t, &mut rt);
 472          assert_eq!(rt.len(),2);
 473          resolve_internal(id(30,EMPTY_CTXT),&mut t, &mut rt);
 474          assert_eq!(rt.len(),2);
 475      }
 476  }


libsyntax/ext/mtwt.rs:89:68-89:68 -fn- definition:
/// Fetch the SCTable from TLS, create one if it doesn't yet exist.
pub fn with_sctable<T>(op: |&SCTable| -> T) -> T {
    local_data_key!(sctable_key: Rc<SCTable>)
references:- 6
138: pub fn resolve(id: Ident) -> Name {
139:     with_sctable(|sctable| {
140:         with_resolve_table_mut(|resolve_table| {
--
245: pub fn outer_mark(ctxt: SyntaxContext) -> Mrk {
246:     with_sctable(|sctable| {
247:         match *sctable.table.borrow().get(ctxt as uint) {


libsyntax/ext/mtwt.rs:33:64-33:64 -struct- definition:
// to a tree containing 50 identifiers would otherwise generate
pub struct SCTable {
    table: RefCell<Vec<SyntaxContext_>>,
references:- 9
113: /// Print out an SCTable for debugging
114: pub fn display_sctable(table: &SCTable) {
115:     error!("SC table:");
--
215:                     stopname: Name,
216:                     table: &SCTable) -> Vec<Mrk> {
217:     let mut result = Vec::new();


libsyntax/ext/mtwt.rs:131:53-131:53 -fn- definition:
// Add a value to the end of a vec, return its index
fn idx_push<T>(vec: &mut Vec<T> , val: T) -> u32 {
    vec.push(val);
references:- 2
83:     let new_ctxt = |_: &(SyntaxContext, Ident, Mrk)|
84:                    idx_push(&mut *table.table.borrow_mut(), Rename(id, to, tail));


libsyntax/ext/mtwt.rs:164:84-164:84 -fn- definition:
// adding memorization to possibly resolve 500+ seconds in resolve for librustc (!)
fn resolve_internal(id: Ident,
                    table: &SCTable,
references:- 4
188:                 let resolvedthis =
189:                     resolve_internal(Ident{name:id.name, ctxt:subctxt},
190:                                      table, resolve_table);


libsyntax/ext/mtwt.rs:57:46-57:46 -fn- definition:
/// Extend a syntax context with a given mark
pub fn new_mark(m: Mrk, tail: SyntaxContext) -> SyntaxContext {
    with_sctable(|table| new_mark_internal(m, tail, table))
references:- 2
libsyntax/ext/expand.rs:
907:                            fold_tts(tts.as_slice(), self),
908:                            mtwt::new_mark(self.mark, ctxt))
909:             }


libsyntax/ext/mtwt.rs:145:1-145:1 -NK_AS_STR_TODO- definition:
type ResolveTable = HashMap<(Name,SyntaxContext),Name>;
// okay, I admit, putting this in TLS is not so nice:
// fetch the SCTable from TLS, create one if it doesn't yet exist.
references:- 3
150: fn with_resolve_table_mut<T>(op: |&mut ResolveTable| -> T) -> T {
151:     local_data_key!(resolve_table_key: Rc<RefCell<ResolveTable>>)
--
166:                     table: &SCTable,
167:                     resolve_table: &mut ResolveTable) -> Name {
168:     let key = (id.name, id.ctxt);


libsyntax/ext/mtwt.rs:137:49-137:49 -fn- definition:
/// Resolve a syntax object to a name, per MTWT.
pub fn resolve(id: Ident) -> Name {
    with_sctable(|sctable| {
references:- 2
libsyntax/parse/token.rs:
723:         (&IDENT(id1,_),&IDENT(id2,_)) | (&LIFETIME(id1),&LIFETIME(id2)) =>
724:             mtwt::resolve(id1) == mtwt::resolve(id2),
725:         _ => *t1 == *t2


libsyntax/ext/mtwt.rs:40:44-40:44 -enum- definition:
pub enum SyntaxContext_ {
    EmptyCtxt,
    Mark (Mrk,SyntaxContext),
references:- 8
41: pub enum SyntaxContext_ {


libsyntax/ext/mtwt.rs:213:35-213:35 -fn- definition:
// vector or a cons-list for this.
fn marksof_internal(ctxt: SyntaxContext,
                    stopname: Name,
references:- 3
191:                 if (resolvedthis == resolvedfrom)
192:                     && (marksof_internal(ctxt, resolvedthis, table)
193:                         == marksof_internal(subctxt, resolvedthis, table)) {
--
207: pub fn marksof(ctxt: SyntaxContext, stopname: Name) -> Vec<Mrk> {
208:     with_sctable(|table| marksof_internal(ctxt, stopname, table))
209: }


libsyntax/ext/mtwt.rs:149:67-149:67 -fn- definition:
// fetch the SCTable from TLS, create one if it doesn't yet exist.
fn with_resolve_table_mut<T>(op: |&mut ResolveTable| -> T) -> T {
    local_data_key!(resolve_table_key: Rc<RefCell<ResolveTable>>)
references:- 2
139:     with_sctable(|sctable| {
140:         with_resolve_table_mut(|resolve_table| {
141:             resolve_internal(id, sctable, resolve_table)