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