|
| 1 | +// Detecting language items. |
| 2 | +// |
| 3 | +// Language items are items that represent concepts intrinsic to the language |
| 4 | +// itself. Examples are: |
| 5 | +// |
| 6 | +// * Traits that specify "kinds"; e.g. "const", "copy", "send". |
| 7 | +// |
| 8 | +// * Traits that represent operators; e.g. "add", "sub", "index". |
| 9 | +// |
| 10 | +// * Functions called by the compiler itself. |
| 11 | + |
| 12 | +import driver::session::session; |
| 13 | +import metadata::csearch::{each_path, get_item_attrs}; |
| 14 | +import metadata::cstore::{iter_crate_data}; |
| 15 | +import metadata::decoder::{dl_def, dl_field, dl_impl}; |
| 16 | +import syntax::ast::{crate, def_id, def_ty, lit_str, meta_item, meta_list}; |
| 17 | +import syntax::ast::{meta_name_value, meta_word}; |
| 18 | +import syntax::ast_util::{local_def}; |
| 19 | +import syntax::visit::{default_simple_visitor, mk_simple_visitor}; |
| 20 | +import syntax::visit::{visit_crate, visit_item}; |
| 21 | + |
| 22 | +import std::map::{hashmap, str_hash}; |
| 23 | +import str_eq = str::eq; |
| 24 | + |
| 25 | +class LanguageItems { |
| 26 | + let mut const_trait: option<def_id>; |
| 27 | + let mut copy_trait: option<def_id>; |
| 28 | + let mut send_trait: option<def_id>; |
| 29 | + let mut owned_trait: option<def_id>; |
| 30 | + |
| 31 | + let mut add_trait: option<def_id>; |
| 32 | + let mut sub_trait: option<def_id>; |
| 33 | + let mut mul_trait: option<def_id>; |
| 34 | + let mut div_trait: option<def_id>; |
| 35 | + let mut modulo_trait: option<def_id>; |
| 36 | + let mut neg_trait: option<def_id>; |
| 37 | + let mut bitops_trait: option<def_id>; |
| 38 | + let mut index_trait: option<def_id>; |
| 39 | + |
| 40 | + new() { |
| 41 | + self.const_trait = none; |
| 42 | + self.copy_trait = none; |
| 43 | + self.send_trait = none; |
| 44 | + self.owned_trait = none; |
| 45 | + |
| 46 | + self.add_trait = none; |
| 47 | + self.sub_trait = none; |
| 48 | + self.mul_trait = none; |
| 49 | + self.div_trait = none; |
| 50 | + self.modulo_trait = none; |
| 51 | + self.neg_trait = none; |
| 52 | + self.bitops_trait = none; |
| 53 | + self.index_trait = none; |
| 54 | + } |
| 55 | +} |
| 56 | + |
| 57 | +class LanguageItemCollector { |
| 58 | + let items: LanguageItems; |
| 59 | + |
| 60 | + let crate: @crate; |
| 61 | + let session: session; |
| 62 | + |
| 63 | + let item_refs: hashmap<~str,&mut option<def_id>>; |
| 64 | + |
| 65 | + new(crate: @crate, session: session) { |
| 66 | + self.crate = crate; |
| 67 | + self.session = session; |
| 68 | + |
| 69 | + self.items = LanguageItems(); |
| 70 | + |
| 71 | + self.item_refs = str_hash(); |
| 72 | + } |
| 73 | + |
| 74 | + // XXX: Needed to work around an issue with constructors. |
| 75 | + fn init() { |
| 76 | + self.item_refs.insert(~"const", &mut self.items.const_trait); |
| 77 | + self.item_refs.insert(~"copy", &mut self.items.copy_trait); |
| 78 | + self.item_refs.insert(~"send", &mut self.items.send_trait); |
| 79 | + self.item_refs.insert(~"owned", &mut self.items.owned_trait); |
| 80 | + |
| 81 | + self.item_refs.insert(~"add", &mut self.items.add_trait); |
| 82 | + self.item_refs.insert(~"sub", &mut self.items.sub_trait); |
| 83 | + self.item_refs.insert(~"mul", &mut self.items.mul_trait); |
| 84 | + self.item_refs.insert(~"div", &mut self.items.div_trait); |
| 85 | + self.item_refs.insert(~"modulo", &mut self.items.modulo_trait); |
| 86 | + self.item_refs.insert(~"neg", &mut self.items.neg_trait); |
| 87 | + self.item_refs.insert(~"bitops", &mut self.items.bitops_trait); |
| 88 | + self.item_refs.insert(~"index", &mut self.items.index_trait); |
| 89 | + } |
| 90 | + |
| 91 | + fn match_and_collect_meta_item(item_def_id: def_id, |
| 92 | + meta_item: meta_item) { |
| 93 | + |
| 94 | + alt meta_item.node { |
| 95 | + meta_name_value(key, literal) => { |
| 96 | + alt literal.node { |
| 97 | + lit_str(value) => { |
| 98 | + self.match_and_collect_item(item_def_id, |
| 99 | + *key, |
| 100 | + *value); |
| 101 | + } |
| 102 | + _ => { |
| 103 | + // Skip. |
| 104 | + } |
| 105 | + } |
| 106 | + } |
| 107 | + meta_word(*) | meta_list(*) { |
| 108 | + // Skip. |
| 109 | + } |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + fn match_and_collect_item(item_def_id: def_id, key: ~str, value: ~str) { |
| 114 | + if !str_eq(key, ~"lang") { |
| 115 | + ret; // Didn't match. |
| 116 | + } |
| 117 | + |
| 118 | + alt self.item_refs.find(value) { |
| 119 | + none => { |
| 120 | + // Didn't match. |
| 121 | + } |
| 122 | + some(item_ref) => { |
| 123 | + // Check for duplicates. |
| 124 | + alt copy *item_ref { |
| 125 | + some(original_def_id) |
| 126 | + if original_def_id != item_def_id => { |
| 127 | + |
| 128 | + self.session.warn(#fmt("duplicate entry for `%s`", |
| 129 | + value)); |
| 130 | + } |
| 131 | + some(_) | none => { |
| 132 | + // OK. |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + // Matched. |
| 137 | + *item_ref = some(item_def_id); |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | + |
| 142 | + fn collect_local_language_items() { |
| 143 | + let this = unsafe { ptr::addr_of(self) }; |
| 144 | + visit_crate(*self.crate, (), mk_simple_visitor(@{ |
| 145 | + visit_item: |item| { |
| 146 | + for item.attrs.each |attribute| { |
| 147 | + unsafe { |
| 148 | + (*this).match_and_collect_meta_item(local_def(item |
| 149 | + .id), |
| 150 | + attribute.node |
| 151 | + .value); |
| 152 | + } |
| 153 | + } |
| 154 | + } |
| 155 | + with *default_simple_visitor() |
| 156 | + })); |
| 157 | + } |
| 158 | + |
| 159 | + fn collect_external_language_items() { |
| 160 | + let crate_store = self.session.cstore; |
| 161 | + do iter_crate_data(crate_store) |crate_number, _crate_metadata| { |
| 162 | + for each_path(crate_store, crate_number) |path_entry| { |
| 163 | + let def_id; |
| 164 | + alt path_entry.def_like { |
| 165 | + dl_def(def_ty(did)) => { |
| 166 | + def_id = did; |
| 167 | + } |
| 168 | + dl_def(_) | dl_impl(_) | dl_field { |
| 169 | + // Skip this. |
| 170 | + again; |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | + do get_item_attrs(crate_store, def_id) |meta_items| { |
| 175 | + for meta_items.each |meta_item| { |
| 176 | + self.match_and_collect_meta_item(def_id, *meta_item); |
| 177 | + } |
| 178 | + } |
| 179 | + } |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + fn check_completeness() { |
| 184 | + for self.item_refs.each |key, item_ref| { |
| 185 | + alt copy *item_ref { |
| 186 | + none => { |
| 187 | + self.session.warn(#fmt("no item found for `%s`", key)); |
| 188 | + } |
| 189 | + some(did) => { |
| 190 | + // OK. |
| 191 | + } |
| 192 | + } |
| 193 | + } |
| 194 | + } |
| 195 | + |
| 196 | + fn collect() { |
| 197 | + self.init(); |
| 198 | + self.collect_local_language_items(); |
| 199 | + self.collect_external_language_items(); |
| 200 | + self.check_completeness(); |
| 201 | + } |
| 202 | +} |
| 203 | + |
| 204 | +fn collect_language_items(crate: @crate, session: session) -> LanguageItems { |
| 205 | + let collector = LanguageItemCollector(crate, session); |
| 206 | + collector.collect(); |
| 207 | + copy collector.items |
| 208 | +} |
| 209 | + |
0 commit comments