@@ -15,12 +15,12 @@ use parse::token;
15
15
use util:: interner:: StrInterner ;
16
16
use util:: interner;
17
17
18
+ use std:: cast;
18
19
use std:: char;
19
20
use std:: cmp:: Equiv ;
20
21
use std:: local_data;
21
22
use std:: rand;
22
23
use std:: rand:: RngUtil ;
23
- use std:: ptr:: to_unsafe_ptr;
24
24
25
25
#[ deriving( Clone , Encodable , Decodable , Eq , IterBytes ) ]
26
26
pub enum binop {
@@ -382,30 +382,8 @@ pub fn token_to_binop(tok: &Token) -> Option<ast::BinOp> {
382
382
}
383
383
}
384
384
385
- pub struct ident_interner {
386
- priv interner : StrInterner ,
387
- }
388
-
389
- impl ident_interner {
390
- pub fn intern ( & self , val : & str ) -> Name {
391
- self . interner . intern ( val)
392
- }
393
- pub fn gensym ( & self , val : & str ) -> Name {
394
- self . interner . gensym ( val)
395
- }
396
- pub fn get ( & self , idx : Name ) -> @str {
397
- self . interner . get ( idx)
398
- }
399
- // is this really something that should be exposed?
400
- pub fn len ( & self ) -> uint {
401
- self . interner . len ( )
402
- }
403
- pub fn find_equiv < Q : Hash + IterBytes + Equiv < @str > > ( & self , val : & Q )
404
- -> Option < Name > {
405
- self . interner . find_equiv ( val)
406
- }
407
- }
408
-
385
+ // looks like we can get rid of this completely...
386
+ pub type ident_interner = StrInterner ;
409
387
410
388
// return a fresh interner, preloaded with special identifiers.
411
389
fn mk_fresh_ident_interner ( ) -> @ident_interner {
@@ -486,9 +464,7 @@ fn mk_fresh_ident_interner() -> @ident_interner {
486
464
"typeof" , // 67
487
465
] ;
488
466
489
- @ident_interner {
490
- interner : interner:: StrInterner :: prefill ( init_vec)
491
- }
467
+ @interner:: StrInterner :: prefill ( init_vec)
492
468
}
493
469
494
470
// if an interner exists in TLS, return it. Otherwise, prepare a
@@ -509,7 +485,7 @@ pub fn get_ident_interner() -> @ident_interner {
509
485
/* for when we don't care about the contents; doesn't interact with TLD or
510
486
serialization */
511
487
pub fn mk_fake_ident_interner ( ) -> @ident_interner {
512
- @ident_interner { interner : interner :: StrInterner :: new ( ) }
488
+ @interner:: StrInterner :: new ( )
513
489
}
514
490
515
491
// maps a string to its interned representation
@@ -545,10 +521,11 @@ pub fn gensym_ident(str : &str) -> ast::Ident {
545
521
}
546
522
547
523
// create a fresh name that maps to the same string as the old one.
548
- // note that this guarantees that ptr_eq (ident_to_str(src),interner_get(fresh_name(src)));
524
+ // note that this guarantees that str_ptr_eq (ident_to_str(src),interner_get(fresh_name(src)));
549
525
// that is, that the new name and the old one are connected to ptr_eq strings.
550
526
pub fn fresh_name ( src : & ast:: Ident ) -> Name {
551
- gensym ( ident_to_str ( src) )
527
+ let interner = get_ident_interner ( ) ;
528
+ interner. gensym_copy ( src. name )
552
529
// following: debug version. Could work in final except that it's incompatible with
553
530
// good error messages and uses of struct names in ambiguous could-be-binding
554
531
// locations. Also definitely destroys the guarantee given above about ptr_eq.
@@ -557,18 +534,26 @@ pub fn fresh_name(src : &ast::Ident) -> Name {
557
534
}
558
535
559
536
// it looks like there oughta be a str_ptr_eq fn, but no one bothered to implement it?
560
- pub fn str_ptr_eq < T > ( a : @str , b : @str ) -> bool {
561
- // doesn't compile! ...because of rebase mangling. this should be fixed
562
- // in the commit that follows this.
563
- let ( a_ptr, b_ptr) : ( * uint , * uint ) = ( to_unsafe_ptr ( a) , to_unsafe_ptr ( b) ) ;
564
- a_ptr == b_ptr
565
- }
566
-
567
537
538
+ // determine whether two @str values are pointer-equal
539
+ pub fn str_ptr_eq ( a : @str , b : @str ) -> bool {
540
+ unsafe {
541
+ let p : uint = cast:: transmute ( a) ;
542
+ let q : uint = cast:: transmute ( b) ;
543
+ let result = p == q;
544
+ // got to transmute them back, to make sure the ref count is correct:
545
+ let junk1 : @str = cast:: transmute ( p) ;
546
+ let junk2 : @str = cast:: transmute ( q) ;
547
+ result
548
+ }
549
+ }
568
550
569
551
// return true when two identifiers refer (through the intern table) to the same ptr_eq
570
552
// string. This is used to compare identifiers in places where hygienic comparison is
571
553
// not wanted (i.e. not lexical vars).
554
+ pub fn ident_spelling_eq ( a : & ast:: Ident , b : & ast:: Ident ) -> bool {
555
+ str_ptr_eq ( interner_get ( a. name ) , interner_get ( b. name ) )
556
+ }
572
557
573
558
// create a fresh mark.
574
559
pub fn fresh_mark ( ) -> Mrk {
@@ -721,13 +706,21 @@ mod test {
721
706
use ast_util;
722
707
723
708
724
- #[ test] fn t1 ( ) {
709
+ #[ test] fn str_ptr_eq_tests ( ) {
710
+ let a = @"abc";
711
+ let b = @"abc";
712
+ let c = a;
713
+ assert ! ( str_ptr_eq( a, c) ) ;
714
+ assert ! ( !str_ptr_eq( a, b) ) ;
715
+ }
716
+
717
+ #[ test] fn fresh_name_pointer_sharing ( ) {
725
718
let ghi = str_to_ident ( "ghi" ) ;
726
719
assert_eq ! ( ident_to_str( & ghi) , @"ghi" ) ;
720
+ assert ! ( str_ptr_eq( ident_to_str( & ghi) , ident_to_str( & ghi) ) )
727
721
let fresh = ast:: Ident :: new ( fresh_name ( & ghi) ) ;
728
722
assert_eq ! ( ident_to_str( & fresh) , @"ghi" ) ;
729
723
assert ! ( str_ptr_eq( ident_to_str( & ghi) , ident_to_str( & fresh) ) ) ;
730
- assert_eq ! ( 3 , 4 ) ;
731
724
}
732
725
733
726
}
0 commit comments