about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJohn Clements <clements@racket-lang.org>2014-07-11 21:22:11 -0700
committerJohn Clements <clements@racket-lang.org>2014-07-13 10:08:27 -0700
commitb0b4b3122a4af7bf9b361c8f646da4a120e7ba38 (patch)
treed3e0fcb19160fcdc2f2977bebc647af9587cf512 /src/libsyntax
parente178ebf681d532c1c965883ae34788713f748960 (diff)
downloadrust-b0b4b3122a4af7bf9b361c8f646da4a120e7ba38.tar.gz
rust-b0b4b3122a4af7bf9b361c8f646da4a120e7ba38.zip
refactor Method definition to make space for macros
This change propagates to many locations, but because of the
Macro Exterminator (or, more properly, the invariant that it
protects), macro invocations can't occur downstream of expansion.
This means that in librustc and librustdoc, extracting the
desired field can simply assume that it can't be a macro
invocation. Functions in ast_util abstract over this check.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs19
-rw-r--r--src/libsyntax/ast_map.rs32
-rw-r--r--src/libsyntax/ast_util.rs75
-rw-r--r--src/libsyntax/ext/deriving/generic/mod.rs14
-rw-r--r--src/libsyntax/ext/expand.rs28
-rw-r--r--src/libsyntax/fold.rs21
-rw-r--r--src/libsyntax/parse/parser.rs16
-rw-r--r--src/libsyntax/print/pprust.rs31
-rw-r--r--src/libsyntax/visit.rs32
9 files changed, 174 insertions, 94 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index dd830401443..98318312d58 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -633,6 +633,8 @@ pub type Mac = Spanned<Mac_>;
 /// There's only one flavor, now, so this could presumably be simplified.
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
 pub enum Mac_ {
+    // NB: the additional ident for a macro_rules-style macro is actually
+    // stored in the enclosing item. Oog.
     MacInvocTT(Path, Vec<TokenTree> , SyntaxContext),   // new macro-invocation
 }
 
@@ -950,19 +952,20 @@ pub enum ExplicitSelf_ {
 
 pub type ExplicitSelf = Spanned<ExplicitSelf_>;
 
-// Represents a method declaration
 #[deriving(PartialEq, Eq, Encodable, Decodable, Hash)]
 pub struct Method {
-    pub ident: Ident,
     pub attrs: Vec<Attribute>,
-    pub generics: Generics,
-    pub explicit_self: ExplicitSelf,
-    pub fn_style: FnStyle,
-    pub decl: P<FnDecl>,
-    pub body: P<Block>,
     pub id: NodeId,
     pub span: Span,
-    pub vis: Visibility,
+    pub node: Method_
+}
+
+#[deriving(PartialEq, Eq, Encodable, Decodable, Hash)]
+pub enum Method_ {
+    /// Represents a method declaration
+    MethDecl(Ident, Generics, ExplicitSelf, FnStyle, P<FnDecl>, P<Block>, Visibility),
+    /// Represents a macro in method position
+    MethMac(Mac),
 }
 
 #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash)]
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index de2ecd9a264..d0a0c4fe380 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -304,8 +304,10 @@ impl Map {
         }
     }
 
+    /// returns the name associated with the given NodeId's AST
     pub fn get_path_elem(&self, id: NodeId) -> PathElem {
-        match self.get(id) {
+        let node = self.get(id);
+        match node {
             NodeItem(item) => {
                 match item.node {
                     ItemMod(_) | ItemForeignMod(_) => {
@@ -315,13 +317,19 @@ impl Map {
                 }
             }
             NodeForeignItem(i) => PathName(i.ident.name),
-            NodeMethod(m) => PathName(m.ident.name),
+            NodeMethod(m) => match m.node {
+                MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
+                MethMac(_) => fail!("no path elem for {:?}", node)
+            },
             NodeTraitMethod(tm) => match *tm {
                 Required(ref m) => PathName(m.ident.name),
-                Provided(ref m) => PathName(m.ident.name)
+                Provided(m) => match m.node {
+                    MethDecl(ident, _, _, _, _, _, _) => PathName(ident.name),
+                    MethMac(_) => fail!("no path elem for {:?}", node),
+                }
             },
             NodeVariant(v) => PathName(v.node.name.name),
-            node => fail!("no path elem for {:?}", node)
+            _ => fail!("no path elem for {:?}", node)
         }
     }
 
@@ -369,6 +377,8 @@ impl Map {
         }
     }
 
+    /// Given a node ID and a closure, apply the closure to the array
+    /// of attributes associated with the AST corresponding to the Node ID
     pub fn with_attrs<T>(&self, id: NodeId, f: |Option<&[Attribute]>| -> T) -> T {
         let node = self.get(id);
         let attrs = match node {
@@ -695,11 +705,15 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String {
             let path_str = map.path_to_str_with_ident(id, item.ident);
             format!("foreign item {} (id={})", path_str, id)
         }
-        Some(NodeMethod(m)) => {
-            format!("method {} in {} (id={})",
-                    token::get_ident(m.ident),
-                    map.path_to_string(id), id)
-        }
+        Some(NodeMethod(m)) => match m.node {
+            MethDecl(ident, _, _, _, _, _, _) =>
+                format!("method {} in {} (id={})",
+                        token::get_ident(ident),
+                        map.path_to_string(id), id),
+            MethMac(ref mac) =>
+                format!("method macro {} (id={})",
+                        pprust::mac_to_string(mac), id)
+        },
         Some(NodeTraitMethod(ref tm)) => {
             let m = ast_util::trait_method_to_ty_method(&**tm);
             format!("method {} in {} (id={})",
diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs
index cd38c9b3e98..a18d8a81ef4 100644
--- a/src/libsyntax/ast_util.rs
+++ b/src/libsyntax/ast_util.rs
@@ -240,32 +240,31 @@ pub fn impl_pretty_name(trait_ref: &Option<TraitRef>, ty: &Ty) -> Ident {
     token::gensym_ident(pretty.as_slice())
 }
 
-pub fn public_methods(ms: Vec<Gc<Method>> ) -> Vec<Gc<Method>> {
-    ms.move_iter().filter(|m| {
-        match m.vis {
-            Public => true,
-            _   => false
-        }
-    }).collect()
-}
-
 /// extract a TypeMethod from a TraitMethod. if the TraitMethod is
 /// a default, pull out the useful fields to make a TypeMethod
+//
+// NB: to be used only after expansion is complete, and macros are gone.
 pub fn trait_method_to_ty_method(method: &TraitMethod) -> TypeMethod {
     match *method {
         Required(ref m) => (*m).clone(),
-        Provided(ref m) => {
-            TypeMethod {
-                ident: m.ident,
-                attrs: m.attrs.clone(),
-                fn_style: m.fn_style,
-                decl: m.decl,
-                generics: m.generics.clone(),
-                explicit_self: m.explicit_self,
-                id: m.id,
-                span: m.span,
-                vis: m.vis,
+        Provided(m) => {
+            match m.node {
+                MethDecl(ident, ref generics, explicit_self, fn_style, decl, _, vis) => {
+                    TypeMethod {
+                        ident: ident,
+                        attrs: m.attrs.clone(),
+                        fn_style: fn_style,
+                        decl: decl,
+                        generics: generics.clone(),
+                        explicit_self: explicit_self,
+                        id: m.id,
+                        span: m.span,
+                        vis: vis,
+                    }
+                },
+                MethMac(_) => fail!("expected non-macro method declaration")
             }
+
         }
     }
 }
@@ -346,6 +345,9 @@ pub trait IdVisitingOperation {
     fn visit_id(&self, node_id: NodeId);
 }
 
+/// A visitor that applies its operation to all of the node IDs
+/// in a visitable thing.
+
 pub struct IdVisitor<'a, O> {
     pub operation: &'a O,
     pub pass_through_items: bool,
@@ -740,6 +742,38 @@ pub fn static_has_significant_address(mutbl: ast::Mutability,
     inline == InlineNever || inline == InlineNone
 }
 
+
+/// Macro invocations are guaranteed not to occur after expansion is complete.
+/// extracting fields of a method requires a dynamic check to make sure that it's
+/// not a macro invocation, though this check is guaranteed to succeed, assuming
+/// that the invocations are indeed gone.
+macro_rules! method_field_extractor {
+    ($fn_name:ident, $field_ty:ty, $field_pat:pat, $result:ident) => {
+        /// Returns the ident of a Method. To be used after expansion is complete
+        pub fn $fn_name<'a>(method: &'a ast::Method) -> $field_ty {
+            match method.node {
+                $field_pat => $result,
+                MethMac(_) => {
+                    fail!("expected an AST without macro invocations");
+                }
+            }
+        }
+    }
+}
+
+// Note: this is unhygienic in the lifetime 'a. In order to fix this, we'd have to
+// add :lifetime as a macro argument type, so that the 'a could be supplied by the macro
+// invocation.
+pub method_field_extractor!(method_ident,ast::Ident,MethDecl(ident,_,_,_,_,_,_),ident)
+pub method_field_extractor!(method_generics,&'a ast::Generics,
+                            MethDecl(_,ref generics,_,_,_,_,_),generics)
+pub method_field_extractor!(method_explicit_self,&'a ast::ExplicitSelf,
+                            MethDecl(_,_,ref explicit_self,_,_,_,_),explicit_self)
+pub method_field_extractor!(method_fn_style,ast::FnStyle,MethDecl(_,_,_,fn_style,_,_,_),fn_style)
+pub method_field_extractor!(method_fn_decl,P<ast::FnDecl>,MethDecl(_,_,_,_,decl,_,_),decl)
+pub method_field_extractor!(method_body,P<ast::Block>,MethDecl(_,_,_,_,_,body,_),body)
+pub method_field_extractor!(method_vis,ast::Visibility,MethDecl(_,_,_,_,_,_,vis),vis)
+
 #[cfg(test)]
 mod test {
     use ast::*;
@@ -765,3 +799,4 @@ mod test {
                 .iter().map(ident_to_segment).collect::<Vec<PathSegment>>().as_slice()));
     }
 }
+
diff --git a/src/libsyntax/ext/deriving/generic/mod.rs b/src/libsyntax/ext/deriving/generic/mod.rs
index 7d454016d60..46efdccadec 100644
--- a/src/libsyntax/ext/deriving/generic/mod.rs
+++ b/src/libsyntax/ext/deriving/generic/mod.rs
@@ -648,16 +648,16 @@ impl<'a> MethodDef<'a> {
 
         // Create the method.
         box(GC) ast::Method {
-            ident: method_ident,
             attrs: self.attributes.clone(),
-            generics: fn_generics,
-            explicit_self: explicit_self,
-            fn_style: ast::NormalFn,
-            decl: fn_decl,
-            body: body_block,
             id: ast::DUMMY_NODE_ID,
             span: trait_.span,
-            vis: ast::Inherited,
+            node: ast::MethDecl(method_ident,
+                                fn_generics,
+                                explicit_self,
+                                ast::NormalFn,
+                                fn_decl,
+                                body_block,
+                                ast::Inherited)
         }
     }
 
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6e44bfa6747..81309181bc0 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -941,21 +941,25 @@ impl<'a> Folder for PatIdentRenamer<'a> {
 // expand a method
 fn expand_method(m: &ast::Method, fld: &mut MacroExpander) -> Gc<ast::Method> {
     let id = fld.new_id(m.id);
-    let (rewritten_fn_decl, rewritten_body)
-        = expand_and_rename_fn_decl_and_block(m.decl,m.body,fld);
-
-    // all of the other standard stuff:
     box(GC) ast::Method {
-        id: id,
-        ident: fld.fold_ident(m.ident),
         attrs: m.attrs.iter().map(|a| fld.fold_attribute(*a)).collect(),
-        generics: fold_generics(&m.generics, fld),
-        explicit_self: fld.fold_explicit_self(&m.explicit_self),
-        fn_style: m.fn_style,
-        decl: rewritten_fn_decl,
-        body: rewritten_body,
+        id: id,
         span: fld.new_span(m.span),
-        vis: m.vis
+        node: match m.node {
+            ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+                let (rewritten_fn_decl, rewritten_body)
+                    = expand_and_rename_fn_decl_and_block(decl,body,fld);
+
+                ast::MethDecl(fld.fold_ident(ident),
+                         fold_generics(generics, fld),
+                         fld.fold_explicit_self(explicit_self),
+                         fn_style,
+                         rewritten_fn_decl,
+                         rewritten_body,
+                         vis)
+            },
+            ast::MethMac(ref _mac) => fail!("expansion in method position not implemented yet!")
+        }
     }
 }
 
diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs
index 3e3b57be6e4..88c8318e1b7 100644
--- a/src/libsyntax/fold.rs
+++ b/src/libsyntax/fold.rs
@@ -794,16 +794,21 @@ pub fn noop_fold_foreign_item<T: Folder>(ni: &ForeignItem,
 pub fn noop_fold_method<T: Folder>(m: &Method, folder: &mut T) -> Gc<Method> {
     let id = folder.new_id(m.id); // Needs to be first, for ast_map.
     box(GC) Method {
-        id: id,
-        ident: folder.fold_ident(m.ident),
         attrs: m.attrs.iter().map(|a| folder.fold_attribute(*a)).collect(),
-        generics: fold_generics(&m.generics, folder),
-        explicit_self: folder.fold_explicit_self(&m.explicit_self),
-        fn_style: m.fn_style,
-        decl: folder.fold_fn_decl(&*m.decl),
-        body: folder.fold_block(m.body),
+        id: id,
         span: folder.new_span(m.span),
-        vis: m.vis
+        node: match m.node {
+            MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+                MethDecl(folder.fold_ident(ident),
+                         fold_generics(generics, folder),
+                         folder.fold_explicit_self(explicit_self),
+                         fn_style,
+                         folder.fold_fn_decl(&*decl),
+                         folder.fold_block(body),
+                         vis)
+            },
+            MethMac(ref mac) => MethMac(folder.fold_mac(mac)),
+        }
     }
 }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 84db2bc5a22..cc3a7dc095b 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -1249,16 +1249,10 @@ impl<'a> Parser<'a> {
                     p.parse_inner_attrs_and_block();
                 let attrs = attrs.append(inner_attrs.as_slice());
                 Provided(box(GC) ast::Method {
-                    ident: ident,
                     attrs: attrs,
-                    generics: generics,
-                    explicit_self: explicit_self,
-                    fn_style: style,
-                    decl: d,
-                    body: body,
                     id: ast::DUMMY_NODE_ID,
                     span: mk_sp(lo, hi),
-                    vis: vis,
+                    node: ast::MethDecl(ident, generics, explicit_self, style, d, body, vis)
                 })
               }
 
@@ -4049,16 +4043,10 @@ impl<'a> Parser<'a> {
         let hi = body.span.hi;
         let attrs = attrs.append(inner_attrs.as_slice());
         box(GC) ast::Method {
-            ident: ident,
             attrs: attrs,
-            generics: generics,
-            explicit_self: explicit_self,
-            fn_style: fn_style,
-            decl: decl,
-            body: body,
             id: ast::DUMMY_NODE_ID,
             span: mk_sp(lo, hi),
-            vis: visa,
+            node: ast::MethDecl(ident, generics, explicit_self, fn_style, decl, body, visa),
         }
     }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 9589a923485..615a4489a73 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -245,6 +245,10 @@ pub fn arg_to_string(arg: &ast::Arg) -> String {
     to_string(|s| s.print_arg(arg))
 }
 
+pub fn mac_to_string(arg: &ast::Mac) -> String {
+    to_string(|s| s.print_mac(arg))
+}
+
 pub fn visibility_qualified(vis: ast::Visibility, s: &str) -> String {
     match vis {
         ast::Public => format!("pub {}", s),
@@ -342,6 +346,7 @@ impl<'a> State<'a> {
         match self.s.last_token() { pp::End => true, _ => false }
     }
 
+    // is this the beginning of a line?
     pub fn is_bol(&mut self) -> bool {
         self.s.last_token().is_eof() || self.s.last_token().is_hardbreak_tok()
     }
@@ -627,6 +632,7 @@ impl<'a> State<'a> {
         }
     }
 
+    /// Pretty-print an item
     pub fn print_item(&mut self, item: &ast::Item) -> IoResult<()> {
         try!(self.hardbreak_if_not_bol());
         try!(self.maybe_print_comment(item.span.lo));
@@ -998,11 +1004,26 @@ impl<'a> State<'a> {
         try!(self.hardbreak_if_not_bol());
         try!(self.maybe_print_comment(meth.span.lo));
         try!(self.print_outer_attributes(meth.attrs.as_slice()));
-        try!(self.print_fn(&*meth.decl, Some(meth.fn_style), abi::Rust,
-                        meth.ident, &meth.generics, Some(meth.explicit_self.node),
-                        meth.vis));
-        try!(word(&mut self.s, " "));
-        self.print_block_with_attrs(&*meth.body, meth.attrs.as_slice())
+        match meth.node {
+            ast::MethDecl(ident, ref generics, ref explicit_self, fn_style, decl, body, vis) => {
+                try!(self.print_fn(&*decl, Some(fn_style), abi::Rust,
+                                   ident, generics, Some(explicit_self.node),
+                                   vis));
+                try!(word(&mut self.s, " "));
+                self.print_block_with_attrs(&*body, meth.attrs.as_slice())
+            },
+            ast::MethMac(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _),
+                                            ..}) => {
+                // code copied from ItemMac:
+                try!(self.print_path(pth, false));
+                try!(word(&mut self.s, "! "));
+                try!(self.cbox(indent_unit));
+                try!(self.popen());
+                try!(self.print_tts(tts.as_slice()));
+                try!(self.pclose());
+                self.end()
+            }
+        }
     }
 
     pub fn print_outer_attributes(&mut self,
diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs
index 7caaf2f6cc1..795f19d0cfb 100644
--- a/src/libsyntax/visit.rs
+++ b/src/libsyntax/visit.rs
@@ -560,15 +560,21 @@ pub fn walk_fn_decl<E: Clone, V: Visitor<E>>(visitor: &mut V,
 pub fn walk_method_helper<E: Clone, V: Visitor<E>>(visitor: &mut V,
                                                    method: &Method,
                                                    env: E) {
-    visitor.visit_ident(method.span, method.ident, env.clone());
-    visitor.visit_fn(&FkMethod(method.ident, &method.generics, method),
-                     &*method.decl,
-                     &*method.body,
-                     method.span,
-                     method.id,
-                     env.clone());
-    for attr in method.attrs.iter() {
-        visitor.visit_attribute(attr, env.clone());
+    match method.node {
+        MethDecl(ident, ref generics, _, _, decl, body, _) => {
+            visitor.visit_ident(method.span, ident, env.clone());
+            visitor.visit_fn(&FkMethod(ident, generics, method),
+                             decl,
+                             body,
+                             method.span,
+                             method.id,
+                             env.clone());
+            for attr in method.attrs.iter() {
+                visitor.visit_attribute(attr, env.clone());
+            }
+
+        },
+        MethMac(ref mac) => visitor.visit_mac(mac, env.clone())
     }
 }
 
@@ -586,8 +592,12 @@ pub fn walk_fn<E: Clone, V: Visitor<E>>(visitor: &mut V,
         }
         FkMethod(_, generics, method) => {
             visitor.visit_generics(generics, env.clone());
-
-            visitor.visit_explicit_self(&method.explicit_self, env.clone());
+            match method.node {
+                MethDecl(_, _, ref explicit_self, _, _, _, _) =>
+                    visitor.visit_explicit_self(explicit_self, env.clone()),
+                MethMac(ref mac) =>
+                    visitor.visit_mac(mac, env.clone())
+            }
         }
         FkFnBlock(..) => {}
     }