]> git.proxmox.com Git - rustc.git/blame - src/libsyntax/ast_map/blocks.rs
Imported Upstream version 1.1.0+dfsg1
[rustc.git] / src / libsyntax / ast_map / blocks.rs
CommitLineData
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
24pub use self::Code::*;
25
26use abi;
27use ast::{Block, FnDecl, NodeId};
28use ast;
c34b1796 29use ast_map::Node;
1a4d82fc 30use ast_map;
1a4d82fc
JJ
31use codemap::Span;
32use 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.
c34b1796 43#[derive(Copy, Clone)]
1a4d82fc
JJ
44pub struct FnLikeNode<'a> { node: ast_map::Node<'a> }
45
46/// MaybeFnLike wraps a method that indicates if an object
47/// corresponds to some FnLikeNode.
48pub trait MaybeFnLike { fn is_fn_like(&self) -> bool; }
49
50/// Components shared by fn-like things (fn items, methods, closures).
51pub 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
59impl MaybeFnLike for ast::Item {
60 fn is_fn_like(&self) -> bool {
61 match self.node { ast::ItemFn(..) => true, _ => false, }
62 }
63}
64
65impl 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
71impl 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
84pub enum Code<'a> {
85 FnLikeCode(FnLikeNode<'a>),
86 BlockCode(&'a Block),
87}
88
89impl<'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.
119struct ItemFnParts<'a> {
120 ident: ast::Ident,
121 decl: &'a ast::FnDecl,
122 unsafety: ast::Unsafety,
123 abi: abi::Abi,
9346a6ac 124 vis: ast::Visibility,
1a4d82fc
JJ
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.
133struct ClosureParts<'a> {
134 decl: &'a FnDecl,
135 body: &'a Block,
136 id: NodeId,
137 span: Span
138}
139
140impl<'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
146impl<'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,
9346a6ac 159 |_, _, _: &'a ast::MethodSig, _, body: &'a ast::Block, _| body,
1a4d82fc
JJ
160 |c: ClosureParts<'a>| c.body)
161 }
162
163 pub fn decl(self) -> &'a FnDecl {
164 self.handle(|i: ItemFnParts<'a>| &*i.decl,
9346a6ac 165 |_, _, sig: &'a ast::MethodSig, _, _, _| &sig.decl,
1a4d82fc
JJ
166 |c: ClosureParts<'a>| c.decl)
167 }
168
169 pub fn span(self) -> Span {
170 self.handle(|i: ItemFnParts| i.span,
9346a6ac 171 |_, _, _: &'a ast::MethodSig, _, _, span| span,
1a4d82fc
JJ
172 |c: ClosureParts| c.span)
173 }
174
175 pub fn id(self) -> NodeId {
176 self.handle(|i: ItemFnParts| i.id,
9346a6ac 177 |id, _, _: &'a ast::MethodSig, _, _, _| id,
1a4d82fc
JJ
178 |c: ClosureParts| c.id)
179 }
180
181 pub fn kind(self) -> visit::FnKind<'a> {
85aaf69f 182 let item = |p: ItemFnParts<'a>| -> visit::FnKind<'a> {
9346a6ac 183 visit::FkItemFn(p.ident, p.generics, p.unsafety, p.abi, p.vis)
1a4d82fc 184 };
85aaf69f 185 let closure = |_: ClosureParts| {
1a4d82fc
JJ
186 visit::FkFnBlock
187 };
9346a6ac
AL
188 let method = |_, ident, sig: &'a ast::MethodSig, vis, _, _| {
189 visit::FkMethod(ident, sig, vis)
1a4d82fc
JJ
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,
9346a6ac
AL
196 M: FnOnce(NodeId,
197 ast::Ident,
198 &'a ast::MethodSig,
199 Option<ast::Visibility>,
200 &'a ast::Block,
201 Span)
202 -> A,
1a4d82fc
JJ
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,
9346a6ac 210 generics: generics, abi: abi, vis: i.vis, id: i.id, span: i.span
1a4d82fc
JJ
211 }),
212 _ => panic!("item FnLikeNode that is not fn-like"),
213 },
c34b1796
AL
214 ast_map::NodeTraitItem(ti) => match ti.node {
215 ast::MethodTraitItem(ref sig, Some(ref body)) => {
9346a6ac 216 method(ti.id, ti.ident, sig, None, body, ti.span)
c34b1796 217 }
1a4d82fc
JJ
218 _ => panic!("trait method FnLikeNode that is not fn-like"),
219 },
220 ast_map::NodeImplItem(ii) => {
c34b1796
AL
221 match ii.node {
222 ast::MethodImplItem(ref sig, ref body) => {
9346a6ac 223 method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
c34b1796 224 }
d9579d0f 225 _ => {
1a4d82fc
JJ
226 panic!("impl method FnLikeNode that is not fn-like")
227 }
228 }
229 }
230 ast_map::NodeExpr(e) => match e.node {
85aaf69f 231 ast::ExprClosure(_, ref decl, ref block) =>
1a4d82fc
JJ
232 closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
233 _ => panic!("expr FnLikeNode that is not fn-like"),
234 },
235 _ => panic!("other FnLikeNode that is not fn-like"),
236 }
237 }
238}