@@ -623,10 +623,12 @@ pub struct Ident {
623
623
624
624
impl Ident {
625
625
#[ inline]
626
+ /// constructs a new identifier from a symbol and a span.
626
627
pub const fn new ( name : Symbol , span : Span ) -> Ident {
627
628
Ident { name, span }
628
629
}
629
630
631
+ /// Constructs a new identifier with an empty syntax context.
630
632
#[ inline]
631
633
pub const fn with_empty_ctxt ( name : Symbol ) -> Ident {
632
634
Ident :: new ( name, DUMMY_SP )
@@ -637,11 +639,16 @@ impl Ident {
637
639
Ident :: with_empty_ctxt ( string. as_symbol ( ) )
638
640
}
639
641
640
- /// Maps a string to an identifier with an empty syntax context .
642
+ /// Maps a string to an identifier with an empty span .
641
643
pub fn from_str ( string : & str ) -> Ident {
642
644
Ident :: with_empty_ctxt ( Symbol :: intern ( string) )
643
645
}
644
646
647
+ /// Maps a string and a span to an identifier.
648
+ pub fn from_str_and_span ( string : & str , span : Span ) -> Ident {
649
+ Ident :: new ( Symbol :: intern ( string) , span)
650
+ }
651
+
645
652
/// Replaces `lo` and `hi` with those from `span`, but keep hygiene context.
646
653
pub fn with_span_pos ( self , span : Span ) -> Ident {
647
654
Ident :: new ( self . name , span. with_ctxt ( self . span . ctxt ( ) ) )
@@ -669,14 +676,23 @@ impl Ident {
669
676
Ident :: new ( self . name , self . span . modern_and_legacy ( ) )
670
677
}
671
678
679
+ /// Transforms an identifier into one with the same name, but gensymed.
672
680
pub fn gensym ( self ) -> Ident {
673
- Ident :: new ( self . name . gensymed ( ) , self . span )
681
+ let name = with_interner ( |interner| interner. gensymed ( self . name ) ) ;
682
+ Ident :: new ( name, self . span )
674
683
}
675
684
685
+ /// Transforms an underscore identifier into one with the same name, but
686
+ /// gensymed. Leaves non-underscore identifiers unchanged.
676
687
pub fn gensym_if_underscore ( self ) -> Ident {
677
688
if self . name == keywords:: Underscore . name ( ) { self . gensym ( ) } else { self }
678
689
}
679
690
691
+ // WARNING: this function is deprecated and will be removed in the future.
692
+ pub fn is_gensymed ( self ) -> bool {
693
+ with_interner ( |interner| interner. is_gensymed ( self . name ) )
694
+ }
695
+
680
696
pub fn as_str ( self ) -> LocalInternedString {
681
697
self . name . as_str ( )
682
698
}
@@ -729,30 +745,34 @@ impl Decodable for Ident {
729
745
Ok ( if !string. starts_with ( '#' ) {
730
746
Ident :: from_str ( & string)
731
747
} else { // FIXME(jseyfried): intercrate hygiene
732
- Ident :: with_empty_ctxt ( Symbol :: gensym ( & string[ 1 ..] ) )
748
+ Ident :: from_str ( & string[ 1 ..] ) . gensym ( )
733
749
} )
734
750
}
735
751
}
736
752
737
753
/// A symbol is an interned or gensymed string. A gensym is a symbol that is
738
- /// never equal to any other symbol. E.g.:
739
- /// ```
740
- /// assert_eq!(Symbol::intern("x"), Symbol::intern("x"))
741
- /// assert_ne!(Symbol::gensym("x"), Symbol::intern("x"))
742
- /// assert_ne!(Symbol::gensym("x"), Symbol::gensym("x"))
743
- /// ```
754
+ /// never equal to any other symbol.
755
+ ///
744
756
/// Conceptually, a gensym can be thought of as a normal symbol with an
745
757
/// invisible unique suffix. Gensyms are useful when creating new identifiers
746
758
/// that must not match any existing identifiers, e.g. during macro expansion
747
- /// and syntax desugaring.
759
+ /// and syntax desugaring. Because gensyms should always be identifiers, all
760
+ /// gensym operations are on `Ident` rather than `Symbol`. (Indeed, in the
761
+ /// future the gensym-ness may be moved from `Symbol` to hygiene data.)
748
762
///
749
- /// Internally, a Symbol is implemented as an index, and all operations
763
+ /// Examples:
764
+ /// ```
765
+ /// assert_eq!(Ident::from_str("x"), Ident::from_str("x"))
766
+ /// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x"))
767
+ /// assert_ne!(Ident::from_str("x").gensym(), Ident::from_str("x").gensym())
768
+ /// ```
769
+ /// Internally, a symbol is implemented as an index, and all operations
750
770
/// (including hashing, equality, and ordering) operate on that index. The use
751
771
/// of `newtype_index!` means that `Option<Symbol>` only takes up 4 bytes,
752
772
/// because `newtype_index!` reserves the last 256 values for tagging purposes.
753
773
///
754
- /// Note that `Symbol` cannot directly be a `newtype_index!` because it implements
755
- /// `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
774
+ /// Note that `Symbol` cannot directly be a `newtype_index!` because it
775
+ /// implements `fmt::Debug`, `Encodable`, and `Decodable` in special ways.
756
776
#[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
757
777
pub struct Symbol ( SymbolIndex ) ;
758
778
@@ -770,20 +790,6 @@ impl Symbol {
770
790
with_interner ( |interner| interner. intern ( string) )
771
791
}
772
792
773
- /// Gensyms a new `usize`, using the current interner.
774
- pub fn gensym ( string : & str ) -> Self {
775
- with_interner ( |interner| interner. gensym ( string) )
776
- }
777
-
778
- pub fn gensymed ( self ) -> Self {
779
- with_interner ( |interner| interner. gensymed ( self ) )
780
- }
781
-
782
- // WARNING: this function is deprecated and will be removed in the future.
783
- pub fn is_gensymed ( self ) -> bool {
784
- with_interner ( |interner| interner. is_gensymed ( self ) )
785
- }
786
-
787
793
pub fn as_str ( self ) -> LocalInternedString {
788
794
with_interner ( |interner| unsafe {
789
795
LocalInternedString {
@@ -891,11 +897,6 @@ impl Interner {
891
897
}
892
898
}
893
899
894
- fn gensym ( & mut self , string : & str ) -> Symbol {
895
- let symbol = self . intern ( string) ;
896
- self . gensymed ( symbol)
897
- }
898
-
899
900
fn gensymed ( & mut self , symbol : Symbol ) -> Symbol {
900
901
self . gensyms . push ( symbol) ;
901
902
Symbol :: new ( SymbolIndex :: MAX_AS_U32 - self . gensyms . len ( ) as u32 + 1 )
@@ -1263,11 +1264,13 @@ mod tests {
1263
1264
assert_eq ! ( i. intern( "cat" ) , Symbol :: new( 1 ) ) ;
1264
1265
// dog is still at zero
1265
1266
assert_eq ! ( i. intern( "dog" ) , Symbol :: new( 0 ) ) ;
1266
- assert_eq ! ( i. gensym( "zebra" ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 ) ) ;
1267
+ let z = i. intern ( "zebra" ) ;
1268
+ assert_eq ! ( i. gensymed( z) , Symbol :: new( SymbolIndex :: MAX_AS_U32 ) ) ;
1267
1269
// gensym of same string gets new number:
1268
- assert_eq ! ( i. gensym ( "zebra" ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 1 ) ) ;
1270
+ assert_eq ! ( i. gensymed ( z ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 1 ) ) ;
1269
1271
// gensym of *existing* string gets new number:
1270
- assert_eq ! ( i. gensym( "dog" ) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 2 ) ) ;
1272
+ let d = i. intern ( "dog" ) ;
1273
+ assert_eq ! ( i. gensymed( d) , Symbol :: new( SymbolIndex :: MAX_AS_U32 - 2 ) ) ;
1271
1274
}
1272
1275
1273
1276
#[ test]
0 commit comments