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