]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
e9174d1e | 26 | use front::map::{self, Node}; |
62682a34 | 27 | use syntax::abi; |
e9174d1e | 28 | use rustc_front::hir::{Block, FnDecl}; |
b039eaaf | 29 | use syntax::ast::{Name, NodeId}; |
e9174d1e | 30 | use rustc_front::hir as ast; |
62682a34 | 31 | use syntax::codemap::Span; |
92a42be0 | 32 | use rustc_front::intravisit::FnKind; |
1a4d82fc JJ |
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. | |
c34b1796 | 43 | #[derive(Copy, Clone)] |
e9174d1e | 44 | pub struct FnLikeNode<'a> { node: map::Node<'a> } |
1a4d82fc JJ |
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, | |
e9174d1e | 54 | pub kind: FnKind<'a>, |
1a4d82fc JJ |
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 { | |
c34b1796 | 67 | match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, } |
1a4d82fc JJ |
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). | |
c34b1796 | 83 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
84 | pub enum Code<'a> { |
85 | FnLikeCode(FnLikeNode<'a>), | |
86 | BlockCode(&'a Block), | |
87 | } | |
88 | ||
89 | impl<'a> Code<'a> { | |
e9174d1e | 90 | pub fn id(&self) -> NodeId { |
1a4d82fc JJ |
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> { | |
e9174d1e | 99 | if let map::NodeBlock(block) = node { |
62682a34 SL |
100 | Some(BlockCode(block)) |
101 | } else { | |
102 | FnLikeNode::from_node(node).map(|fn_like| FnLikeCode(fn_like)) | |
1a4d82fc JJ |
103 | } |
104 | } | |
105 | } | |
106 | ||
107 | /// These are all the components one can extract from a fn item for | |
108 | /// use when implementing FnLikeNode operations. | |
109 | struct ItemFnParts<'a> { | |
b039eaaf | 110 | name: Name, |
1a4d82fc JJ |
111 | decl: &'a ast::FnDecl, |
112 | unsafety: ast::Unsafety, | |
62682a34 | 113 | constness: ast::Constness, |
1a4d82fc | 114 | abi: abi::Abi, |
9346a6ac | 115 | vis: ast::Visibility, |
1a4d82fc JJ |
116 | generics: &'a ast::Generics, |
117 | body: &'a Block, | |
e9174d1e | 118 | id: NodeId, |
1a4d82fc JJ |
119 | span: Span |
120 | } | |
121 | ||
122 | /// These are all the components one can extract from a closure expr | |
123 | /// for use when implementing FnLikeNode operations. | |
124 | struct ClosureParts<'a> { | |
125 | decl: &'a FnDecl, | |
126 | body: &'a Block, | |
127 | id: NodeId, | |
128 | span: Span | |
129 | } | |
130 | ||
131 | impl<'a> ClosureParts<'a> { | |
132 | fn new(d: &'a FnDecl, b: &'a Block, id: NodeId, s: Span) -> ClosureParts<'a> { | |
133 | ClosureParts { decl: d, body: b, id: id, span: s } | |
134 | } | |
135 | } | |
136 | ||
137 | impl<'a> FnLikeNode<'a> { | |
62682a34 SL |
138 | /// Attempts to construct a FnLikeNode from presumed FnLike node input. |
139 | pub fn from_node(node: Node) -> Option<FnLikeNode> { | |
140 | let fn_like = match node { | |
e9174d1e SL |
141 | map::NodeItem(item) => item.is_fn_like(), |
142 | map::NodeTraitItem(tm) => tm.is_fn_like(), | |
143 | map::NodeImplItem(_) => true, | |
144 | map::NodeExpr(e) => e.is_fn_like(), | |
62682a34 SL |
145 | _ => false |
146 | }; | |
147 | if fn_like { | |
148 | Some(FnLikeNode { | |
149 | node: node | |
150 | }) | |
151 | } else { | |
152 | None | |
153 | } | |
154 | } | |
155 | ||
1a4d82fc JJ |
156 | pub fn to_fn_parts(self) -> FnParts<'a> { |
157 | FnParts { | |
158 | decl: self.decl(), | |
159 | body: self.body(), | |
160 | kind: self.kind(), | |
161 | span: self.span(), | |
162 | id: self.id(), | |
163 | } | |
164 | } | |
165 | ||
166 | pub fn body(self) -> &'a Block { | |
167 | self.handle(|i: ItemFnParts<'a>| &*i.body, | |
9346a6ac | 168 | |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body, |
1a4d82fc JJ |
169 | |c: ClosureParts<'a>| c.body) |
170 | } | |
171 | ||
172 | pub fn decl(self) -> &'a FnDecl { | |
173 | self.handle(|i: ItemFnParts<'a>| &*i.decl, | |
9346a6ac | 174 | |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl, |
1a4d82fc JJ |
175 | |c: ClosureParts<'a>| c.decl) |
176 | } | |
177 | ||
178 | pub fn span(self) -> Span { | |
179 | self.handle(|i: ItemFnParts| i.span, | |
9346a6ac | 180 | |_, _, _: &'a ast::MethodSig, _, _, span| span, |
1a4d82fc JJ |
181 | |c: ClosureParts| c.span) |
182 | } | |
183 | ||
184 | pub fn id(self) -> NodeId { | |
185 | self.handle(|i: ItemFnParts| i.id, | |
9346a6ac | 186 | |id, _, _: &'a ast::MethodSig, _, _, _| id, |
1a4d82fc JJ |
187 | |c: ClosureParts| c.id) |
188 | } | |
189 | ||
e9174d1e SL |
190 | pub fn kind(self) -> FnKind<'a> { |
191 | let item = |p: ItemFnParts<'a>| -> FnKind<'a> { | |
b039eaaf | 192 | FnKind::ItemFn(p.name, p.generics, p.unsafety, p.constness, p.abi, p.vis) |
1a4d82fc | 193 | }; |
85aaf69f | 194 | let closure = |_: ClosureParts| { |
e9174d1e | 195 | FnKind::Closure |
1a4d82fc | 196 | }; |
b039eaaf SL |
197 | let method = |_, name: Name, sig: &'a ast::MethodSig, vis, _, _| { |
198 | FnKind::Method(name, sig, vis) | |
1a4d82fc JJ |
199 | }; |
200 | self.handle(item, method, closure) | |
201 | } | |
202 | ||
203 | fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where | |
204 | I: FnOnce(ItemFnParts<'a>) -> A, | |
9346a6ac | 205 | M: FnOnce(NodeId, |
b039eaaf | 206 | Name, |
9346a6ac AL |
207 | &'a ast::MethodSig, |
208 | Option<ast::Visibility>, | |
209 | &'a ast::Block, | |
210 | Span) | |
211 | -> A, | |
1a4d82fc JJ |
212 | C: FnOnce(ClosureParts<'a>) -> A, |
213 | { | |
214 | match self.node { | |
e9174d1e | 215 | map::NodeItem(i) => match i.node { |
62682a34 SL |
216 | ast::ItemFn(ref decl, unsafety, constness, abi, ref generics, ref block) => |
217 | item_fn(ItemFnParts { | |
218 | id: i.id, | |
b039eaaf | 219 | name: i.name, |
7453a54e | 220 | decl: &decl, |
62682a34 | 221 | unsafety: unsafety, |
7453a54e | 222 | body: &block, |
62682a34 SL |
223 | generics: generics, |
224 | abi: abi, | |
225 | vis: i.vis, | |
226 | constness: constness, | |
227 | span: i.span | |
1a4d82fc JJ |
228 | }), |
229 | _ => panic!("item FnLikeNode that is not fn-like"), | |
230 | }, | |
e9174d1e | 231 | map::NodeTraitItem(ti) => match ti.node { |
c34b1796 | 232 | ast::MethodTraitItem(ref sig, Some(ref body)) => { |
b039eaaf | 233 | method(ti.id, ti.name, sig, None, body, ti.span) |
c34b1796 | 234 | } |
1a4d82fc JJ |
235 | _ => panic!("trait method FnLikeNode that is not fn-like"), |
236 | }, | |
e9174d1e | 237 | map::NodeImplItem(ii) => { |
c34b1796 | 238 | match ii.node { |
92a42be0 | 239 | ast::ImplItemKind::Method(ref sig, ref body) => { |
b039eaaf | 240 | method(ii.id, ii.name, sig, Some(ii.vis), body, ii.span) |
c34b1796 | 241 | } |
d9579d0f | 242 | _ => { |
1a4d82fc JJ |
243 | panic!("impl method FnLikeNode that is not fn-like") |
244 | } | |
245 | } | |
246 | } | |
e9174d1e | 247 | map::NodeExpr(e) => match e.node { |
85aaf69f | 248 | ast::ExprClosure(_, ref decl, ref block) => |
7453a54e | 249 | closure(ClosureParts::new(&decl, &block, e.id, e.span)), |
1a4d82fc JJ |
250 | _ => panic!("expr FnLikeNode that is not fn-like"), |
251 | }, | |
252 | _ => panic!("other FnLikeNode that is not fn-like"), | |
253 | } | |
254 | } | |
255 | } |