]> git.proxmox.com Git - rustc.git/blob - src/libsyntax/ast_map/blocks.rs
Imported Upstream version 1.0.0~beta.3
[rustc.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 codemap::Span;
32 use visit;
33
34 /// An FnLikeNode is a Node that is like a fn, in that it has a decl
35 /// and a body (as well as a NodeId, a span, etc).
36 ///
37 /// More specifically, it is one of either:
38 /// - A function item,
39 /// - A closure expr (i.e. an ExprClosure), or
40 /// - The default implementation for a trait method.
41 ///
42 /// To construct one, use the `Code::from_node` function.
43 #[derive(Copy, Clone)]
44 pub struct FnLikeNode<'a> { node: ast_map::Node<'a> }
45
46 /// MaybeFnLike wraps a method that indicates if an object
47 /// corresponds to some FnLikeNode.
48 pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
49
50 /// Components shared by fn-like things (fn items, methods, closures).
51 pub struct FnParts<'a> {
52 pub decl: &'a FnDecl,
53 pub body: &'a Block,
54 pub kind: visit::FnKind<'a>,
55 pub span: Span,
56 pub id: NodeId,
57 }
58
59 impl MaybeFnLike for ast::Item {
60 fn is_fn_like(&self) -> bool {
61 match self.node { ast::ItemFn(..) => true, _ => false, }
62 }
63 }
64
65 impl MaybeFnLike for ast::TraitItem {
66 fn is_fn_like(&self) -> bool {
67 match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
68 }
69 }
70
71 impl MaybeFnLike for ast::Expr {
72 fn is_fn_like(&self) -> bool {
73 match self.node {
74 ast::ExprClosure(..) => true,
75 _ => false,
76 }
77 }
78 }
79
80 /// Carries either an FnLikeNode or a Block, as these are the two
81 /// constructs that correspond to "code" (as in, something from which
82 /// we can construct a control-flow graph).
83 #[derive(Copy, Clone)]
84 pub enum Code<'a> {
85 FnLikeCode(FnLikeNode<'a>),
86 BlockCode(&'a Block),
87 }
88
89 impl<'a> Code<'a> {
90 pub fn id(&self) -> ast::NodeId {
91 match *self {
92 FnLikeCode(node) => node.id(),
93 BlockCode(block) => block.id,
94 }
95 }
96
97 /// Attempts to construct a Code from presumed FnLike or Block node input.
98 pub fn from_node(node: Node) -> Option<Code> {
99 fn new(node: Node) -> FnLikeNode { FnLikeNode { node: node } }
100 match node {
101 ast_map::NodeItem(item) if item.is_fn_like() =>
102 Some(FnLikeCode(new(node))),
103 ast_map::NodeTraitItem(tm) if tm.is_fn_like() =>
104 Some(FnLikeCode(new(node))),
105 ast_map::NodeImplItem(_) =>
106 Some(FnLikeCode(new(node))),
107 ast_map::NodeExpr(e) if e.is_fn_like() =>
108 Some(FnLikeCode(new(node))),
109 ast_map::NodeBlock(block) =>
110 Some(BlockCode(block)),
111 _ =>
112 None,
113 }
114 }
115 }
116
117 /// These are all the components one can extract from a fn item for
118 /// use when implementing FnLikeNode operations.
119 struct ItemFnParts<'a> {
120 ident: ast::Ident,
121 decl: &'a ast::FnDecl,
122 unsafety: ast::Unsafety,
123 abi: abi::Abi,
124 vis: ast::Visibility,
125 generics: &'a ast::Generics,
126 body: &'a Block,
127 id: ast::NodeId,
128 span: Span
129 }
130
131 /// These are all the components one can extract from a closure expr
132 /// for use when implementing FnLikeNode operations.
133 struct ClosureParts<'a> {
134 decl: &'a FnDecl,
135 body: &'a Block,
136 id: NodeId,
137 span: Span
138 }
139
140 impl<'a> ClosureParts<'a> {
141 fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> {
142 ClosureParts { decl: d, body: b, id: id, span: s }
143 }
144 }
145
146 impl<'a> FnLikeNode<'a> {
147 pub fn to_fn_parts(self) -> FnParts<'a> {
148 FnParts {
149 decl: self.decl(),
150 body: self.body(),
151 kind: self.kind(),
152 span: self.span(),
153 id: self.id(),
154 }
155 }
156
157 pub fn body(self) -> &'a Block {
158 self.handle(|i: ItemFnParts<'a>| &*i.body,
159 |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body,
160 |c: ClosureParts<'a>| c.body)
161 }
162
163 pub fn decl(self) -> &'a FnDecl {
164 self.handle(|i: ItemFnParts<'a>| &*i.decl,
165 |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl,
166 |c: ClosureParts<'a>| c.decl)
167 }
168
169 pub fn span(self) -> Span {
170 self.handle(|i: ItemFnParts| i.span,
171 |_, _, _: &'a ast::MethodSig, _, _, span| span,
172 |c: ClosureParts| c.span)
173 }
174
175 pub fn id(self) -> NodeId {
176 self.handle(|i: ItemFnParts| i.id,
177 |id, _, _: &'a ast::MethodSig, _, _, _| id,
178 |c: ClosureParts| c.id)
179 }
180
181 pub fn kind(self) -> visit::FnKind<'a> {
182 let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> {
183 visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi, p.vis)
184 };
185 let closure = |_: ClosureParts| {
186 visit::FkFnBlock
187 };
188 let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| {
189 visit::FkMethod(ident, sig, vis)
190 };
191 self.handle(item, method, closure)
192 }
193
194 fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
195 I: FnOnce(ItemFnParts<'a>) -> A,
196 M: FnOnce(NodeId,
197 ast::Ident,
198 &'a ast::MethodSig,
199 Option<ast::Visibility>,
200 &'a ast::Block,
201 Span)
202 -> A,
203 C: FnOnce(ClosureParts<'a>) -> A,
204 {
205 match self.node {
206 ast_map::NodeItem(i) => match i.node {
207 ast::ItemFn(ref decl, unsafety, abi, ref generics, ref block) =>
208 item_fn(ItemFnParts{
209 ident: i.ident, decl: &**decl, unsafety: unsafety, body: &**block,
210 generics: generics, abi: abi, vis: i.vis, id: i.id, span: i.span
211 }),
212 _ => panic!("item FnLikeNode that is not fn-like"),
213 },
214 ast_map::NodeTraitItem(ti) => match ti.node {
215 ast::MethodTraitItem(ref sig, Some(ref body)) => {
216 method(ti.id, ti.ident, sig, None, body, ti.span)
217 }
218 _ => panic!("trait method FnLikeNode that is not fn-like"),
219 },
220 ast_map::NodeImplItem(ii) => {
221 match ii.node {
222 ast::MethodImplItem(ref sig, ref body) => {
223 method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
224 }
225 ast::TypeImplItem(_) |
226 ast::MacImplItem(_) => {
227 panic!("impl method FnLikeNode that is not fn-like")
228 }
229 }
230 }
231 ast_map::NodeExpr(e) => match e.node {
232 ast::ExprClosure(_, ref decl, ref block) =>
233 closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
234 _ => panic!("expr FnLikeNode that is not fn-like"),
235 },
236 _ => panic!("other FnLikeNode that is not fn-like"),
237 }
238 }
239 }