]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/ast_map/blocks.rs
auto merge of #19628 : jbranchaud/rust/add-string-as-string-doctest, r=steveklabnik
[rust.git] / src / libsyntax / ast_map / blocks.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! This module provides a simplified abstraction for working with
12 //! code blocks identified by their integer node-id.  In particular,
13 //! it captures a common set of attributes that all "function-like
14 //! things" (represented by `FnLike` instances) share.  For example,
15 //! all `FnLike` instances have a type signature (be it explicit or
16 //! inferred).  And all `FnLike` instances have a body, i.e. the code
17 //! that is run when the function-like thing it represents is invoked.
18 //!
19 //! With the above abstraction in place, one can treat the program
20 //! text as a collection of blocks of code (and most such blocks are
21 //! nested within a uniquely determined `FnLike`), and users can ask
22 //! for the `Code` associated with a particular NodeId.
23
24 pub use self::Code::*;
25
26 use abi;
27 use ast::{Block, FnDecl, NodeId};
28 use ast;
29 use ast_map::{Node};
30 use ast_map;
31 use ast_util::PostExpansionMethod;
32 use codemap::Span;
33 use visit;
34
35 /// An FnLikeNode is a Node that is like a fn, in that it has a decl
36 /// and a body (as well as a NodeId, a span, etc).
37 ///
38 /// More specifically, it is one of either:
39 ///   - A function item,
40 ///   - A closure expr (i.e. an ExprClosure or ExprProc), or
41 ///   - The default implementation for a trait method.
42 ///
43 /// To construct one, use the `Code::from_node` function.
44 pub struct FnLikeNode<'a> { node: ast_map::Node<'a> }
45
46 impl<'a> Copy for FnLikeNode<'a> {}
47
48 /// MaybeFnLike wraps a method that indicates if an object
49 /// corresponds to some FnLikeNode.
50 pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
51
52 /// Components shared by fn-like things (fn items, methods, closures).
53 pub struct FnParts<'a> {
54     pub decl: &'a FnDecl,
55     pub body: &'a Block,
56     pub kind: visit::FnKind<'a>,
57     pub span: Span,
58     pub id:   NodeId,
59 }
60
61 impl MaybeFnLike for ast::Item {
62     fn is_fn_like(&self) -> bool {
63         match self.node { ast::ItemFn(..) => true, _ => false, }
64     }
65 }
66
67 impl MaybeFnLike for ast::TraitItem {
68     fn is_fn_like(&self) -> bool {
69         match *self { ast::ProvidedMethod(_) => true, _ => false, }
70     }
71 }
72
73 impl MaybeFnLike for ast::Expr {
74     fn is_fn_like(&self) -> bool {
75         match self.node {
76             ast::ExprClosure(..) | ast::ExprProc(..) => true,
77             _ => false,
78         }
79     }
80 }
81
82 /// Carries either an FnLikeNode or a Block, as these are the two
83 /// constructs that correspond to "code" (as in, something from which
84 /// we can construct a control-flow graph).
85 pub enum Code<'a> {
86     FnLikeCode(FnLikeNode<'a>),
87     BlockCode(&'a Block),
88 }
89
90 impl<'a> Copy for Code<'a> {}
91
92 impl<'a> Code<'a> {
93     pub fn id(&self) -> ast::NodeId {
94         match *self {
95             FnLikeCode(node) => node.id(),
96             BlockCode(block) => block.id,
97         }
98     }
99
100     /// Attempts to construct a Code from presumed FnLike or Block node input.
101     pub fn from_node(node: Node) -> Option<Code> {
102         fn new(node: Node) -> FnLikeNode { FnLikeNode { node: node } }
103         match node {
104             ast_map::NodeItem(item) if item.is_fn_like() =>
105                 Some(FnLikeCode(new(node))),
106             ast_map::NodeTraitItem(tm) if tm.is_fn_like() =>
107                 Some(FnLikeCode(new(node))),
108             ast_map::NodeImplItem(_) =>
109                 Some(FnLikeCode(new(node))),
110             ast_map::NodeExpr(e) if e.is_fn_like() =>
111                 Some(FnLikeCode(new(node))),
112             ast_map::NodeBlock(block) =>
113                 Some(BlockCode(block)),
114             _ =>
115                 None,
116         }
117     }
118 }
119
120 /// These are all the components one can extract from a fn item for
121 /// use when implementing FnLikeNode operations.
122 struct ItemFnParts<'a> {
123     ident:    ast::Ident,
124     decl:     &'a ast::FnDecl,
125     style:    ast::FnStyle,
126     abi:      abi::Abi,
127     generics: &'a ast::Generics,
128     body:     &'a Block,
129     id:       ast::NodeId,
130     span:     Span
131 }
132
133 /// These are all the components one can extract from a closure expr
134 /// for use when implementing FnLikeNode operations.
135 struct ClosureParts<'a> {
136     decl: &'a FnDecl,
137     body: &'a Block,
138     id: NodeId,
139     span: Span
140 }
141
142 impl<'a> ClosureParts<'a> {
143     fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> {
144         ClosureParts { decl: d, body: b, id: id, span: s }
145     }
146 }
147
148 impl<'a> FnLikeNode<'a> {
149     pub fn to_fn_parts(self) -> FnParts<'a> {
150         FnParts {
151             decl: self.decl(),
152             body: self.body(),
153             kind: self.kind(),
154             span: self.span(),
155             id:   self.id(),
156         }
157     }
158
159     pub fn body(self) -> &'a Block {
160         self.handle(|i: ItemFnParts<'a>|  &*i.body,
161                     |m: &'a ast::Method|  m.pe_body(),
162                     |c: ClosureParts<'a>| c.body)
163     }
164
165     pub fn decl(self) -> &'a FnDecl {
166         self.handle(|i: ItemFnParts<'a>|  &*i.decl,
167                     |m: &'a ast::Method|  m.pe_fn_decl(),
168                     |c: ClosureParts<'a>| c.decl)
169     }
170
171     pub fn span(self) -> Span {
172         self.handle(|i: ItemFnParts|     i.span,
173                     |m: &'a ast::Method| m.span,
174                     |c: ClosureParts|    c.span)
175     }
176
177     pub fn id(self) -> NodeId {
178         self.handle(|i: ItemFnParts|     i.id,
179                     |m: &'a ast::Method| m.id,
180                     |c: ClosureParts|    c.id)
181     }
182
183     pub fn kind(self) -> visit::FnKind<'a> {
184         let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> {
185             visit::FkItemFn(p.ident, p.generics, p.style, p.abi)
186         };
187         let closure = |_: ClosureParts| {
188             visit::FkFnBlock
189         };
190         let method = |m: &'a ast::Method| {
191             visit::FkMethod(m.pe_ident(), m.pe_generics(), m)
192         };
193         self.handle(item, method, closure)
194     }
195
196     fn handle<A>(self,
197                  item_fn: |ItemFnParts<'a>| -> A,
198                  method: |&'a ast::Method| -> A,
199                  closure: |ClosureParts<'a>| -> A) -> A {
200         match self.node {
201             ast_map::NodeItem(i) => match i.node {
202                 ast::ItemFn(ref decl, style, abi, ref generics, ref block) =>
203                     item_fn(ItemFnParts{
204                         ident: i.ident, decl: &**decl, style: style, body: &**block,
205                         generics: generics, abi: abi, id: i.id, span: i.span
206                     }),
207                 _ => panic!("item FnLikeNode that is not fn-like"),
208             },
209             ast_map::NodeTraitItem(t) => match *t {
210                 ast::ProvidedMethod(ref m) => method(&**m),
211                 _ => panic!("trait method FnLikeNode that is not fn-like"),
212             },
213             ast_map::NodeImplItem(ii) => {
214                 match *ii {
215                     ast::MethodImplItem(ref m) => method(&**m),
216                     ast::TypeImplItem(_) => {
217                         panic!("impl method FnLikeNode that is not fn-like")
218                     }
219                 }
220             }
221             ast_map::NodeExpr(e) => match e.node {
222                 ast::ExprClosure(_, _, ref decl, ref block) =>
223                     closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
224                 ast::ExprProc(ref decl, ref block) =>
225                     closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
226                 _ => panic!("expr FnLikeNode that is not fn-like"),
227             },
228             _ => panic!("other FnLikeNode that is not fn-like"),
229         }
230     }
231 }