]> git.lizzy.rs Git - rust.git/blob - src/librustc/front/config.rs
f2130033eed922ddf3699e0a92fac8441d1443aa
[rust.git] / src / librustc / front / config.rs
1 // Copyright 2012 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
12 use syntax::fold::Folder;
13 use syntax::{ast, fold, attr};
14 use syntax::codemap;
15
16 struct Context<'a> {
17     in_cfg: 'a |attrs: &[ast::Attribute]| -> bool,
18 }
19
20 // Support conditional compilation by transforming the AST, stripping out
21 // any items that do not belong in the current configuration
22 pub fn strip_unconfigured_items(krate: ast::Crate) -> ast::Crate {
23     let config = krate.config.clone();
24     strip_items(krate, |attrs| in_cfg(config, attrs))
25 }
26
27 impl<'a> fold::Folder for Context<'a> {
28     fn fold_mod(&mut self, module: &ast::Mod) -> ast::Mod {
29         fold_mod(self, module)
30     }
31     fn fold_block(&mut self, block: ast::P<ast::Block>) -> ast::P<ast::Block> {
32         fold_block(self, block)
33     }
34     fn fold_foreign_mod(&mut self, foreign_mod: &ast::ForeignMod) -> ast::ForeignMod {
35         fold_foreign_mod(self, foreign_mod)
36     }
37     fn fold_item_underscore(&mut self, item: &ast::Item_) -> ast::Item_ {
38         fold_item_underscore(self, item)
39     }
40 }
41
42 pub fn strip_items(krate: ast::Crate,
43                    in_cfg: |attrs: &[ast::Attribute]| -> bool)
44                    -> ast::Crate {
45     let mut ctxt = Context {
46         in_cfg: in_cfg,
47     };
48     ctxt.fold_crate(krate)
49 }
50
51 fn filter_view_item<'r>(cx: &Context, view_item: &'r ast::ViewItem)
52                         -> Option<&'r ast::ViewItem> {
53     if view_item_in_cfg(cx, view_item) {
54         Some(view_item)
55     } else {
56         None
57     }
58 }
59
60 fn fold_mod(cx: &mut Context, m: &ast::Mod) -> ast::Mod {
61     let filtered_items: ~[&@ast::Item] = m.items.iter()
62             .filter(|&a| item_in_cfg(cx, *a))
63             .collect();
64     let flattened_items = filtered_items.move_iter()
65             .flat_map(|&x| cx.fold_item(x).move_iter())
66             .collect();
67     let filtered_view_items = m.view_items.iter().filter_map(|a| {
68         filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
69     }).collect();
70     ast::Mod {
71         view_items: filtered_view_items,
72         items: flattened_items
73     }
74 }
75
76 fn filter_foreign_item(cx: &Context, item: @ast::ForeignItem)
77                        -> Option<@ast::ForeignItem> {
78     if foreign_item_in_cfg(cx, item) {
79         Some(item)
80     } else {
81         None
82     }
83 }
84
85 fn fold_foreign_mod(cx: &mut Context, nm: &ast::ForeignMod) -> ast::ForeignMod {
86     let filtered_items = nm.items
87                            .iter()
88                            .filter_map(|a| filter_foreign_item(cx, *a))
89                            .collect();
90     let filtered_view_items = nm.view_items.iter().filter_map(|a| {
91         filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
92     }).collect();
93     ast::ForeignMod {
94         abis: nm.abis,
95         view_items: filtered_view_items,
96         items: filtered_items
97     }
98 }
99
100 fn fold_item_underscore(cx: &mut Context, item: &ast::Item_) -> ast::Item_ {
101     let item = match *item {
102         ast::ItemImpl(ref a, ref b, c, ref methods) => {
103             let methods = methods.iter().filter(|m| method_in_cfg(cx, **m))
104                 .map(|x| *x).collect();
105             ast::ItemImpl((*a).clone(), (*b).clone(), c, methods)
106         }
107         ast::ItemTrait(ref a, ref b, ref methods) => {
108             let methods = methods.iter()
109                                  .filter(|m| trait_method_in_cfg(cx, *m) )
110                                  .map(|x| (*x).clone())
111                                  .collect();
112             ast::ItemTrait((*a).clone(), (*b).clone(), methods)
113         }
114         ast::ItemStruct(def, ref generics) => {
115             ast::ItemStruct(fold_struct(cx, def), generics.clone())
116         }
117         ast::ItemEnum(ref def, ref generics) => {
118             let mut variants = def.variants.iter().map(|c| c.clone()).
119             filter_map(|v| {
120                 if !(cx.in_cfg)(v.node.attrs) {
121                     None
122                 } else {
123                     Some(match v.node.kind {
124                                 ast::TupleVariantKind(..) => v,
125                                 ast::StructVariantKind(def) => {
126                                     let def = fold_struct(cx, def);
127                                     @codemap::Spanned {
128                                         node: ast::Variant_ {
129                                             kind: ast::StructVariantKind(def),
130                                             ..v.node.clone()
131                                         },
132                                         ..*v
133                                     }
134                                 }
135                             })
136                     }
137                 });
138             ast::ItemEnum(ast::EnumDef {
139                 variants: variants.collect(),
140             }, generics.clone())
141         }
142         ref item => item.clone(),
143     };
144
145     fold::noop_fold_item_underscore(&item, cx)
146 }
147
148 fn fold_struct(cx: &Context, def: &ast::StructDef) -> @ast::StructDef {
149     let mut fields = def.fields.iter().map(|c| c.clone()).filter(|m| {
150         (cx.in_cfg)(m.node.attrs)
151     });
152     @ast::StructDef {
153         fields: fields.collect(),
154         ctor_id: def.ctor_id,
155     }
156 }
157
158 fn retain_stmt(cx: &Context, stmt: @ast::Stmt) -> bool {
159     match stmt.node {
160       ast::StmtDecl(decl, _) => {
161         match decl.node {
162           ast::DeclItem(item) => {
163             item_in_cfg(cx, item)
164           }
165           _ => true
166         }
167       }
168       _ => true
169     }
170 }
171
172 fn fold_block(cx: &mut Context, b: ast::P<ast::Block>) -> ast::P<ast::Block> {
173     let resulting_stmts: ~[&@ast::Stmt] =
174         b.stmts.iter().filter(|&a| retain_stmt(cx, *a)).collect();
175     let resulting_stmts = resulting_stmts.move_iter()
176         .flat_map(|&stmt| cx.fold_stmt(stmt).move_iter())
177         .collect();
178     let filtered_view_items = b.view_items.iter().filter_map(|a| {
179         filter_view_item(cx, a).map(|x| cx.fold_view_item(x))
180     }).collect();
181     ast::P(ast::Block {
182         view_items: filtered_view_items,
183         stmts: resulting_stmts,
184         expr: b.expr.map(|x| cx.fold_expr(x)),
185         id: b.id,
186         rules: b.rules,
187         span: b.span,
188     })
189 }
190
191 fn item_in_cfg(cx: &Context, item: &ast::Item) -> bool {
192     return (cx.in_cfg)(item.attrs);
193 }
194
195 fn foreign_item_in_cfg(cx: &Context, item: &ast::ForeignItem) -> bool {
196     return (cx.in_cfg)(item.attrs);
197 }
198
199 fn view_item_in_cfg(cx: &Context, item: &ast::ViewItem) -> bool {
200     return (cx.in_cfg)(item.attrs);
201 }
202
203 fn method_in_cfg(cx: &Context, meth: &ast::Method) -> bool {
204     return (cx.in_cfg)(meth.attrs);
205 }
206
207 fn trait_method_in_cfg(cx: &Context, meth: &ast::TraitMethod) -> bool {
208     match *meth {
209         ast::Required(ref meth) => (cx.in_cfg)(meth.attrs),
210         ast::Provided(meth) => (cx.in_cfg)(meth.attrs)
211     }
212 }
213
214 // Determine if an item should be translated in the current crate
215 // configuration based on the item's attributes
216 fn in_cfg(cfg: &[@ast::MetaItem], attrs: &[ast::Attribute]) -> bool {
217     attr::test_cfg(cfg, attrs.iter().map(|x| *x))
218 }
219