]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/parse/token.rs
syntax: Clean out obsolete syntax parsing
[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::fmt;
21 use std::path::BytesContainer;
22 use std::mem;
23 use std::rc::Rc;
24 use std::strbuf::StrBuf;
25
26 #[allow(non_camel_case_types)]
27 #[deriving(Clone, Encodable, Decodable, Eq, TotalEq, Hash, Show)]
28 pub enum BinOp {
29     PLUS,
30     MINUS,
31     STAR,
32     SLASH,
33     PERCENT,
34     CARET,
35     AND,
36     OR,
37     SHL,
38     SHR,
39 }
40
41 #[allow(non_camel_case_types)]
42 #[deriving(Clone, Encodable, Decodable, Eq, TotalEq, Hash, Show)]
43 pub enum Token {
44     /* Expression-operator symbols. */
45     EQ,
46     LT,
47     LE,
48     EQEQ,
49     NE,
50     GE,
51     GT,
52     ANDAND,
53     OROR,
54     NOT,
55     TILDE,
56     BINOP(BinOp),
57     BINOPEQ(BinOp),
58
59     /* Structural symbols */
60     AT,
61     DOT,
62     DOTDOT,
63     DOTDOTDOT,
64     COMMA,
65     SEMI,
66     COLON,
67     MOD_SEP,
68     RARROW,
69     LARROW,
70     FAT_ARROW,
71     LPAREN,
72     RPAREN,
73     LBRACKET,
74     RBRACKET,
75     LBRACE,
76     RBRACE,
77     POUND,
78     DOLLAR,
79
80     /* Literals */
81     LIT_CHAR(char),
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, TotalEq, 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(Box<ast::Ident>, bool),
115     NtMeta(@ast::MetaItem), // stuff inside brackets for attributes
116     NtPath(Box<ast::Path>),
117     NtTT(  @ast::TokenTree), // needs @ed to break a circularity
118     NtMatchers(Vec<ast::Matcher> )
119 }
120
121 impl fmt::Show for Nonterminal {
122     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123         match *self {
124             NtItem(..) => f.pad("NtItem(..)"),
125             NtBlock(..) => f.pad("NtBlock(..)"),
126             NtStmt(..) => f.pad("NtStmt(..)"),
127             NtPat(..) => f.pad("NtPat(..)"),
128             NtExpr(..) => f.pad("NtExpr(..)"),
129             NtTy(..) => f.pad("NtTy(..)"),
130             NtIdent(..) => f.pad("NtIdent(..)"),
131             NtMeta(..) => f.pad("NtMeta(..)"),
132             NtPath(..) => f.pad("NtPath(..)"),
133             NtTT(..) => f.pad("NtTT(..)"),
134             NtMatchers(..) => f.pad("NtMatchers(..)"),
135         }
136     }
137 }
138
139 pub fn binop_to_str(o: BinOp) -> StrBuf {
140     match o {
141       PLUS => "+".to_strbuf(),
142       MINUS => "-".to_strbuf(),
143       STAR => "*".to_strbuf(),
144       SLASH => "/".to_strbuf(),
145       PERCENT => "%".to_strbuf(),
146       CARET => "^".to_strbuf(),
147       AND => "&".to_strbuf(),
148       OR => "|".to_strbuf(),
149       SHL => "<<".to_strbuf(),
150       SHR => ">>".to_strbuf()
151     }
152 }
153
154 pub fn to_str(t: &Token) -> StrBuf {
155     match *t {
156       EQ => "=".to_strbuf(),
157       LT => "<".to_strbuf(),
158       LE => "<=".to_strbuf(),
159       EQEQ => "==".to_strbuf(),
160       NE => "!=".to_strbuf(),
161       GE => ">=".to_strbuf(),
162       GT => ">".to_strbuf(),
163       NOT => "!".to_strbuf(),
164       TILDE => "~".to_strbuf(),
165       OROR => "||".to_strbuf(),
166       ANDAND => "&&".to_strbuf(),
167       BINOP(op) => binop_to_str(op),
168       BINOPEQ(op) => {
169           let mut s = binop_to_str(op);
170           s.push_str("=");
171           s
172       }
173
174       /* Structural symbols */
175       AT => "@".to_strbuf(),
176       DOT => ".".to_strbuf(),
177       DOTDOT => "..".to_strbuf(),
178       DOTDOTDOT => "...".to_strbuf(),
179       COMMA => ",".to_strbuf(),
180       SEMI => ";".to_strbuf(),
181       COLON => ":".to_strbuf(),
182       MOD_SEP => "::".to_strbuf(),
183       RARROW => "->".to_strbuf(),
184       LARROW => "<-".to_strbuf(),
185       FAT_ARROW => "=>".to_strbuf(),
186       LPAREN => "(".to_strbuf(),
187       RPAREN => ")".to_strbuf(),
188       LBRACKET => "[".to_strbuf(),
189       RBRACKET => "]".to_strbuf(),
190       LBRACE => "{".to_strbuf(),
191       RBRACE => "}".to_strbuf(),
192       POUND => "#".to_strbuf(),
193       DOLLAR => "$".to_strbuf(),
194
195       /* Literals */
196       LIT_CHAR(c) => {
197           let mut res = StrBuf::from_str("'");
198           c.escape_default(|c| {
199               res.push_char(c);
200           });
201           res.push_char('\'');
202           res
203       }
204       LIT_INT(i, t) => ast_util::int_ty_to_str(t, Some(i),
205                                                ast_util::ForceSuffix),
206       LIT_UINT(u, t) => ast_util::uint_ty_to_str(t, Some(u),
207                                                  ast_util::ForceSuffix),
208       LIT_INT_UNSUFFIXED(i) => { (i as u64).to_str().to_strbuf() }
209       LIT_FLOAT(s, t) => {
210         let mut body = StrBuf::from_str(get_ident(s).get());
211         if body.as_slice().ends_with(".") {
212             body.push_char('0');  // `10.f` is not a float literal
213         }
214         body.push_str(ast_util::float_ty_to_str(t).as_slice());
215         body
216       }
217       LIT_FLOAT_UNSUFFIXED(s) => {
218         let mut body = StrBuf::from_str(get_ident(s).get());
219         if body.as_slice().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())).to_strbuf()
226       }
227       LIT_STR_RAW(s, n) => {
228           (format!("r{delim}\"{string}\"{delim}",
229                   delim="#".repeat(n), string=get_ident(s))).to_strbuf()
230       }
231
232       /* Name components */
233       IDENT(s, _) => get_ident(s).get().to_strbuf(),
234       LIFETIME(s) => {
235           (format!("'{}", get_ident(s))).to_strbuf()
236       }
237       UNDERSCORE => "_".to_strbuf(),
238
239       /* Other */
240       DOC_COMMENT(s) => get_ident(s).get().to_strbuf(),
241       EOF => "<eof>".to_strbuf(),
242       INTERPOLATED(ref nt) => {
243         match nt {
244             &NtExpr(e) => ::print::pprust::expr_to_str(e),
245             &NtMeta(e) => ::print::pprust::meta_item_to_str(e),
246             _ => {
247                 let mut s = "an interpolated ".to_strbuf();
248                 match *nt {
249                     NtItem(..) => s.push_str("item"),
250                     NtBlock(..) => s.push_str("block"),
251                     NtStmt(..) => s.push_str("statement"),
252                     NtPat(..) => s.push_str("pattern"),
253                     NtMeta(..) => fail!("should have been handled"),
254                     NtExpr(..) => fail!("should have been handled above"),
255                     NtTy(..) => s.push_str("type"),
256                     NtIdent(..) => s.push_str("identifier"),
257                     NtPath(..) => s.push_str("path"),
258                     NtTT(..) => s.push_str("tt"),
259                     NtMatchers(..) => s.push_str("matcher sequence")
260                 };
261                 s
262             }
263         }
264       }
265     }
266 }
267
268 pub fn can_begin_expr(t: &Token) -> bool {
269     match *t {
270       LPAREN => true,
271       LBRACE => true,
272       LBRACKET => true,
273       IDENT(_, _) => true,
274       UNDERSCORE => true,
275       TILDE => true,
276       LIT_CHAR(_) => true,
277       LIT_INT(_, _) => true,
278       LIT_UINT(_, _) => true,
279       LIT_INT_UNSUFFIXED(_) => true,
280       LIT_FLOAT(_, _) => true,
281       LIT_FLOAT_UNSUFFIXED(_) => true,
282       LIT_STR(_) => true,
283       LIT_STR_RAW(_, _) => true,
284       POUND => true,
285       AT => true,
286       NOT => true,
287       BINOP(MINUS) => true,
288       BINOP(STAR) => true,
289       BINOP(AND) => true,
290       BINOP(OR) => true, // in lambda syntax
291       OROR => true, // in lambda syntax
292       MOD_SEP => true,
293       INTERPOLATED(NtExpr(..))
294       | INTERPOLATED(NtIdent(..))
295       | INTERPOLATED(NtBlock(..))
296       | INTERPOLATED(NtPath(..)) => true,
297       _ => false
298     }
299 }
300
301 /// Returns the matching close delimiter if this is an open delimiter,
302 /// otherwise `None`.
303 pub fn close_delimiter_for(t: &Token) -> Option<Token> {
304     match *t {
305         LPAREN   => Some(RPAREN),
306         LBRACE   => Some(RBRACE),
307         LBRACKET => Some(RBRACKET),
308         _        => None
309     }
310 }
311
312 pub fn is_lit(t: &Token) -> bool {
313     match *t {
314       LIT_CHAR(_) => true,
315       LIT_INT(_, _) => true,
316       LIT_UINT(_, _) => true,
317       LIT_INT_UNSUFFIXED(_) => true,
318       LIT_FLOAT(_, _) => true,
319       LIT_FLOAT_UNSUFFIXED(_) => true,
320       LIT_STR(_) => true,
321       LIT_STR_RAW(_, _) => true,
322       _ => false
323     }
324 }
325
326 pub fn is_ident(t: &Token) -> bool {
327     match *t { IDENT(_, _) => true, _ => false }
328 }
329
330 pub fn is_ident_or_path(t: &Token) -> bool {
331     match *t {
332       IDENT(_, _) | INTERPOLATED(NtPath(..)) => true,
333       _ => false
334     }
335 }
336
337 pub fn is_plain_ident(t: &Token) -> bool {
338     match *t { IDENT(_, false) => true, _ => false }
339 }
340
341 pub fn is_bar(t: &Token) -> bool {
342     match *t { BINOP(OR) | OROR => true, _ => false }
343 }
344
345 // Get the first "argument"
346 macro_rules! first {
347     ( $first:expr, $( $remainder:expr, )* ) => ( $first )
348 }
349
350 // Get the last "argument" (has to be done recursively to avoid phoney local ambiguity error)
351 macro_rules! last {
352     ( $first:expr, $( $remainder:expr, )+ ) => ( last!( $( $remainder, )+ ) );
353     ( $first:expr, ) => ( $first )
354 }
355
356 // In this macro, there is the requirement that the name (the number) must be monotonically
357 // increasing by one in the special identifiers, starting at 0; the same holds for the keywords,
358 // except starting from the next number instead of zero, and with the additional exception that
359 // special identifiers are *also* allowed (they are deduplicated in the important place, the
360 // interner), an exception which is demonstrated by "static" and "self".
361 macro_rules! declare_special_idents_and_keywords {(
362     // So now, in these rules, why is each definition parenthesised?
363     // Answer: otherwise we get a spurious local ambiguity bug on the "}"
364     pub mod special_idents {
365         $( ($si_name:expr, $si_static:ident, $si_str:expr); )*
366     }
367
368     pub mod keywords {
369         'strict:
370         $( ($sk_name:expr, $sk_variant:ident, $sk_str:expr); )*
371         'reserved:
372         $( ($rk_name:expr, $rk_variant:ident, $rk_str:expr); )*
373     }
374 ) => {
375     static STRICT_KEYWORD_START: Name = first!($( $sk_name, )*);
376     static STRICT_KEYWORD_FINAL: Name = last!($( $sk_name, )*);
377     static RESERVED_KEYWORD_START: Name = first!($( $rk_name, )*);
378     static RESERVED_KEYWORD_FINAL: Name = last!($( $rk_name, )*);
379
380     pub mod special_idents {
381         use ast::Ident;
382         $( pub static $si_static: Ident = Ident { name: $si_name, ctxt: 0 }; )*
383     }
384
385     /**
386      * All the valid words that have meaning in the Rust language.
387      *
388      * Rust keywords are either 'strict' or 'reserved'.  Strict keywords may not
389      * appear as identifiers at all. Reserved keywords are not used anywhere in
390      * the language and may not appear as identifiers.
391      */
392     pub mod keywords {
393         use ast::Ident;
394
395         pub enum Keyword {
396             $( $sk_variant, )*
397             $( $rk_variant, )*
398         }
399
400         impl Keyword {
401             pub fn to_ident(&self) -> Ident {
402                 match *self {
403                     $( $sk_variant => Ident { name: $sk_name, ctxt: 0 }, )*
404                     $( $rk_variant => Ident { name: $rk_name, ctxt: 0 }, )*
405                 }
406             }
407         }
408     }
409
410     fn mk_fresh_ident_interner() -> IdentInterner {
411         // The indices here must correspond to the numbers in
412         // special_idents, in Keyword to_ident(), and in static
413         // constants below.
414         let mut init_vec = Vec::new();
415         $(init_vec.push($si_str);)*
416         $(init_vec.push($sk_str);)*
417         $(init_vec.push($rk_str);)*
418         interner::StrInterner::prefill(init_vec.as_slice())
419     }
420 }}
421
422 // If the special idents get renumbered, remember to modify these two as appropriate
423 static SELF_KEYWORD_NAME: Name = 1;
424 static STATIC_KEYWORD_NAME: Name = 2;
425
426 declare_special_idents_and_keywords! {
427     pub mod special_idents {
428         // These ones are statics
429         (0,                          invalid,                "");
430         (super::SELF_KEYWORD_NAME,   self_,                  "self");
431         (super::STATIC_KEYWORD_NAME, statik,                 "static");
432
433         // for matcher NTs
434         (3,                          tt,                     "tt");
435         (4,                          matchers,               "matchers");
436
437         // outside of libsyntax
438         (5,                          clownshoe_abi,          "__rust_abi");
439         (6,                          opaque,                 "<opaque>");
440         (7,                          unnamed_field,          "<unnamed_field>");
441         (8,                          type_self,              "Self");
442     }
443
444     pub mod keywords {
445         // These ones are variants of the Keyword enum
446
447         'strict:
448         (9,                          As,         "as");
449         (10,                         Break,      "break");
450         (11,                         Crate,      "crate");
451         (12,                         Else,       "else");
452         (13,                         Enum,       "enum");
453         (14,                         Extern,     "extern");
454         (15,                         False,      "false");
455         (16,                         Fn,         "fn");
456         (17,                         For,        "for");
457         (18,                         If,         "if");
458         (19,                         Impl,       "impl");
459         (20,                         In,         "in");
460         (21,                         Let,        "let");
461         (22,                         Loop,       "loop");
462         (23,                         Match,      "match");
463         (24,                         Mod,        "mod");
464         (25,                         Mut,        "mut");
465         (26,                         Once,       "once");
466         (27,                         Pub,        "pub");
467         (28,                         Ref,        "ref");
468         (29,                         Return,     "return");
469         // Static and Self are also special idents (prefill de-dupes)
470         (super::STATIC_KEYWORD_NAME, Static,     "static");
471         (super::SELF_KEYWORD_NAME,   Self,       "self");
472         (30,                         Struct,     "struct");
473         (31,                         Super,      "super");
474         (32,                         True,       "true");
475         (33,                         Trait,      "trait");
476         (34,                         Type,       "type");
477         (35,                         Unsafe,     "unsafe");
478         (36,                         Use,        "use");
479         (37,                         Virtual,    "virtual");
480         (38,                         While,      "while");
481         (39,                         Continue,   "continue");
482         (40,                         Proc,       "proc");
483         (41,                         Box,        "box");
484
485         'reserved:
486         (42,                         Alignof,    "alignof");
487         (43,                         Be,         "be");
488         (44,                         Const,      "const");
489         (45,                         Offsetof,   "offsetof");
490         (46,                         Priv,       "priv");
491         (47,                         Pure,       "pure");
492         (48,                         Sizeof,     "sizeof");
493         (49,                         Typeof,     "typeof");
494         (50,                         Unsized,    "unsized");
495         (51,                         Yield,      "yield");
496         (52,                         Do,         "do");
497     }
498 }
499
500 /**
501  * Maps a token to a record specifying the corresponding binary
502  * operator
503  */
504 pub fn token_to_binop(tok: &Token) -> Option<ast::BinOp> {
505   match *tok {
506       BINOP(STAR)    => Some(ast::BiMul),
507       BINOP(SLASH)   => Some(ast::BiDiv),
508       BINOP(PERCENT) => Some(ast::BiRem),
509       BINOP(PLUS)    => Some(ast::BiAdd),
510       BINOP(MINUS)   => Some(ast::BiSub),
511       BINOP(SHL)     => Some(ast::BiShl),
512       BINOP(SHR)     => Some(ast::BiShr),
513       BINOP(AND)     => Some(ast::BiBitAnd),
514       BINOP(CARET)   => Some(ast::BiBitXor),
515       BINOP(OR)      => Some(ast::BiBitOr),
516       LT             => Some(ast::BiLt),
517       LE             => Some(ast::BiLe),
518       GE             => Some(ast::BiGe),
519       GT             => Some(ast::BiGt),
520       EQEQ           => Some(ast::BiEq),
521       NE             => Some(ast::BiNe),
522       ANDAND         => Some(ast::BiAnd),
523       OROR           => Some(ast::BiOr),
524       _              => None
525   }
526 }
527
528 // looks like we can get rid of this completely...
529 pub type IdentInterner = StrInterner;
530
531 // if an interner exists in TLS, return it. Otherwise, prepare a
532 // fresh one.
533 // FIXME(eddyb) #8726 This should probably use a task-local reference.
534 pub fn get_ident_interner() -> Rc<IdentInterner> {
535     local_data_key!(key: Rc<::parse::token::IdentInterner>)
536     match key.get() {
537         Some(interner) => interner.clone(),
538         None => {
539             let interner = Rc::new(mk_fresh_ident_interner());
540             key.replace(Some(interner.clone()));
541             interner
542         }
543     }
544 }
545
546 /// Represents a string stored in the task-local interner. Because the
547 /// interner lives for the life of the task, this can be safely treated as an
548 /// immortal string, as long as it never crosses between tasks.
549 ///
550 /// FIXME(pcwalton): You must be careful about what you do in the destructors
551 /// of objects stored in TLS, because they may run after the interner is
552 /// destroyed. In particular, they must not access string contents. This can
553 /// be fixed in the future by just leaking all strings until task death
554 /// somehow.
555 #[deriving(Clone, Eq, Hash, Ord, TotalEq, TotalOrd)]
556 pub struct InternedString {
557     string: RcStr,
558 }
559
560 impl InternedString {
561     #[inline]
562     pub fn new(string: &'static str) -> InternedString {
563         InternedString {
564             string: RcStr::new(string),
565         }
566     }
567
568     #[inline]
569     fn new_from_rc_str(string: RcStr) -> InternedString {
570         InternedString {
571             string: string,
572         }
573     }
574
575     #[inline]
576     pub fn get<'a>(&'a self) -> &'a str {
577         self.string.as_slice()
578     }
579 }
580
581 impl BytesContainer for InternedString {
582     fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
583         // FIXME(pcwalton): This is a workaround for the incorrect signature
584         // of `BytesContainer`, which is itself a workaround for the lack of
585         // DST.
586         unsafe {
587             let this = self.get();
588             mem::transmute(this.container_as_bytes())
589         }
590     }
591 }
592
593 impl fmt::Show for InternedString {
594     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
595         write!(f, "{}", self.string.as_slice())
596     }
597 }
598
599 impl<'a> Equiv<&'a str> for InternedString {
600     fn equiv(&self, other: & &'a str) -> bool {
601         (*other) == self.string.as_slice()
602     }
603 }
604
605 impl<D:Decoder<E>, E> Decodable<D, E> for InternedString {
606     fn decode(d: &mut D) -> Result<InternedString, E> {
607         Ok(get_name(get_ident_interner().intern(
608                     try!(d.read_str()).as_slice())))
609     }
610 }
611
612 impl<S:Encoder<E>, E> Encodable<S, E> for InternedString {
613     fn encode(&self, s: &mut S) -> Result<(), E> {
614         s.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 }