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 | |
| 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')
| -rw-r--r-- | src/libsyntax/ast.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/attr.rs | 83 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 28 | ||||
| -rw-r--r-- | src/libsyntax/ext/cfg.rs | 7 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/generic.rs | 12 | ||||
| -rw-r--r-- | src/libsyntax/ext/deriving/mod.rs | 8 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/ext/format.rs | 16 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 11 | ||||
| -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 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 10 | ||||
| -rw-r--r-- | src/libsyntax/util/interner.rs | 11 |
14 files changed, 221 insertions, 79 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 1513946e401..f7e474f666c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -14,7 +14,8 @@ use codemap::{Span, Spanned, DUMMY_SP}; use abi::AbiSet; use ast_util; use opt_vec::OptVec; -use parse::token::{interner_get, str_to_ident, special_idents}; +use parse::token::{InternedString, interner_get, special_idents}; +use parse::token::{str_to_ident}; use std::cell::RefCell; use std::hashmap::HashMap; @@ -295,9 +296,9 @@ pub type MetaItem = Spanned<MetaItem_>; #[deriving(Clone, Encodable, Decodable, IterBytes)] pub enum MetaItem_ { - MetaWord(@str), - MetaList(@str, ~[@MetaItem]), - MetaNameValue(@str, Lit), + MetaWord(InternedString), + MetaList(InternedString, ~[@MetaItem]), + MetaNameValue(InternedString, Lit), } // can't be derived because the MetaList requires an unordered comparison diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index c44861bd7d7..6c6f47bae8a 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -16,18 +16,19 @@ use codemap::{Span, Spanned, spanned, dummy_spanned}; use codemap::BytePos; use diagnostic::SpanHandler; use parse::comments::{doc_comment_style, strip_doc_comment_decoration}; +use parse::token::InternedString; use crateid::CrateId; use std::hashmap::HashSet; pub trait AttrMetaMethods { - // This could be changed to `fn check_name(&self, name: @str) -> + // This could be changed to `fn check_name(&self, name: InternedString) -> // bool` which would facilitate a side table recording which // attributes/meta items are used/unused. /// Retrieve the name of the meta item, e.g. foo in #[foo], /// #[foo="bar"] and #[foo(bar)] - fn name(&self) -> @str; + fn name(&self) -> InternedString; /** * Gets the string value if self is a MetaNameValue variant @@ -41,24 +42,26 @@ pub trait AttrMetaMethods { * If the meta item is a name-value type with a string value then returns * a tuple containing the name and string value, otherwise `None` */ - fn name_str_pair(&self) -> Option<(@str, @str)>; + fn name_str_pair(&self) -> Option<(InternedString, @str)>; } impl AttrMetaMethods for Attribute { - fn name(&self) -> @str { self.meta().name() } + fn name(&self) -> InternedString { self.meta().name() } fn value_str(&self) -> Option<@str> { self.meta().value_str() } fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> { self.node.value.meta_item_list() } - fn name_str_pair(&self) -> Option<(@str, @str)> { self.meta().name_str_pair() } + fn name_str_pair(&self) -> Option<(InternedString, @str)> { + self.meta().name_str_pair() + } } impl AttrMetaMethods for MetaItem { - fn name(&self) -> @str { + fn name(&self) -> InternedString { match self.node { - MetaWord(n) => n, - MetaNameValue(n, _) => n, - MetaList(n, _) => n + MetaWord(ref n) => (*n).clone(), + MetaNameValue(ref n, _) => (*n).clone(), + MetaList(ref n, _) => (*n).clone(), } } @@ -81,19 +84,21 @@ impl AttrMetaMethods for MetaItem { } } - fn name_str_pair(&self) -> Option<(@str, @str)> { + fn name_str_pair(&self) -> Option<(InternedString, @str)> { self.value_str().map(|s| (self.name(), s)) } } // Annoying, but required to get test_cfg to work impl AttrMetaMethods for @MetaItem { - fn name(&self) -> @str { (**self).name() } + fn name(&self) -> InternedString { (**self).name() } fn value_str(&self) -> Option<@str> { (**self).value_str() } fn meta_item_list<'a>(&'a self) -> Option<&'a [@MetaItem]> { (**self).meta_item_list() } - fn name_str_pair(&self) -> Option<(@str, @str)> { (**self).name_str_pair() } + fn name_str_pair(&self) -> Option<(InternedString, @str)> { + (**self).name_str_pair() + } } @@ -114,7 +119,7 @@ impl AttributeMethods for Attribute { fn desugar_doc(&self) -> Attribute { if self.node.is_sugared_doc { let comment = self.value_str().unwrap(); - let meta = mk_name_value_item_str(@"doc", + let meta = mk_name_value_item_str(InternedString::new("doc"), strip_doc_comment_decoration(comment).to_managed()); mk_attr(meta) } else { @@ -125,20 +130,22 @@ impl AttributeMethods for Attribute { /* Constructors */ -pub fn mk_name_value_item_str(name: @str, value: @str) -> @MetaItem { +pub fn mk_name_value_item_str(name: InternedString, value: @str) + -> @MetaItem { let value_lit = dummy_spanned(ast::LitStr(value, ast::CookedStr)); mk_name_value_item(name, value_lit) } -pub fn mk_name_value_item(name: @str, value: ast::Lit) -> @MetaItem { +pub fn mk_name_value_item(name: InternedString, value: ast::Lit) + -> @MetaItem { @dummy_spanned(MetaNameValue(name, value)) } -pub fn mk_list_item(name: @str, items: ~[@MetaItem]) -> @MetaItem { +pub fn mk_list_item(name: InternedString, items: ~[@MetaItem]) -> @MetaItem { @dummy_spanned(MetaList(name, items)) } -pub fn mk_word_item(name: @str) -> @MetaItem { +pub fn mk_word_item(name: InternedString) -> @MetaItem { @dummy_spanned(MetaWord(name)) } @@ -155,7 +162,8 @@ pub fn mk_sugared_doc_attr(text: @str, lo: BytePos, hi: BytePos) -> Attribute { let lit = spanned(lo, hi, ast::LitStr(text, ast::CookedStr)); let attr = Attribute_ { style: style, - value: @spanned(lo, hi, MetaNameValue(@"doc", lit)), + value: @spanned(lo, hi, MetaNameValue(InternedString::new("doc"), + lit)), is_sugared_doc: true }; spanned(lo, hi, attr) @@ -178,20 +186,22 @@ pub fn contains_name<AM: AttrMetaMethods>(metas: &[AM], name: &str) -> bool { debug!("attr::contains_name (name={})", name); metas.iter().any(|item| { debug!(" testing: {}", item.name()); - name == item.name() + item.name().equiv(&name) }) } pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: &str) -> Option<@str> { attrs.iter() - .find(|at| name == at.name()) + .find(|at| at.name().equiv(&name)) .and_then(|at| at.value_str()) } pub fn last_meta_item_value_str_by_name(items: &[@MetaItem], name: &str) -> Option<@str> { - items.rev_iter().find(|mi| name == mi.name()).and_then(|i| i.value_str()) + items.rev_iter() + .find(|mi| mi.name().equiv(&name)) + .and_then(|i| i.value_str()) } /* Higher-level applications */ @@ -201,16 +211,16 @@ pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] { // human-readable strings. let mut v = items.iter() .map(|&mi| (mi.name(), mi)) - .collect::<~[(@str, @MetaItem)]>(); + .collect::<~[(InternedString, @MetaItem)]>(); - v.sort_by(|&(a, _), &(b, _)| a.cmp(&b)); + v.sort_by(|&(ref a, _), &(ref b, _)| a.cmp(b)); // There doesn't seem to be a more optimal way to do this v.move_iter().map(|(_, m)| { match m.node { - MetaList(n, ref mis) => { + MetaList(ref n, ref mis) => { @Spanned { - node: MetaList(n, sort_meta_items(*mis)), + node: MetaList((*n).clone(), sort_meta_items(*mis)), .. /*bad*/ (*m).clone() } } @@ -225,7 +235,7 @@ pub fn sort_meta_items(items: &[@MetaItem]) -> ~[@MetaItem] { */ pub fn find_linkage_metas(attrs: &[Attribute]) -> ~[@MetaItem] { let mut result = ~[]; - for attr in attrs.iter().filter(|at| "link" == at.name()) { + for attr in attrs.iter().filter(|at| at.name().equiv(&("link"))) { match attr.meta().node { MetaList(_, ref items) => result.push_all(*items), _ => () @@ -254,8 +264,8 @@ pub fn find_inline_attr(attrs: &[Attribute]) -> InlineAttr { // FIXME (#2809)---validate the usage of #[inline] and #[inline] attrs.iter().fold(InlineNone, |ia,attr| { match attr.node.value.node { - MetaWord(n) if "inline" == n => InlineHint, - MetaList(n, ref items) if "inline" == n => { + MetaWord(ref n) if n.equiv(&("inline")) => InlineHint, + MetaList(ref n, ref items) if n.equiv(&("inline")) => { if contains_name(*items, "always") { InlineAlways } else if contains_name(*items, "never") { @@ -284,7 +294,7 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>> // this doesn't work. let some_cfg_matches = metas.any(|mi| { debug!("testing name: {}", mi.name()); - if "cfg" == mi.name() { // it is a #[cfg()] attribute + if mi.name().equiv(&("cfg")) { // it is a #[cfg()] attribute debug!("is cfg"); no_cfgs = false; // only #[cfg(...)] ones are understood. @@ -294,7 +304,8 @@ pub fn test_cfg<AM: AttrMetaMethods, It: Iterator<AM>> cfg_meta.iter().all(|cfg_mi| { debug!("cfg({}[...])", cfg_mi.name()); match cfg_mi.node { - ast::MetaList(s, ref not_cfgs) if "not" == s => { + ast::MetaList(ref s, ref not_cfgs) + if s.equiv(&("not")) => { debug!("not!"); // inside #[cfg(not(...))], so these need to all // not match. @@ -337,7 +348,7 @@ pub enum StabilityLevel { /// Find the first stability attribute. `None` if none exists. pub fn find_stability<AM: AttrMetaMethods, It: Iterator<AM>>(mut metas: It) -> Option<Stability> { for m in metas { - let level = match m.name().as_slice() { + let level = match m.name().get() { "deprecated" => Deprecated, "experimental" => Experimental, "unstable" => Unstable, @@ -360,7 +371,7 @@ pub fn require_unique_names(diagnostic: @SpanHandler, metas: &[@MetaItem]) { for meta in metas.iter() { let name = meta.name(); - if !set.insert(name) { + if !set.insert(name.clone()) { diagnostic.span_fatal(meta.span, format!("duplicate meta item `{}`", name)); } @@ -384,14 +395,14 @@ pub fn find_repr_attr(diagnostic: @SpanHandler, attr: @ast::MetaItem, acc: ReprA -> ReprAttr { let mut acc = acc; match attr.node { - ast::MetaList(s, ref items) if "repr" == s => { + ast::MetaList(ref s, ref items) if s.equiv(&("repr")) => { for item in items.iter() { match item.node { - ast::MetaWord(word) => { - let hint = match word.as_slice() { + ast::MetaWord(ref word) => { + let hint = match word.get() { // Can't use "extern" because it's not a lexical identifier. "C" => ReprExtern, - _ => match int_type_of_word(word) { + _ => match int_type_of_word(word.get()) { Some(ity) => ReprInt(item.span, ity), None => { // Not a word we recognize diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9ad4f4f7fac..884bd831ce8 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -228,9 +228,17 @@ pub trait AstBuilder { fn attribute(&self, sp: Span, mi: @ast::MetaItem) -> ast::Attribute; - fn meta_word(&self, sp: Span, w: @str) -> @ast::MetaItem; - fn meta_list(&self, sp: Span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem; - fn meta_name_value(&self, sp: Span, name: @str, value: ast::Lit_) -> @ast::MetaItem; + fn meta_word(&self, sp: Span, w: InternedString) -> @ast::MetaItem; + fn meta_list(&self, + sp: Span, + name: InternedString, + mis: ~[@ast::MetaItem]) + -> @ast::MetaItem; + fn meta_name_value(&self, + sp: Span, + name: InternedString, + value: ast::Lit_) + -> @ast::MetaItem; fn view_use(&self, sp: Span, vis: ast::Visibility, vp: ~[@ast::ViewPath]) -> ast::ViewItem; @@ -866,13 +874,21 @@ impl<'a> AstBuilder for ExtCtxt<'a> { }) } - fn meta_word(&self, sp: Span, w: @str) -> @ast::MetaItem { + fn meta_word(&self, sp: Span, w: InternedString) -> @ast::MetaItem { @respan(sp, ast::MetaWord(w)) } - fn meta_list(&self, sp: Span, name: @str, mis: ~[@ast::MetaItem]) -> @ast::MetaItem { + fn meta_list(&self, + sp: Span, + name: InternedString, + mis: ~[@ast::MetaItem]) + -> @ast::MetaItem { @respan(sp, ast::MetaList(name, mis)) } - fn meta_name_value(&self, sp: Span, name: @str, value: ast::Lit_) -> @ast::MetaItem { + fn meta_name_value(&self, + sp: Span, + name: InternedString, + value: ast::Lit_) + -> @ast::MetaItem { @respan(sp, ast::MetaNameValue(name, respan(sp, value))) } diff --git a/src/libsyntax/ext/cfg.rs b/src/libsyntax/ext/cfg.rs index 9af295c0b11..295c456c9d0 100644 --- a/src/libsyntax/ext/cfg.rs +++ b/src/libsyntax/ext/cfg.rs @@ -21,9 +21,10 @@ use ext::base; use ext::build::AstBuilder; use attr; use attr::*; -use parse; -use parse::token; use parse::attr::ParserAttr; +use parse::token::InternedString; +use parse::token; +use parse; pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::MacResult { let mut p = parse::new_parser_from_tts(cx.parse_sess(), @@ -39,7 +40,7 @@ pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) -> base::M } // test_cfg searches for meta items looking like `cfg(foo, ...)` - let in_cfg = &[cx.meta_list(sp, @"cfg", cfgs)]; + let in_cfg = &[cx.meta_list(sp, InternedString::new("cfg"), cfgs)]; let matches_cfg = attr::test_cfg(cx.cfg(), in_cfg.iter().map(|&x| x)); let e = cx.expr_bool(sp, matches_cfg); diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs index 6449d0aab5e..20a515692e1 100644 --- a/src/libsyntax/ext/deriving/generic.rs +++ b/src/libsyntax/ext/deriving/generic.rs @@ -184,6 +184,7 @@ use ext::build::AstBuilder; use codemap; use codemap::Span; use opt_vec; +use parse::token::InternedString; use std::vec; @@ -396,7 +397,7 @@ impl<'a> TraitDef<'a> { let doc_attr = cx.attribute( self.span, cx.meta_name_value(self.span, - @"doc", + InternedString::new("doc"), ast::LitStr(@"Automatically derived.", ast::CookedStr))); cx.item( self.span, @@ -567,7 +568,14 @@ impl<'a> MethodDef<'a> { let body_block = trait_.cx.block_expr(body); let attrs = if self.inline { - ~[trait_.cx.attribute(trait_.span, trait_.cx.meta_word(trait_.span, @"inline"))] + ~[ + trait_.cx + .attribute(trait_.span, + trait_.cx + .meta_word(trait_.span, + InternedString::new( + "inline"))) + ] } else { ~[] }; diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 652f5ebe6c7..9c487146639 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -75,12 +75,12 @@ pub fn expand_meta_deriving(cx: &ExtCtxt, MetaList(_, ref titems) => { titems.rev_iter().fold(in_items, |in_items, &titem| { match titem.node { - MetaNameValue(tname, _) | - MetaList(tname, _) | - MetaWord(tname) => { + MetaNameValue(ref tname, _) | + MetaList(ref tname, _) | + MetaWord(ref tname) => { macro_rules! expand(($func:path) => ($func(cx, titem.span, titem, in_items))); - match tname.as_slice() { + match tname.get() { "Clone" => expand!(clone::expand_deriving_clone), "DeepClone" => expand!(clone::expand_deriving_deep_clone), diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 1ffff03a80f..d98a549725c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -221,12 +221,12 @@ pub fn expand_mod_items(module_: &ast::Mod, fld: &mut MacroExpander) -> ast::Mod item.attrs.rev_iter().fold(~[*item], |items, attr| { let mname = attr.name(); - match fld.extsbox.find(&intern(mname)) { + match fld.extsbox.find(&intern(mname.get())) { Some(&ItemDecorator(dec_fn)) => { fld.cx.bt_push(ExpnInfo { call_site: attr.span, callee: NameAndSpan { - name: mname, + name: mname.get().to_managed(), format: MacroAttribute, span: None } diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs index bbf6f7fff7f..5730d435c15 100644 --- a/src/libsyntax/ext/format.rs +++ b/src/libsyntax/ext/format.rs @@ -14,9 +14,10 @@ use codemap::{Span, respan}; use ext::base::*; use ext::base; use ext::build::AstBuilder; -use rsparse = parse; -use parse::token; use opt_vec; +use parse::token::InternedString; +use parse::token; +use rsparse = parse; use std::fmt::parse; use std::hashmap::{HashMap, HashSet}; use std::vec; @@ -333,13 +334,18 @@ impl<'a> Context<'a> { fn static_attrs(&self) -> ~[ast::Attribute] { // Flag statics as `address_insignificant` so LLVM can merge duplicate // globals as much as possible (which we're generating a whole lot of). - let unnamed = self.ecx.meta_word(self.fmtsp, @"address_insignificant"); + let unnamed = self.ecx + .meta_word(self.fmtsp, + InternedString::new( + "address_insignificant")); let unnamed = self.ecx.attribute(self.fmtsp, unnamed); // Do not warn format string as dead code - let dead_code = self.ecx.meta_word(self.fmtsp, @"dead_code"); + let dead_code = self.ecx.meta_word(self.fmtsp, + InternedString::new("dead_code")); let allow_dead_code = self.ecx.meta_list(self.fmtsp, - @"allow", ~[dead_code]); + InternedString::new("allow"), + ~[dead_code]); let allow_dead_code = self.ecx.attribute(self.fmtsp, allow_dead_code); return ~[unnamed, allow_dead_code]; } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8dac13f1e31..c2d54a4f368 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -321,15 +321,12 @@ fn fold_meta_item_<T: Folder>(mi: @MetaItem, fld: &mut T) -> @MetaItem { @Spanned { node: match mi.node { - MetaWord(id) => MetaWord(id), - MetaList(id, ref mis) => { + MetaWord(ref id) => MetaWord((*id).clone()), + MetaList(ref id, ref mis) => { let fold_meta_item = |x| fold_meta_item_(x, fld); - MetaList( - id, - mis.map(|e| fold_meta_item(*e)) - ) + MetaList((*id).clone(), mis.map(|e| fold_meta_item(*e))) } - MetaNameValue(id, s) => MetaNameValue(id, s) + MetaNameValue(ref id, s) => MetaNameValue((*id).clone(), s) }, span: fld.new_span(mi.span) } } 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) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 2783284ea8b..89d8173f7e7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1930,14 +1930,14 @@ pub fn print_generics(s: &mut State, generics: &ast::Generics) { pub fn print_meta_item(s: &mut State, item: &ast::MetaItem) { ibox(s, indent_unit); match item.node { - ast::MetaWord(name) => word(&mut s.s, name), - ast::MetaNameValue(name, value) => { - word_space(s, name); + ast::MetaWord(ref name) => word(&mut s.s, name.get()), + ast::MetaNameValue(ref name, value) => { + word_space(s, name.get()); word_space(s, "="); print_literal(s, &value); } - ast::MetaList(name, ref items) => { - word(&mut s.s, name); + ast::MetaList(ref name, ref items) => { + word(&mut s.s, name.get()); popen(s); commasep(s, Consistent, diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index fdc54f1f140..c0fe19ede01 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -14,6 +14,7 @@ use ast::Name; +use std::cast; use std::cell::RefCell; use std::cmp::Equiv; use std::hashmap::HashMap; @@ -151,6 +152,16 @@ impl StrInterner { vect.get()[idx] } + /// Returns this string with lifetime tied to the interner. Since + /// strings may never be removed from the interner, this is safe. + pub fn get_ref<'a>(&'a self, idx: Name) -> &'a str { + let vect = self.vect.borrow(); + let s: &str = vect.get()[idx]; + unsafe { + cast::transmute(s) + } + } + pub fn len(&self) -> uint { let vect = self.vect.borrow(); vect.get().len() |
