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.
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 use syntax::{ast, fold, attr};
13 type in_cfg_pred = @fn(attrs: ~[ast::attribute]) -> bool;
19 // Support conditional compilation by transforming the AST, stripping out
20 // any items that do not belong in the current configuration
21 pub fn strip_unconfigured_items(crate: @ast::crate) -> @ast::crate {
22 do strip_items(crate) |attrs| {
23 in_cfg(/*bad*/copy crate.node.config, attrs)
27 pub fn strip_items(crate: @ast::crate, in_cfg: in_cfg_pred)
30 let ctxt = @Context { in_cfg: in_cfg };
32 let precursor = @fold::AstFoldFns {
33 fold_mod: |a,b| fold_mod(ctxt, a, b),
34 fold_block: fold::wrap(|a,b| fold_block(ctxt, a, b) ),
35 fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b),
36 fold_item_underscore: |a,b| {
38 fold_item_underscore(ctxt, copy a, b)
40 .. *fold::default_ast_fold()};
42 let fold = fold::make_fold(precursor);
43 let res = @fold.fold_crate(&*crate);
47 fn filter_item(cx: @Context, item: @ast::item) ->
49 if item_in_cfg(cx, item) { option::Some(item) } else { option::None }
52 fn filter_view_item(cx: @Context, view_item: @ast::view_item
53 )-> Option<@ast::view_item> {
54 if view_item_in_cfg(cx, view_item) {
55 option::Some(view_item)
61 fn fold_mod(cx: @Context, m: &ast::_mod, fld: @fold::ast_fold) -> ast::_mod {
63 m.items.filter_mapped(|a| filter_item(cx, *a));
64 let filtered_view_items =
65 m.view_items.filter_mapped(|a| filter_view_item(cx, *a));
67 view_items: filtered_view_items.map(|x| fld.fold_view_item(*x)),
68 items: vec::filter_map(filtered_items, |x| fld.fold_item(x))
72 fn filter_foreign_item(cx: @Context, item: @ast::foreign_item) ->
73 Option<@ast::foreign_item> {
74 if foreign_item_in_cfg(cx, item) {
76 } else { option::None }
81 nm: &ast::foreign_mod,
83 ) -> ast::foreign_mod {
85 nm.items.filter_mapped(|a| filter_foreign_item(cx, *a));
86 let filtered_view_items =
87 nm.view_items.filter_mapped(|a| filter_view_item(cx, *a));
91 view_items: vec::map(filtered_view_items, |x| fld.fold_view_item(*x)),
96 fn fold_item_underscore(cx: @Context, item: &ast::item_,
97 fld: @fold::ast_fold) -> ast::item_ {
98 let item = match *item {
99 ast::item_impl(ref a, b, c, ref methods) => {
100 let methods = methods.filtered(|m| method_in_cfg(cx, *m) );
101 ast::item_impl(/*bad*/ copy *a, b, c, methods)
103 ast::item_trait(ref a, ref b, ref methods) => {
104 let methods = methods.filtered(|m| trait_method_in_cfg(cx, m) );
105 ast::item_trait(/*bad*/copy *a, /*bad*/copy *b, methods)
107 ref item => /*bad*/ copy *item
110 fold::noop_fold_item_underscore(&item, fld)
113 fn filter_stmt(cx: @Context, stmt: @ast::stmt) ->
116 ast::stmt_decl(decl, _) => {
118 ast::decl_item(item) => {
119 if item_in_cfg(cx, item) {
121 } else { option::None }
123 _ => option::Some(stmt)
126 _ => option::Some(stmt)
136 b.stmts.filter_mapped(|a| filter_stmt(cx, *a));
138 view_items: /*bad*/copy b.view_items,
139 stmts: vec::map(filtered_stmts, |x| fld.fold_stmt(*x)),
140 expr: b.expr.map(|x| fld.fold_expr(*x)),
146 fn item_in_cfg(cx: @Context, item: @ast::item) -> bool {
147 return (cx.in_cfg)(/*bad*/copy item.attrs);
150 fn foreign_item_in_cfg(cx: @Context, item: @ast::foreign_item) -> bool {
151 return (cx.in_cfg)(/*bad*/copy item.attrs);
154 fn view_item_in_cfg(cx: @Context, item: @ast::view_item) -> bool {
155 return (cx.in_cfg)(/*bad*/copy item.attrs);
158 fn method_in_cfg(cx: @Context, meth: @ast::method) -> bool {
159 return (cx.in_cfg)(/*bad*/copy meth.attrs);
162 fn trait_method_in_cfg(cx: @Context, meth: &ast::trait_method) -> bool {
164 ast::required(ref meth) => (cx.in_cfg)(/*bad*/copy meth.attrs),
165 ast::provided(@ref meth) => (cx.in_cfg)(/*bad*/copy meth.attrs)
169 // Determine if an item should be translated in the current crate
170 // configuration based on the item's attributes
171 fn in_cfg(cfg: ast::crate_cfg, attrs: ~[ast::attribute]) -> bool {
172 metas_in_cfg(cfg, attr::attr_metas(attrs))
175 pub fn metas_in_cfg(cfg: ast::crate_cfg,
176 metas: ~[@ast::meta_item]) -> bool {
177 // The "cfg" attributes on the item
178 let cfg_metas = attr::find_meta_items_by_name(metas, ~"cfg");
180 // Pull the inner meta_items from the #[cfg(meta_item, ...)] attributes,
181 // so we can match against them. This is the list of configurations for
182 // which the item is valid
183 let cfg_metas = vec::filter_map(cfg_metas, |i| attr::get_meta_item_list(i));
185 if cfg_metas.all(|c| c.is_empty()) { return true; }
187 cfg_metas.any(|cfg_meta| {
188 cfg_meta.all(|cfg_mi| {
190 ast::meta_list(s, ref it) if *s == ~"not"
191 => it.all(|mi| !attr::contains(cfg, *mi)),
192 _ => attr::contains(cfg, *cfg_mi)