]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/parse/token.rs
Imported Upstream version 1.6.0+dfsg1
[rustc.git] / src / libsyntax / parse / token.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
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
11 pub use self::BinOpToken::*;
12 pub use self::Nonterminal::*;
13 pub use self::DelimToken::*;
14 pub use self::IdentStyle::*;
15 pub use self::Lit::*;
16 pub use self::Token::*;
17
18 use ast;
19 use ext::mtwt;
20 use ptr::P;
21 use util::interner::{RcStr, StrInterner};
22 use util::interner;
23
24 use serialize::{Decodable, Decoder, Encodable, Encoder};
25 use std::fmt;
26 use std::ops::Deref;
27 use std::rc::Rc;
28
29 #[allow(non_camel_case_types)]
30 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
31 pub enum BinOpToken {
32 Plus,
33 Minus,
34 Star,
35 Slash,
36 Percent,
37 Caret,
38 And,
39 Or,
40 Shl,
41 Shr,
42 }
43
44 /// A delimiter token
45 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
46 pub enum DelimToken {
47 /// A round parenthesis: `(` or `)`
48 Paren,
49 /// A square bracket: `[` or `]`
50 Bracket,
51 /// A curly brace: `{` or `}`
52 Brace,
53 }
54
55 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
56 pub enum IdentStyle {
57 /// `::` follows the identifier with no whitespace in-between.
58 ModName,
59 Plain,
60 }
61
62 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
63 pub enum SpecialMacroVar {
64 /// `$crate` will be filled in with the name of the crate a macro was
65 /// imported from, if any.
66 CrateMacroVar,
67 }
68
69 impl SpecialMacroVar {
70 pub fn as_str(self) -> &'static str {
71 match self {
72 SpecialMacroVar::CrateMacroVar => "crate",
73 }
74 }
75 }
76
77 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
78 pub enum Lit {
79 Byte(ast::Name),
80 Char(ast::Name),
81 Integer(ast::Name),
82 Float(ast::Name),
83 Str_(ast::Name),
84 StrRaw(ast::Name, usize), /* raw str delimited by n hash symbols */
85 ByteStr(ast::Name),
86 ByteStrRaw(ast::Name, usize), /* raw byte str delimited by n hash symbols */
87 }
88
89 impl Lit {
90 pub fn short_name(&self) -> &'static str {
91 match *self {
92 Byte(_) => "byte",
93 Char(_) => "char",
94 Integer(_) => "integer",
95 Float(_) => "float",
96 Str_(_) | StrRaw(..) => "string",
97 ByteStr(_) | ByteStrRaw(..) => "byte string"
98 }
99 }
100 }
101
102 #[allow(non_camel_case_types)]
103 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)]
104 pub enum Token {
105 /* Expression-operator symbols. */
106 Eq,
107 Lt,
108 Le,
109 EqEq,
110 Ne,
111 Ge,
112 Gt,
113 AndAnd,
114 OrOr,
115 Not,
116 Tilde,
117 BinOp(BinOpToken),
118 BinOpEq(BinOpToken),
119
120 /* Structural symbols */
121 At,
122 Dot,
123 DotDot,
124 DotDotDot,
125 Comma,
126 Semi,
127 Colon,
128 ModSep,
129 RArrow,
130 LArrow,
131 FatArrow,
132 Pound,
133 Dollar,
134 Question,
135 /// An opening delimiter, eg. `{`
136 OpenDelim(DelimToken),
137 /// A closing delimiter, eg. `}`
138 CloseDelim(DelimToken),
139
140 /* Literals */
141 Literal(Lit, Option<ast::Name>),
142
143 /* Name components */
144 Ident(ast::Ident, IdentStyle),
145 Underscore,
146 Lifetime(ast::Ident),
147
148 /* For interpolation */
149 Interpolated(Nonterminal),
150 // Can be expanded into several tokens.
151 /// Doc comment
152 DocComment(ast::Name),
153 // In left-hand-sides of MBE macros:
154 /// Parse a nonterminal (name to bind, name of NT, styles of their idents)
155 MatchNt(ast::Ident, ast::Ident, IdentStyle, IdentStyle),
156 // In right-hand-sides of MBE macros:
157 /// A syntactic variable that will be filled in by macro expansion.
158 SubstNt(ast::Ident, IdentStyle),
159 /// A macro variable with special meaning.
160 SpecialVarNt(SpecialMacroVar),
161
162 // Junk. These carry no data because we don't really care about the data
163 // they *would* carry, and don't really want to allocate a new ident for
164 // them. Instead, users could extract that from the associated span.
165
166 /// Whitespace
167 Whitespace,
168 /// Comment
169 Comment,
170 Shebang(ast::Name),
171
172 Eof,
173 }
174
175 impl Token {
176 /// Returns `true` if the token starts with '>'.
177 pub fn is_like_gt(&self) -> bool {
178 match *self {
179 BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true,
180 _ => false,
181 }
182 }
183
184 /// Returns `true` if the token can appear at the start of an expression.
185 pub fn can_begin_expr(&self) -> bool {
186 match *self {
187 OpenDelim(_) => true,
188 Ident(_, _) => true,
189 Underscore => true,
190 Tilde => true,
191 Literal(_, _) => true,
192 Not => true,
193 BinOp(Minus) => true,
194 BinOp(Star) => true,
195 BinOp(And) => true,
196 BinOp(Or) => true, // in lambda syntax
197 OrOr => true, // in lambda syntax
198 AndAnd => true, // double borrow
199 DotDot => true, // range notation
200 ModSep => true,
201 Interpolated(NtExpr(..)) => true,
202 Interpolated(NtIdent(..)) => true,
203 Interpolated(NtBlock(..)) => true,
204 Interpolated(NtPath(..)) => true,
205 Pound => true, // for expression attributes
206 _ => false,
207 }
208 }
209
210 /// Returns `true` if the token is any literal
211 pub fn is_lit(&self) -> bool {
212 match *self {
213 Literal(_, _) => true,
214 _ => false,
215 }
216 }
217
218 /// Returns `true` if the token is an identifier.
219 pub fn is_ident(&self) -> bool {
220 match *self {
221 Ident(_, _) => true,
222 _ => false,
223 }
224 }
225
226 /// Returns `true` if the token is an interpolated path.
227 pub fn is_path(&self) -> bool {
228 match *self {
229 Interpolated(NtPath(..)) => true,
230 _ => false,
231 }
232 }
233
234 /// Returns `true` if the token is a path that is not followed by a `::`
235 /// token.
236 #[allow(non_upper_case_globals)]
237 pub fn is_plain_ident(&self) -> bool {
238 match *self {
239 Ident(_, Plain) => true,
240 _ => false,
241 }
242 }
243
244 /// Returns `true` if the token is a lifetime.
245 pub fn is_lifetime(&self) -> bool {
246 match *self {
247 Lifetime(..) => true,
248 _ => false,
249 }
250 }
251
252 /// Returns `true` if the token is either the `mut` or `const` keyword.
253 pub fn is_mutability(&self) -> bool {
254 self.is_keyword(keywords::Mut) ||
255 self.is_keyword(keywords::Const)
256 }
257
258 /// Maps a token to its corresponding binary operator.
259 pub fn to_binop(&self) -> Option<ast::BinOp_> {
260 match *self {
261 BinOp(Star) => Some(ast::BiMul),
262 BinOp(Slash) => Some(ast::BiDiv),
263 BinOp(Percent) => Some(ast::BiRem),
264 BinOp(Plus) => Some(ast::BiAdd),
265 BinOp(Minus) => Some(ast::BiSub),
266 BinOp(Shl) => Some(ast::BiShl),
267 BinOp(Shr) => Some(ast::BiShr),
268 BinOp(And) => Some(ast::BiBitAnd),
269 BinOp(Caret) => Some(ast::BiBitXor),
270 BinOp(Or) => Some(ast::BiBitOr),
271 Lt => Some(ast::BiLt),
272 Le => Some(ast::BiLe),
273 Ge => Some(ast::BiGe),
274 Gt => Some(ast::BiGt),
275 EqEq => Some(ast::BiEq),
276 Ne => Some(ast::BiNe),
277 AndAnd => Some(ast::BiAnd),
278 OrOr => Some(ast::BiOr),
279 _ => None,
280 }
281 }
282
283 /// Returns `true` if the token is a given keyword, `kw`.
284 #[allow(non_upper_case_globals)]
285 pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
286 match *self {
287 Ident(sid, Plain) => kw.to_name() == sid.name,
288 _ => false,
289 }
290 }
291
292 pub fn is_keyword_allow_following_colon(&self, kw: keywords::Keyword) -> bool {
293 match *self {
294 Ident(sid, _) => { kw.to_name() == sid.name }
295 _ => { false }
296 }
297 }
298
299 /// Returns `true` if the token is either a special identifier, or a strict
300 /// or reserved keyword.
301 #[allow(non_upper_case_globals)]
302 pub fn is_any_keyword(&self) -> bool {
303 match *self {
304 Ident(sid, Plain) => {
305 let n = sid.name;
306
307 n == SELF_KEYWORD_NAME
308 || n == STATIC_KEYWORD_NAME
309 || n == SUPER_KEYWORD_NAME
310 || n == SELF_TYPE_KEYWORD_NAME
311 || STRICT_KEYWORD_START <= n
312 && n <= RESERVED_KEYWORD_FINAL
313 },
314 _ => false
315 }
316 }
317
318 /// Returns `true` if the token may not appear as an identifier.
319 #[allow(non_upper_case_globals)]
320 pub fn is_strict_keyword(&self) -> bool {
321 match *self {
322 Ident(sid, Plain) => {
323 let n = sid.name;
324
325 n == SELF_KEYWORD_NAME
326 || n == STATIC_KEYWORD_NAME
327 || n == SUPER_KEYWORD_NAME
328 || n == SELF_TYPE_KEYWORD_NAME
329 || STRICT_KEYWORD_START <= n
330 && n <= STRICT_KEYWORD_FINAL
331 },
332 Ident(sid, ModName) => {
333 let n = sid.name;
334
335 n != SELF_KEYWORD_NAME
336 && n != SUPER_KEYWORD_NAME
337 && STRICT_KEYWORD_START <= n
338 && n <= STRICT_KEYWORD_FINAL
339 }
340 _ => false,
341 }
342 }
343
344 /// Returns `true` if the token is a keyword that has been reserved for
345 /// possible future use.
346 #[allow(non_upper_case_globals)]
347 pub fn is_reserved_keyword(&self) -> bool {
348 match *self {
349 Ident(sid, Plain) => {
350 let n = sid.name;
351
352 RESERVED_KEYWORD_START <= n
353 && n <= RESERVED_KEYWORD_FINAL
354 },
355 _ => false,
356 }
357 }
358
359 /// Hygienic identifier equality comparison.
360 ///
361 /// See `styntax::ext::mtwt`.
362 pub fn mtwt_eq(&self, other : &Token) -> bool {
363 match (self, other) {
364 (&Ident(id1,_), &Ident(id2,_)) | (&Lifetime(id1), &Lifetime(id2)) =>
365 mtwt::resolve(id1) == mtwt::resolve(id2),
366 _ => *self == *other
367 }
368 }
369 }
370
371 #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
372 /// For interpolation during macro expansion.
373 pub enum Nonterminal {
374 NtItem(P<ast::Item>),
375 NtBlock(P<ast::Block>),
376 NtStmt(P<ast::Stmt>),
377 NtPat(P<ast::Pat>),
378 NtExpr(P<ast::Expr>),
379 NtTy(P<ast::Ty>),
380 NtIdent(Box<ast::Ident>, IdentStyle),
381 /// Stuff inside brackets for attributes
382 NtMeta(P<ast::MetaItem>),
383 NtPath(Box<ast::Path>),
384 NtTT(P<ast::TokenTree>), // needs P'ed to break a circularity
385 // These are not exposed to macros, but are used by quasiquote.
386 NtArm(ast::Arm),
387 NtImplItem(P<ast::ImplItem>),
388 NtTraitItem(P<ast::TraitItem>),
389 NtGenerics(ast::Generics),
390 NtWhereClause(ast::WhereClause),
391 NtArg(ast::Arg),
392 }
393
394 impl fmt::Debug for Nonterminal {
395 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
396 match *self {
397 NtItem(..) => f.pad("NtItem(..)"),
398 NtBlock(..) => f.pad("NtBlock(..)"),
399 NtStmt(..) => f.pad("NtStmt(..)"),
400 NtPat(..) => f.pad("NtPat(..)"),
401 NtExpr(..) => f.pad("NtExpr(..)"),
402 NtTy(..) => f.pad("NtTy(..)"),
403 NtIdent(..) => f.pad("NtIdent(..)"),
404 NtMeta(..) => f.pad("NtMeta(..)"),
405 NtPath(..) => f.pad("NtPath(..)"),
406 NtTT(..) => f.pad("NtTT(..)"),
407 NtArm(..) => f.pad("NtArm(..)"),
408 NtImplItem(..) => f.pad("NtImplItem(..)"),
409 NtTraitItem(..) => f.pad("NtTraitItem(..)"),
410 NtGenerics(..) => f.pad("NtGenerics(..)"),
411 NtWhereClause(..) => f.pad("NtWhereClause(..)"),
412 NtArg(..) => f.pad("NtArg(..)"),
413 }
414 }
415 }
416
417
418 // Get the first "argument"
419 macro_rules! first {
420 ( $first:expr, $( $remainder:expr, )* ) => ( $first )
421 }
422
423 // Get the last "argument" (has to be done recursively to avoid phoney local ambiguity error)
424 macro_rules! last {
425 ( $first:expr, $( $remainder:expr, )+ ) => ( last!( $( $remainder, )+ ) );
426 ( $first:expr, ) => ( $first )
427 }
428
429 // In this macro, there is the requirement that the name (the number) must be monotonically
430 // increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
431 // except starting from the next number instead of zero, and with the additional exception that
432 // special identifiers are *also* allowed (they are deduplicated in the important place, the
433 // interner), an exception which is demonstrated by "static" and "self".
434 macro_rules! declare_special_idents_and_keywords {(
435 // So now, in these rules, why is each definition parenthesised?
436 // Answer: otherwise we get a spurious local ambiguity bug on the "}"
437 pub mod special_idents {
438 $( ($si_name:expr, $si_static:ident, $si_str:expr); )*
439 }
440
441 pub mod keywords {
442 'strict:
443 $( ($sk_name:expr, $sk_variant:ident, $sk_str:expr); )*
444 'reserved:
445 $( ($rk_name:expr, $rk_variant:ident, $rk_str:expr); )*
446 }
447 ) => {
448 const STRICT_KEYWORD_START: ast::Name = first!($( ast::Name($sk_name), )*);
449 const STRICT_KEYWORD_FINAL: ast::Name = last!($( ast::Name($sk_name), )*);
450 const RESERVED_KEYWORD_START: ast::Name = first!($( ast::Name($rk_name), )*);
451 const RESERVED_KEYWORD_FINAL: ast::Name = last!($( ast::Name($rk_name), )*);
452
453 pub mod special_idents {
454 use ast;
455 $(
456 #[allow(non_upper_case_globals)]
457 pub const $si_static: ast::Ident = ast::Ident {
458 name: ast::Name($si_name),
459 ctxt: ast::EMPTY_CTXT,
460 };
461 )*
462 }
463
464 pub mod special_names {
465 use ast;
466 $(
467 #[allow(non_upper_case_globals)]
468 pub const $si_static: ast::Name = ast::Name($si_name);
469 )*
470 }
471
472 /// All the valid words that have meaning in the Rust language.
473 ///
474 /// Rust keywords are either 'strict' or 'reserved'. Strict keywords may not
475 /// appear as identifiers at all. Reserved keywords are not used anywhere in
476 /// the language and may not appear as identifiers.
477 pub mod keywords {
478 pub use self::Keyword::*;
479 use ast;
480
481 #[derive(Copy, Clone, PartialEq, Eq)]
482 pub enum Keyword {
483 $( $sk_variant, )*
484 $( $rk_variant, )*
485 }
486
487 impl Keyword {
488 pub fn to_name(&self) -> ast::Name {
489 match *self {
490 $( $sk_variant => ast::Name($sk_name), )*
491 $( $rk_variant => ast::Name($rk_name), )*
492 }
493 }
494 }
495 }
496
497 fn mk_fresh_ident_interner() -> IdentInterner {
498 // The indices here must correspond to the numbers in
499 // special_idents, in Keyword to_name(), and in static
500 // constants below.
501 let mut init_vec = Vec::new();
502 $(init_vec.push($si_str);)*
503 $(init_vec.push($sk_str);)*
504 $(init_vec.push($rk_str);)*
505 interner::StrInterner::prefill(&init_vec[..])
506 }
507 }}
508
509 // If the special idents get renumbered, remember to modify these two as appropriate
510 pub const SELF_KEYWORD_NAME: ast::Name = ast::Name(SELF_KEYWORD_NAME_NUM);
511 const STATIC_KEYWORD_NAME: ast::Name = ast::Name(STATIC_KEYWORD_NAME_NUM);
512 const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM);
513 const SELF_TYPE_KEYWORD_NAME: ast::Name = ast::Name(SELF_TYPE_KEYWORD_NAME_NUM);
514
515 pub const SELF_KEYWORD_NAME_NUM: u32 = 1;
516 const STATIC_KEYWORD_NAME_NUM: u32 = 2;
517 const SUPER_KEYWORD_NAME_NUM: u32 = 3;
518 const SELF_TYPE_KEYWORD_NAME_NUM: u32 = 10;
519
520 // NB: leaving holes in the ident table is bad! a different ident will get
521 // interned with the id from the hole, but it will be between the min and max
522 // of the reserved words, and thus tagged as "reserved".
523
524 declare_special_idents_and_keywords! {
525 pub mod special_idents {
526 // These ones are statics
527 (0, invalid, "");
528 (super::SELF_KEYWORD_NAME_NUM, self_, "self");
529 (super::STATIC_KEYWORD_NAME_NUM, statik, "static");
530 (super::SUPER_KEYWORD_NAME_NUM, super_, "super");
531 (4, static_lifetime, "'static");
532
533 // for matcher NTs
534 (5, tt, "tt");
535 (6, matchers, "matchers");
536
537 // outside of libsyntax
538 (7, clownshoe_abi, "__rust_abi");
539 (8, opaque, "<opaque>");
540 (9, unnamed_field, "<unnamed_field>");
541 (super::SELF_TYPE_KEYWORD_NAME_NUM, type_self, "Self");
542 (11, prelude_import, "prelude_import");
543 }
544
545 pub mod keywords {
546 // These ones are variants of the Keyword enum
547
548 'strict:
549 (12, As, "as");
550 (13, Break, "break");
551 (14, Crate, "crate");
552 (15, Else, "else");
553 (16, Enum, "enum");
554 (17, Extern, "extern");
555 (18, False, "false");
556 (19, Fn, "fn");
557 (20, For, "for");
558 (21, If, "if");
559 (22, Impl, "impl");
560 (23, In, "in");
561 (24, Let, "let");
562 (25, Loop, "loop");
563 (26, Match, "match");
564 (27, Mod, "mod");
565 (28, Move, "move");
566 (29, Mut, "mut");
567 (30, Pub, "pub");
568 (31, Ref, "ref");
569 (32, Return, "return");
570 // Static and Self are also special idents (prefill de-dupes)
571 (super::STATIC_KEYWORD_NAME_NUM, Static, "static");
572 (super::SELF_KEYWORD_NAME_NUM, SelfValue, "self");
573 (super::SELF_TYPE_KEYWORD_NAME_NUM, SelfType, "Self");
574 (33, Struct, "struct");
575 (super::SUPER_KEYWORD_NAME_NUM, Super, "super");
576 (34, True, "true");
577 (35, Trait, "trait");
578 (36, Type, "type");
579 (37, Unsafe, "unsafe");
580 (38, Use, "use");
581 (39, While, "while");
582 (40, Continue, "continue");
583 (41, Box, "box");
584 (42, Const, "const");
585 (43, Where, "where");
586 'reserved:
587 (44, Virtual, "virtual");
588 (45, Proc, "proc");
589 (46, Alignof, "alignof");
590 (47, Become, "become");
591 (48, Offsetof, "offsetof");
592 (49, Priv, "priv");
593 (50, Pure, "pure");
594 (51, Sizeof, "sizeof");
595 (52, Typeof, "typeof");
596 (53, Unsized, "unsized");
597 (54, Yield, "yield");
598 (55, Do, "do");
599 (56, Abstract, "abstract");
600 (57, Final, "final");
601 (58, Override, "override");
602 (59, Macro, "macro");
603 }
604 }
605
606 // looks like we can get rid of this completely...
607 pub type IdentInterner = StrInterner;
608
609 // if an interner exists in TLS, return it. Otherwise, prepare a
610 // fresh one.
611 // FIXME(eddyb) #8726 This should probably use a thread-local reference.
612 pub fn get_ident_interner() -> Rc<IdentInterner> {
613 thread_local!(static KEY: Rc<::parse::token::IdentInterner> = {
614 Rc::new(mk_fresh_ident_interner())
615 });
616 KEY.with(|k| k.clone())
617 }
618
619 /// Reset the ident interner to its initial state.
620 pub fn reset_ident_interner() {
621 let interner = get_ident_interner();
622 interner.reset(mk_fresh_ident_interner());
623 }
624
625 /// Represents a string stored in the thread-local interner. Because the
626 /// interner lives for the life of the thread, this can be safely treated as an
627 /// immortal string, as long as it never crosses between threads.
628 ///
629 /// FIXME(pcwalton): You must be careful about what you do in the destructors
630 /// of objects stored in TLS, because they may run after the interner is
631 /// destroyed. In particular, they must not access string contents. This can
632 /// be fixed in the future by just leaking all strings until thread death
633 /// somehow.
634 #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
635 pub struct InternedString {
636 string: RcStr,
637 }
638
639 impl InternedString {
640 #[inline]
641 pub fn new(string: &'static str) -> InternedString {
642 InternedString {
643 string: RcStr::new(string),
644 }
645 }
646
647 #[inline]
648 fn new_from_rc_str(string: RcStr) -> InternedString {
649 InternedString {
650 string: string,
651 }
652 }
653
654 #[inline]
655 pub fn new_from_name(name: ast::Name) -> InternedString {
656 let interner = get_ident_interner();
657 InternedString::new_from_rc_str(interner.get(name))
658 }
659 }
660
661 impl Deref for InternedString {
662 type Target = str;
663
664 fn deref(&self) -> &str { &*self.string }
665 }
666
667 impl fmt::Debug for InternedString {
668 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
669 fmt::Debug::fmt(&self.string, f)
670 }
671 }
672
673 impl fmt::Display for InternedString {
674 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
675 fmt::Display::fmt(&self.string, f)
676 }
677 }
678
679 impl<'a> PartialEq<&'a str> for InternedString {
680 #[inline(always)]
681 fn eq(&self, other: & &'a str) -> bool {
682 PartialEq::eq(&self.string[..], *other)
683 }
684 #[inline(always)]
685 fn ne(&self, other: & &'a str) -> bool {
686 PartialEq::ne(&self.string[..], *other)
687 }
688 }
689
690 impl<'a> PartialEq<InternedString> for &'a str {
691 #[inline(always)]
692 fn eq(&self, other: &InternedString) -> bool {
693 PartialEq::eq(*self, &other.string[..])
694 }
695 #[inline(always)]
696 fn ne(&self, other: &InternedString) -> bool {
697 PartialEq::ne(*self, &other.string[..])
698 }
699 }
700
701 impl Decodable for InternedString {
702 fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
703 Ok(intern(try!(d.read_str()).as_ref()).as_str())
704 }
705 }
706
707 impl Encodable for InternedString {
708 fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
709 s.emit_str(&self.string)
710 }
711 }
712
713 /// Interns and returns the string contents of an identifier, using the
714 /// thread-local interner.
715 #[inline]
716 pub fn intern_and_get_ident(s: &str) -> InternedString {
717 intern(s).as_str()
718 }
719
720 /// Maps a string to its interned representation.
721 #[inline]
722 pub fn intern(s: &str) -> ast::Name {
723 get_ident_interner().intern(s)
724 }
725
726 /// gensym's a new usize, using the current interner.
727 #[inline]
728 pub fn gensym(s: &str) -> ast::Name {
729 get_ident_interner().gensym(s)
730 }
731
732 /// Maps a string to an identifier with an empty syntax context.
733 #[inline]
734 pub fn str_to_ident(s: &str) -> ast::Ident {
735 ast::Ident::with_empty_ctxt(intern(s))
736 }
737
738 /// Maps a string to a gensym'ed identifier.
739 #[inline]
740 pub fn gensym_ident(s: &str) -> ast::Ident {
741 ast::Ident::with_empty_ctxt(gensym(s))
742 }
743
744 // create a fresh name that maps to the same string as the old one.
745 // note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src)));
746 // that is, that the new name and the old one are connected to ptr_eq strings.
747 pub fn fresh_name(src: ast::Ident) -> ast::Name {
748 let interner = get_ident_interner();
749 interner.gensym_copy(src.name)
750 // following: debug version. Could work in final except that it's incompatible with
751 // good error messages and uses of struct names in ambiguous could-be-binding
752 // locations. Also definitely destroys the guarantee given above about ptr_eq.
753 /*let num = rand::thread_rng().gen_uint_range(0,0xffff);
754 gensym(format!("{}_{}",ident_to_string(src),num))*/
755 }
756
757 // create a fresh mark.
758 pub fn fresh_mark() -> ast::Mrk {
759 gensym("mark").0
760 }
761
762 #[cfg(test)]
763 mod tests {
764 use super::*;
765 use ast;
766 use ext::mtwt;
767
768 fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
769 ast::Ident::new(id.name, mtwt::apply_mark(m, id.ctxt))
770 }
771
772 #[test] fn mtwt_token_eq_test() {
773 assert!(Gt.mtwt_eq(&Gt));
774 let a = str_to_ident("bac");
775 let a1 = mark_ident(a,92);
776 assert!(Ident(a, ModName).mtwt_eq(&Ident(a1, Plain)));
777 }
778 }