Move syntax::util::interner
-> syntax::symbol
, cleanup.
This commit is contained in:
parent
f177a00ac9
commit
d2f8fb0a0a
102 changed files with 752 additions and 806 deletions
|
@ -16,13 +16,10 @@ pub use self::Token::*;
|
|||
|
||||
use ast::{self};
|
||||
use ptr::P;
|
||||
use util::interner::Interner;
|
||||
use symbol::keywords;
|
||||
use tokenstream;
|
||||
|
||||
use serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
|
||||
|
@ -335,266 +332,3 @@ impl fmt::Debug for Nonterminal {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// In this macro, there is the requirement that the name (the number) must be monotonically
|
||||
// increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
|
||||
// except starting from the next number instead of zero.
|
||||
macro_rules! declare_keywords {(
|
||||
$( ($index: expr, $konst: ident, $string: expr) )*
|
||||
) => {
|
||||
pub mod keywords {
|
||||
use ast;
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Keyword {
|
||||
ident: ast::Ident,
|
||||
}
|
||||
impl Keyword {
|
||||
#[inline] pub fn ident(self) -> ast::Ident { self.ident }
|
||||
#[inline] pub fn name(self) -> ast::Name { self.ident.name }
|
||||
}
|
||||
$(
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const $konst: Keyword = Keyword {
|
||||
ident: ast::Ident::with_empty_ctxt(ast::Name($index))
|
||||
};
|
||||
)*
|
||||
}
|
||||
|
||||
fn mk_fresh_ident_interner() -> IdentInterner {
|
||||
Interner::prefill(&[$($string,)*])
|
||||
}
|
||||
}}
|
||||
|
||||
// NB: leaving holes in the ident table is bad! a different ident will get
|
||||
// interned with the id from the hole, but it will be between the min and max
|
||||
// of the reserved words, and thus tagged as "reserved".
|
||||
// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`,
|
||||
// this should be rarely necessary though if the keywords are kept in alphabetic order.
|
||||
declare_keywords! {
|
||||
// Invalid identifier
|
||||
(0, Invalid, "")
|
||||
|
||||
// Strict keywords used in the language.
|
||||
(1, As, "as")
|
||||
(2, Box, "box")
|
||||
(3, Break, "break")
|
||||
(4, Const, "const")
|
||||
(5, Continue, "continue")
|
||||
(6, Crate, "crate")
|
||||
(7, Else, "else")
|
||||
(8, Enum, "enum")
|
||||
(9, Extern, "extern")
|
||||
(10, False, "false")
|
||||
(11, Fn, "fn")
|
||||
(12, For, "for")
|
||||
(13, If, "if")
|
||||
(14, Impl, "impl")
|
||||
(15, In, "in")
|
||||
(16, Let, "let")
|
||||
(17, Loop, "loop")
|
||||
(18, Match, "match")
|
||||
(19, Mod, "mod")
|
||||
(20, Move, "move")
|
||||
(21, Mut, "mut")
|
||||
(22, Pub, "pub")
|
||||
(23, Ref, "ref")
|
||||
(24, Return, "return")
|
||||
(25, SelfValue, "self")
|
||||
(26, SelfType, "Self")
|
||||
(27, Static, "static")
|
||||
(28, Struct, "struct")
|
||||
(29, Super, "super")
|
||||
(30, Trait, "trait")
|
||||
(31, True, "true")
|
||||
(32, Type, "type")
|
||||
(33, Unsafe, "unsafe")
|
||||
(34, Use, "use")
|
||||
(35, Where, "where")
|
||||
(36, While, "while")
|
||||
|
||||
// Keywords reserved for future use.
|
||||
(37, Abstract, "abstract")
|
||||
(38, Alignof, "alignof")
|
||||
(39, Become, "become")
|
||||
(40, Do, "do")
|
||||
(41, Final, "final")
|
||||
(42, Macro, "macro")
|
||||
(43, Offsetof, "offsetof")
|
||||
(44, Override, "override")
|
||||
(45, Priv, "priv")
|
||||
(46, Proc, "proc")
|
||||
(47, Pure, "pure")
|
||||
(48, Sizeof, "sizeof")
|
||||
(49, Typeof, "typeof")
|
||||
(50, Unsized, "unsized")
|
||||
(51, Virtual, "virtual")
|
||||
(52, Yield, "yield")
|
||||
|
||||
// Weak keywords, have special meaning only in specific contexts.
|
||||
(53, Default, "default")
|
||||
(54, StaticLifetime, "'static")
|
||||
(55, Union, "union")
|
||||
}
|
||||
|
||||
// looks like we can get rid of this completely...
|
||||
pub type IdentInterner = Interner;
|
||||
|
||||
// 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(&mut IdentInterner) -> T>(f: F) -> T {
|
||||
thread_local!(static KEY: RefCell<IdentInterner> = {
|
||||
RefCell::new(mk_fresh_ident_interner())
|
||||
});
|
||||
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 = mk_fresh_ident_interner());
|
||||
}
|
||||
|
||||
/// Represents a string stored in the thread-local interner. Because the
|
||||
/// interner lives for the life of the thread, this can be safely treated as an
|
||||
/// immortal string, as long as it never crosses between threads.
|
||||
///
|
||||
/// FIXME(pcwalton): You must be careful about what you do in the destructors
|
||||
/// of objects stored in TLS, because they may run after the interner is
|
||||
/// destroyed. In particular, they must not access string contents. This can
|
||||
/// be fixed in the future by just leaking all strings until thread death
|
||||
/// somehow.
|
||||
#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
|
||||
pub struct InternedString {
|
||||
string: Rc<str>,
|
||||
}
|
||||
|
||||
impl InternedString {
|
||||
#[inline]
|
||||
pub fn new(string: &'static str) -> InternedString {
|
||||
InternedString {
|
||||
string: Rc::__from_str(string),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new_from_name(name: ast::Name) -> InternedString {
|
||||
with_ident_interner(|interner| InternedString { string: interner.get(name) })
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for InternedString {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &str { &self.string }
|
||||
}
|
||||
|
||||
impl fmt::Debug for InternedString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Debug::fmt(&self.string, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for InternedString {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.string, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<&'a str> for InternedString {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: & &'a str) -> bool {
|
||||
PartialEq::eq(&self.string[..], *other)
|
||||
}
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: & &'a str) -> bool {
|
||||
PartialEq::ne(&self.string[..], *other)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PartialEq<InternedString> for &'a str {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &InternedString) -> bool {
|
||||
PartialEq::eq(*self, &other.string[..])
|
||||
}
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &InternedString) -> bool {
|
||||
PartialEq::ne(*self, &other.string[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for InternedString {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
PartialEq::eq(&self.string[..], other)
|
||||
}
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &str) -> bool {
|
||||
PartialEq::ne(&self.string[..], other)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<InternedString> for str {
|
||||
#[inline(always)]
|
||||
fn eq(&self, other: &InternedString) -> bool {
|
||||
PartialEq::eq(self, &other.string[..])
|
||||
}
|
||||
#[inline(always)]
|
||||
fn ne(&self, other: &InternedString) -> bool {
|
||||
PartialEq::ne(self, &other.string[..])
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for InternedString {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
|
||||
Ok(intern(&d.read_str()?).as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Encodable for InternedString {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_str(&self.string)
|
||||
}
|
||||
}
|
||||
|
||||
/// Interns and returns the string contents of an identifier, using the
|
||||
/// thread-local interner.
|
||||
#[inline]
|
||||
pub fn intern_and_get_ident(s: &str) -> InternedString {
|
||||
intern(s).as_str()
|
||||
}
|
||||
|
||||
/// Maps a string to its interned representation.
|
||||
#[inline]
|
||||
pub fn intern(s: &str) -> ast::Name {
|
||||
with_ident_interner(|interner| interner.intern(s))
|
||||
}
|
||||
|
||||
/// gensym's a new usize, using the current interner.
|
||||
#[inline]
|
||||
pub fn gensym(s: &str) -> ast::Name {
|
||||
with_ident_interner(|interner| interner.gensym(s))
|
||||
}
|
||||
|
||||
/// Maps a string to an identifier with an empty syntax context.
|
||||
#[inline]
|
||||
pub fn str_to_ident(s: &str) -> ast::Ident {
|
||||
ast::Ident::with_empty_ctxt(intern(s))
|
||||
}
|
||||
|
||||
/// Maps a string to a gensym'ed identifier.
|
||||
#[inline]
|
||||
pub fn gensym_ident(s: &str) -> ast::Ident {
|
||||
ast::Ident::with_empty_ctxt(gensym(s))
|
||||
}
|
||||
|
||||
// create a fresh name that maps to the same string as the old one.
|
||||
// note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src)));
|
||||
// that is, that the new name and the old one are connected to ptr_eq strings.
|
||||
pub fn fresh_name(src: ast::Ident) -> ast::Name {
|
||||
with_ident_interner(|interner| interner.gensym_copy(src.name))
|
||||
// following: debug version. Could work in final except that it's incompatible with
|
||||
// good error messages and uses of struct names in ambiguous could-be-binding
|
||||
// locations. Also definitely destroys the guarantee given above about ptr_eq.
|
||||
/*let num = rand::thread_rng().gen_uint_range(0,0xffff);
|
||||
gensym(format!("{}_{}",ident_to_string(src),num))*/
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue