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