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