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};
31 use ast_util::PostExpansionMethod;
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).
38 /// More specifically, it is one of either:
39 /// - A function item,
40 /// - A closure expr (i.e. an ExprClosure), or
41 /// - The default implementation for a trait method.
43 /// To construct one, use the `Code::from_node` function.
45 pub struct FnLikeNode<'a> { node: ast_map::Node<'a> }
47 /// MaybeFnLike wraps a method that indicates if an object
48 /// corresponds to some FnLikeNode.
49 pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
51 /// Components shared by fn-like things (fn items, methods, closures).
52 pub struct FnParts<'a> {
55 pub kind: visit::FnKind<'a>,
60 impl MaybeFnLike for ast::Item {
61 fn is_fn_like(&self) -> bool {
62 match self.node { ast::ItemFn(..) => true, _ => false, }
66 impl MaybeFnLike for ast::TraitItem {
67 fn is_fn_like(&self) -> bool {
68 match *self { ast::ProvidedMethod(_) => true, _ => false, }
72 impl MaybeFnLike for ast::Expr {
73 fn is_fn_like(&self) -> bool {
75 ast::ExprClosure(..) => true,
81 /// Carries either an FnLikeNode or a Block, as these are the two
82 /// constructs that correspond to "code" (as in, something from which
83 /// we can construct a control-flow graph).
86 FnLikeCode(FnLikeNode<'a>),
91 pub fn id(&self) -> ast::NodeId {
93 FnLikeCode(node) => node.id(),
94 BlockCode(block) => block.id,
98 /// Attempts to construct a Code from presumed FnLike or Block node input.
99 pub fn from_node(node: Node) -> Option<Code> {
100 fn new(node: Node) -> FnLikeNode { FnLikeNode { node: node } }
102 ast_map::NodeItem(item) if item.is_fn_like() =>
103 Some(FnLikeCode(new(node))),
104 ast_map::NodeTraitItem(tm) if tm.is_fn_like() =>
105 Some(FnLikeCode(new(node))),
106 ast_map::NodeImplItem(_) =>
107 Some(FnLikeCode(new(node))),
108 ast_map::NodeExpr(e) if e.is_fn_like() =>
109 Some(FnLikeCode(new(node))),
110 ast_map::NodeBlock(block) =>
111 Some(BlockCode(block)),
118 /// These are all the components one can extract from a fn item for
119 /// use when implementing FnLikeNode operations.
120 struct ItemFnParts<'a> {
122 decl: &'a ast::FnDecl,
123 unsafety: ast::Unsafety,
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 |m: &'a ast::Method| m.pe_body(),
160 |c: ClosureParts<'a>| c.body)
163 pub fn decl(self) -> &'a FnDecl {
164 self.handle(|i: ItemFnParts<'a>| &*i.decl,
165 |m: &'a ast::Method| m.pe_fn_decl(),
166 |c: ClosureParts<'a>| c.decl)
169 pub fn span(self) -> Span {
170 self.handle(|i: ItemFnParts| i.span,
171 |m: &'a ast::Method| m.span,
172 |c: ClosureParts| c.span)
175 pub fn id(self) -> NodeId {
176 self.handle(|i: ItemFnParts| i.id,
177 |m: &'a ast::Method| m.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)
185 let closure = |: _: ClosureParts| {
188 let method = |: m: &'a ast::Method| {
189 visit::FkMethod(m.pe_ident(), m.pe_generics(), m)
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,
196 M: FnOnce(&'a ast::Method) -> A,
197 C: FnOnce(ClosureParts<'a>) -> A,
200 ast_map::NodeItem(i) => match i.node {
201 ast::ItemFn(ref decl, unsafety, abi, ref generics, ref block) =>
203 ident: i.ident, decl: &**decl, unsafety: unsafety, body: &**block,
204 generics: generics, abi: abi, id: i.id, span: i.span
206 _ => panic!("item FnLikeNode that is not fn-like"),
208 ast_map::NodeTraitItem(t) => match *t {
209 ast::ProvidedMethod(ref m) => method(&**m),
210 _ => panic!("trait method FnLikeNode that is not fn-like"),
212 ast_map::NodeImplItem(ii) => {
214 ast::MethodImplItem(ref m) => method(&**m),
215 ast::TypeImplItem(_) => {
216 panic!("impl method FnLikeNode that is not fn-like")
220 ast_map::NodeExpr(e) => match e.node {
221 ast::ExprClosure(_, _, ref decl, ref block) =>
222 closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
223 _ => panic!("expr FnLikeNode that is not fn-like"),
225 _ => panic!("other FnLikeNode that is not fn-like"),