about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-09-06 23:35:57 -0700
committerbors <bors@rust-lang.org>2013-09-06 23:35:57 -0700
commit124eb2119c78651cfaaa7a046a101fa2e20f83ca (patch)
tree7efa84a80df29080ae0314d0e3788131c72bdceb /src/libsyntax/parse
parent3e6de6b7da8ee88bf84b0e217900051334be08da (diff)
parentb6f3d3f24546a525d1eb80923692c1296eddc4dc (diff)
downloadrust-124eb2119c78651cfaaa7a046a101fa2e20f83ca.tar.gz
rust-124eb2119c78651cfaaa7a046a101fa2e20f83ca.zip
auto merge of #9026 : jbclements/rust/let-var-hygiene, r=jbclements
This is a rebase of my approved pull request from ... the end of June? It introduces hygiene for let-bound variables.
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/parser.rs15
-rw-r--r--src/libsyntax/parse/token.rs169
2 files changed, 123 insertions, 61 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 51c5522ae2f..8b11a25f13c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -21,7 +21,7 @@ use ast::{_mod, BiAdd, arg, Arm, Attribute, BindByRef, BindInfer};
 use ast::{BiBitAnd, BiBitOr, BiBitXor, Block};
 use ast::{BlockCheckMode, UnBox};
 use ast::{Crate, CrateConfig, Decl, DeclItem};
-use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, enum_def, explicit_self};
+use ast::{DeclLocal, DefaultBlock, UnDeref, BiDiv, EMPTY_CTXT, enum_def, explicit_self};
 use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
 use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock};
 use ast::{ExprBreak, ExprCall, ExprCast, ExprDoBody};
@@ -1875,7 +1875,7 @@ impl Parser {
                                                 |p| p.parse_token_tree());
                 let hi = self.span.hi;
 
-                return self.mk_mac_expr(lo, hi, mac_invoc_tt(pth, tts));
+                return self.mk_mac_expr(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT));
             } else if *self.token == token::LBRACE {
                 // This might be a struct literal.
                 if self.looking_at_record_literal() {
@@ -3197,14 +3197,14 @@ impl Parser {
 
             if id == token::special_idents::invalid {
                 return @spanned(lo, hi, StmtMac(
-                    spanned(lo, hi, mac_invoc_tt(pth, tts)), false));
+                    spanned(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT)), false));
             } else {
                 // if it has a special ident, it's definitely an item
                 return @spanned(lo, hi, StmtDecl(
                     @spanned(lo, hi, DeclItem(
                         self.mk_item(
                             lo, hi, id /*id is good here*/,
-                            item_mac(spanned(lo, hi, mac_invoc_tt(pth, tts))),
+                            item_mac(spanned(lo, hi, mac_invoc_tt(pth, tts, EMPTY_CTXT))),
                             inherited, ~[/*no attrs*/]))),
                     self.get_id()));
             }
@@ -3518,7 +3518,10 @@ impl Parser {
     }
 
     fn is_self_ident(&self) -> bool {
-        *self.token == token::IDENT(special_idents::self_, false)
+        match *self.token {
+          token::IDENT(id, false) => id.name == special_idents::self_.name,
+          _ => false
+        }
     }
 
     fn expect_self_ident(&self) {
@@ -4806,7 +4809,7 @@ impl Parser {
                 _ => self.fatal("expected open delimiter")
             };
             // single-variant-enum... :
-            let m = ast::mac_invoc_tt(pth, tts);
+            let m = ast::mac_invoc_tt(pth, tts, EMPTY_CTXT);
             let m: ast::mac = codemap::Spanned { node: m,
                                              span: mk_sp(self.span.lo,
                                                          self.span.hi) };
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 591b4b10bd3..6b3a95a14f8 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -9,17 +9,15 @@
 // except according to those terms.
 
 use ast;
-use ast::Name;
+use ast::{Name, Mrk};
 use ast_util;
 use parse::token;
 use util::interner::StrInterner;
 use util::interner;
 
+use std::cast;
 use std::char;
-use std::cmp::Equiv;
 use std::local_data;
-use std::rand;
-use std::rand::RngUtil;
 
 #[deriving(Clone, Encodable, Decodable, Eq, IterBytes)]
 pub enum binop {
@@ -309,22 +307,23 @@ pub fn is_bar(t: &Token) -> bool {
     match *t { BINOP(OR) | OROR => true, _ => false }
 }
 
-
 pub mod special_idents {
     use ast::Ident;
 
-    pub static underscore : Ident = Ident { name: 0, ctxt: 0};
+    pub static underscore : Ident = Ident { name: 0, ctxt: 0}; // apparently unused?
     pub static anon : Ident = Ident { name: 1, ctxt: 0};
     pub static invalid : Ident = Ident { name: 2, ctxt: 0}; // ''
-    pub static unary : Ident = Ident { name: 3, ctxt: 0};
-    pub static not_fn : Ident = Ident { name: 4, ctxt: 0};
-    pub static idx_fn : Ident = Ident { name: 5, ctxt: 0};
-    pub static unary_minus_fn : Ident = Ident { name: 6, ctxt: 0};
+    pub static unary : Ident = Ident { name: 3, ctxt: 0}; // apparently unused?
+    pub static not_fn : Ident = Ident { name: 4, ctxt: 0}; // apparently unused?
+    pub static idx_fn : Ident = Ident { name: 5, ctxt: 0}; // apparently unused?
+    pub static unary_minus_fn : Ident = Ident { name: 6, ctxt: 0}; // apparently unused?
     pub static clownshoes_extensions : Ident = Ident { name: 7, ctxt: 0};
 
     pub static self_ : Ident = Ident { name: 8, ctxt: 0}; // 'self'
 
     /* for matcher NTs */
+    // none of these appear to be used, but perhaps references to
+    // these are artificially fabricated by the macro system....
     pub static item : Ident = Ident { name: 9, ctxt: 0};
     pub static block : Ident = Ident { name: 10, ctxt: 0};
     pub static stmt : Ident = Ident { name: 11, ctxt: 0};
@@ -336,7 +335,7 @@ pub mod special_idents {
     pub static tt : Ident = Ident { name: 17, ctxt: 0};
     pub static matchers : Ident = Ident { name: 18, ctxt: 0};
 
-    pub static str : Ident = Ident { name: 19, ctxt: 0}; // for the type
+    pub static str : Ident = Ident { name: 19, ctxt: 0}; // for the type // apparently unused?
 
     /* outside of libsyntax */
     pub static arg : Ident = Ident { name: 20, ctxt: 0};
@@ -349,10 +348,32 @@ pub mod special_idents {
     pub static statik : Ident = Ident { name: 27, ctxt: 0};
     pub static clownshoes_foreign_mod: Ident = Ident { name: 28, ctxt: 0};
     pub static unnamed_field: Ident = Ident { name: 29, ctxt: 0};
-    pub static c_abi: Ident = Ident { name: 30, ctxt: 0};
+    pub static c_abi: Ident = Ident { name: 30, ctxt: 0}; // apparently unused?
     pub static type_self: Ident = Ident { name: 31, ctxt: 0};    // `Self`
 }
 
+// here are the ones that actually occur in the source. Maybe the rest
+// should be removed?
+/*
+special_idents::anon
+special_idents::arg
+special_idents::blk
+special_idents::clownshoe_abi
+special_idents::clownshoe_stack_shim
+special_idents::clownshoes_extensions
+special_idents::clownshoes_foreign_mod
+special_idents::descrim
+special_idents::invalid
+special_idents::main
+special_idents::matchers
+special_idents::opaque
+special_idents::self_
+special_idents::statik
+special_idents::tt
+special_idents::type_self
+special_idents::unnamed_field
+*/
+
 /**
  * Maps a token to a record specifying the corresponding binary
  * operator
@@ -381,30 +402,8 @@ pub fn token_to_binop(tok: &Token) -> Option<ast::BinOp> {
   }
 }
 
-pub struct ident_interner {
-    priv interner: StrInterner,
-}
-
-impl ident_interner {
-    pub fn intern(&self, val: &str) -> Name {
-        self.interner.intern(val)
-    }
-    pub fn gensym(&self, val: &str) -> Name {
-        self.interner.gensym(val)
-    }
-    pub fn get(&self, idx: Name) -> @str {
-        self.interner.get(idx)
-    }
-    // is this really something that should be exposed?
-    pub fn len(&self) -> uint {
-        self.interner.len()
-    }
-    pub fn find_equiv<Q:Hash + IterBytes + Equiv<@str>>(&self, val: &Q)
-                                                     -> Option<Name> {
-        self.interner.find_equiv(val)
-    }
-}
-
+// looks like we can get rid of this completely...
+pub type ident_interner = StrInterner;
 
 // return a fresh interner, preloaded with special identifiers.
 fn mk_fresh_ident_interner() -> @ident_interner {
@@ -485,9 +484,7 @@ fn mk_fresh_ident_interner() -> @ident_interner {
         "typeof",             // 67
     ];
 
-    @ident_interner {
-        interner: interner::StrInterner::prefill(init_vec)
-    }
+    @interner::StrInterner::prefill(init_vec)
 }
 
 // if an interner exists in TLS, return it. Otherwise, prepare a
@@ -508,7 +505,7 @@ pub fn get_ident_interner() -> @ident_interner {
 /* for when we don't care about the contents; doesn't interact with TLD or
    serialization */
 pub fn mk_fake_ident_interner() -> @ident_interner {
-    @ident_interner { interner: interner::StrInterner::new() }
+    @interner::StrInterner::new()
 }
 
 // maps a string to its interned representation
@@ -543,18 +540,44 @@ pub fn gensym_ident(str : &str) -> ast::Ident {
     ast::Ident::new(gensym(str))
 }
 
+// create a fresh name that maps to the same string as the old one.
+// note that this guarantees that str_ptr_eq(ident_to_str(src),interner_get(fresh_name(src)));
+// that is, that the new name and the old one are connected to ptr_eq strings.
+pub fn fresh_name(src : &ast::Ident) -> Name {
+    let interner = get_ident_interner();
+    interner.gensym_copy(src.name)
+    // following: debug version. Could work in final except that it's incompatible with
+    // good error messages and uses of struct names in ambiguous could-be-binding
+    // locations. Also definitely destroys the guarantee given above about ptr_eq.
+    /*let num = rand::rng().gen_uint_range(0,0xffff);
+    gensym(fmt!("%s_%u",ident_to_str(src),num))*/
+}
+
+// it looks like there oughta be a str_ptr_eq fn, but no one bothered to implement it?
+
+// determine whether two @str values are pointer-equal
+pub fn str_ptr_eq(a : @str, b : @str) -> bool {
+    unsafe {
+        let p : uint = cast::transmute(a);
+        let q : uint = cast::transmute(b);
+        let result = p == q;
+        // got to transmute them back, to make sure the ref count is correct:
+        let _junk1 : @str = cast::transmute(p);
+        let _junk2 : @str = cast::transmute(q);
+        result
+    }
+}
+
+// return true when two identifiers refer (through the intern table) to the same ptr_eq
+// string. This is used to compare identifiers in places where hygienic comparison is
+// not wanted (i.e. not lexical vars).
+pub fn ident_spelling_eq(a : &ast::Ident, b : &ast::Ident) -> bool {
+    str_ptr_eq(interner_get(a.name),interner_get(b.name))
+}
 
-// create a fresh name. In principle, this is just a
-// gensym, but for debugging purposes, you'd like the
-// resulting name to have a suggestive stringify, without
-// paying the cost of guaranteeing that the name is
-// truly unique.  I'm going to try to strike a balance
-// by using a gensym with a name that has a random number
-// at the end. So, the gensym guarantees the uniqueness,
-// and the int helps to avoid confusion.
-pub fn fresh_name(src_name : &str) -> Name {
-    let num = rand::rng().gen_uint_range(0,0xffff);
-   gensym(fmt!("%s_%u",src_name,num))
+// create a fresh mark.
+pub fn fresh_mark() -> Mrk {
+    gensym("mark")
 }
 
 /**
@@ -694,12 +717,48 @@ pub fn is_reserved_keyword(tok: &Token) -> bool {
     }
 }
 
+pub fn mtwt_token_eq(t1 : &Token, t2 : &Token) -> bool {
+    match (t1,t2) {
+        (&IDENT(id1,_),&IDENT(id2,_)) =>
+        ast_util::mtwt_resolve(id1) == ast_util::mtwt_resolve(id2),
+        _ => *t1 == *t2
+    }
+}
+
+
 #[cfg(test)]
 mod test {
     use super::*;
-    #[test] fn t1() {
-        let a = fresh_name("ghi");
-        printfln!("interned name: %u,\ntextual name: %s\n",
-                  a, interner_get(a));
+    use ast;
+    use ast_util;
+
+    fn mark_ident(id : ast::Ident, m : ast::Mrk) -> ast::Ident {
+        ast::Ident{name:id.name,ctxt:ast_util::new_mark(m,id.ctxt)}
     }
+
+    #[test] fn mtwt_token_eq_test() {
+        assert!(mtwt_token_eq(&GT,&GT));
+        let a = str_to_ident("bac");
+        let a1 = mark_ident(a,92);
+        assert!(mtwt_token_eq(&IDENT(a,true),&IDENT(a1,false)));
+    }
+
+
+    #[test] fn str_ptr_eq_tests(){
+        let a = @"abc";
+        let b = @"abc";
+        let c = a;
+        assert!(str_ptr_eq(a,c));
+        assert!(!str_ptr_eq(a,b));
+    }
+
+    #[test] fn fresh_name_pointer_sharing() {
+        let ghi = str_to_ident("ghi");
+        assert_eq!(ident_to_str(&ghi),@"ghi");
+        assert!(str_ptr_eq(ident_to_str(&ghi),ident_to_str(&ghi)))
+        let fresh = ast::Ident::new(fresh_name(&ghi));
+        assert_eq!(ident_to_str(&fresh),@"ghi");
+        assert!(str_ptr_eq(ident_to_str(&ghi),ident_to_str(&fresh)));
+    }
+
 }