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