]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/parse/token.rs
Imported Upstream version 1.9.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 198 AndAnd => true, // double borrow
54a0048b 199 DotDot | DotDotDot => 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);
54a0048b 517pub const 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>");
54a0048b 545 (9, __unused1, "<__unused1>");
85aaf69f 546 (super::SELF_TYPE_KEYWORD_NAME_NUM, type_self, "Self");
1a4d82fc 547 (11, prelude_import, "prelude_import");
54a0048b 548 (12, DEFAULT, "default");
1a4d82fc
JJ
549 }
550
551 pub mod keywords {
552 // These ones are variants of the Keyword enum
553
554 'strict:
54a0048b
SL
555 (13, As, "as");
556 (14, Break, "break");
557 (15, Crate, "crate");
558 (16, Else, "else");
559 (17, Enum, "enum");
560 (18, Extern, "extern");
561 (19, False, "false");
562 (20, Fn, "fn");
563 (21, For, "for");
564 (22, If, "if");
565 (23, Impl, "impl");
566 (24, In, "in");
567 (25, Let, "let");
568 (26, Loop, "loop");
569 (27, Match, "match");
570 (28, Mod, "mod");
571 (29, Move, "move");
572 (30, Mut, "mut");
573 (31, Pub, "pub");
574 (32, Ref, "ref");
575 (33, Return, "return");
1a4d82fc
JJ
576 // Static and Self are also special idents (prefill de-dupes)
577 (super::STATIC_KEYWORD_NAME_NUM, Static, "static");
85aaf69f
SL
578 (super::SELF_KEYWORD_NAME_NUM, SelfValue, "self");
579 (super::SELF_TYPE_KEYWORD_NAME_NUM, SelfType, "Self");
54a0048b 580 (34, Struct, "struct");
1a4d82fc 581 (super::SUPER_KEYWORD_NAME_NUM, Super, "super");
54a0048b
SL
582 (35, True, "true");
583 (36, Trait, "trait");
584 (37, Type, "type");
585 (38, Unsafe, "unsafe");
586 (39, Use, "use");
587 (40, While, "while");
588 (41, Continue, "continue");
589 (42, Box, "box");
590 (43, Const, "const");
591 (44, Where, "where");
1a4d82fc 592 'reserved:
54a0048b
SL
593 (45, Virtual, "virtual");
594 (46, Proc, "proc");
595 (47, Alignof, "alignof");
596 (48, Become, "become");
597 (49, Offsetof, "offsetof");
598 (50, Priv, "priv");
599 (51, Pure, "pure");
600 (52, Sizeof, "sizeof");
601 (53, Typeof, "typeof");
602 (54, Unsized, "unsized");
603 (55, Yield, "yield");
604 (56, Do, "do");
605 (57, Abstract, "abstract");
606 (58, Final, "final");
607 (59, Override, "override");
608 (60, Macro, "macro");
1a4d82fc 609 }
223e47cc
LB
610}
611
1a4d82fc
JJ
612// looks like we can get rid of this completely...
613pub type IdentInterner = StrInterner;
614
615// if an interner exists in TLS, return it. Otherwise, prepare a
616// fresh one.
bd371182 617// FIXME(eddyb) #8726 This should probably use a thread-local reference.
1a4d82fc
JJ
618pub fn get_ident_interner() -> Rc<IdentInterner> {
619 thread_local!(static KEY: Rc<::parse::token::IdentInterner> = {
620 Rc::new(mk_fresh_ident_interner())
621 });
622 KEY.with(|k| k.clone())
970d7e83
LB
623}
624
1a4d82fc
JJ
625/// Reset the ident interner to its initial state.
626pub fn reset_ident_interner() {
970d7e83 627 let interner = get_ident_interner();
1a4d82fc
JJ
628 interner.reset(mk_fresh_ident_interner());
629}
630
bd371182
AL
631/// Represents a string stored in the thread-local interner. Because the
632/// interner lives for the life of the thread, this can be safely treated as an
633/// immortal string, as long as it never crosses between threads.
1a4d82fc
JJ
634///
635/// FIXME(pcwalton): You must be careful about what you do in the destructors
636/// of objects stored in TLS, because they may run after the interner is
637/// destroyed. In particular, they must not access string contents. This can
bd371182 638/// be fixed in the future by just leaking all strings until thread death
1a4d82fc
JJ
639/// somehow.
640#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
641pub struct InternedString {
642 string: RcStr,
643}
644
645impl InternedString {
646 #[inline]
647 pub fn new(string: &'static str) -> InternedString {
648 InternedString {
649 string: RcStr::new(string),
650 }
651 }
652
653 #[inline]
654 fn new_from_rc_str(string: RcStr) -> InternedString {
655 InternedString {
656 string: string,
657 }
658 }
c1a9b12d
SL
659
660 #[inline]
661 pub fn new_from_name(name: ast::Name) -> InternedString {
662 let interner = get_ident_interner();
663 InternedString::new_from_rc_str(interner.get(name))
664 }
970d7e83
LB
665}
666
1a4d82fc
JJ
667impl Deref for InternedString {
668 type Target = str;
669
7453a54e 670 fn deref(&self) -> &str { &self.string }
1a4d82fc
JJ
671}
672
85aaf69f 673impl fmt::Debug for InternedString {
1a4d82fc 674 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
c34b1796 675 fmt::Debug::fmt(&self.string, f)
223e47cc 676 }
223e47cc
LB
677}
678
85aaf69f 679impl fmt::Display for InternedString {
1a4d82fc 680 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
c34b1796 681 fmt::Display::fmt(&self.string, f)
970d7e83
LB
682 }
683}
684
1a4d82fc
JJ
685impl<'a> PartialEq<&'a str> for InternedString {
686 #[inline(always)]
687 fn eq(&self, other: & &'a str) -> bool {
c34b1796 688 PartialEq::eq(&self.string[..], *other)
1a4d82fc
JJ
689 }
690 #[inline(always)]
691 fn ne(&self, other: & &'a str) -> bool {
c34b1796 692 PartialEq::ne(&self.string[..], *other)
970d7e83
LB
693 }
694}
223e47cc 695
c1a9b12d 696impl<'a> PartialEq<InternedString> for &'a str {
1a4d82fc
JJ
697 #[inline(always)]
698 fn eq(&self, other: &InternedString) -> bool {
c34b1796 699 PartialEq::eq(*self, &other.string[..])
1a4d82fc
JJ
700 }
701 #[inline(always)]
702 fn ne(&self, other: &InternedString) -> bool {
c34b1796 703 PartialEq::ne(*self, &other.string[..])
1a4d82fc
JJ
704 }
705}
706
707impl Decodable for InternedString {
708 fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
54a0048b 709 Ok(intern(d.read_str()?.as_ref()).as_str())
970d7e83
LB
710 }
711}
712
1a4d82fc
JJ
713impl Encodable for InternedString {
714 fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
c34b1796 715 s.emit_str(&self.string)
1a4d82fc
JJ
716 }
717}
718
1a4d82fc 719/// Interns and returns the string contents of an identifier, using the
bd371182 720/// thread-local interner.
1a4d82fc
JJ
721#[inline]
722pub fn intern_and_get_ident(s: &str) -> InternedString {
c1a9b12d 723 intern(s).as_str()
1a4d82fc
JJ
724}
725
726/// Maps a string to its interned representation.
727#[inline]
728pub fn intern(s: &str) -> ast::Name {
729 get_ident_interner().intern(s)
730}
731
85aaf69f 732/// gensym's a new usize, using the current interner.
1a4d82fc
JJ
733#[inline]
734pub fn gensym(s: &str) -> ast::Name {
735 get_ident_interner().gensym(s)
736}
737
738/// Maps a string to an identifier with an empty syntax context.
739#[inline]
740pub fn str_to_ident(s: &str) -> ast::Ident {
b039eaaf 741 ast::Ident::with_empty_ctxt(intern(s))
1a4d82fc
JJ
742}
743
744/// Maps a string to a gensym'ed identifier.
745#[inline]
746pub fn gensym_ident(s: &str) -> ast::Ident {
b039eaaf 747 ast::Ident::with_empty_ctxt(gensym(s))
1a4d82fc
JJ
748}
749
750// create a fresh name that maps to the same string as the old one.
751// note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src)));
752// that is, that the new name and the old one are connected to ptr_eq strings.
b039eaaf 753pub fn fresh_name(src: ast::Ident) -> ast::Name {
1a4d82fc
JJ
754 let interner = get_ident_interner();
755 interner.gensym_copy(src.name)
756 // following: debug version. Could work in final except that it's incompatible with
757 // good error messages and uses of struct names in ambiguous could-be-binding
758 // locations. Also definitely destroys the guarantee given above about ptr_eq.
759 /*let num = rand::thread_rng().gen_uint_range(0,0xffff);
760 gensym(format!("{}_{}",ident_to_string(src),num))*/
761}
762
763// create a fresh mark.
764pub fn fresh_mark() -> ast::Mrk {
b039eaaf 765 gensym("mark").0
1a4d82fc 766}
970d7e83
LB
767
768#[cfg(test)]
d9579d0f 769mod tests {
970d7e83 770 use super::*;
1a4d82fc
JJ
771 use ast;
772 use ext::mtwt;
773
774 fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
b039eaaf 775 ast::Ident::new(id.name, mtwt::apply_mark(m, id.ctxt))
1a4d82fc
JJ
776 }
777
778 #[test] fn mtwt_token_eq_test() {
779 assert!(Gt.mtwt_eq(&Gt));
780 let a = str_to_ident("bac");
781 let a1 = mark_ident(a,92);
782 assert!(Ident(a, ModName).mtwt_eq(&Ident(a1, Plain)));
970d7e83
LB
783 }
784}