]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/parse/token.rs
Imported Upstream version 1.3.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
d9579d0f
AL
384 // These is not exposed to macros, but is used by quasiquote.
385 NtArm(ast::Arm),
386 NtImplItem(P<ast::ImplItem>),
387 NtTraitItem(P<ast::TraitItem>),
388 NtGenerics(ast::Generics),
389 NtWhereClause(ast::WhereClause),
1a4d82fc
JJ
390}
391
85aaf69f 392impl fmt::Debug for Nonterminal {
1a4d82fc
JJ
393 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394 match *self {
395 NtItem(..) => f.pad("NtItem(..)"),
396 NtBlock(..) => f.pad("NtBlock(..)"),
397 NtStmt(..) => f.pad("NtStmt(..)"),
398 NtPat(..) => f.pad("NtPat(..)"),
399 NtExpr(..) => f.pad("NtExpr(..)"),
400 NtTy(..) => f.pad("NtTy(..)"),
401 NtIdent(..) => f.pad("NtIdent(..)"),
402 NtMeta(..) => f.pad("NtMeta(..)"),
403 NtPath(..) => f.pad("NtPath(..)"),
404 NtTT(..) => f.pad("NtTT(..)"),
d9579d0f
AL
405 NtArm(..) => f.pad("NtArm(..)"),
406 NtImplItem(..) => f.pad("NtImplItem(..)"),
407 NtTraitItem(..) => f.pad("NtTraitItem(..)"),
408 NtGenerics(..) => f.pad("NtGenerics(..)"),
409 NtWhereClause(..) => f.pad("NtWhereClause(..)"),
1a4d82fc 410 }
970d7e83
LB
411 }
412}
413
1a4d82fc
JJ
414
415// Get the first "argument"
416macro_rules! first {
417 ( $first:expr, $( $remainder:expr, )* ) => ( $first )
418}
419
420// Get the last "argument" (has to be done recursively to avoid phoney local ambiguity error)
421macro_rules! last {
422 ( $first:expr, $( $remainder:expr, )+ ) => ( last!( $( $remainder, )+ ) );
423 ( $first:expr, ) => ( $first )
424}
425
426// In this macro, there is the requirement that the name (the number) must be monotonically
427// increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
428// except starting from the next number instead of zero, and with the additional exception that
429// special identifiers are *also* allowed (they are deduplicated in the important place, the
430// interner), an exception which is demonstrated by "static" and "self".
431macro_rules! declare_special_idents_and_keywords {(
432 // So now, in these rules, why is each definition parenthesised?
433 // Answer: otherwise we get a spurious local ambiguity bug on the "}"
434 pub mod special_idents {
435 $( ($si_name:expr, $si_static:ident, $si_str:expr); )*
436 }
437
438 pub mod keywords {
439 'strict:
440 $( ($sk_name:expr, $sk_variant:ident, $sk_str:expr); )*
441 'reserved:
442 $( ($rk_name:expr, $rk_variant:ident, $rk_str:expr); )*
443 }
444) => {
c34b1796
AL
445 const STRICT_KEYWORD_START: ast::Name = first!($( ast::Name($sk_name), )*);
446 const STRICT_KEYWORD_FINAL: ast::Name = last!($( ast::Name($sk_name), )*);
447 const RESERVED_KEYWORD_START: ast::Name = first!($( ast::Name($rk_name), )*);
448 const RESERVED_KEYWORD_FINAL: ast::Name = last!($( ast::Name($rk_name), )*);
1a4d82fc
JJ
449
450 pub mod special_idents {
451 use ast;
452 $(
453 #[allow(non_upper_case_globals)]
454 pub const $si_static: ast::Ident = ast::Ident {
455 name: ast::Name($si_name),
456 ctxt: 0,
457 };
458 )*
459 }
460
461 pub mod special_names {
462 use ast;
463 $(
464 #[allow(non_upper_case_globals)]
465 pub const $si_static: ast::Name = ast::Name($si_name);
466 )*
467 }
468
469 /// All the valid words that have meaning in the Rust language.
470 ///
471 /// Rust keywords are either 'strict' or 'reserved'. Strict keywords may not
472 /// appear as identifiers at all. Reserved keywords are not used anywhere in
473 /// the language and may not appear as identifiers.
474 pub mod keywords {
475 pub use self::Keyword::*;
476 use ast;
477
85aaf69f 478 #[derive(Copy, Clone, PartialEq, Eq)]
1a4d82fc
JJ
479 pub enum Keyword {
480 $( $sk_variant, )*
481 $( $rk_variant, )*
482 }
483
484 impl Keyword {
485 pub fn to_name(&self) -> ast::Name {
486 match *self {
487 $( $sk_variant => ast::Name($sk_name), )*
488 $( $rk_variant => ast::Name($rk_name), )*
489 }
223e47cc
LB
490 }
491 }
492 }
1a4d82fc
JJ
493
494 fn mk_fresh_ident_interner() -> IdentInterner {
495 // The indices here must correspond to the numbers in
496 // special_idents, in Keyword to_name(), and in static
497 // constants below.
498 let mut init_vec = Vec::new();
499 $(init_vec.push($si_str);)*
500 $(init_vec.push($sk_str);)*
501 $(init_vec.push($rk_str);)*
85aaf69f 502 interner::StrInterner::prefill(&init_vec[..])
1a4d82fc
JJ
503 }
504}}
505
506// If the special idents get renumbered, remember to modify these two as appropriate
507pub const SELF_KEYWORD_NAME: ast::Name = ast::Name(SELF_KEYWORD_NAME_NUM);
508const STATIC_KEYWORD_NAME: ast::Name = ast::Name(STATIC_KEYWORD_NAME_NUM);
509const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM);
85aaf69f 510const SELF_TYPE_KEYWORD_NAME: ast::Name = ast::Name(SELF_TYPE_KEYWORD_NAME_NUM);
1a4d82fc
JJ
511
512pub const SELF_KEYWORD_NAME_NUM: u32 = 1;
513const STATIC_KEYWORD_NAME_NUM: u32 = 2;
514const SUPER_KEYWORD_NAME_NUM: u32 = 3;
85aaf69f 515const SELF_TYPE_KEYWORD_NAME_NUM: u32 = 10;
1a4d82fc
JJ
516
517// NB: leaving holes in the ident table is bad! a different ident will get
518// interned with the id from the hole, but it will be between the min and max
519// of the reserved words, and thus tagged as "reserved".
520
521declare_special_idents_and_keywords! {
522 pub mod special_idents {
523 // These ones are statics
524 (0, invalid, "");
525 (super::SELF_KEYWORD_NAME_NUM, self_, "self");
526 (super::STATIC_KEYWORD_NAME_NUM, statik, "static");
527 (super::SUPER_KEYWORD_NAME_NUM, super_, "super");
528 (4, static_lifetime, "'static");
529
530 // for matcher NTs
531 (5, tt, "tt");
532 (6, matchers, "matchers");
533
534 // outside of libsyntax
535 (7, clownshoe_abi, "__rust_abi");
536 (8, opaque, "<opaque>");
537 (9, unnamed_field, "<unnamed_field>");
85aaf69f 538 (super::SELF_TYPE_KEYWORD_NAME_NUM, type_self, "Self");
1a4d82fc 539 (11, prelude_import, "prelude_import");
1a4d82fc
JJ
540 }
541
542 pub mod keywords {
543 // These ones are variants of the Keyword enum
544
545 'strict:
85aaf69f
SL
546 (12, As, "as");
547 (13, Break, "break");
548 (14, Crate, "crate");
549 (15, Else, "else");
550 (16, Enum, "enum");
551 (17, Extern, "extern");
552 (18, False, "false");
553 (19, Fn, "fn");
554 (20, For, "for");
555 (21, If, "if");
556 (22, Impl, "impl");
557 (23, In, "in");
558 (24, Let, "let");
559 (25, Loop, "loop");
560 (26, Match, "match");
561 (27, Mod, "mod");
562 (28, Move, "move");
563 (29, Mut, "mut");
564 (30, Pub, "pub");
565 (31, Ref, "ref");
566 (32, Return, "return");
1a4d82fc
JJ
567 // Static and Self are also special idents (prefill de-dupes)
568 (super::STATIC_KEYWORD_NAME_NUM, Static, "static");
85aaf69f
SL
569 (super::SELF_KEYWORD_NAME_NUM, SelfValue, "self");
570 (super::SELF_TYPE_KEYWORD_NAME_NUM, SelfType, "Self");
571 (33, Struct, "struct");
1a4d82fc 572 (super::SUPER_KEYWORD_NAME_NUM, Super, "super");
85aaf69f
SL
573 (34, True, "true");
574 (35, Trait, "trait");
575 (36, Type, "type");
576 (37, Unsafe, "unsafe");
577 (38, Use, "use");
578 (39, Virtual, "virtual");
579 (40, While, "while");
580 (41, Continue, "continue");
c34b1796
AL
581 (42, Box, "box");
582 (43, Const, "const");
583 (44, Where, "where");
1a4d82fc 584 'reserved:
c34b1796 585 (45, Proc, "proc");
85aaf69f
SL
586 (46, Alignof, "alignof");
587 (47, Become, "become");
588 (48, Offsetof, "offsetof");
589 (49, Priv, "priv");
590 (50, Pure, "pure");
591 (51, Sizeof, "sizeof");
592 (52, Typeof, "typeof");
593 (53, Unsized, "unsized");
594 (54, Yield, "yield");
595 (55, Do, "do");
596 (56, Abstract, "abstract");
597 (57, Final, "final");
598 (58, Override, "override");
599 (59, Macro, "macro");
1a4d82fc 600 }
223e47cc
LB
601}
602
1a4d82fc
JJ
603// looks like we can get rid of this completely...
604pub type IdentInterner = StrInterner;
605
606// if an interner exists in TLS, return it. Otherwise, prepare a
607// fresh one.
bd371182 608// FIXME(eddyb) #8726 This should probably use a thread-local reference.
1a4d82fc
JJ
609pub fn get_ident_interner() -> Rc<IdentInterner> {
610 thread_local!(static KEY: Rc<::parse::token::IdentInterner> = {
611 Rc::new(mk_fresh_ident_interner())
612 });
613 KEY.with(|k| k.clone())
970d7e83
LB
614}
615
1a4d82fc
JJ
616/// Reset the ident interner to its initial state.
617pub fn reset_ident_interner() {
970d7e83 618 let interner = get_ident_interner();
1a4d82fc
JJ
619 interner.reset(mk_fresh_ident_interner());
620}
621
bd371182
AL
622/// Represents a string stored in the thread-local interner. Because the
623/// interner lives for the life of the thread, this can be safely treated as an
624/// immortal string, as long as it never crosses between threads.
1a4d82fc
JJ
625///
626/// FIXME(pcwalton): You must be careful about what you do in the destructors
627/// of objects stored in TLS, because they may run after the interner is
628/// destroyed. In particular, they must not access string contents. This can
bd371182 629/// be fixed in the future by just leaking all strings until thread death
1a4d82fc
JJ
630/// somehow.
631#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
632pub struct InternedString {
633 string: RcStr,
634}
635
636impl InternedString {
637 #[inline]
638 pub fn new(string: &'static str) -> InternedString {
639 InternedString {
640 string: RcStr::new(string),
641 }
642 }
643
644 #[inline]
645 fn new_from_rc_str(string: RcStr) -> InternedString {
646 InternedString {
647 string: string,
648 }
649 }
c1a9b12d
SL
650
651 #[inline]
652 pub fn new_from_name(name: ast::Name) -> InternedString {
653 let interner = get_ident_interner();
654 InternedString::new_from_rc_str(interner.get(name))
655 }
970d7e83
LB
656}
657
1a4d82fc
JJ
658impl Deref for InternedString {
659 type Target = str;
660
661 fn deref(&self) -> &str { &*self.string }
662}
663
85aaf69f 664impl fmt::Debug for InternedString {
1a4d82fc 665 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
c34b1796 666 fmt::Debug::fmt(&self.string, f)
223e47cc 667 }
223e47cc
LB
668}
669
85aaf69f 670impl fmt::Display for InternedString {
1a4d82fc 671 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
c34b1796 672 fmt::Display::fmt(&self.string, f)
970d7e83
LB
673 }
674}
675
1a4d82fc
JJ
676impl<'a> PartialEq<&'a str> for InternedString {
677 #[inline(always)]
678 fn eq(&self, other: & &'a str) -> bool {
c34b1796 679 PartialEq::eq(&self.string[..], *other)
1a4d82fc
JJ
680 }
681 #[inline(always)]
682 fn ne(&self, other: & &'a str) -> bool {
c34b1796 683 PartialEq::ne(&self.string[..], *other)
970d7e83
LB
684 }
685}
223e47cc 686
c1a9b12d 687impl<'a> PartialEq<InternedString> for &'a str {
1a4d82fc
JJ
688 #[inline(always)]
689 fn eq(&self, other: &InternedString) -> bool {
c34b1796 690 PartialEq::eq(*self, &other.string[..])
1a4d82fc
JJ
691 }
692 #[inline(always)]
693 fn ne(&self, other: &InternedString) -> bool {
c34b1796 694 PartialEq::ne(*self, &other.string[..])
1a4d82fc
JJ
695 }
696}
697
698impl Decodable for InternedString {
699 fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
c1a9b12d 700 Ok(intern(try!(d.read_str()).as_ref()).as_str())
970d7e83
LB
701 }
702}
703
1a4d82fc
JJ
704impl Encodable for InternedString {
705 fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
c34b1796 706 s.emit_str(&self.string)
1a4d82fc
JJ
707 }
708}
709
1a4d82fc 710/// Interns and returns the string contents of an identifier, using the
bd371182 711/// thread-local interner.
1a4d82fc
JJ
712#[inline]
713pub fn intern_and_get_ident(s: &str) -> InternedString {
c1a9b12d 714 intern(s).as_str()
1a4d82fc
JJ
715}
716
717/// Maps a string to its interned representation.
718#[inline]
719pub fn intern(s: &str) -> ast::Name {
720 get_ident_interner().intern(s)
721}
722
85aaf69f 723/// gensym's a new usize, using the current interner.
1a4d82fc
JJ
724#[inline]
725pub fn gensym(s: &str) -> ast::Name {
726 get_ident_interner().gensym(s)
727}
728
729/// Maps a string to an identifier with an empty syntax context.
730#[inline]
731pub fn str_to_ident(s: &str) -> ast::Ident {
732 ast::Ident::new(intern(s))
733}
734
735/// Maps a string to a gensym'ed identifier.
736#[inline]
737pub fn gensym_ident(s: &str) -> ast::Ident {
738 ast::Ident::new(gensym(s))
739}
740
741// create a fresh name that maps to the same string as the old one.
742// note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src)));
743// that is, that the new name and the old one are connected to ptr_eq strings.
744pub fn fresh_name(src: &ast::Ident) -> ast::Name {
745 let interner = get_ident_interner();
746 interner.gensym_copy(src.name)
747 // following: debug version. Could work in final except that it's incompatible with
748 // good error messages and uses of struct names in ambiguous could-be-binding
749 // locations. Also definitely destroys the guarantee given above about ptr_eq.
750 /*let num = rand::thread_rng().gen_uint_range(0,0xffff);
751 gensym(format!("{}_{}",ident_to_string(src),num))*/
752}
753
754// create a fresh mark.
755pub fn fresh_mark() -> ast::Mrk {
85aaf69f 756 gensym("mark").usize() as u32
1a4d82fc 757}
970d7e83
LB
758
759#[cfg(test)]
d9579d0f 760mod tests {
970d7e83 761 use super::*;
1a4d82fc
JJ
762 use ast;
763 use ext::mtwt;
764
765 fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
766 ast::Ident { name: id.name, ctxt:mtwt::apply_mark(m, id.ctxt) }
767 }
768
769 #[test] fn mtwt_token_eq_test() {
770 assert!(Gt.mtwt_eq(&Gt));
771 let a = str_to_ident("bac");
772 let a1 = mark_ident(a,92);
773 assert!(Ident(a, ModName).mtwt_eq(&Ident(a1, Plain)));
970d7e83
LB
774 }
775}