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