]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/token.rs
de6dacbe766c298e9d41667ef8d540aa2de03afc
[rust.git] / src / libsyntax / parse / token.rs
1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
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
11 use ast;
12 use ast::{P, Ident, Name, Mrk};
13 use ast_util;
14 use ext::mtwt;
15 use parse::token;
16 use util::interner::{RcStr, StrInterner};
17 use util::interner;
18
19 use serialize::{Decodable, Decoder, Encodable, Encoder};
20 use std::cast;
21 use std::char;
22 use std::fmt;
23 use std::local_data;
24 use std::path::BytesContainer;
25 use std::rc::Rc;
26 use std::strbuf::StrBuf;
27
28 #[allow(non_camel_case_types)]
29 #[deriving(Clone, Encodable, Decodable, Eq, TotalEq, Hash, Show)]
30 pub enum BinOp {
31     PLUS,
32     MINUS,
33     STAR,
34     SLASH,
35     PERCENT,
36     CARET,
37     AND,
38     OR,
39     SHL,
40     SHR,
41 }
42
43 #[allow(non_camel_case_types)]
44 #[deriving(Clone, Encodable, Decodable, Eq, TotalEq, Hash, Show)]
45 pub enum Token {
46     /* Expression-operator symbols. */
47     EQ,
48     LT,
49     LE,
50     EQEQ,
51     NE,
52     GE,
53     GT,
54     ANDAND,
55     OROR,
56     NOT,
57     TILDE,
58     BINOP(BinOp),
59     BINOPEQ(BinOp),
60
61     /* Structural symbols */
62     AT,
63     DOT,
64     DOTDOT,
65     DOTDOTDOT,
66     COMMA,
67     SEMI,
68     COLON,
69     MOD_SEP,
70     RARROW,
71     LARROW,
72     DARROW,
73     FAT_ARROW,
74     LPAREN,
75     RPAREN,
76     LBRACKET,
77     RBRACKET,
78     LBRACE,
79     RBRACE,
80     POUND,
81     DOLLAR,
82
83     /* Literals */
84     LIT_CHAR(u32),
85     LIT_INT(i64, ast::IntTy),
86     LIT_UINT(u64, ast::UintTy),
87     LIT_INT_UNSUFFIXED(i64),
88     LIT_FLOAT(ast::Ident, ast::FloatTy),
89     LIT_FLOAT_UNSUFFIXED(ast::Ident),
90     LIT_STR(ast::Ident),
91     LIT_STR_RAW(ast::Ident, uint), /* raw str delimited by n hash symbols */
92
93     /* Name components */
94     // an identifier contains an "is_mod_name" boolean,
95     // indicating whether :: follows this token with no
96     // whitespace in between.
97     IDENT(ast::Ident, bool),
98     UNDERSCORE,
99     LIFETIME(ast::Ident),
100
101     /* For interpolation */
102     INTERPOLATED(Nonterminal),
103
104     DOC_COMMENT(ast::Ident),
105     EOF,
106 }
107
108 #[deriving(Clone, Encodable, Decodable, Eq, TotalEq, Hash)]
109 /// For interpolation during macro expansion.
110 pub enum Nonterminal {
111     NtItem(@ast::Item),
112     NtBlock(P<ast::Block>),
113     NtStmt(@ast::Stmt),
114     NtPat( @ast::Pat),
115     NtExpr(@ast::Expr),
116     NtTy(  P<ast::Ty>),
117     NtIdent(~ast::Ident, bool),
118     NtMeta(@ast::MetaItem), // stuff inside brackets for attributes
119     NtPath(~ast::Path),
120     NtTT(  @ast::TokenTree), // needs @ed to break a circularity
121     NtMatchers(Vec<ast::Matcher> )
122 }
123
124 impl fmt::Show for Nonterminal {
125     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
126         match *self {
127             NtItem(..) => f.pad("NtItem(..)"),
128             NtBlock(..) => f.pad("NtBlock(..)"),
129             NtStmt(..) => f.pad("NtStmt(..)"),
130             NtPat(..) => f.pad("NtPat(..)"),
131             NtExpr(..) => f.pad("NtExpr(..)"),
132             NtTy(..) => f.pad("NtTy(..)"),
133             NtIdent(..) => f.pad("NtIdent(..)"),
134             NtMeta(..) => f.pad("NtMeta(..)"),
135             NtPath(..) => f.pad("NtPath(..)"),
136             NtTT(..) => f.pad("NtTT(..)"),
137             NtMatchers(..) => f.pad("NtMatchers(..)"),
138         }
139     }
140 }
141
142 pub fn binop_to_str(o: BinOp) -> ~str {
143     match o {
144       PLUS => ~"+",
145       MINUS => ~"-",
146       STAR => ~"*",
147       SLASH => ~"/",
148       PERCENT => ~"%",
149       CARET => ~"^",
150       AND => ~"&",
151       OR => ~"|",
152       SHL => ~"<<",
153       SHR => ~">>"
154     }
155 }
156
157 pub fn to_str(t: &Token) -> ~str {
158     match *t {
159       EQ => ~"=",
160       LT => ~"<",
161       LE => ~"<=",
162       EQEQ => ~"==",
163       NE => ~"!=",
164       GE => ~">=",
165       GT => ~">",
166       NOT => ~"!",
167       TILDE => ~"~",
168       OROR => ~"||",
169       ANDAND => ~"&&",
170       BINOP(op) => binop_to_str(op),
171       BINOPEQ(op) => binop_to_str(op) + "=",
172
173       /* Structural symbols */
174       AT => ~"@",
175       DOT => ~".",
176       DOTDOT => ~"..",
177       DOTDOTDOT => ~"...",
178       COMMA => ~",",
179       SEMI => ~";",
180       COLON => ~":",
181       MOD_SEP => ~"::",
182       RARROW => ~"->",
183       LARROW => ~"<-",
184       DARROW => ~"<->",
185       FAT_ARROW => ~"=>",
186       LPAREN => ~"(",
187       RPAREN => ~")",
188       LBRACKET => ~"[",
189       RBRACKET => ~"]",
190       LBRACE => ~"{",
191       RBRACE => ~"}",
192       POUND => ~"#",
193       DOLLAR => ~"$",
194
195       /* Literals */
196       LIT_CHAR(c) => {
197           let mut res = StrBuf::from_str("'");
198           char::from_u32(c).unwrap().escape_default(|c| {
199               res.push_char(c);
200           });
201           res.push_char('\'');
202           res.into_owned()
203       }
204       LIT_INT(i, t) => ast_util::int_ty_to_str(t, Some(i)),
205       LIT_UINT(u, t) => ast_util::uint_ty_to_str(t, Some(u)),
206       LIT_INT_UNSUFFIXED(i) => { i.to_str() }
207       LIT_FLOAT(s, t) => {
208         let mut body = StrBuf::from_str(get_ident(s).get());
209         if body.as_slice().ends_with(".") {
210             body.push_char('0');  // `10.f` is not a float literal
211         }
212         body.push_str(ast_util::float_ty_to_str(t));
213         body.into_owned()
214       }
215       LIT_FLOAT_UNSUFFIXED(s) => {
216         let mut body = StrBuf::from_str(get_ident(s).get());
217         if body.as_slice().ends_with(".") {
218             body.push_char('0');  // `10.f` is not a float literal
219         }
220         body.into_owned()
221       }
222       LIT_STR(s) => {
223           format!("\"{}\"", get_ident(s).get().escape_default())
224       }
225       LIT_STR_RAW(s, n) => {
226           format!("r{delim}\"{string}\"{delim}",
227                   delim="#".repeat(n), string=get_ident(s))
228       }
229
230       /* Name components */
231       IDENT(s, _) => get_ident(s).get().to_str(),
232       LIFETIME(s) => {
233           format!("'{}", get_ident(s))
234       }
235       UNDERSCORE => ~"_",
236
237       /* Other */
238       DOC_COMMENT(s) => get_ident(s).get().to_str(),
239       EOF => ~"<eof>",
240       INTERPOLATED(ref nt) => {
241         match nt {
242             &NtExpr(e) => ::print::pprust::expr_to_str(e),
243             &NtMeta(e) => ::print::pprust::meta_item_to_str(e),
244             _ => {
245                 ~"an interpolated " +
246                     match *nt {
247                         NtItem(..) => ~"item",
248                         NtBlock(..) => ~"block",
249                         NtStmt(..) => ~"statement",
250                         NtPat(..) => ~"pattern",
251                         NtMeta(..) => fail!("should have been handled"),
252                         NtExpr(..) => fail!("should have been handled above"),
253                         NtTy(..) => ~"type",
254                         NtIdent(..) => ~"identifier",
255                         NtPath(..) => ~"path",
256                         NtTT(..) => ~"tt",
257                         NtMatchers(..) => ~"matcher sequence"
258                     }
259             }
260         }
261       }
262     }
263 }
264
265 pub fn can_begin_expr(t: &Token) -> bool {
266     match *t {
267       LPAREN => true,
268       LBRACE => true,
269       LBRACKET => true,
270       IDENT(_, _) => true,
271       UNDERSCORE => true,
272       TILDE => true,
273       LIT_CHAR(_) => true,
274       LIT_INT(_, _) => true,
275       LIT_UINT(_, _) => true,
276       LIT_INT_UNSUFFIXED(_) => true,
277       LIT_FLOAT(_, _) => true,
278       LIT_FLOAT_UNSUFFIXED(_) => true,
279       LIT_STR(_) => true,
280       LIT_STR_RAW(_, _) => true,
281       POUND => true,
282       AT => true,
283       NOT => true,
284       BINOP(MINUS) => true,
285       BINOP(STAR) => true,
286       BINOP(AND) => true,
287       BINOP(OR) => true, // in lambda syntax
288       OROR => true, // in lambda syntax
289       MOD_SEP => true,
290       INTERPOLATED(NtExpr(..))
291       | INTERPOLATED(NtIdent(..))
292       | INTERPOLATED(NtBlock(..))
293       | INTERPOLATED(NtPath(..)) => true,
294       _ => false
295     }
296 }
297
298 /// Returns the matching close delimiter if this is an open delimiter,
299 /// otherwise `None`.
300 pub fn close_delimiter_for(t: &Token) -> Option<Token> {
301     match *t {
302         LPAREN   => Some(RPAREN),
303         LBRACE   => Some(RBRACE),
304         LBRACKET => Some(RBRACKET),
305         _        => None
306     }
307 }
308
309 pub fn is_lit(t: &Token) -> bool {
310     match *t {
311       LIT_CHAR(_) => true,
312       LIT_INT(_, _) => true,
313       LIT_UINT(_, _) => true,
314       LIT_INT_UNSUFFIXED(_) => true,
315       LIT_FLOAT(_, _) => true,
316       LIT_FLOAT_UNSUFFIXED(_) => true,
317       LIT_STR(_) => true,
318       LIT_STR_RAW(_, _) => true,
319       _ => false
320     }
321 }
322
323 pub fn is_ident(t: &Token) -> bool {
324     match *t { IDENT(_, _) => true, _ => false }
325 }
326
327 pub fn is_ident_or_path(t: &Token) -> bool {
328     match *t {
329       IDENT(_, _) | INTERPOLATED(NtPath(..)) => true,
330       _ => false
331     }
332 }
333
334 pub fn is_plain_ident(t: &Token) -> bool {
335     match *t { IDENT(_, false) => true, _ => false }
336 }
337
338 pub fn is_bar(t: &Token) -> bool {
339     match *t { BINOP(OR) | OROR => true, _ => false }
340 }
341
342 // Get the first "argument"
343 macro_rules! first {
344     ( $first:expr, $( $remainder:expr, )* ) => ( $first )
345 }
346
347 // Get the last "argument" (has to be done recursively to avoid phoney local ambiguity error)
348 macro_rules! last {
349     ( $first:expr, $( $remainder:expr, )+ ) => ( last!( $( $remainder, )+ ) );
350     ( $first:expr, ) => ( $first )
351 }
352
353 // In this macro, there is the requirement that the name (the number) must be monotonically
354 // increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
355 // except starting from the next number instead of zero, and with the additional exception that
356 // special identifiers are *also* allowed (they are deduplicated in the important place, the
357 // interner), an exception which is demonstrated by "static" and "self".
358 macro_rules! declare_special_idents_and_keywords {(
359     // So now, in these rules, why is each definition parenthesised?
360     // Answer: otherwise we get a spurious local ambiguity bug on the "}"
361     pub mod special_idents {
362         $( ($si_name:expr, $si_static:ident, $si_str:expr); )*
363     }
364
365     pub mod keywords {
366         'strict:
367         $( ($sk_name:expr, $sk_variant:ident, $sk_str:expr); )*
368         'reserved:
369         $( ($rk_name:expr, $rk_variant:ident, $rk_str:expr); )*
370     }
371 ) => {
372     static STRICT_KEYWORD_START: Name = first!($( $sk_name, )*);
373     static STRICT_KEYWORD_FINAL: Name = last!($( $sk_name, )*);
374     static RESERVED_KEYWORD_START: Name = first!($( $rk_name, )*);
375     static RESERVED_KEYWORD_FINAL: Name = last!($( $rk_name, )*);
376
377     pub mod special_idents {
378         use ast::Ident;
379         $( pub static $si_static: Ident = Ident { name: $si_name, ctxt: 0 }; )*
380     }
381
382     /**
383      * All the valid words that have meaning in the Rust language.
384      *
385      * Rust keywords are either 'strict' or 'reserved'.  Strict keywords may not
386      * appear as identifiers at all. Reserved keywords are not used anywhere in
387      * the language and may not appear as identifiers.
388      */
389     pub mod keywords {
390         use ast::Ident;
391
392         pub enum Keyword {
393             $( $sk_variant, )*
394             $( $rk_variant, )*
395         }
396
397         impl Keyword {
398             pub fn to_ident(&self) -> Ident {
399                 match *self {
400                     $( $sk_variant => Ident { name: $sk_name, ctxt: 0 }, )*
401                     $( $rk_variant => Ident { name: $rk_name, ctxt: 0 }, )*
402                 }
403             }
404         }
405     }
406
407     fn mk_fresh_ident_interner() -> IdentInterner {
408         // The indices here must correspond to the numbers in
409         // special_idents, in Keyword to_ident(), and in static
410         // constants below.
411         let mut init_vec = Vec::new();
412         $(init_vec.push($si_str);)*
413         $(init_vec.push($sk_str);)*
414         $(init_vec.push($rk_str);)*
415         interner::StrInterner::prefill(init_vec.as_slice())
416     }
417 }}
418
419 // If the special idents get renumbered, remember to modify these two as appropriate
420 static SELF_KEYWORD_NAME: Name = 1;
421 static STATIC_KEYWORD_NAME: Name = 2;
422
423 declare_special_idents_and_keywords! {
424     pub mod special_idents {
425         // These ones are statics
426         (0,                          invalid,                "");
427         (super::SELF_KEYWORD_NAME,   self_,                  "self");
428         (super::STATIC_KEYWORD_NAME, statik,                 "static");
429
430         // for matcher NTs
431         (3,                          tt,                     "tt");
432         (4,                          matchers,               "matchers");
433
434         // outside of libsyntax
435         (5,                          clownshoe_abi,          "__rust_abi");
436         (6,                          opaque,                 "<opaque>");
437         (7,                          unnamed_field,          "<unnamed_field>");
438         (8,                          type_self,              "Self");
439     }
440
441     pub mod keywords {
442         // These ones are variants of the Keyword enum
443
444         'strict:
445         (9,                          As,         "as");
446         (10,                         Break,      "break");
447         (11,                         Const,      "const");
448         (12,                         Crate,      "crate");
449         (13,                         Else,       "else");
450         (14,                         Enum,       "enum");
451         (15,                         Extern,     "extern");
452         (16,                         False,      "false");
453         (17,                         Fn,         "fn");
454         (18,                         For,        "for");
455         (19,                         If,         "if");
456         (20,                         Impl,       "impl");
457         (21,                         In,         "in");
458         (22,                         Let,        "let");
459         (23,                         Loop,       "loop");
460         (24,                         Match,      "match");
461         (25,                         Mod,        "mod");
462         (26,                         Mut,        "mut");
463         (27,                         Once,       "once");
464         (28,                         Pub,        "pub");
465         (29,                         Ref,        "ref");
466         (30,                         Return,     "return");
467         // Static and Self are also special idents (prefill de-dupes)
468         (super::STATIC_KEYWORD_NAME, Static,     "static");
469         (super::SELF_KEYWORD_NAME,   Self,       "self");
470         (31,                         Struct,     "struct");
471         (32,                         Super,      "super");
472         (33,                         True,       "true");
473         (34,                         Trait,      "trait");
474         (35,                         Type,       "type");
475         (36,                         Unsafe,     "unsafe");
476         (37,                         Use,        "use");
477         (38,                         While,      "while");
478         (39,                         Continue,   "continue");
479         (40,                         Proc,       "proc");
480         (41,                         Box,        "box");
481
482         'reserved:
483         (42,                         Alignof,    "alignof");
484         (43,                         Be,         "be");
485         (44,                         Offsetof,   "offsetof");
486         (45,                         Priv,       "priv");
487         (46,                         Pure,       "pure");
488         (47,                         Sizeof,     "sizeof");
489         (48,                         Typeof,     "typeof");
490         (49,                         Unsized,    "unsized");
491         (50,                         Yield,      "yield");
492         (51,                         Do,         "do");
493     }
494 }
495
496 /**
497  * Maps a token to a record specifying the corresponding binary
498  * operator
499  */
500 pub fn token_to_binop(tok: &Token) -> Option<ast::BinOp> {
501   match *tok {
502       BINOP(STAR)    => Some(ast::BiMul),
503       BINOP(SLASH)   => Some(ast::BiDiv),
504       BINOP(PERCENT) => Some(ast::BiRem),
505       BINOP(PLUS)    => Some(ast::BiAdd),
506       BINOP(MINUS)   => Some(ast::BiSub),
507       BINOP(SHL)     => Some(ast::BiShl),
508       BINOP(SHR)     => Some(ast::BiShr),
509       BINOP(AND)     => Some(ast::BiBitAnd),
510       BINOP(CARET)   => Some(ast::BiBitXor),
511       BINOP(OR)      => Some(ast::BiBitOr),
512       LT             => Some(ast::BiLt),
513       LE             => Some(ast::BiLe),
514       GE             => Some(ast::BiGe),
515       GT             => Some(ast::BiGt),
516       EQEQ           => Some(ast::BiEq),
517       NE             => Some(ast::BiNe),
518       ANDAND         => Some(ast::BiAnd),
519       OROR           => Some(ast::BiOr),
520       _              => None
521   }
522 }
523
524 // looks like we can get rid of this completely...
525 pub type IdentInterner = StrInterner;
526
527 // if an interner exists in TLS, return it. Otherwise, prepare a
528 // fresh one.
529 // FIXME(eddyb) #8726 This should probably use a task-local reference.
530 pub fn get_ident_interner() -> Rc<IdentInterner> {
531     local_data_key!(key: Rc<::parse::token::IdentInterner>)
532     match local_data::get(key, |k| k.map(|k| k.clone())) {
533         Some(interner) => interner,
534         None => {
535             let interner = Rc::new(mk_fresh_ident_interner());
536             local_data::set(key, interner.clone());
537             interner
538         }
539     }
540 }
541
542 /// Represents a string stored in the task-local interner. Because the
543 /// interner lives for the life of the task, this can be safely treated as an
544 /// immortal string, as long as it never crosses between tasks.
545 ///
546 /// FIXME(pcwalton): You must be careful about what you do in the destructors
547 /// of objects stored in TLS, because they may run after the interner is
548 /// destroyed. In particular, they must not access string contents. This can
549 /// be fixed in the future by just leaking all strings until task death
550 /// somehow.
551 #[deriving(Clone, Eq, Hash, Ord, TotalEq, TotalOrd)]
552 pub struct InternedString {
553     string: RcStr,
554 }
555
556 impl InternedString {
557     #[inline]
558     pub fn new(string: &'static str) -> InternedString {
559         InternedString {
560             string: RcStr::new(string),
561         }
562     }
563
564     #[inline]
565     fn new_from_rc_str(string: RcStr) -> InternedString {
566         InternedString {
567             string: string,
568         }
569     }
570
571     #[inline]
572     pub fn get<'a>(&'a self) -> &'a str {
573         self.string.as_slice()
574     }
575 }
576
577 impl BytesContainer for InternedString {
578     fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
579         // FIXME(pcwalton): This is a workaround for the incorrect signature
580         // of `BytesContainer`, which is itself a workaround for the lack of
581         // DST.
582         unsafe {
583             let this = self.get();
584             cast::transmute(this.container_as_bytes())
585         }
586     }
587 }
588
589 impl fmt::Show for InternedString {
590     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
591         write!(f.buf, "{}", self.string.as_slice())
592     }
593 }
594
595 impl<'a> Equiv<&'a str> for InternedString {
596     fn equiv(&self, other: & &'a str) -> bool {
597         (*other) == self.string.as_slice()
598     }
599 }
600
601 impl<D:Decoder<E>, E> Decodable<D, E> for InternedString {
602     fn decode(d: &mut D) -> Result<InternedString, E> {
603         Ok(get_name(get_ident_interner().intern(try!(d.read_str()))))
604     }
605 }
606
607 impl<S:Encoder<E>, E> Encodable<S, E> for InternedString {
608     fn encode(&self, s: &mut S) -> Result<(), E> {
609         s.emit_str(self.string.as_slice())
610     }
611 }
612
613 /// Returns the string contents of a name, using the task-local interner.
614 #[inline]
615 pub fn get_name(name: Name) -> InternedString {
616     let interner = get_ident_interner();
617     InternedString::new_from_rc_str(interner.get(name))
618 }
619
620 /// Returns the string contents of an identifier, using the task-local
621 /// interner.
622 #[inline]
623 pub fn get_ident(ident: Ident) -> InternedString {
624     get_name(ident.name)
625 }
626
627 /// Interns and returns the string contents of an identifier, using the
628 /// task-local interner.
629 #[inline]
630 pub fn intern_and_get_ident(s: &str) -> InternedString {
631     get_name(intern(s))
632 }
633
634 /// Maps a string to its interned representation.
635 #[inline]
636 pub fn intern(s: &str) -> Name {
637     get_ident_interner().intern(s)
638 }
639
640 /// gensym's a new uint, using the current interner.
641 #[inline]
642 pub fn gensym(s: &str) -> Name {
643     get_ident_interner().gensym(s)
644 }
645
646 /// Maps a string to an identifier with an empty syntax context.
647 #[inline]
648 pub fn str_to_ident(s: &str) -> ast::Ident {
649     ast::Ident::new(intern(s))
650 }
651
652 /// Maps a string to a gensym'ed identifier.
653 #[inline]
654 pub fn gensym_ident(s: &str) -> ast::Ident {
655     ast::Ident::new(gensym(s))
656 }
657
658 // create a fresh name that maps to the same string as the old one.
659 // note that this guarantees that str_ptr_eq(ident_to_str(src),interner_get(fresh_name(src)));
660 // that is, that the new name and the old one are connected to ptr_eq strings.
661 pub fn fresh_name(src: &ast::Ident) -> Name {
662     let interner = get_ident_interner();
663     interner.gensym_copy(src.name)
664     // following: debug version. Could work in final except that it's incompatible with
665     // good error messages and uses of struct names in ambiguous could-be-binding
666     // locations. Also definitely destroys the guarantee given above about ptr_eq.
667     /*let num = rand::task_rng().gen_uint_range(0,0xffff);
668     gensym(format!("{}_{}",ident_to_str(src),num))*/
669 }
670
671 // create a fresh mark.
672 pub fn fresh_mark() -> Mrk {
673     gensym("mark")
674 }
675
676 // See the macro above about the types of keywords
677
678 pub fn is_keyword(kw: keywords::Keyword, tok: &Token) -> bool {
679     match *tok {
680         token::IDENT(sid, false) => { kw.to_ident().name == sid.name }
681         _ => { false }
682     }
683 }
684
685 pub fn is_any_keyword(tok: &Token) -> bool {
686     match *tok {
687         token::IDENT(sid, false) => match sid.name {
688             SELF_KEYWORD_NAME | STATIC_KEYWORD_NAME |
689             STRICT_KEYWORD_START .. RESERVED_KEYWORD_FINAL => true,
690             _ => false,
691         },
692         _ => false
693     }
694 }
695
696 pub fn is_strict_keyword(tok: &Token) -> bool {
697     match *tok {
698         token::IDENT(sid, false) => match sid.name {
699             SELF_KEYWORD_NAME | STATIC_KEYWORD_NAME |
700             STRICT_KEYWORD_START .. STRICT_KEYWORD_FINAL => true,
701             _ => false,
702         },
703         _ => false,
704     }
705 }
706
707 pub fn is_reserved_keyword(tok: &Token) -> bool {
708     match *tok {
709         token::IDENT(sid, false) => match sid.name {
710             RESERVED_KEYWORD_START .. RESERVED_KEYWORD_FINAL => true,
711             _ => false,
712         },
713         _ => false,
714     }
715 }
716
717 pub fn mtwt_token_eq(t1 : &Token, t2 : &Token) -> bool {
718     match (t1,t2) {
719         (&IDENT(id1,_),&IDENT(id2,_)) | (&LIFETIME(id1),&LIFETIME(id2)) =>
720             mtwt::resolve(id1) == mtwt::resolve(id2),
721         _ => *t1 == *t2
722     }
723 }
724
725
726 #[cfg(test)]
727 mod test {
728     use super::*;
729     use ast;
730     use ext::mtwt;
731
732     fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
733         ast::Ident{name:id.name,ctxt:mtwt::new_mark(m,id.ctxt)}
734     }
735
736     #[test] fn mtwt_token_eq_test() {
737         assert!(mtwt_token_eq(&GT,&GT));
738         let a = str_to_ident("bac");
739         let a1 = mark_ident(a,92);
740         assert!(mtwt_token_eq(&IDENT(a,true),&IDENT(a1,false)));
741     }
742 }