2011-06-28 17:25:20 -05:00
|
|
|
// Functions dealing with attributes and meta_items
|
|
|
|
|
2011-07-05 19:02:51 -05:00
|
|
|
import std::ivec;
|
2011-07-05 13:46:02 -05:00
|
|
|
import std::str;
|
|
|
|
import std::map;
|
2011-06-28 13:24:24 -05:00
|
|
|
import std::option;
|
2011-07-05 04:48:19 -05:00
|
|
|
import syntax::ast;
|
2011-06-30 18:53:13 -05:00
|
|
|
import util::common;
|
2011-07-05 13:46:02 -05:00
|
|
|
import driver::session;
|
2011-06-28 13:24:24 -05:00
|
|
|
|
2011-07-05 19:01:23 -05:00
|
|
|
export attr_meta;
|
2011-06-28 14:53:59 -05:00
|
|
|
export attr_metas;
|
|
|
|
export find_linkage_metas;
|
2011-06-28 13:24:24 -05:00
|
|
|
export find_attrs_by_name;
|
2011-06-28 18:52:11 -05:00
|
|
|
export find_meta_items_by_name;
|
2011-06-28 14:53:59 -05:00
|
|
|
export contains;
|
2011-07-13 20:13:19 -05:00
|
|
|
export contains_name;
|
2011-06-28 17:46:09 -05:00
|
|
|
export sort_meta_items;
|
2011-06-29 16:17:23 -05:00
|
|
|
export remove_meta_items_by_name;
|
2011-07-05 13:46:02 -05:00
|
|
|
export require_unique_names;
|
2011-06-29 16:17:23 -05:00
|
|
|
export get_attr_name;
|
2011-07-05 19:01:23 -05:00
|
|
|
export get_meta_item_name;
|
|
|
|
export get_meta_item_value_str;
|
|
|
|
export mk_name_value_item_str;
|
2011-06-30 18:53:13 -05:00
|
|
|
export mk_name_value_item;
|
2011-06-30 19:03:08 -05:00
|
|
|
export mk_list_item;
|
2011-06-30 18:53:13 -05:00
|
|
|
export mk_word_item;
|
2011-06-30 19:03:08 -05:00
|
|
|
export mk_attr;
|
2011-06-28 13:24:24 -05:00
|
|
|
|
|
|
|
// From a list of crate attributes get only the meta_items that impact crate
|
|
|
|
// linkage
|
2011-08-04 18:20:09 -05:00
|
|
|
fn find_linkage_metas(attrs: &[ast::attribute]) -> [@ast::meta_item] {
|
|
|
|
let metas: [@ast::meta_item] = ~[];
|
2011-07-27 07:19:39 -05:00
|
|
|
for attr: ast::attribute in find_attrs_by_name(attrs, "link") {
|
|
|
|
alt attr.node.value.node {
|
|
|
|
ast::meta_list(_, items) { metas += items; }
|
|
|
|
_ { log "ignoring link attribute that has incorrect type"; }
|
2011-06-28 13:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret metas;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Search a list of attributes and return only those with a specific name
|
2011-08-04 18:20:09 -05:00
|
|
|
fn find_attrs_by_name(attrs: &[ast::attribute], name: ast::ident) ->
|
|
|
|
[ast::attribute] {
|
2011-07-27 07:19:39 -05:00
|
|
|
let filter =
|
|
|
|
bind fn (a: &ast::attribute, name: ast::ident) ->
|
|
|
|
option::t[ast::attribute] {
|
|
|
|
if get_attr_name(a) == name {
|
|
|
|
option::some(a)
|
|
|
|
} else { option::none }
|
|
|
|
}(_, name);
|
2011-07-05 19:02:51 -05:00
|
|
|
ret ivec::filter_map(filter, attrs);
|
2011-06-28 13:24:24 -05:00
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn get_attr_name(attr: &ast::attribute) -> ast::ident {
|
2011-06-28 13:24:24 -05:00
|
|
|
get_meta_item_name(@attr.node.value)
|
|
|
|
}
|
|
|
|
|
2011-08-04 18:20:09 -05:00
|
|
|
fn find_meta_items_by_name(metas: &[@ast::meta_item], name: ast::ident) ->
|
|
|
|
[@ast::meta_item] {
|
2011-07-27 07:19:39 -05:00
|
|
|
let filter =
|
|
|
|
bind fn (m: &@ast::meta_item, name: ast::ident) ->
|
|
|
|
option::t[@ast::meta_item] {
|
|
|
|
if get_meta_item_name(m) == name {
|
|
|
|
option::some(m)
|
|
|
|
} else { option::none }
|
|
|
|
}(_, name);
|
2011-07-05 19:57:34 -05:00
|
|
|
ret ivec::filter_map(filter, metas);
|
2011-06-28 13:24:24 -05:00
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn get_meta_item_name(meta: &@ast::meta_item) -> ast::ident {
|
|
|
|
alt meta.node {
|
|
|
|
ast::meta_word(n) { n }
|
|
|
|
ast::meta_name_value(n, _) { n }
|
|
|
|
ast::meta_list(n, _) { n }
|
2011-06-28 13:24:24 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-05 19:01:23 -05:00
|
|
|
// Gets the string value if the meta_item is a meta_name_value variant
|
|
|
|
// containing a string, otherwise none
|
2011-07-27 07:19:39 -05:00
|
|
|
fn get_meta_item_value_str(meta: &@ast::meta_item) -> option::t[str] {
|
|
|
|
alt meta.node {
|
|
|
|
ast::meta_name_value(_, v) {
|
|
|
|
alt v.node {
|
|
|
|
ast::lit_str(s, _) { option::some(s) }
|
|
|
|
_ { option::none }
|
2011-07-05 19:01:23 -05:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
|
|
|
_ { option::none }
|
2011-07-05 19:01:23 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn attr_meta(attr: &ast::attribute) -> @ast::meta_item { @attr.node.value }
|
2011-06-28 14:53:59 -05:00
|
|
|
|
2011-07-05 19:01:23 -05:00
|
|
|
// Get the meta_items from inside a vector of attributes
|
2011-08-04 18:20:09 -05:00
|
|
|
fn attr_metas(attrs: &[ast::attribute]) -> [@ast::meta_item] {
|
2011-07-27 07:19:39 -05:00
|
|
|
let mitems = ~[];
|
|
|
|
for a: ast::attribute in attrs { mitems += ~[attr_meta(a)]; }
|
2011-07-05 19:02:51 -05:00
|
|
|
ret mitems;
|
2011-06-28 14:53:59 -05:00
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool {
|
|
|
|
ret alt a.node {
|
|
|
|
ast::meta_word(na) {
|
|
|
|
alt b.node { ast::meta_word(nb) { na == nb } _ { false } }
|
|
|
|
}
|
|
|
|
ast::meta_name_value(na, va) {
|
|
|
|
alt b.node {
|
|
|
|
ast::meta_name_value(nb, vb) { na == nb && va.node == vb.node }
|
|
|
|
_ { false }
|
2011-06-28 14:53:59 -05:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
|
|
|
ast::meta_list(na, la) {
|
|
|
|
|
2011-07-01 14:51:46 -05:00
|
|
|
// FIXME (#607): Needs implementing
|
|
|
|
// This involves probably sorting the list by name and
|
|
|
|
// meta_item variant
|
2011-06-28 14:53:59 -05:00
|
|
|
fail "unimplemented meta_item variant"
|
2011-07-27 07:19:39 -05:00
|
|
|
}
|
2011-06-28 14:53:59 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-04 18:20:09 -05:00
|
|
|
fn contains(haystack: &[@ast::meta_item], needle: @ast::meta_item) -> bool {
|
2011-07-05 04:48:19 -05:00
|
|
|
log #fmt("looking for %s",
|
|
|
|
syntax::print::pprust::meta_item_to_str(*needle));
|
2011-07-27 07:19:39 -05:00
|
|
|
for item: @ast::meta_item in haystack {
|
2011-07-05 04:48:19 -05:00
|
|
|
log #fmt("looking in %s",
|
|
|
|
syntax::print::pprust::meta_item_to_str(*item));
|
2011-07-27 07:19:39 -05:00
|
|
|
if eq(item, needle) { log "found it!"; ret true; }
|
2011-06-28 14:53:59 -05:00
|
|
|
}
|
2011-06-30 16:12:11 -05:00
|
|
|
log "found it not :(";
|
2011-06-28 14:53:59 -05:00
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
|
2011-08-04 18:20:09 -05:00
|
|
|
fn contains_name(metas: &[@ast::meta_item], name: ast::ident) -> bool {
|
2011-07-27 07:19:39 -05:00
|
|
|
let matches = find_meta_items_by_name(metas, name);
|
2011-07-13 20:13:19 -05:00
|
|
|
ret ivec::len(matches) > 0u;
|
|
|
|
}
|
|
|
|
|
2011-07-01 14:51:46 -05:00
|
|
|
// FIXME: This needs to sort by meta_item variant in addition to the item name
|
2011-08-04 18:20:09 -05:00
|
|
|
fn sort_meta_items(items: &[@ast::meta_item]) -> [@ast::meta_item] {
|
2011-07-27 07:19:39 -05:00
|
|
|
fn lteq(ma: &@ast::meta_item, mb: &@ast::meta_item) -> bool {
|
|
|
|
fn key(m: &@ast::meta_item) -> ast::ident {
|
|
|
|
alt m.node {
|
|
|
|
ast::meta_word(name) { name }
|
|
|
|
ast::meta_name_value(name, _) { name }
|
|
|
|
ast::meta_list(name, _) { name }
|
2011-06-28 17:46:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ret key(ma) <= key(mb);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is sort of stupid here, converting to a vec of mutables and back
|
2011-08-04 18:20:09 -05:00
|
|
|
let v: [mutable @ast::meta_item] = ~[mutable];
|
2011-07-27 07:19:39 -05:00
|
|
|
for mi: @ast::meta_item in items { v += ~[mutable mi]; }
|
2011-06-28 17:46:09 -05:00
|
|
|
|
2011-07-12 17:36:36 -05:00
|
|
|
std::sort::ivector::quick_sort(lteq, v);
|
2011-06-28 17:46:09 -05:00
|
|
|
|
2011-08-04 18:20:09 -05:00
|
|
|
let v2: [@ast::meta_item] = ~[];
|
2011-07-27 07:19:39 -05:00
|
|
|
for mi: @ast::meta_item in v { v2 += ~[mi]; }
|
2011-06-28 17:46:09 -05:00
|
|
|
ret v2;
|
|
|
|
}
|
|
|
|
|
2011-08-04 18:20:09 -05:00
|
|
|
fn remove_meta_items_by_name(items: &[@ast::meta_item], name: str) ->
|
|
|
|
[@ast::meta_item] {
|
2011-06-29 16:17:23 -05:00
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
let filter =
|
|
|
|
bind fn (item: &@ast::meta_item, name: str) ->
|
|
|
|
option::t[@ast::meta_item] {
|
|
|
|
if get_meta_item_name(item) != name {
|
|
|
|
option::some(item)
|
|
|
|
} else { option::none }
|
|
|
|
}(_, name);
|
2011-06-29 16:17:23 -05:00
|
|
|
|
2011-07-05 19:57:34 -05:00
|
|
|
ret ivec::filter_map(filter, items);
|
2011-06-29 16:17:23 -05:00
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn require_unique_names(sess: &session::session,
|
2011-08-04 18:20:09 -05:00
|
|
|
metas: &[@ast::meta_item]) {
|
2011-07-27 07:19:39 -05:00
|
|
|
let map = map::mk_hashmap[str, ()](str::hash, str::eq);
|
|
|
|
for meta: @ast::meta_item in metas {
|
|
|
|
let name = get_meta_item_name(meta);
|
|
|
|
if map.contains_key(name) {
|
2011-07-13 17:44:09 -05:00
|
|
|
sess.span_fatal(meta.span,
|
2011-07-05 13:46:02 -05:00
|
|
|
#fmt("duplicate meta item `%s`", name));
|
|
|
|
}
|
|
|
|
map.insert(name, ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn span[T](item: &T) -> ast::spanned[T] {
|
|
|
|
ret {node: item, span: {lo: 0u, hi: 0u}};
|
2011-06-30 18:53:13 -05:00
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn mk_name_value_item_str(name: ast::ident, value: str) -> @ast::meta_item {
|
|
|
|
let value_lit = span(ast::lit_str(value, ast::sk_rc));
|
2011-07-05 19:01:23 -05:00
|
|
|
ret mk_name_value_item(name, value_lit);
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn mk_name_value_item(name: ast::ident, value: ast::lit) -> @ast::meta_item {
|
2011-06-30 18:53:13 -05:00
|
|
|
ret @span(ast::meta_name_value(name, value));
|
|
|
|
}
|
|
|
|
|
2011-08-04 18:20:09 -05:00
|
|
|
fn mk_list_item(name: ast::ident, items: &[@ast::meta_item]) ->
|
2011-07-27 07:19:39 -05:00
|
|
|
@ast::meta_item {
|
2011-06-30 18:53:13 -05:00
|
|
|
ret @span(ast::meta_list(name, items));
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn mk_word_item(name: ast::ident) -> @ast::meta_item {
|
2011-06-30 18:53:13 -05:00
|
|
|
ret @span(ast::meta_word(name));
|
|
|
|
}
|
|
|
|
|
2011-07-27 07:19:39 -05:00
|
|
|
fn mk_attr(item: @ast::meta_item) -> ast::attribute {
|
|
|
|
ret span({style: ast::attr_inner, value: *item});
|
2011-06-30 19:03:08 -05:00
|
|
|
}
|
|
|
|
|
2011-06-28 13:24:24 -05:00
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
|
|
|
// End:
|
|
|
|
//
|