1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
import syntax::{ast, fold, attr};
export strip_unconfigured_items;
export metas_in_cfg;
export strip_items;
type in_cfg_pred = fn@(~[ast::attribute]) -> bool;
type ctxt = @{
in_cfg: in_cfg_pred
};
// Support conditional compilation by transforming the AST, stripping out
// any items that do not belong in the current configuration
fn strip_unconfigured_items(crate: @ast::crate) -> @ast::crate {
do strip_items(crate) |attrs| {
in_cfg(crate.node.config, attrs)
}
}
fn strip_items(crate: @ast::crate, in_cfg: in_cfg_pred)
-> @ast::crate {
let ctxt = @{in_cfg: in_cfg};
let precursor =
@{fold_mod: |a,b| fold_mod(ctxt, a, b),
fold_block: fold::wrap(|a,b| fold_block(ctxt, a, b) ),
fold_foreign_mod: |a,b| fold_foreign_mod(ctxt, a, b)
with *fold::default_ast_fold()};
let fold = fold::make_fold(precursor);
let res = @fold.fold_crate(*crate);
ret res;
}
fn filter_item(cx: ctxt, &&item: @ast::item) ->
option<@ast::item> {
if item_in_cfg(cx, item) { option::some(item) } else { option::none }
}
fn filter_view_item(cx: ctxt, &&view_item: @ast::view_item
)-> option<@ast::view_item> {
if view_item_in_cfg(cx, view_item) {
option::some(view_item)
} else {
option::none
}
}
fn fold_mod(cx: ctxt, m: ast::_mod, fld: fold::ast_fold) ->
ast::_mod {
let item_filter = |a| filter_item(cx, a);
let filtered_items = vec::filter_map(m.items, item_filter);
let view_item_filter = |a| filter_view_item(cx, a);
let filtered_view_items = vec::filter_map(m.view_items, view_item_filter);
ret {view_items: vec::map(filtered_view_items, |x| fld.fold_view_item(x)),
items: vec::filter_map(filtered_items, |x| fld.fold_item(x))};
}
fn filter_foreign_item(cx: ctxt, &&item: @ast::foreign_item) ->
option<@ast::foreign_item> {
if foreign_item_in_cfg(cx, item) {
option::some(item)
} else { option::none }
}
fn fold_foreign_mod(cx: ctxt, nm: ast::foreign_mod,
fld: fold::ast_fold) -> ast::foreign_mod {
let item_filter = |a| filter_foreign_item(cx, a);
let filtered_items = vec::filter_map(nm.items, item_filter);
let view_item_filter = |a| filter_view_item(cx, a);
let filtered_view_items = vec::filter_map(
nm.view_items, view_item_filter);
ret {view_items: vec::map(filtered_view_items, |x| fld.fold_view_item(x)),
items: filtered_items};
}
fn filter_stmt(cx: ctxt, &&stmt: @ast::stmt) ->
option<@ast::stmt> {
alt stmt.node {
ast::stmt_decl(decl, _) {
alt decl.node {
ast::decl_item(item) {
if item_in_cfg(cx, item) {
option::some(stmt)
} else { option::none }
}
_ { option::some(stmt) }
}
}
_ { option::some(stmt) }
}
}
fn fold_block(cx: ctxt, b: ast::blk_, fld: fold::ast_fold) ->
ast::blk_ {
let filter = |a| filter_stmt(cx, a);
let filtered_stmts = vec::filter_map(b.stmts, filter);
ret {view_items: b.view_items,
stmts: vec::map(filtered_stmts, |x| fld.fold_stmt(x)),
expr: option::map(b.expr, |x| fld.fold_expr(x)),
id: b.id,
rules: b.rules};
}
fn item_in_cfg(cx: ctxt, item: @ast::item) -> bool {
ret cx.in_cfg(item.attrs);
}
fn foreign_item_in_cfg(cx: ctxt, item: @ast::foreign_item) -> bool {
ret cx.in_cfg(item.attrs);
}
fn view_item_in_cfg(cx: ctxt, item: @ast::view_item) -> bool {
ret cx.in_cfg(item.attrs);
}
// Determine if an item should be translated in the current crate
// configuration based on the item's attributes
fn in_cfg(cfg: ast::crate_cfg, attrs: ~[ast::attribute]) -> bool {
metas_in_cfg(cfg, attr::attr_metas(attrs))
}
fn metas_in_cfg(cfg: ast::crate_cfg, metas: ~[@ast::meta_item]) -> bool {
// The "cfg" attributes on the item
let cfg_metas = attr::find_meta_items_by_name(metas, "cfg");
// Pull the inner meta_items from the #[cfg(meta_item, ...)] attributes,
// so we can match against them. This is the list of configurations for
// which the item is valid
let cfg_metas = vec::concat(vec::filter_map(cfg_metas,
|&&i| attr::get_meta_item_list(i) ));
let has_cfg_metas = vec::len(cfg_metas) > 0u;
if !has_cfg_metas { ret true; }
for cfg_metas.each |cfg_mi| {
if attr::contains(cfg, cfg_mi) { ret true; }
}
ret false;
}
// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
|