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