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