diff options
| author | Patrick Walton <pcwalton@mimiga.net> | 2014-01-08 10:35:15 -0800 |
|---|---|---|
| committer | Huon Wilson <dbau.pp+github@gmail.com> | 2014-02-02 01:44:47 +1100 |
| commit | 70c5a0fbf784d6a89b1c2c50f9fe83093bd21abc (patch) | |
| tree | c0d73d05918545051a9e1d10f5496ee588df3693 /src/libsyntax/parse | |
| parent | 1d494198bbb9701b6336febcf9d0ceb39e4b7975 (diff) | |
| download | rust-70c5a0fbf784d6a89b1c2c50f9fe83093bd21abc.tar.gz rust-70c5a0fbf784d6a89b1c2c50f9fe83093bd21abc.zip | |
libsyntax: Introduce an `InternedString` type to reduce `@str` in the
compiler and use it for attributes
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/attr.rs | 2 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/parse/token.rs | 87 |
3 files changed, 96 insertions, 5 deletions
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index e7630a66855..bc9f7e4b195 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -157,7 +157,7 @@ impl ParserAttr for Parser { fn parse_meta_item(&mut self) -> @ast::MetaItem { let lo = self.span.lo; let ident = self.parse_ident(); - let name = self.id_to_str(ident); + let name = self.id_to_interned_str(ident); match self.token { token::EQ => { self.bump(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 642624adfb2..93264f5a6c6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -71,10 +71,10 @@ use parse::common::{seq_sep_trailing_disallowed, seq_sep_trailing_allowed}; use parse::lexer::Reader; use parse::lexer::TokenAndSpan; use parse::obsolete::*; -use parse::token::{can_begin_expr, get_ident_interner, ident_to_str, is_ident}; -use parse::token::{is_ident_or_path}; -use parse::token::{is_plain_ident, INTERPOLATED, keywords, special_idents}; -use parse::token::{token_to_binop}; +use parse::token::{INTERPOLATED, InternedString, can_begin_expr, get_ident}; +use parse::token::{get_ident_interner, ident_to_str, is_ident}; +use parse::token::{is_ident_or_path, is_plain_ident, keywords}; +use parse::token::{special_idents, token_to_binop}; use parse::token; use parse::{new_sub_parser_from_file, ParseSess}; use opt_vec; @@ -806,6 +806,10 @@ impl Parser { get_ident_interner().get(id.name) } + pub fn id_to_interned_str(&mut self, id: Ident) -> InternedString { + get_ident(id.name) + } + // Is the current token one of the keywords that signals a bare function // type? pub fn token_is_bare_fn_keyword(&mut self) -> bool { diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 68e2f44ebb1..97b9b4d53a4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -15,8 +15,10 @@ use parse::token; use util::interner::StrInterner; use util::interner; +use extra::serialize::{Decodable, Decoder, Encodable, Encoder}; use std::cast; use std::char; +use std::fmt; use std::local_data; #[allow(non_camel_case_types)] @@ -525,6 +527,90 @@ pub fn get_ident_interner() -> @IdentInterner { } } +/// Represents a string stored in the task-local interner. Because the +/// interner lives for the life of the task, this can be safely treated as an +/// immortal string, as long as it never crosses between tasks. +/// +/// XXX(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 task death +/// somehow. +#[no_send] +#[deriving(Clone, Eq, IterBytes, TotalEq, TotalOrd)] +pub struct InternedString { + priv string: @str, +} + +#[unsafe_destructor] +impl Drop for InternedString { + fn drop(&mut self) { + // No-op just to make this not implicitly copyable. + } +} + +impl InternedString { + #[inline] + pub fn new(string: &'static str) -> InternedString { + InternedString { + string: string.to_managed(), + } + } + + // NB: Do not make this public. We are trying to remove `@str`. + #[inline] + fn new_from_at_str(string: @str) -> InternedString { + InternedString { + string: string, + } + } + + #[inline] + pub fn get<'a>(&'a self) -> &'a str { + self.string.as_slice() + } +} + +impl fmt::Default for InternedString { + fn fmt(obj: &InternedString, f: &mut fmt::Formatter) { + write!(f.buf, "{}", obj.string); + } +} + +impl<'a> Equiv<&'a str> for InternedString { + fn equiv(&self, other: & &'a str) -> bool { + (*other) == self.string.as_slice() + } +} + +impl<D:Decoder> Decodable<D> for InternedString { + fn decode(d: &mut D) -> InternedString { + let interner = get_ident_interner(); + get_ident(interner.intern(d.read_str())) + } +} + +impl<E:Encoder> Encodable<E> for InternedString { + fn encode(&self, e: &mut E) { + e.emit_str(self.string) + } +} + +/// Returns the string contents of an identifier, using the task-local +/// interner. +#[inline] +pub fn get_ident(idx: Name) -> InternedString { + let interner = get_ident_interner(); + InternedString::new_from_at_str(interner.get(idx)) +} + +/// Interns and returns the string contents of an identifier, using the +/// task-local interner. +#[inline] +pub fn intern_and_get_ident(s: &str) -> InternedString { + get_ident(intern(s)) +} + /* for when we don't care about the contents; doesn't interact with TLD or serialization */ pub fn mk_fake_ident_interner() -> @IdentInterner { @@ -532,6 +618,7 @@ pub fn mk_fake_ident_interner() -> @IdentInterner { } // maps a string to its interned representation +#[inline] pub fn intern(str : &str) -> Name { let interner = get_ident_interner(); interner.intern(str) |
