use tokenstream;
use serialize::{Decodable, Decoder, Encodable, Encoder};
+use std::cell::RefCell;
use std::fmt;
use std::ops::Deref;
use std::rc::Rc;
// if an interner exists in TLS, return it. Otherwise, prepare a
// fresh one.
// FIXME(eddyb) #8726 This should probably use a thread-local reference.
-pub fn with_ident_interner<T, F: FnOnce(&IdentInterner) -> T>(f: F) -> T {
- thread_local!(static KEY: IdentInterner = {
- mk_fresh_ident_interner()
+pub fn with_ident_interner<T, F: FnOnce(&mut IdentInterner) -> T>(f: F) -> T {
+ thread_local!(static KEY: RefCell<IdentInterner> = {
+ RefCell::new(mk_fresh_ident_interner())
});
- KEY.with(f)
+ KEY.with(|interner| f(&mut *interner.borrow_mut()))
}
/// Reset the ident interner to its initial state.
pub fn reset_ident_interner() {
- with_ident_interner(|interner| interner.reset(mk_fresh_ident_interner()));
+ with_ident_interner(|interner| *interner = mk_fresh_ident_interner());
}
pub fn clear_ident_interner() {
- with_ident_interner(|interner| interner.clear());
+ with_ident_interner(|interner| *interner = IdentInterner::new());
}
/// Represents a string stored in the thread-local interner. Because the
use ast::Name;
use std::borrow::Borrow;
-use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
}
}
+#[derive(Default)]
pub struct Interner {
- map: RefCell<HashMap<RcStr, Name>>,
- vect: RefCell<Vec<Rc<String>> >,
+ names: HashMap<RcStr, Name>,
+ strings: Vec<Rc<String>>,
}
/// When traits can extend traits, we should extend index<Name,T> to get []
impl Interner {
pub fn new() -> Self {
- Interner {
- map: RefCell::new(HashMap::new()),
- vect: RefCell::new(Vec::new()),
- }
+ Interner::default()
}
pub fn prefill(init: &[&str]) -> Self {
- let rv = Interner::new();
- for &v in init { rv.intern(v); }
- rv
- }
-
- pub fn intern<T: Borrow<str> + Into<String>>(&self, val: T) -> Name {
- let mut map = self.map.borrow_mut();
- if let Some(&idx) = map.get(val.borrow()) {
- return idx;
+ let mut this = Interner::new();
+ for &string in init {
+ this.intern(string);
}
-
- let new_idx = Name(self.len() as u32);
- let val = Rc::new(val.into());
- map.insert(RcStr(val.clone()), new_idx);
- self.vect.borrow_mut().push(val);
- new_idx
+ this
}
- pub fn gensym(&self, val: &str) -> Name {
- let new_idx = Name(self.len() as u32);
- // leave out of .map to avoid colliding
- self.vect.borrow_mut().push(Rc::new(val.to_owned()));
- new_idx
- }
-
- // I want these gensyms to share name pointers
- // with existing entries. This would be automatic,
- // except that the existing gensym creates its
- // own managed ptr using to_managed. I think that
- // adding this utility function is the most
- // lightweight way to get what I want, though not
- // necessarily the cleanest.
-
- /// Create a gensym with the same name as an existing
- /// entry.
- pub fn gensym_copy(&self, idx : Name) -> Name {
- let new_idx = Name(self.len() as u32);
- // leave out of map to avoid colliding
- let mut vect = self.vect.borrow_mut();
- let existing = (*vect)[idx.0 as usize].clone();
- vect.push(existing);
- new_idx
- }
+ pub fn intern<T: Borrow<str> + Into<String>>(&mut self, string: T) -> Name {
+ if let Some(&name) = self.names.get(string.borrow()) {
+ return name;
+ }
- pub fn get(&self, idx: Name) -> Rc<String> {
- (*self.vect.borrow())[idx.0 as usize].clone()
+ let name = Name(self.strings.len() as u32);
+ let string = Rc::new(string.into());
+ self.strings.push(string.clone());
+ self.names.insert(RcStr(string), name);
+ name
}
- pub fn len(&self) -> usize {
- self.vect.borrow().len()
+ pub fn gensym(&mut self, string: &str) -> Name {
+ let gensym = Name(self.strings.len() as u32);
+ // leave out of `names` to avoid colliding
+ self.strings.push(Rc::new(string.to_owned()));
+ gensym
}
- pub fn find(&self, val: &str) -> Option<Name> {
- self.map.borrow().get(val).cloned()
+ /// Create a gensym with the same name as an existing entry.
+ pub fn gensym_copy(&mut self, name: Name) -> Name {
+ let gensym = Name(self.strings.len() as u32);
+ // leave out of `names` to avoid colliding
+ let string = self.strings[name.0 as usize].clone();
+ self.strings.push(string);
+ gensym
}
- pub fn clear(&self) {
- *self.map.borrow_mut() = HashMap::new();
- *self.vect.borrow_mut() = Vec::new();
+ pub fn get(&self, name: Name) -> Rc<String> {
+ self.strings[name.0 as usize].clone()
}
- pub fn reset(&self, other: Interner) {
- *self.map.borrow_mut() = other.map.into_inner();
- *self.vect.borrow_mut() = other.vect.into_inner();
+ pub fn find(&self, string: &str) -> Option<Name> {
+ self.names.get(string).cloned()
}
}
#[test]
fn interner_tests() {
- let i : Interner = Interner::new();
+ let mut i: Interner = Interner::new();
// first one is zero:
assert_eq!(i.intern("dog"), Name(0));
// re-use gets the same entry: