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