]>
Commit | Line | Data |
---|---|---|
970d7e83 | 1 | // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
1a4d82fc JJ |
11 | pub use self::BinOpToken::*; |
12 | pub use self::Nonterminal::*; | |
13 | pub use self::DelimToken::*; | |
1a4d82fc JJ |
14 | pub use self::Lit::*; |
15 | pub use self::Token::*; | |
16 | ||
9e0c209e | 17 | use ast::{self}; |
1a4d82fc | 18 | use ptr::P; |
5bcae85e | 19 | use util::interner::Interner; |
3157f602 | 20 | use tokenstream; |
223e47cc | 21 | |
1a4d82fc | 22 | use serialize::{Decodable, Decoder, Encodable, Encoder}; |
5bcae85e | 23 | use std::cell::RefCell; |
1a4d82fc | 24 | use std::fmt; |
1a4d82fc | 25 | use std::ops::Deref; |
1a4d82fc JJ |
26 | use std::rc::Rc; |
27 | ||
85aaf69f | 28 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] |
1a4d82fc JJ |
29 | pub enum BinOpToken { |
30 | Plus, | |
31 | Minus, | |
32 | Star, | |
33 | Slash, | |
34 | Percent, | |
35 | Caret, | |
36 | And, | |
37 | Or, | |
38 | Shl, | |
39 | Shr, | |
40 | } | |
41 | ||
42 | /// A delimiter token | |
85aaf69f | 43 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] |
1a4d82fc JJ |
44 | pub enum DelimToken { |
45 | /// A round parenthesis: `(` or `)` | |
46 | Paren, | |
47 | /// A square bracket: `[` or `]` | |
48 | Bracket, | |
49 | /// A curly brace: `{` or `}` | |
50 | Brace, | |
5bcae85e SL |
51 | /// An empty delimiter |
52 | NoDelim, | |
1a4d82fc JJ |
53 | } |
54 | ||
85aaf69f | 55 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] |
1a4d82fc JJ |
56 | pub enum Lit { |
57 | Byte(ast::Name), | |
58 | Char(ast::Name), | |
59 | Integer(ast::Name), | |
60 | Float(ast::Name), | |
61 | Str_(ast::Name), | |
85aaf69f | 62 | StrRaw(ast::Name, usize), /* raw str delimited by n hash symbols */ |
e9174d1e SL |
63 | ByteStr(ast::Name), |
64 | ByteStrRaw(ast::Name, usize), /* raw byte str delimited by n hash symbols */ | |
1a4d82fc JJ |
65 | } |
66 | ||
67 | impl Lit { | |
68 | pub fn short_name(&self) -> &'static str { | |
69 | match *self { | |
70 | Byte(_) => "byte", | |
71 | Char(_) => "char", | |
72 | Integer(_) => "integer", | |
73 | Float(_) => "float", | |
e9174d1e SL |
74 | Str_(_) | StrRaw(..) => "string", |
75 | ByteStr(_) | ByteStrRaw(..) => "byte string" | |
1a4d82fc JJ |
76 | } |
77 | } | |
78 | } | |
79 | ||
85aaf69f | 80 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] |
223e47cc LB |
81 | pub enum Token { |
82 | /* Expression-operator symbols. */ | |
1a4d82fc JJ |
83 | Eq, |
84 | Lt, | |
85 | Le, | |
86 | EqEq, | |
87 | Ne, | |
88 | Ge, | |
89 | Gt, | |
90 | AndAnd, | |
91 | OrOr, | |
92 | Not, | |
93 | Tilde, | |
94 | BinOp(BinOpToken), | |
95 | BinOpEq(BinOpToken), | |
223e47cc LB |
96 | |
97 | /* Structural symbols */ | |
1a4d82fc JJ |
98 | At, |
99 | Dot, | |
100 | DotDot, | |
101 | DotDotDot, | |
102 | Comma, | |
103 | Semi, | |
104 | Colon, | |
105 | ModSep, | |
106 | RArrow, | |
107 | LArrow, | |
108 | FatArrow, | |
109 | Pound, | |
110 | Dollar, | |
111 | Question, | |
112 | /// An opening delimiter, eg. `{` | |
113 | OpenDelim(DelimToken), | |
114 | /// A closing delimiter, eg. `}` | |
115 | CloseDelim(DelimToken), | |
223e47cc LB |
116 | |
117 | /* Literals */ | |
1a4d82fc | 118 | Literal(Lit, Option<ast::Name>), |
223e47cc LB |
119 | |
120 | /* Name components */ | |
a7813a04 | 121 | Ident(ast::Ident), |
1a4d82fc JJ |
122 | Underscore, |
123 | Lifetime(ast::Ident), | |
223e47cc LB |
124 | |
125 | /* For interpolation */ | |
c30ab7b3 | 126 | Interpolated(Rc<Nonterminal>), |
1a4d82fc JJ |
127 | // Can be expanded into several tokens. |
128 | /// Doc comment | |
129 | DocComment(ast::Name), | |
130 | // In left-hand-sides of MBE macros: | |
a7813a04 XL |
131 | /// Parse a nonterminal (name to bind, name of NT) |
132 | MatchNt(ast::Ident, ast::Ident), | |
1a4d82fc JJ |
133 | // In right-hand-sides of MBE macros: |
134 | /// A syntactic variable that will be filled in by macro expansion. | |
a7813a04 | 135 | SubstNt(ast::Ident), |
1a4d82fc JJ |
136 | |
137 | // Junk. These carry no data because we don't really care about the data | |
138 | // they *would* carry, and don't really want to allocate a new ident for | |
139 | // them. Instead, users could extract that from the associated span. | |
140 | ||
141 | /// Whitespace | |
142 | Whitespace, | |
143 | /// Comment | |
144 | Comment, | |
145 | Shebang(ast::Name), | |
146 | ||
147 | Eof, | |
148 | } | |
149 | ||
150 | impl Token { | |
bd371182 AL |
151 | /// Returns `true` if the token starts with '>'. |
152 | pub fn is_like_gt(&self) -> bool { | |
153 | match *self { | |
154 | BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true, | |
155 | _ => false, | |
156 | } | |
157 | } | |
158 | ||
1a4d82fc JJ |
159 | /// Returns `true` if the token can appear at the start of an expression. |
160 | pub fn can_begin_expr(&self) -> bool { | |
161 | match *self { | |
c30ab7b3 | 162 | OpenDelim(..) => true, |
a7813a04 | 163 | Ident(..) => true, |
9e0c209e | 164 | Literal(..) => true, |
1a4d82fc JJ |
165 | Not => true, |
166 | BinOp(Minus) => true, | |
167 | BinOp(Star) => true, | |
168 | BinOp(And) => true, | |
169 | BinOp(Or) => true, // in lambda syntax | |
170 | OrOr => true, // in lambda syntax | |
85aaf69f | 171 | AndAnd => true, // double borrow |
54a0048b | 172 | DotDot | DotDotDot => true, // range notation |
c30ab7b3 | 173 | Lt | BinOp(Shl) => true, // associated path |
1a4d82fc | 174 | ModSep => true, |
92a42be0 | 175 | Pound => true, // for expression attributes |
c30ab7b3 SL |
176 | Interpolated(ref nt) => match **nt { |
177 | NtExpr(..) => true, | |
178 | NtIdent(..) => true, | |
179 | NtBlock(..) => true, | |
180 | NtPath(..) => true, | |
181 | _ => false, | |
182 | }, | |
183 | _ => false, | |
1a4d82fc JJ |
184 | } |
185 | } | |
223e47cc | 186 | |
1a4d82fc JJ |
187 | /// Returns `true` if the token is any literal |
188 | pub fn is_lit(&self) -> bool { | |
189 | match *self { | |
9e0c209e SL |
190 | Literal(..) => true, |
191 | _ => false, | |
1a4d82fc JJ |
192 | } |
193 | } | |
223e47cc | 194 | |
1a4d82fc JJ |
195 | /// Returns `true` if the token is an identifier. |
196 | pub fn is_ident(&self) -> bool { | |
197 | match *self { | |
a7813a04 | 198 | Ident(..) => true, |
1a4d82fc | 199 | _ => false, |
223e47cc | 200 | } |
1a4d82fc JJ |
201 | } |
202 | ||
9e0c209e SL |
203 | /// Returns `true` if the token is a documentation comment. |
204 | pub fn is_doc_comment(&self) -> bool { | |
205 | match *self { | |
206 | DocComment(..) => true, | |
207 | _ => false, | |
208 | } | |
209 | } | |
210 | ||
7453a54e SL |
211 | /// Returns `true` if the token is interpolated. |
212 | pub fn is_interpolated(&self) -> bool { | |
213 | match *self { | |
214 | Interpolated(..) => true, | |
215 | _ => false, | |
216 | } | |
217 | } | |
218 | ||
1a4d82fc JJ |
219 | /// Returns `true` if the token is an interpolated path. |
220 | pub fn is_path(&self) -> bool { | |
c30ab7b3 SL |
221 | if let Interpolated(ref nt) = *self { |
222 | if let NtPath(..) = **nt { | |
223 | return true; | |
224 | } | |
1a4d82fc | 225 | } |
c30ab7b3 | 226 | false |
1a4d82fc JJ |
227 | } |
228 | ||
1a4d82fc JJ |
229 | /// Returns `true` if the token is a lifetime. |
230 | pub fn is_lifetime(&self) -> bool { | |
231 | match *self { | |
232 | Lifetime(..) => true, | |
233 | _ => false, | |
223e47cc | 234 | } |
1a4d82fc JJ |
235 | } |
236 | ||
237 | /// Returns `true` if the token is either the `mut` or `const` keyword. | |
238 | pub fn is_mutability(&self) -> bool { | |
239 | self.is_keyword(keywords::Mut) || | |
240 | self.is_keyword(keywords::Const) | |
241 | } | |
242 | ||
c30ab7b3 SL |
243 | pub fn is_qpath_start(&self) -> bool { |
244 | self == &Lt || self == &BinOp(Shl) | |
245 | } | |
246 | ||
a7813a04 | 247 | pub fn is_path_start(&self) -> bool { |
c30ab7b3 | 248 | self == &ModSep || self.is_qpath_start() || self.is_path() || |
a7813a04 XL |
249 | self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword() |
250 | } | |
251 | ||
1a4d82fc | 252 | /// Returns `true` if the token is a given keyword, `kw`. |
1a4d82fc JJ |
253 | pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { |
254 | match *self { | |
a7813a04 XL |
255 | Ident(id) => id.name == kw.name(), |
256 | _ => false, | |
1a4d82fc JJ |
257 | } |
258 | } | |
259 | ||
a7813a04 | 260 | pub fn is_path_segment_keyword(&self) -> bool { |
1a4d82fc | 261 | match *self { |
a7813a04 XL |
262 | Ident(id) => id.name == keywords::Super.name() || |
263 | id.name == keywords::SelfValue.name() || | |
264 | id.name == keywords::SelfType.name(), | |
265 | _ => false, | |
1a4d82fc JJ |
266 | } |
267 | } | |
268 | ||
a7813a04 | 269 | /// Returns `true` if the token is either a strict or reserved keyword. |
1a4d82fc | 270 | pub fn is_any_keyword(&self) -> bool { |
a7813a04 | 271 | self.is_strict_keyword() || self.is_reserved_keyword() |
1a4d82fc JJ |
272 | } |
273 | ||
a7813a04 | 274 | /// Returns `true` if the token is a strict keyword. |
1a4d82fc JJ |
275 | pub fn is_strict_keyword(&self) -> bool { |
276 | match *self { | |
a7813a04 XL |
277 | Ident(id) => id.name >= keywords::As.name() && |
278 | id.name <= keywords::While.name(), | |
1a4d82fc JJ |
279 | _ => false, |
280 | } | |
281 | } | |
282 | ||
a7813a04 | 283 | /// Returns `true` if the token is a keyword reserved for possible future use. |
1a4d82fc JJ |
284 | pub fn is_reserved_keyword(&self) -> bool { |
285 | match *self { | |
a7813a04 XL |
286 | Ident(id) => id.name >= keywords::Abstract.name() && |
287 | id.name <= keywords::Yield.name(), | |
1a4d82fc JJ |
288 | _ => false, |
289 | } | |
290 | } | |
223e47cc LB |
291 | } |
292 | ||
1a4d82fc JJ |
293 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)] |
294 | /// For interpolation during macro expansion. | |
295 | pub enum Nonterminal { | |
296 | NtItem(P<ast::Item>), | |
297 | NtBlock(P<ast::Block>), | |
c30ab7b3 | 298 | NtStmt(ast::Stmt), |
1a4d82fc JJ |
299 | NtPat(P<ast::Pat>), |
300 | NtExpr(P<ast::Expr>), | |
301 | NtTy(P<ast::Ty>), | |
c30ab7b3 | 302 | NtIdent(ast::SpannedIdent), |
1a4d82fc JJ |
303 | /// Stuff inside brackets for attributes |
304 | NtMeta(P<ast::MetaItem>), | |
c30ab7b3 SL |
305 | NtPath(ast::Path), |
306 | NtTT(tokenstream::TokenTree), | |
92a42be0 | 307 | // These are not exposed to macros, but are used by quasiquote. |
d9579d0f | 308 | NtArm(ast::Arm), |
c30ab7b3 SL |
309 | NtImplItem(ast::ImplItem), |
310 | NtTraitItem(ast::TraitItem), | |
d9579d0f AL |
311 | NtGenerics(ast::Generics), |
312 | NtWhereClause(ast::WhereClause), | |
92a42be0 | 313 | NtArg(ast::Arg), |
1a4d82fc JJ |
314 | } |
315 | ||
85aaf69f | 316 | impl fmt::Debug for Nonterminal { |
1a4d82fc JJ |
317 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
318 | match *self { | |
319 | NtItem(..) => f.pad("NtItem(..)"), | |
320 | NtBlock(..) => f.pad("NtBlock(..)"), | |
321 | NtStmt(..) => f.pad("NtStmt(..)"), | |
322 | NtPat(..) => f.pad("NtPat(..)"), | |
323 | NtExpr(..) => f.pad("NtExpr(..)"), | |
324 | NtTy(..) => f.pad("NtTy(..)"), | |
325 | NtIdent(..) => f.pad("NtIdent(..)"), | |
326 | NtMeta(..) => f.pad("NtMeta(..)"), | |
327 | NtPath(..) => f.pad("NtPath(..)"), | |
328 | NtTT(..) => f.pad("NtTT(..)"), | |
d9579d0f AL |
329 | NtArm(..) => f.pad("NtArm(..)"), |
330 | NtImplItem(..) => f.pad("NtImplItem(..)"), | |
331 | NtTraitItem(..) => f.pad("NtTraitItem(..)"), | |
332 | NtGenerics(..) => f.pad("NtGenerics(..)"), | |
333 | NtWhereClause(..) => f.pad("NtWhereClause(..)"), | |
92a42be0 | 334 | NtArg(..) => f.pad("NtArg(..)"), |
1a4d82fc | 335 | } |
970d7e83 LB |
336 | } |
337 | } | |
338 | ||
1a4d82fc JJ |
339 | // In this macro, there is the requirement that the name (the number) must be monotonically |
340 | // increasing by one in the special identifiers, starting at 0; the same holds for the keywords, | |
a7813a04 XL |
341 | // except starting from the next number instead of zero. |
342 | macro_rules! declare_keywords {( | |
343 | $( ($index: expr, $konst: ident, $string: expr) )* | |
1a4d82fc | 344 | ) => { |
1a4d82fc | 345 | pub mod keywords { |
1a4d82fc | 346 | use ast; |
a7813a04 XL |
347 | #[derive(Clone, Copy, PartialEq, Eq)] |
348 | pub struct Keyword { | |
349 | ident: ast::Ident, | |
1a4d82fc | 350 | } |
1a4d82fc | 351 | impl Keyword { |
a7813a04 XL |
352 | #[inline] pub fn ident(self) -> ast::Ident { self.ident } |
353 | #[inline] pub fn name(self) -> ast::Name { self.ident.name } | |
223e47cc | 354 | } |
a7813a04 XL |
355 | $( |
356 | #[allow(non_upper_case_globals)] | |
357 | pub const $konst: Keyword = Keyword { | |
358 | ident: ast::Ident::with_empty_ctxt(ast::Name($index)) | |
359 | }; | |
360 | )* | |
223e47cc | 361 | } |
1a4d82fc JJ |
362 | |
363 | fn mk_fresh_ident_interner() -> IdentInterner { | |
5bcae85e | 364 | Interner::prefill(&[$($string,)*]) |
1a4d82fc JJ |
365 | } |
366 | }} | |
367 | ||
1a4d82fc JJ |
368 | // NB: leaving holes in the ident table is bad! a different ident will get |
369 | // interned with the id from the hole, but it will be between the min and max | |
370 | // of the reserved words, and thus tagged as "reserved". | |
a7813a04 XL |
371 | // After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, |
372 | // this should be rarely necessary though if the keywords are kept in alphabetic order. | |
373 | declare_keywords! { | |
374 | // Invalid identifier | |
375 | (0, Invalid, "") | |
376 | ||
377 | // Strict keywords used in the language. | |
378 | (1, As, "as") | |
379 | (2, Box, "box") | |
380 | (3, Break, "break") | |
381 | (4, Const, "const") | |
382 | (5, Continue, "continue") | |
383 | (6, Crate, "crate") | |
384 | (7, Else, "else") | |
385 | (8, Enum, "enum") | |
386 | (9, Extern, "extern") | |
387 | (10, False, "false") | |
388 | (11, Fn, "fn") | |
389 | (12, For, "for") | |
390 | (13, If, "if") | |
391 | (14, Impl, "impl") | |
392 | (15, In, "in") | |
393 | (16, Let, "let") | |
394 | (17, Loop, "loop") | |
395 | (18, Match, "match") | |
396 | (19, Mod, "mod") | |
397 | (20, Move, "move") | |
398 | (21, Mut, "mut") | |
399 | (22, Pub, "pub") | |
400 | (23, Ref, "ref") | |
401 | (24, Return, "return") | |
402 | (25, SelfValue, "self") | |
403 | (26, SelfType, "Self") | |
404 | (27, Static, "static") | |
405 | (28, Struct, "struct") | |
406 | (29, Super, "super") | |
407 | (30, Trait, "trait") | |
408 | (31, True, "true") | |
409 | (32, Type, "type") | |
410 | (33, Unsafe, "unsafe") | |
411 | (34, Use, "use") | |
412 | (35, Where, "where") | |
413 | (36, While, "while") | |
414 | ||
415 | // Keywords reserved for future use. | |
416 | (37, Abstract, "abstract") | |
417 | (38, Alignof, "alignof") | |
418 | (39, Become, "become") | |
419 | (40, Do, "do") | |
420 | (41, Final, "final") | |
421 | (42, Macro, "macro") | |
422 | (43, Offsetof, "offsetof") | |
423 | (44, Override, "override") | |
424 | (45, Priv, "priv") | |
425 | (46, Proc, "proc") | |
426 | (47, Pure, "pure") | |
427 | (48, Sizeof, "sizeof") | |
428 | (49, Typeof, "typeof") | |
429 | (50, Unsized, "unsized") | |
430 | (51, Virtual, "virtual") | |
431 | (52, Yield, "yield") | |
432 | ||
433 | // Weak keywords, have special meaning only in specific contexts. | |
434 | (53, Default, "default") | |
435 | (54, StaticLifetime, "'static") | |
436 | (55, Union, "union") | |
223e47cc LB |
437 | } |
438 | ||
1a4d82fc | 439 | // looks like we can get rid of this completely... |
5bcae85e | 440 | pub type IdentInterner = Interner; |
1a4d82fc JJ |
441 | |
442 | // if an interner exists in TLS, return it. Otherwise, prepare a | |
443 | // fresh one. | |
bd371182 | 444 | // FIXME(eddyb) #8726 This should probably use a thread-local reference. |
5bcae85e SL |
445 | pub fn with_ident_interner<T, F: FnOnce(&mut IdentInterner) -> T>(f: F) -> T { |
446 | thread_local!(static KEY: RefCell<IdentInterner> = { | |
447 | RefCell::new(mk_fresh_ident_interner()) | |
1a4d82fc | 448 | }); |
5bcae85e | 449 | KEY.with(|interner| f(&mut *interner.borrow_mut())) |
970d7e83 LB |
450 | } |
451 | ||
1a4d82fc JJ |
452 | /// Reset the ident interner to its initial state. |
453 | pub fn reset_ident_interner() { | |
5bcae85e SL |
454 | with_ident_interner(|interner| *interner = mk_fresh_ident_interner()); |
455 | } | |
456 | ||
457 | pub fn clear_ident_interner() { | |
458 | with_ident_interner(|interner| *interner = IdentInterner::new()); | |
1a4d82fc JJ |
459 | } |
460 | ||
bd371182 AL |
461 | /// Represents a string stored in the thread-local interner. Because the |
462 | /// interner lives for the life of the thread, this can be safely treated as an | |
463 | /// immortal string, as long as it never crosses between threads. | |
1a4d82fc JJ |
464 | /// |
465 | /// FIXME(pcwalton): You must be careful about what you do in the destructors | |
466 | /// of objects stored in TLS, because they may run after the interner is | |
467 | /// destroyed. In particular, they must not access string contents. This can | |
bd371182 | 468 | /// be fixed in the future by just leaking all strings until thread death |
1a4d82fc JJ |
469 | /// somehow. |
470 | #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] | |
471 | pub struct InternedString { | |
c30ab7b3 | 472 | string: Rc<str>, |
1a4d82fc JJ |
473 | } |
474 | ||
475 | impl InternedString { | |
476 | #[inline] | |
477 | pub fn new(string: &'static str) -> InternedString { | |
478 | InternedString { | |
c30ab7b3 | 479 | string: Rc::__from_str(string), |
1a4d82fc JJ |
480 | } |
481 | } | |
c1a9b12d SL |
482 | |
483 | #[inline] | |
484 | pub fn new_from_name(name: ast::Name) -> InternedString { | |
c30ab7b3 | 485 | with_ident_interner(|interner| InternedString { string: interner.get(name) }) |
c1a9b12d | 486 | } |
970d7e83 LB |
487 | } |
488 | ||
1a4d82fc JJ |
489 | impl Deref for InternedString { |
490 | type Target = str; | |
491 | ||
7453a54e | 492 | fn deref(&self) -> &str { &self.string } |
1a4d82fc JJ |
493 | } |
494 | ||
85aaf69f | 495 | impl fmt::Debug for InternedString { |
1a4d82fc | 496 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
c34b1796 | 497 | fmt::Debug::fmt(&self.string, f) |
223e47cc | 498 | } |
223e47cc LB |
499 | } |
500 | ||
85aaf69f | 501 | impl fmt::Display for InternedString { |
1a4d82fc | 502 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
c34b1796 | 503 | fmt::Display::fmt(&self.string, f) |
970d7e83 LB |
504 | } |
505 | } | |
506 | ||
1a4d82fc JJ |
507 | impl<'a> PartialEq<&'a str> for InternedString { |
508 | #[inline(always)] | |
509 | fn eq(&self, other: & &'a str) -> bool { | |
c34b1796 | 510 | PartialEq::eq(&self.string[..], *other) |
1a4d82fc JJ |
511 | } |
512 | #[inline(always)] | |
513 | fn ne(&self, other: & &'a str) -> bool { | |
c34b1796 | 514 | PartialEq::ne(&self.string[..], *other) |
970d7e83 LB |
515 | } |
516 | } | |
223e47cc | 517 | |
c1a9b12d | 518 | impl<'a> PartialEq<InternedString> for &'a str { |
1a4d82fc JJ |
519 | #[inline(always)] |
520 | fn eq(&self, other: &InternedString) -> bool { | |
c34b1796 | 521 | PartialEq::eq(*self, &other.string[..]) |
1a4d82fc JJ |
522 | } |
523 | #[inline(always)] | |
524 | fn ne(&self, other: &InternedString) -> bool { | |
c34b1796 | 525 | PartialEq::ne(*self, &other.string[..]) |
1a4d82fc JJ |
526 | } |
527 | } | |
528 | ||
a7813a04 XL |
529 | impl PartialEq<str> for InternedString { |
530 | #[inline(always)] | |
531 | fn eq(&self, other: &str) -> bool { | |
532 | PartialEq::eq(&self.string[..], other) | |
533 | } | |
534 | #[inline(always)] | |
535 | fn ne(&self, other: &str) -> bool { | |
536 | PartialEq::ne(&self.string[..], other) | |
537 | } | |
538 | } | |
539 | ||
540 | impl PartialEq<InternedString> for str { | |
541 | #[inline(always)] | |
542 | fn eq(&self, other: &InternedString) -> bool { | |
543 | PartialEq::eq(self, &other.string[..]) | |
544 | } | |
545 | #[inline(always)] | |
546 | fn ne(&self, other: &InternedString) -> bool { | |
547 | PartialEq::ne(self, &other.string[..]) | |
548 | } | |
549 | } | |
550 | ||
1a4d82fc JJ |
551 | impl Decodable for InternedString { |
552 | fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> { | |
c30ab7b3 | 553 | Ok(intern(&d.read_str()?).as_str()) |
970d7e83 LB |
554 | } |
555 | } | |
556 | ||
1a4d82fc JJ |
557 | impl Encodable for InternedString { |
558 | fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { | |
c34b1796 | 559 | s.emit_str(&self.string) |
1a4d82fc JJ |
560 | } |
561 | } | |
562 | ||
1a4d82fc | 563 | /// Interns and returns the string contents of an identifier, using the |
bd371182 | 564 | /// thread-local interner. |
1a4d82fc JJ |
565 | #[inline] |
566 | pub fn intern_and_get_ident(s: &str) -> InternedString { | |
c1a9b12d | 567 | intern(s).as_str() |
1a4d82fc JJ |
568 | } |
569 | ||
570 | /// Maps a string to its interned representation. | |
571 | #[inline] | |
572 | pub fn intern(s: &str) -> ast::Name { | |
5bcae85e | 573 | with_ident_interner(|interner| interner.intern(s)) |
1a4d82fc JJ |
574 | } |
575 | ||
85aaf69f | 576 | /// gensym's a new usize, using the current interner. |
1a4d82fc JJ |
577 | #[inline] |
578 | pub fn gensym(s: &str) -> ast::Name { | |
5bcae85e | 579 | with_ident_interner(|interner| interner.gensym(s)) |
1a4d82fc JJ |
580 | } |
581 | ||
582 | /// Maps a string to an identifier with an empty syntax context. | |
583 | #[inline] | |
584 | pub fn str_to_ident(s: &str) -> ast::Ident { | |
b039eaaf | 585 | ast::Ident::with_empty_ctxt(intern(s)) |
1a4d82fc JJ |
586 | } |
587 | ||
588 | /// Maps a string to a gensym'ed identifier. | |
589 | #[inline] | |
590 | pub fn gensym_ident(s: &str) -> ast::Ident { | |
b039eaaf | 591 | ast::Ident::with_empty_ctxt(gensym(s)) |
1a4d82fc JJ |
592 | } |
593 | ||
594 | // create a fresh name that maps to the same string as the old one. | |
595 | // note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src))); | |
596 | // that is, that the new name and the old one are connected to ptr_eq strings. | |
b039eaaf | 597 | pub fn fresh_name(src: ast::Ident) -> ast::Name { |
5bcae85e | 598 | with_ident_interner(|interner| interner.gensym_copy(src.name)) |
1a4d82fc JJ |
599 | // following: debug version. Could work in final except that it's incompatible with |
600 | // good error messages and uses of struct names in ambiguous could-be-binding | |
601 | // locations. Also definitely destroys the guarantee given above about ptr_eq. | |
602 | /*let num = rand::thread_rng().gen_uint_range(0,0xffff); | |
603 | gensym(format!("{}_{}",ident_to_string(src),num))*/ | |
604 | } |