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.
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.
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.
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.
24 pub use self::Code
::*;
27 use ast
::{Block, FnDecl, NodeId}
;
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).
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.
42 /// To construct one, use the `Code::from_node` function.
43 #[derive(Copy, Clone)]
44 pub struct FnLikeNode
<'a
> { node: ast_map::Node<'a> }
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; }
50 /// Components shared by fn-like things (fn items, methods, closures).
51 pub struct FnParts
<'a
> {
54 pub kind
: visit
::FnKind
<'a
>,
59 impl MaybeFnLike
for ast
::Item
{
60 fn is_fn_like(&self) -> bool
{
61 match self.node { ast::ItemFn(..) => true, _ => false, }
65 impl MaybeFnLike
for ast
::TraitItem
{
66 fn is_fn_like(&self) -> bool
{
67 match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
71 impl MaybeFnLike
for ast
::Expr
{
72 fn is_fn_like(&self) -> bool
{
74 ast
::ExprClosure(..) => true,
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)]
85 FnLikeCode(FnLikeNode
<'a
>),
90 pub fn id(&self) -> ast
::NodeId
{
92 FnLikeCode(node
) => node
.id(),
93 BlockCode(block
) => block
.id
,
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 }
}
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
)),
117 /// These are all the components one can extract from a fn item for
118 /// use when implementing FnLikeNode operations.
119 struct ItemFnParts
<'a
> {
121 decl
: &'a ast
::FnDecl
,
122 unsafety
: ast
::Unsafety
,
124 vis
: ast
::Visibility
,
125 generics
: &'a ast
::Generics
,
131 /// These are all the components one can extract from a closure expr
132 /// for use when implementing FnLikeNode operations.
133 struct ClosureParts
<'a
> {
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 }
146 impl<'a
> FnLikeNode
<'a
> {
147 pub fn to_fn_parts(self) -> FnParts
<'a
> {
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
)
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
)
169 pub fn span(self) -> Span
{
170 self.handle(|i
: ItemFnParts
| i
.span
,
171 |_
, _
, _
: &'a ast
::MethodSig
, _
, _
, span
| span
,
172 |c
: ClosureParts
| c
.span
)
175 pub fn id(self) -> NodeId
{
176 self.handle(|i
: ItemFnParts
| i
.id
,
177 |id
, _
, _
: &'a ast
::MethodSig
, _
, _
, _
| id
,
178 |c
: ClosureParts
| c
.id
)
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
)
185 let closure
= |_
: ClosureParts
| {
188 let method
= |_
, ident
, sig
: &'a ast
::MethodSig
, vis
, _
, _
| {
189 visit
::FkMethod(ident
, sig
, vis
)
191 self.handle(item
, method
, closure
)
194 fn handle
<A
, I
, M
, C
>(self, item_fn
: I
, method
: M
, closure
: C
) -> A
where
195 I
: FnOnce(ItemFnParts
<'a
>) -> A
,
199 Option
<ast
::Visibility
>,
203 C
: FnOnce(ClosureParts
<'a
>) -> A
,
206 ast_map
::NodeItem(i
) => match i
.node
{
207 ast
::ItemFn(ref decl
, unsafety
, abi
, ref generics
, ref block
) =>
209 ident
: i
.ident
, decl
: &**decl
, unsafety
: unsafety
, body
: &**block
,
210 generics
: generics
, abi
: abi
, vis
: i
.vis
, id
: i
.id
, span
: i
.span
212 _
=> panic
!("item FnLikeNode that is not fn-like"),
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
)
218 _
=> panic
!("trait method FnLikeNode that is not fn-like"),
220 ast_map
::NodeImplItem(ii
) => {
222 ast
::MethodImplItem(ref sig
, ref body
) => {
223 method(ii
.id
, ii
.ident
, sig
, Some(ii
.vis
), body
, ii
.span
)
225 ast
::TypeImplItem(_
) |
226 ast
::MacImplItem(_
) => {
227 panic
!("impl method FnLikeNode that is not fn-like")
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"),
236 _
=> panic
!("other FnLikeNode that is not fn-like"),