]>
Commit | Line | Data |
---|---|---|
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 |
11 | pub use self::BinOpToken::*; |
12 | pub use self::Nonterminal::*; | |
13 | pub use self::DelimToken::*; | |
1a4d82fc JJ |
14 | pub use self::Lit::*; |
15 | pub use self::Token::*; | |
16 | ||
7453a54e | 17 | use ast::{self, BinOpKind}; |
1a4d82fc | 18 | use ptr::P; |
5bcae85e | 19 | use util::interner::Interner; |
3157f602 | 20 | use tokenstream; |
223e47cc | 21 | |
1a4d82fc | 22 | use serialize::{Decodable, Decoder, Encodable, Encoder}; |
5bcae85e | 23 | use std::cell::RefCell; |
1a4d82fc | 24 | use std::fmt; |
1a4d82fc | 25 | use std::ops::Deref; |
1a4d82fc JJ |
26 | use std::rc::Rc; |
27 | ||
85aaf69f | 28 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] |
1a4d82fc JJ |
29 | pub enum BinOpToken { |
30 | Plus, | |
31 | Minus, | |
32 | Star, | |
33 | Slash, | |
34 | Percent, | |
35 | Caret, | |
36 | And, | |
37 | Or, | |
38 | Shl, | |
39 | Shr, | |
40 | } | |
41 | ||
42 | /// A delimiter token | |
85aaf69f | 43 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] |
1a4d82fc JJ |
44 | pub enum DelimToken { |
45 | /// A round parenthesis: `(` or `)` | |
46 | Paren, | |
47 | /// A square bracket: `[` or `]` | |
48 | Bracket, | |
49 | /// A curly brace: `{` or `}` | |
50 | Brace, | |
5bcae85e SL |
51 | /// An empty delimiter |
52 | NoDelim, | |
1a4d82fc JJ |
53 | } |
54 | ||
85aaf69f | 55 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] |
1a4d82fc JJ |
56 | pub enum SpecialMacroVar { |
57 | /// `$crate` will be filled in with the name of the crate a macro was | |
58 | /// imported from, if any. | |
59 | CrateMacroVar, | |
60 | } | |
61 | ||
62 | impl SpecialMacroVar { | |
63 | pub fn as_str(self) -> &'static str { | |
64 | match self { | |
65 | SpecialMacroVar::CrateMacroVar => "crate", | |
66 | } | |
67 | } | |
68 | } | |
69 | ||
85aaf69f | 70 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)] |
1a4d82fc JJ |
71 | pub enum Lit { |
72 | Byte(ast::Name), | |
73 | Char(ast::Name), | |
74 | Integer(ast::Name), | |
75 | Float(ast::Name), | |
76 | Str_(ast::Name), | |
85aaf69f | 77 | StrRaw(ast::Name, usize), /* raw str delimited by n hash symbols */ |
e9174d1e SL |
78 | ByteStr(ast::Name), |
79 | ByteStrRaw(ast::Name, usize), /* raw byte str delimited by n hash symbols */ | |
1a4d82fc JJ |
80 | } |
81 | ||
82 | impl Lit { | |
83 | pub fn short_name(&self) -> &'static str { | |
84 | match *self { | |
85 | Byte(_) => "byte", | |
86 | Char(_) => "char", | |
87 | Integer(_) => "integer", | |
88 | Float(_) => "float", | |
e9174d1e SL |
89 | Str_(_) | StrRaw(..) => "string", |
90 | ByteStr(_) | ByteStrRaw(..) => "byte string" | |
1a4d82fc JJ |
91 | } |
92 | } | |
93 | } | |
94 | ||
85aaf69f | 95 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)] |
223e47cc LB |
96 | pub enum Token { |
97 | /* Expression-operator symbols. */ | |
1a4d82fc JJ |
98 | Eq, |
99 | Lt, | |
100 | Le, | |
101 | EqEq, | |
102 | Ne, | |
103 | Ge, | |
104 | Gt, | |
105 | AndAnd, | |
106 | OrOr, | |
107 | Not, | |
108 | Tilde, | |
109 | BinOp(BinOpToken), | |
110 | BinOpEq(BinOpToken), | |
223e47cc LB |
111 | |
112 | /* Structural symbols */ | |
1a4d82fc JJ |
113 | At, |
114 | Dot, | |
115 | DotDot, | |
116 | DotDotDot, | |
117 | Comma, | |
118 | Semi, | |
119 | Colon, | |
120 | ModSep, | |
121 | RArrow, | |
122 | LArrow, | |
123 | FatArrow, | |
124 | Pound, | |
125 | Dollar, | |
126 | Question, | |
127 | /// An opening delimiter, eg. `{` | |
128 | OpenDelim(DelimToken), | |
129 | /// A closing delimiter, eg. `}` | |
130 | CloseDelim(DelimToken), | |
223e47cc LB |
131 | |
132 | /* Literals */ | |
1a4d82fc | 133 | Literal(Lit, Option<ast::Name>), |
223e47cc LB |
134 | |
135 | /* Name components */ | |
a7813a04 | 136 | Ident(ast::Ident), |
1a4d82fc JJ |
137 | Underscore, |
138 | Lifetime(ast::Ident), | |
223e47cc LB |
139 | |
140 | /* For interpolation */ | |
1a4d82fc JJ |
141 | Interpolated(Nonterminal), |
142 | // Can be expanded into several tokens. | |
143 | /// Doc comment | |
144 | DocComment(ast::Name), | |
145 | // In left-hand-sides of MBE macros: | |
a7813a04 XL |
146 | /// Parse a nonterminal (name to bind, name of NT) |
147 | MatchNt(ast::Ident, ast::Ident), | |
1a4d82fc JJ |
148 | // In right-hand-sides of MBE macros: |
149 | /// A syntactic variable that will be filled in by macro expansion. | |
a7813a04 | 150 | SubstNt(ast::Ident), |
1a4d82fc JJ |
151 | /// A macro variable with special meaning. |
152 | SpecialVarNt(SpecialMacroVar), | |
153 | ||
154 | // Junk. These carry no data because we don't really care about the data | |
155 | // they *would* carry, and don't really want to allocate a new ident for | |
156 | // them. Instead, users could extract that from the associated span. | |
157 | ||
158 | /// Whitespace | |
159 | Whitespace, | |
160 | /// Comment | |
161 | Comment, | |
162 | Shebang(ast::Name), | |
163 | ||
164 | Eof, | |
165 | } | |
166 | ||
167 | impl Token { | |
bd371182 AL |
168 | /// Returns `true` if the token starts with '>'. |
169 | pub fn is_like_gt(&self) -> bool { | |
170 | match *self { | |
171 | BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true, | |
172 | _ => false, | |
173 | } | |
174 | } | |
175 | ||
1a4d82fc JJ |
176 | /// Returns `true` if the token can appear at the start of an expression. |
177 | pub fn can_begin_expr(&self) -> bool { | |
178 | match *self { | |
179 | OpenDelim(_) => true, | |
a7813a04 | 180 | Ident(..) => true, |
1a4d82fc JJ |
181 | Underscore => true, |
182 | Tilde => true, | |
183 | Literal(_, _) => true, | |
1a4d82fc JJ |
184 | Not => true, |
185 | BinOp(Minus) => true, | |
186 | BinOp(Star) => true, | |
187 | BinOp(And) => true, | |
188 | BinOp(Or) => true, // in lambda syntax | |
189 | OrOr => true, // in lambda syntax | |
85aaf69f | 190 | AndAnd => true, // double borrow |
54a0048b | 191 | DotDot | DotDotDot => true, // range notation |
1a4d82fc JJ |
192 | ModSep => true, |
193 | Interpolated(NtExpr(..)) => true, | |
194 | Interpolated(NtIdent(..)) => true, | |
195 | Interpolated(NtBlock(..)) => true, | |
196 | Interpolated(NtPath(..)) => true, | |
92a42be0 | 197 | Pound => true, // for expression attributes |
1a4d82fc JJ |
198 | _ => false, |
199 | } | |
200 | } | |
223e47cc | 201 | |
1a4d82fc JJ |
202 | /// Returns `true` if the token is any literal |
203 | pub fn is_lit(&self) -> bool { | |
204 | match *self { | |
205 | Literal(_, _) => true, | |
206 | _ => false, | |
207 | } | |
208 | } | |
223e47cc | 209 | |
1a4d82fc JJ |
210 | /// Returns `true` if the token is an identifier. |
211 | pub fn is_ident(&self) -> bool { | |
212 | match *self { | |
a7813a04 | 213 | Ident(..) => true, |
1a4d82fc | 214 | _ => false, |
223e47cc | 215 | } |
1a4d82fc JJ |
216 | } |
217 | ||
7453a54e SL |
218 | /// Returns `true` if the token is interpolated. |
219 | pub fn is_interpolated(&self) -> bool { | |
220 | match *self { | |
221 | Interpolated(..) => true, | |
222 | _ => false, | |
223 | } | |
224 | } | |
225 | ||
1a4d82fc JJ |
226 | /// Returns `true` if the token is an interpolated path. |
227 | pub fn is_path(&self) -> bool { | |
228 | match *self { | |
229 | Interpolated(NtPath(..)) => true, | |
230 | _ => false, | |
231 | } | |
232 | } | |
233 | ||
1a4d82fc JJ |
234 | /// Returns `true` if the token is a lifetime. |
235 | pub fn is_lifetime(&self) -> bool { | |
236 | match *self { | |
237 | Lifetime(..) => true, | |
238 | _ => false, | |
223e47cc | 239 | } |
1a4d82fc JJ |
240 | } |
241 | ||
242 | /// Returns `true` if the token is either the `mut` or `const` keyword. | |
243 | pub fn is_mutability(&self) -> bool { | |
244 | self.is_keyword(keywords::Mut) || | |
245 | self.is_keyword(keywords::Const) | |
246 | } | |
247 | ||
a7813a04 XL |
248 | pub fn is_path_start(&self) -> bool { |
249 | self == &ModSep || self == &Lt || self.is_path() || | |
250 | self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword() | |
251 | } | |
252 | ||
1a4d82fc | 253 | /// Maps a token to its corresponding binary operator. |
7453a54e | 254 | pub fn to_binop(&self) -> Option<BinOpKind> { |
1a4d82fc | 255 | match *self { |
7453a54e SL |
256 | BinOp(Star) => Some(BinOpKind::Mul), |
257 | BinOp(Slash) => Some(BinOpKind::Div), | |
258 | BinOp(Percent) => Some(BinOpKind::Rem), | |
259 | BinOp(Plus) => Some(BinOpKind::Add), | |
260 | BinOp(Minus) => Some(BinOpKind::Sub), | |
261 | BinOp(Shl) => Some(BinOpKind::Shl), | |
262 | BinOp(Shr) => Some(BinOpKind::Shr), | |
263 | BinOp(And) => Some(BinOpKind::BitAnd), | |
264 | BinOp(Caret) => Some(BinOpKind::BitXor), | |
265 | BinOp(Or) => Some(BinOpKind::BitOr), | |
266 | Lt => Some(BinOpKind::Lt), | |
267 | Le => Some(BinOpKind::Le), | |
268 | Ge => Some(BinOpKind::Ge), | |
269 | Gt => Some(BinOpKind::Gt), | |
270 | EqEq => Some(BinOpKind::Eq), | |
271 | Ne => Some(BinOpKind::Ne), | |
272 | AndAnd => Some(BinOpKind::And), | |
273 | OrOr => Some(BinOpKind::Or), | |
1a4d82fc JJ |
274 | _ => None, |
275 | } | |
276 | } | |
277 | ||
278 | /// Returns `true` if the token is a given keyword, `kw`. | |
1a4d82fc JJ |
279 | pub fn is_keyword(&self, kw: keywords::Keyword) -> bool { |
280 | match *self { | |
a7813a04 XL |
281 | Ident(id) => id.name == kw.name(), |
282 | _ => false, | |
1a4d82fc JJ |
283 | } |
284 | } | |
285 | ||
a7813a04 | 286 | pub fn is_path_segment_keyword(&self) -> bool { |
1a4d82fc | 287 | match *self { |
a7813a04 XL |
288 | Ident(id) => id.name == keywords::Super.name() || |
289 | id.name == keywords::SelfValue.name() || | |
290 | id.name == keywords::SelfType.name(), | |
291 | _ => false, | |
1a4d82fc JJ |
292 | } |
293 | } | |
294 | ||
a7813a04 | 295 | /// Returns `true` if the token is either a strict or reserved keyword. |
1a4d82fc | 296 | pub fn is_any_keyword(&self) -> bool { |
a7813a04 | 297 | self.is_strict_keyword() || self.is_reserved_keyword() |
1a4d82fc JJ |
298 | } |
299 | ||
a7813a04 | 300 | /// Returns `true` if the token is a strict keyword. |
1a4d82fc JJ |
301 | pub fn is_strict_keyword(&self) -> bool { |
302 | match *self { | |
a7813a04 XL |
303 | Ident(id) => id.name >= keywords::As.name() && |
304 | id.name <= keywords::While.name(), | |
1a4d82fc JJ |
305 | _ => false, |
306 | } | |
307 | } | |
308 | ||
a7813a04 | 309 | /// Returns `true` if the token is a keyword reserved for possible future use. |
1a4d82fc JJ |
310 | pub fn is_reserved_keyword(&self) -> bool { |
311 | match *self { | |
a7813a04 XL |
312 | Ident(id) => id.name >= keywords::Abstract.name() && |
313 | id.name <= keywords::Yield.name(), | |
1a4d82fc JJ |
314 | _ => false, |
315 | } | |
316 | } | |
223e47cc LB |
317 | } |
318 | ||
1a4d82fc JJ |
319 | #[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)] |
320 | /// For interpolation during macro expansion. | |
321 | pub enum Nonterminal { | |
322 | NtItem(P<ast::Item>), | |
323 | NtBlock(P<ast::Block>), | |
324 | NtStmt(P<ast::Stmt>), | |
325 | NtPat(P<ast::Pat>), | |
326 | NtExpr(P<ast::Expr>), | |
327 | NtTy(P<ast::Ty>), | |
a7813a04 | 328 | NtIdent(Box<ast::SpannedIdent>), |
1a4d82fc JJ |
329 | /// Stuff inside brackets for attributes |
330 | NtMeta(P<ast::MetaItem>), | |
331 | NtPath(Box<ast::Path>), | |
3157f602 | 332 | NtTT(P<tokenstream::TokenTree>), // needs P'ed to break a circularity |
92a42be0 | 333 | // These are not exposed to macros, but are used by quasiquote. |
d9579d0f AL |
334 | NtArm(ast::Arm), |
335 | NtImplItem(P<ast::ImplItem>), | |
336 | NtTraitItem(P<ast::TraitItem>), | |
337 | NtGenerics(ast::Generics), | |
338 | NtWhereClause(ast::WhereClause), | |
92a42be0 | 339 | NtArg(ast::Arg), |
1a4d82fc JJ |
340 | } |
341 | ||
85aaf69f | 342 | impl fmt::Debug for Nonterminal { |
1a4d82fc JJ |
343 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
344 | match *self { | |
345 | NtItem(..) => f.pad("NtItem(..)"), | |
346 | NtBlock(..) => f.pad("NtBlock(..)"), | |
347 | NtStmt(..) => f.pad("NtStmt(..)"), | |
348 | NtPat(..) => f.pad("NtPat(..)"), | |
349 | NtExpr(..) => f.pad("NtExpr(..)"), | |
350 | NtTy(..) => f.pad("NtTy(..)"), | |
351 | NtIdent(..) => f.pad("NtIdent(..)"), | |
352 | NtMeta(..) => f.pad("NtMeta(..)"), | |
353 | NtPath(..) => f.pad("NtPath(..)"), | |
354 | NtTT(..) => f.pad("NtTT(..)"), | |
d9579d0f AL |
355 | NtArm(..) => f.pad("NtArm(..)"), |
356 | NtImplItem(..) => f.pad("NtImplItem(..)"), | |
357 | NtTraitItem(..) => f.pad("NtTraitItem(..)"), | |
358 | NtGenerics(..) => f.pad("NtGenerics(..)"), | |
359 | NtWhereClause(..) => f.pad("NtWhereClause(..)"), | |
92a42be0 | 360 | NtArg(..) => f.pad("NtArg(..)"), |
1a4d82fc | 361 | } |
970d7e83 LB |
362 | } |
363 | } | |
364 | ||
1a4d82fc JJ |
365 | // In this macro, there is the requirement that the name (the number) must be monotonically |
366 | // increasing by one in the special identifiers, starting at 0; the same holds for the keywords, | |
a7813a04 XL |
367 | // except starting from the next number instead of zero. |
368 | macro_rules! declare_keywords {( | |
369 | $( ($index: expr, $konst: ident, $string: expr) )* | |
1a4d82fc | 370 | ) => { |
1a4d82fc | 371 | pub mod keywords { |
1a4d82fc | 372 | use ast; |
a7813a04 XL |
373 | #[derive(Clone, Copy, PartialEq, Eq)] |
374 | pub struct Keyword { | |
375 | ident: ast::Ident, | |
1a4d82fc | 376 | } |
1a4d82fc | 377 | impl Keyword { |
a7813a04 XL |
378 | #[inline] pub fn ident(self) -> ast::Ident { self.ident } |
379 | #[inline] pub fn name(self) -> ast::Name { self.ident.name } | |
223e47cc | 380 | } |
a7813a04 XL |
381 | $( |
382 | #[allow(non_upper_case_globals)] | |
383 | pub const $konst: Keyword = Keyword { | |
384 | ident: ast::Ident::with_empty_ctxt(ast::Name($index)) | |
385 | }; | |
386 | )* | |
223e47cc | 387 | } |
1a4d82fc JJ |
388 | |
389 | fn mk_fresh_ident_interner() -> IdentInterner { | |
5bcae85e | 390 | Interner::prefill(&[$($string,)*]) |
1a4d82fc JJ |
391 | } |
392 | }} | |
393 | ||
1a4d82fc JJ |
394 | // NB: leaving holes in the ident table is bad! a different ident will get |
395 | // interned with the id from the hole, but it will be between the min and max | |
396 | // of the reserved words, and thus tagged as "reserved". | |
a7813a04 XL |
397 | // After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`, |
398 | // this should be rarely necessary though if the keywords are kept in alphabetic order. | |
399 | declare_keywords! { | |
400 | // Invalid identifier | |
401 | (0, Invalid, "") | |
402 | ||
403 | // Strict keywords used in the language. | |
404 | (1, As, "as") | |
405 | (2, Box, "box") | |
406 | (3, Break, "break") | |
407 | (4, Const, "const") | |
408 | (5, Continue, "continue") | |
409 | (6, Crate, "crate") | |
410 | (7, Else, "else") | |
411 | (8, Enum, "enum") | |
412 | (9, Extern, "extern") | |
413 | (10, False, "false") | |
414 | (11, Fn, "fn") | |
415 | (12, For, "for") | |
416 | (13, If, "if") | |
417 | (14, Impl, "impl") | |
418 | (15, In, "in") | |
419 | (16, Let, "let") | |
420 | (17, Loop, "loop") | |
421 | (18, Match, "match") | |
422 | (19, Mod, "mod") | |
423 | (20, Move, "move") | |
424 | (21, Mut, "mut") | |
425 | (22, Pub, "pub") | |
426 | (23, Ref, "ref") | |
427 | (24, Return, "return") | |
428 | (25, SelfValue, "self") | |
429 | (26, SelfType, "Self") | |
430 | (27, Static, "static") | |
431 | (28, Struct, "struct") | |
432 | (29, Super, "super") | |
433 | (30, Trait, "trait") | |
434 | (31, True, "true") | |
435 | (32, Type, "type") | |
436 | (33, Unsafe, "unsafe") | |
437 | (34, Use, "use") | |
438 | (35, Where, "where") | |
439 | (36, While, "while") | |
440 | ||
441 | // Keywords reserved for future use. | |
442 | (37, Abstract, "abstract") | |
443 | (38, Alignof, "alignof") | |
444 | (39, Become, "become") | |
445 | (40, Do, "do") | |
446 | (41, Final, "final") | |
447 | (42, Macro, "macro") | |
448 | (43, Offsetof, "offsetof") | |
449 | (44, Override, "override") | |
450 | (45, Priv, "priv") | |
451 | (46, Proc, "proc") | |
452 | (47, Pure, "pure") | |
453 | (48, Sizeof, "sizeof") | |
454 | (49, Typeof, "typeof") | |
455 | (50, Unsized, "unsized") | |
456 | (51, Virtual, "virtual") | |
457 | (52, Yield, "yield") | |
458 | ||
459 | // Weak keywords, have special meaning only in specific contexts. | |
460 | (53, Default, "default") | |
461 | (54, StaticLifetime, "'static") | |
462 | (55, Union, "union") | |
223e47cc LB |
463 | } |
464 | ||
1a4d82fc | 465 | // looks like we can get rid of this completely... |
5bcae85e | 466 | pub type IdentInterner = Interner; |
1a4d82fc JJ |
467 | |
468 | // if an interner exists in TLS, return it. Otherwise, prepare a | |
469 | // fresh one. | |
bd371182 | 470 | // FIXME(eddyb) #8726 This should probably use a thread-local reference. |
5bcae85e SL |
471 | pub fn with_ident_interner<T, F: FnOnce(&mut IdentInterner) -> T>(f: F) -> T { |
472 | thread_local!(static KEY: RefCell<IdentInterner> = { | |
473 | RefCell::new(mk_fresh_ident_interner()) | |
1a4d82fc | 474 | }); |
5bcae85e | 475 | KEY.with(|interner| f(&mut *interner.borrow_mut())) |
970d7e83 LB |
476 | } |
477 | ||
1a4d82fc JJ |
478 | /// Reset the ident interner to its initial state. |
479 | pub fn reset_ident_interner() { | |
5bcae85e SL |
480 | with_ident_interner(|interner| *interner = mk_fresh_ident_interner()); |
481 | } | |
482 | ||
483 | pub fn clear_ident_interner() { | |
484 | with_ident_interner(|interner| *interner = IdentInterner::new()); | |
1a4d82fc JJ |
485 | } |
486 | ||
bd371182 AL |
487 | /// Represents a string stored in the thread-local interner. Because the |
488 | /// interner lives for the life of the thread, this can be safely treated as an | |
489 | /// immortal string, as long as it never crosses between threads. | |
1a4d82fc JJ |
490 | /// |
491 | /// FIXME(pcwalton): You must be careful about what you do in the destructors | |
492 | /// of objects stored in TLS, because they may run after the interner is | |
493 | /// destroyed. In particular, they must not access string contents. This can | |
bd371182 | 494 | /// be fixed in the future by just leaking all strings until thread death |
1a4d82fc JJ |
495 | /// somehow. |
496 | #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)] | |
497 | pub struct InternedString { | |
5bcae85e | 498 | string: Rc<String>, |
1a4d82fc JJ |
499 | } |
500 | ||
501 | impl InternedString { | |
502 | #[inline] | |
503 | pub fn new(string: &'static str) -> InternedString { | |
504 | InternedString { | |
5bcae85e | 505 | string: Rc::new(string.to_owned()), |
1a4d82fc JJ |
506 | } |
507 | } | |
508 | ||
509 | #[inline] | |
5bcae85e | 510 | fn new_from_rc_str(string: Rc<String>) -> InternedString { |
1a4d82fc JJ |
511 | InternedString { |
512 | string: string, | |
513 | } | |
514 | } | |
c1a9b12d SL |
515 | |
516 | #[inline] | |
517 | pub fn new_from_name(name: ast::Name) -> InternedString { | |
5bcae85e | 518 | with_ident_interner(|interner| InternedString::new_from_rc_str(interner.get(name))) |
c1a9b12d | 519 | } |
970d7e83 LB |
520 | } |
521 | ||
1a4d82fc JJ |
522 | impl Deref for InternedString { |
523 | type Target = str; | |
524 | ||
7453a54e | 525 | fn deref(&self) -> &str { &self.string } |
1a4d82fc JJ |
526 | } |
527 | ||
85aaf69f | 528 | impl fmt::Debug for InternedString { |
1a4d82fc | 529 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
c34b1796 | 530 | fmt::Debug::fmt(&self.string, f) |
223e47cc | 531 | } |
223e47cc LB |
532 | } |
533 | ||
85aaf69f | 534 | impl fmt::Display for InternedString { |
1a4d82fc | 535 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
c34b1796 | 536 | fmt::Display::fmt(&self.string, f) |
970d7e83 LB |
537 | } |
538 | } | |
539 | ||
1a4d82fc JJ |
540 | impl<'a> PartialEq<&'a str> for InternedString { |
541 | #[inline(always)] | |
542 | fn eq(&self, other: & &'a str) -> bool { | |
c34b1796 | 543 | PartialEq::eq(&self.string[..], *other) |
1a4d82fc JJ |
544 | } |
545 | #[inline(always)] | |
546 | fn ne(&self, other: & &'a str) -> bool { | |
c34b1796 | 547 | PartialEq::ne(&self.string[..], *other) |
970d7e83 LB |
548 | } |
549 | } | |
223e47cc | 550 | |
c1a9b12d | 551 | impl<'a> PartialEq<InternedString> for &'a str { |
1a4d82fc JJ |
552 | #[inline(always)] |
553 | fn eq(&self, other: &InternedString) -> bool { | |
c34b1796 | 554 | PartialEq::eq(*self, &other.string[..]) |
1a4d82fc JJ |
555 | } |
556 | #[inline(always)] | |
557 | fn ne(&self, other: &InternedString) -> bool { | |
c34b1796 | 558 | PartialEq::ne(*self, &other.string[..]) |
1a4d82fc JJ |
559 | } |
560 | } | |
561 | ||
a7813a04 XL |
562 | impl PartialEq<str> for InternedString { |
563 | #[inline(always)] | |
564 | fn eq(&self, other: &str) -> bool { | |
565 | PartialEq::eq(&self.string[..], other) | |
566 | } | |
567 | #[inline(always)] | |
568 | fn ne(&self, other: &str) -> bool { | |
569 | PartialEq::ne(&self.string[..], other) | |
570 | } | |
571 | } | |
572 | ||
573 | impl PartialEq<InternedString> for str { | |
574 | #[inline(always)] | |
575 | fn eq(&self, other: &InternedString) -> bool { | |
576 | PartialEq::eq(self, &other.string[..]) | |
577 | } | |
578 | #[inline(always)] | |
579 | fn ne(&self, other: &InternedString) -> bool { | |
580 | PartialEq::ne(self, &other.string[..]) | |
581 | } | |
582 | } | |
583 | ||
1a4d82fc JJ |
584 | impl Decodable for InternedString { |
585 | fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> { | |
54a0048b | 586 | Ok(intern(d.read_str()?.as_ref()).as_str()) |
970d7e83 LB |
587 | } |
588 | } | |
589 | ||
1a4d82fc JJ |
590 | impl Encodable for InternedString { |
591 | fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> { | |
c34b1796 | 592 | s.emit_str(&self.string) |
1a4d82fc JJ |
593 | } |
594 | } | |
595 | ||
1a4d82fc | 596 | /// Interns and returns the string contents of an identifier, using the |
bd371182 | 597 | /// thread-local interner. |
1a4d82fc JJ |
598 | #[inline] |
599 | pub fn intern_and_get_ident(s: &str) -> InternedString { | |
c1a9b12d | 600 | intern(s).as_str() |
1a4d82fc JJ |
601 | } |
602 | ||
603 | /// Maps a string to its interned representation. | |
604 | #[inline] | |
605 | pub fn intern(s: &str) -> ast::Name { | |
5bcae85e | 606 | with_ident_interner(|interner| interner.intern(s)) |
1a4d82fc JJ |
607 | } |
608 | ||
85aaf69f | 609 | /// gensym's a new usize, using the current interner. |
1a4d82fc JJ |
610 | #[inline] |
611 | pub fn gensym(s: &str) -> ast::Name { | |
5bcae85e | 612 | with_ident_interner(|interner| interner.gensym(s)) |
1a4d82fc JJ |
613 | } |
614 | ||
615 | /// Maps a string to an identifier with an empty syntax context. | |
616 | #[inline] | |
617 | pub fn str_to_ident(s: &str) -> ast::Ident { | |
b039eaaf | 618 | ast::Ident::with_empty_ctxt(intern(s)) |
1a4d82fc JJ |
619 | } |
620 | ||
621 | /// Maps a string to a gensym'ed identifier. | |
622 | #[inline] | |
623 | pub fn gensym_ident(s: &str) -> ast::Ident { | |
b039eaaf | 624 | ast::Ident::with_empty_ctxt(gensym(s)) |
1a4d82fc JJ |
625 | } |
626 | ||
627 | // create a fresh name that maps to the same string as the old one. | |
628 | // note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src))); | |
629 | // that is, that the new name and the old one are connected to ptr_eq strings. | |
b039eaaf | 630 | pub fn fresh_name(src: ast::Ident) -> ast::Name { |
5bcae85e | 631 | with_ident_interner(|interner| interner.gensym_copy(src.name)) |
1a4d82fc JJ |
632 | // following: debug version. Could work in final except that it's incompatible with |
633 | // good error messages and uses of struct names in ambiguous could-be-binding | |
634 | // locations. Also definitely destroys the guarantee given above about ptr_eq. | |
635 | /*let num = rand::thread_rng().gen_uint_range(0,0xffff); | |
636 | gensym(format!("{}_{}",ident_to_string(src),num))*/ | |
637 | } |