]>
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 | ||
7453a54e | 18 | use ast::{self, BinOpKind}; |
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 */ |
e9174d1e SL |
85 | ByteStr(ast::Name), |
86 | ByteStrRaw(ast::Name, usize), /* raw byte 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", | |
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 |
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 | 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. | |
381 | pub 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 | 402 | impl 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" | |
427 | macro_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) | |
432 | macro_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". | |
442 | macro_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 | |
515 | pub const SELF_KEYWORD_NAME: ast::Name = ast::Name(SELF_KEYWORD_NAME_NUM); | |
516 | const STATIC_KEYWORD_NAME: ast::Name = ast::Name(STATIC_KEYWORD_NAME_NUM); | |
54a0048b | 517 | pub const SUPER_KEYWORD_NAME: ast::Name = ast::Name(SUPER_KEYWORD_NAME_NUM); |
85aaf69f | 518 | const SELF_TYPE_KEYWORD_NAME: ast::Name = ast::Name(SELF_TYPE_KEYWORD_NAME_NUM); |
1a4d82fc JJ |
519 | |
520 | pub const SELF_KEYWORD_NAME_NUM: u32 = 1; | |
521 | const STATIC_KEYWORD_NAME_NUM: u32 = 2; | |
522 | const SUPER_KEYWORD_NAME_NUM: u32 = 3; | |
85aaf69f | 523 | const 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 | ||
529 | declare_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... |
613 | pub 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 |
618 | pub 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. |
626 | pub 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)] | |
641 | pub struct InternedString { | |
642 | string: RcStr, | |
643 | } | |
644 | ||
645 | impl 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 |
667 | impl Deref for InternedString { |
668 | type Target = str; | |
669 | ||
7453a54e | 670 | fn deref(&self) -> &str { &self.string } |
1a4d82fc JJ |
671 | } |
672 | ||
85aaf69f | 673 | impl 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 | 679 | impl 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 |
685 | impl<'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 | 696 | impl<'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 | ||
707 | impl 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 |
713 | impl 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] |
722 | pub 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] | |
728 | pub 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] |
734 | pub 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] | |
740 | pub 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] | |
746 | pub 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 | 753 | pub 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. | |
764 | pub fn fresh_mark() -> ast::Mrk { | |
b039eaaf | 765 | gensym("mark").0 |
1a4d82fc | 766 | } |
970d7e83 LB |
767 | |
768 | #[cfg(test)] | |
d9579d0f | 769 | mod 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 | } |