]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/parse/token.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / libsyntax / parse / token.rs
CommitLineData
970d7e83 1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
223e47cc
LB
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
1a4d82fc
JJ
11pub use self::BinOpToken::*;
12pub use self::Nonterminal::*;
13pub use self::DelimToken::*;
1a4d82fc
JJ
14pub use self::Lit::*;
15pub use self::Token::*;
16
9e0c209e 17use ast::{self};
1a4d82fc 18use ptr::P;
5bcae85e 19use util::interner::Interner;
3157f602 20use tokenstream;
223e47cc 21
1a4d82fc 22use serialize::{Decodable, Decoder, Encodable, Encoder};
5bcae85e 23use std::cell::RefCell;
1a4d82fc 24use std::fmt;
1a4d82fc 25use std::ops::Deref;
1a4d82fc
JJ
26use std::rc::Rc;
27
85aaf69f 28#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
1a4d82fc
JJ
29pub enum BinOpToken {
30 Plus,
31 Minus,
32 Star,
33 Slash,
34 Percent,
35 Caret,
36 And,
37 Or,
38 Shl,
39 Shr,
40}
41
42/// A delimiter token
85aaf69f 43#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
1a4d82fc
JJ
44pub enum DelimToken {
45 /// A round parenthesis: `(` or `)`
46 Paren,
47 /// A square bracket: `[` or `]`
48 Bracket,
49 /// A curly brace: `{` or `}`
50 Brace,
5bcae85e
SL
51 /// An empty delimiter
52 NoDelim,
1a4d82fc
JJ
53}
54
85aaf69f 55#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug, Copy)]
1a4d82fc
JJ
56pub enum Lit {
57 Byte(ast::Name),
58 Char(ast::Name),
59 Integer(ast::Name),
60 Float(ast::Name),
61 Str_(ast::Name),
85aaf69f 62 StrRaw(ast::Name, usize), /* raw str delimited by n hash symbols */
e9174d1e
SL
63 ByteStr(ast::Name),
64 ByteStrRaw(ast::Name, usize), /* raw byte str delimited by n hash symbols */
1a4d82fc
JJ
65}
66
67impl Lit {
68 pub fn short_name(&self) -> &'static str {
69 match *self {
70 Byte(_) => "byte",
71 Char(_) => "char",
72 Integer(_) => "integer",
73 Float(_) => "float",
e9174d1e
SL
74 Str_(_) | StrRaw(..) => "string",
75 ByteStr(_) | ByteStrRaw(..) => "byte string"
1a4d82fc
JJ
76 }
77 }
78}
79
85aaf69f 80#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)]
223e47cc
LB
81pub enum Token {
82 /* Expression-operator symbols. */
1a4d82fc
JJ
83 Eq,
84 Lt,
85 Le,
86 EqEq,
87 Ne,
88 Ge,
89 Gt,
90 AndAnd,
91 OrOr,
92 Not,
93 Tilde,
94 BinOp(BinOpToken),
95 BinOpEq(BinOpToken),
223e47cc
LB
96
97 /* Structural symbols */
1a4d82fc
JJ
98 At,
99 Dot,
100 DotDot,
101 DotDotDot,
102 Comma,
103 Semi,
104 Colon,
105 ModSep,
106 RArrow,
107 LArrow,
108 FatArrow,
109 Pound,
110 Dollar,
111 Question,
112 /// An opening delimiter, eg. `{`
113 OpenDelim(DelimToken),
114 /// A closing delimiter, eg. `}`
115 CloseDelim(DelimToken),
223e47cc
LB
116
117 /* Literals */
1a4d82fc 118 Literal(Lit, Option<ast::Name>),
223e47cc
LB
119
120 /* Name components */
a7813a04 121 Ident(ast::Ident),
1a4d82fc
JJ
122 Underscore,
123 Lifetime(ast::Ident),
223e47cc
LB
124
125 /* For interpolation */
c30ab7b3 126 Interpolated(Rc<Nonterminal>),
1a4d82fc
JJ
127 // Can be expanded into several tokens.
128 /// Doc comment
129 DocComment(ast::Name),
130 // In left-hand-sides of MBE macros:
a7813a04
XL
131 /// Parse a nonterminal (name to bind, name of NT)
132 MatchNt(ast::Ident, ast::Ident),
1a4d82fc
JJ
133 // In right-hand-sides of MBE macros:
134 /// A syntactic variable that will be filled in by macro expansion.
a7813a04 135 SubstNt(ast::Ident),
1a4d82fc
JJ
136
137 // Junk. These carry no data because we don't really care about the data
138 // they *would* carry, and don't really want to allocate a new ident for
139 // them. Instead, users could extract that from the associated span.
140
141 /// Whitespace
142 Whitespace,
143 /// Comment
144 Comment,
145 Shebang(ast::Name),
146
147 Eof,
148}
149
150impl Token {
bd371182
AL
151 /// Returns `true` if the token starts with '>'.
152 pub fn is_like_gt(&self) -> bool {
153 match *self {
154 BinOp(Shr) | BinOpEq(Shr) | Gt | Ge => true,
155 _ => false,
156 }
157 }
158
1a4d82fc
JJ
159 /// Returns `true` if the token can appear at the start of an expression.
160 pub fn can_begin_expr(&self) -> bool {
161 match *self {
c30ab7b3 162 OpenDelim(..) => true,
a7813a04 163 Ident(..) => true,
9e0c209e 164 Literal(..) => true,
1a4d82fc
JJ
165 Not => true,
166 BinOp(Minus) => true,
167 BinOp(Star) => true,
168 BinOp(And) => true,
169 BinOp(Or) => true, // in lambda syntax
170 OrOr => true, // in lambda syntax
85aaf69f 171 AndAnd => true, // double borrow
54a0048b 172 DotDot | DotDotDot => true, // range notation
c30ab7b3 173 Lt | BinOp(Shl) => true, // associated path
1a4d82fc 174 ModSep => true,
92a42be0 175 Pound => true, // for expression attributes
c30ab7b3
SL
176 Interpolated(ref nt) => match **nt {
177 NtExpr(..) => true,
178 NtIdent(..) => true,
179 NtBlock(..) => true,
180 NtPath(..) => true,
181 _ => false,
182 },
183 _ => false,
1a4d82fc
JJ
184 }
185 }
223e47cc 186
1a4d82fc
JJ
187 /// Returns `true` if the token is any literal
188 pub fn is_lit(&self) -> bool {
189 match *self {
9e0c209e
SL
190 Literal(..) => true,
191 _ => false,
1a4d82fc
JJ
192 }
193 }
223e47cc 194
1a4d82fc
JJ
195 /// Returns `true` if the token is an identifier.
196 pub fn is_ident(&self) -> bool {
197 match *self {
a7813a04 198 Ident(..) => true,
1a4d82fc 199 _ => false,
223e47cc 200 }
1a4d82fc
JJ
201 }
202
9e0c209e
SL
203 /// Returns `true` if the token is a documentation comment.
204 pub fn is_doc_comment(&self) -> bool {
205 match *self {
206 DocComment(..) => true,
207 _ => false,
208 }
209 }
210
7453a54e
SL
211 /// Returns `true` if the token is interpolated.
212 pub fn is_interpolated(&self) -> bool {
213 match *self {
214 Interpolated(..) => true,
215 _ => false,
216 }
217 }
218
1a4d82fc
JJ
219 /// Returns `true` if the token is an interpolated path.
220 pub fn is_path(&self) -> bool {
c30ab7b3
SL
221 if let Interpolated(ref nt) = *self {
222 if let NtPath(..) = **nt {
223 return true;
224 }
1a4d82fc 225 }
c30ab7b3 226 false
1a4d82fc
JJ
227 }
228
1a4d82fc
JJ
229 /// Returns `true` if the token is a lifetime.
230 pub fn is_lifetime(&self) -> bool {
231 match *self {
232 Lifetime(..) => true,
233 _ => false,
223e47cc 234 }
1a4d82fc
JJ
235 }
236
237 /// Returns `true` if the token is either the `mut` or `const` keyword.
238 pub fn is_mutability(&self) -> bool {
239 self.is_keyword(keywords::Mut) ||
240 self.is_keyword(keywords::Const)
241 }
242
c30ab7b3
SL
243 pub fn is_qpath_start(&self) -> bool {
244 self == &Lt || self == &BinOp(Shl)
245 }
246
a7813a04 247 pub fn is_path_start(&self) -> bool {
c30ab7b3 248 self == &ModSep || self.is_qpath_start() || self.is_path() ||
a7813a04
XL
249 self.is_path_segment_keyword() || self.is_ident() && !self.is_any_keyword()
250 }
251
1a4d82fc 252 /// Returns `true` if the token is a given keyword, `kw`.
1a4d82fc
JJ
253 pub fn is_keyword(&self, kw: keywords::Keyword) -> bool {
254 match *self {
a7813a04
XL
255 Ident(id) => id.name == kw.name(),
256 _ => false,
1a4d82fc
JJ
257 }
258 }
259
a7813a04 260 pub fn is_path_segment_keyword(&self) -> bool {
1a4d82fc 261 match *self {
a7813a04
XL
262 Ident(id) => id.name == keywords::Super.name() ||
263 id.name == keywords::SelfValue.name() ||
264 id.name == keywords::SelfType.name(),
265 _ => false,
1a4d82fc
JJ
266 }
267 }
268
a7813a04 269 /// Returns `true` if the token is either a strict or reserved keyword.
1a4d82fc 270 pub fn is_any_keyword(&self) -> bool {
a7813a04 271 self.is_strict_keyword() || self.is_reserved_keyword()
1a4d82fc
JJ
272 }
273
a7813a04 274 /// Returns `true` if the token is a strict keyword.
1a4d82fc
JJ
275 pub fn is_strict_keyword(&self) -> bool {
276 match *self {
a7813a04
XL
277 Ident(id) => id.name >= keywords::As.name() &&
278 id.name <= keywords::While.name(),
1a4d82fc
JJ
279 _ => false,
280 }
281 }
282
a7813a04 283 /// Returns `true` if the token is a keyword reserved for possible future use.
1a4d82fc
JJ
284 pub fn is_reserved_keyword(&self) -> bool {
285 match *self {
a7813a04
XL
286 Ident(id) => id.name >= keywords::Abstract.name() &&
287 id.name <= keywords::Yield.name(),
1a4d82fc
JJ
288 _ => false,
289 }
290 }
223e47cc
LB
291}
292
1a4d82fc
JJ
293#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash)]
294/// For interpolation during macro expansion.
295pub enum Nonterminal {
296 NtItem(P<ast::Item>),
297 NtBlock(P<ast::Block>),
c30ab7b3 298 NtStmt(ast::Stmt),
1a4d82fc
JJ
299 NtPat(P<ast::Pat>),
300 NtExpr(P<ast::Expr>),
301 NtTy(P<ast::Ty>),
c30ab7b3 302 NtIdent(ast::SpannedIdent),
1a4d82fc
JJ
303 /// Stuff inside brackets for attributes
304 NtMeta(P<ast::MetaItem>),
c30ab7b3
SL
305 NtPath(ast::Path),
306 NtTT(tokenstream::TokenTree),
92a42be0 307 // These are not exposed to macros, but are used by quasiquote.
d9579d0f 308 NtArm(ast::Arm),
c30ab7b3
SL
309 NtImplItem(ast::ImplItem),
310 NtTraitItem(ast::TraitItem),
d9579d0f
AL
311 NtGenerics(ast::Generics),
312 NtWhereClause(ast::WhereClause),
92a42be0 313 NtArg(ast::Arg),
1a4d82fc
JJ
314}
315
85aaf69f 316impl fmt::Debug for Nonterminal {
1a4d82fc
JJ
317 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
318 match *self {
319 NtItem(..) => f.pad("NtItem(..)"),
320 NtBlock(..) => f.pad("NtBlock(..)"),
321 NtStmt(..) => f.pad("NtStmt(..)"),
322 NtPat(..) => f.pad("NtPat(..)"),
323 NtExpr(..) => f.pad("NtExpr(..)"),
324 NtTy(..) => f.pad("NtTy(..)"),
325 NtIdent(..) => f.pad("NtIdent(..)"),
326 NtMeta(..) => f.pad("NtMeta(..)"),
327 NtPath(..) => f.pad("NtPath(..)"),
328 NtTT(..) => f.pad("NtTT(..)"),
d9579d0f
AL
329 NtArm(..) => f.pad("NtArm(..)"),
330 NtImplItem(..) => f.pad("NtImplItem(..)"),
331 NtTraitItem(..) => f.pad("NtTraitItem(..)"),
332 NtGenerics(..) => f.pad("NtGenerics(..)"),
333 NtWhereClause(..) => f.pad("NtWhereClause(..)"),
92a42be0 334 NtArg(..) => f.pad("NtArg(..)"),
1a4d82fc 335 }
970d7e83
LB
336 }
337}
338
1a4d82fc
JJ
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,
a7813a04
XL
341// except starting from the next number instead of zero.
342macro_rules! declare_keywords {(
343 $( ($index: expr, $konst: ident, $string: expr) )*
1a4d82fc 344) => {
1a4d82fc 345 pub mod keywords {
1a4d82fc 346 use ast;
a7813a04
XL
347 #[derive(Clone, Copy, PartialEq, Eq)]
348 pub struct Keyword {
349 ident: ast::Ident,
1a4d82fc 350 }
1a4d82fc 351 impl Keyword {
a7813a04
XL
352 #[inline] pub fn ident(self) -> ast::Ident { self.ident }
353 #[inline] pub fn name(self) -> ast::Name { self.ident.name }
223e47cc 354 }
a7813a04
XL
355 $(
356 #[allow(non_upper_case_globals)]
357 pub const $konst: Keyword = Keyword {
358 ident: ast::Ident::with_empty_ctxt(ast::Name($index))
359 };
360 )*
223e47cc 361 }
1a4d82fc
JJ
362
363 fn mk_fresh_ident_interner() -> IdentInterner {
5bcae85e 364 Interner::prefill(&[$($string,)*])
1a4d82fc
JJ
365 }
366}}
367
1a4d82fc
JJ
368// NB: leaving holes in the ident table is bad! a different ident will get
369// interned with the id from the hole, but it will be between the min and max
370// of the reserved words, and thus tagged as "reserved".
a7813a04
XL
371// After modifying this list adjust `is_strict_keyword`/`is_reserved_keyword`,
372// this should be rarely necessary though if the keywords are kept in alphabetic order.
373declare_keywords! {
374 // Invalid identifier
375 (0, Invalid, "")
376
377 // Strict keywords used in the language.
378 (1, As, "as")
379 (2, Box, "box")
380 (3, Break, "break")
381 (4, Const, "const")
382 (5, Continue, "continue")
383 (6, Crate, "crate")
384 (7, Else, "else")
385 (8, Enum, "enum")
386 (9, Extern, "extern")
387 (10, False, "false")
388 (11, Fn, "fn")
389 (12, For, "for")
390 (13, If, "if")
391 (14, Impl, "impl")
392 (15, In, "in")
393 (16, Let, "let")
394 (17, Loop, "loop")
395 (18, Match, "match")
396 (19, Mod, "mod")
397 (20, Move, "move")
398 (21, Mut, "mut")
399 (22, Pub, "pub")
400 (23, Ref, "ref")
401 (24, Return, "return")
402 (25, SelfValue, "self")
403 (26, SelfType, "Self")
404 (27, Static, "static")
405 (28, Struct, "struct")
406 (29, Super, "super")
407 (30, Trait, "trait")
408 (31, True, "true")
409 (32, Type, "type")
410 (33, Unsafe, "unsafe")
411 (34, Use, "use")
412 (35, Where, "where")
413 (36, While, "while")
414
415 // Keywords reserved for future use.
416 (37, Abstract, "abstract")
417 (38, Alignof, "alignof")
418 (39, Become, "become")
419 (40, Do, "do")
420 (41, Final, "final")
421 (42, Macro, "macro")
422 (43, Offsetof, "offsetof")
423 (44, Override, "override")
424 (45, Priv, "priv")
425 (46, Proc, "proc")
426 (47, Pure, "pure")
427 (48, Sizeof, "sizeof")
428 (49, Typeof, "typeof")
429 (50, Unsized, "unsized")
430 (51, Virtual, "virtual")
431 (52, Yield, "yield")
432
433 // Weak keywords, have special meaning only in specific contexts.
434 (53, Default, "default")
435 (54, StaticLifetime, "'static")
436 (55, Union, "union")
223e47cc
LB
437}
438
1a4d82fc 439// looks like we can get rid of this completely...
5bcae85e 440pub type IdentInterner = Interner;
1a4d82fc
JJ
441
442// if an interner exists in TLS, return it. Otherwise, prepare a
443// fresh one.
bd371182 444// FIXME(eddyb) #8726 This should probably use a thread-local reference.
5bcae85e
SL
445pub fn with_ident_interner<T, F: FnOnce(&mut IdentInterner) -> T>(f: F) -> T {
446 thread_local!(static KEY: RefCell<IdentInterner> = {
447 RefCell::new(mk_fresh_ident_interner())
1a4d82fc 448 });
5bcae85e 449 KEY.with(|interner| f(&mut *interner.borrow_mut()))
970d7e83
LB
450}
451
1a4d82fc
JJ
452/// Reset the ident interner to its initial state.
453pub fn reset_ident_interner() {
5bcae85e
SL
454 with_ident_interner(|interner| *interner = mk_fresh_ident_interner());
455}
456
457pub fn clear_ident_interner() {
458 with_ident_interner(|interner| *interner = IdentInterner::new());
1a4d82fc
JJ
459}
460
bd371182
AL
461/// Represents a string stored in the thread-local interner. Because the
462/// interner lives for the life of the thread, this can be safely treated as an
463/// immortal string, as long as it never crosses between threads.
1a4d82fc
JJ
464///
465/// FIXME(pcwalton): You must be careful about what you do in the destructors
466/// of objects stored in TLS, because they may run after the interner is
467/// destroyed. In particular, they must not access string contents. This can
bd371182 468/// be fixed in the future by just leaking all strings until thread death
1a4d82fc
JJ
469/// somehow.
470#[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
471pub struct InternedString {
c30ab7b3 472 string: Rc<str>,
1a4d82fc
JJ
473}
474
475impl InternedString {
476 #[inline]
477 pub fn new(string: &'static str) -> InternedString {
478 InternedString {
c30ab7b3 479 string: Rc::__from_str(string),
1a4d82fc
JJ
480 }
481 }
c1a9b12d
SL
482
483 #[inline]
484 pub fn new_from_name(name: ast::Name) -> InternedString {
c30ab7b3 485 with_ident_interner(|interner| InternedString { string: interner.get(name) })
c1a9b12d 486 }
970d7e83
LB
487}
488
1a4d82fc
JJ
489impl Deref for InternedString {
490 type Target = str;
491
7453a54e 492 fn deref(&self) -> &str { &self.string }
1a4d82fc
JJ
493}
494
85aaf69f 495impl fmt::Debug for InternedString {
1a4d82fc 496 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
c34b1796 497 fmt::Debug::fmt(&self.string, f)
223e47cc 498 }
223e47cc
LB
499}
500
85aaf69f 501impl fmt::Display for InternedString {
1a4d82fc 502 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
c34b1796 503 fmt::Display::fmt(&self.string, f)
970d7e83
LB
504 }
505}
506
1a4d82fc
JJ
507impl<'a> PartialEq<&'a str> for InternedString {
508 #[inline(always)]
509 fn eq(&self, other: & &'a str) -> bool {
c34b1796 510 PartialEq::eq(&self.string[..], *other)
1a4d82fc
JJ
511 }
512 #[inline(always)]
513 fn ne(&self, other: & &'a str) -> bool {
c34b1796 514 PartialEq::ne(&self.string[..], *other)
970d7e83
LB
515 }
516}
223e47cc 517
c1a9b12d 518impl<'a> PartialEq<InternedString> for &'a str {
1a4d82fc
JJ
519 #[inline(always)]
520 fn eq(&self, other: &InternedString) -> bool {
c34b1796 521 PartialEq::eq(*self, &other.string[..])
1a4d82fc
JJ
522 }
523 #[inline(always)]
524 fn ne(&self, other: &InternedString) -> bool {
c34b1796 525 PartialEq::ne(*self, &other.string[..])
1a4d82fc
JJ
526 }
527}
528
a7813a04
XL
529impl PartialEq<str> for InternedString {
530 #[inline(always)]
531 fn eq(&self, other: &str) -> bool {
532 PartialEq::eq(&self.string[..], other)
533 }
534 #[inline(always)]
535 fn ne(&self, other: &str) -> bool {
536 PartialEq::ne(&self.string[..], other)
537 }
538}
539
540impl PartialEq<InternedString> for str {
541 #[inline(always)]
542 fn eq(&self, other: &InternedString) -> bool {
543 PartialEq::eq(self, &other.string[..])
544 }
545 #[inline(always)]
546 fn ne(&self, other: &InternedString) -> bool {
547 PartialEq::ne(self, &other.string[..])
548 }
549}
550
1a4d82fc
JJ
551impl Decodable for InternedString {
552 fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
c30ab7b3 553 Ok(intern(&d.read_str()?).as_str())
970d7e83
LB
554 }
555}
556
1a4d82fc
JJ
557impl Encodable for InternedString {
558 fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
c34b1796 559 s.emit_str(&self.string)
1a4d82fc
JJ
560 }
561}
562
1a4d82fc 563/// Interns and returns the string contents of an identifier, using the
bd371182 564/// thread-local interner.
1a4d82fc
JJ
565#[inline]
566pub fn intern_and_get_ident(s: &str) -> InternedString {
c1a9b12d 567 intern(s).as_str()
1a4d82fc
JJ
568}
569
570/// Maps a string to its interned representation.
571#[inline]
572pub fn intern(s: &str) -> ast::Name {
5bcae85e 573 with_ident_interner(|interner| interner.intern(s))
1a4d82fc
JJ
574}
575
85aaf69f 576/// gensym's a new usize, using the current interner.
1a4d82fc
JJ
577#[inline]
578pub fn gensym(s: &str) -> ast::Name {
5bcae85e 579 with_ident_interner(|interner| interner.gensym(s))
1a4d82fc
JJ
580}
581
582/// Maps a string to an identifier with an empty syntax context.
583#[inline]
584pub fn str_to_ident(s: &str) -> ast::Ident {
b039eaaf 585 ast::Ident::with_empty_ctxt(intern(s))
1a4d82fc
JJ
586}
587
588/// Maps a string to a gensym'ed identifier.
589#[inline]
590pub fn gensym_ident(s: &str) -> ast::Ident {
b039eaaf 591 ast::Ident::with_empty_ctxt(gensym(s))
1a4d82fc
JJ
592}
593
594// create a fresh name that maps to the same string as the old one.
595// note that this guarantees that str_ptr_eq(ident_to_string(src),interner_get(fresh_name(src)));
596// that is, that the new name and the old one are connected to ptr_eq strings.
b039eaaf 597pub fn fresh_name(src: ast::Ident) -> ast::Name {
5bcae85e 598 with_ident_interner(|interner| interner.gensym_copy(src.name))
1a4d82fc
JJ
599 // following: debug version. Could work in final except that it's incompatible with
600 // good error messages and uses of struct names in ambiguous could-be-binding
601 // locations. Also definitely destroys the guarantee given above about ptr_eq.
602 /*let num = rand::thread_rng().gen_uint_range(0,0xffff);
603 gensym(format!("{}_{}",ident_to_string(src),num))*/
604}