2011-06-28 17:25:20 -05:00
|
|
|
// Functions dealing with attributes and meta_items
|
|
|
|
|
2011-06-28 13:24:24 -05:00
|
|
|
import std::vec;
|
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-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-07-06 13:26:26 -05:00
|
|
|
fn find_linkage_metas(vec[ast::attribute] attrs) -> vec[@ast::meta_item] {
|
|
|
|
let vec[@ast::meta_item] metas = [];
|
2011-06-28 13:24:24 -05:00
|
|
|
for (ast::attribute attr in find_attrs_by_name(attrs, "link")) {
|
|
|
|
alt (attr.node.value.node) {
|
2011-07-06 13:26:26 -05:00
|
|
|
case (ast::meta_list(_, ?items)) {
|
|
|
|
metas += items;
|
|
|
|
}
|
2011-06-28 13:24:24 -05:00
|
|
|
case (_) {
|
2011-07-01 14:30:27 -05:00
|
|
|
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-07-06 13:26:26 -05:00
|
|
|
fn find_attrs_by_name(vec[ast::attribute] attrs,
|
|
|
|
ast::ident name) -> vec[ast::attribute] {
|
2011-06-28 13:24:24 -05:00
|
|
|
auto filter = bind fn(&ast::attribute a,
|
|
|
|
ast::ident name) -> option::t[ast::attribute] {
|
|
|
|
if (get_attr_name(a) == name) {
|
|
|
|
option::some(a)
|
|
|
|
} else {
|
|
|
|
option::none
|
|
|
|
}
|
|
|
|
} (_, name);
|
2011-07-06 13:26:26 -05:00
|
|
|
ret vec::filter_map(filter, attrs);
|
2011-06-28 13:24:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_attr_name(&ast::attribute attr) -> ast::ident {
|
|
|
|
get_meta_item_name(@attr.node.value)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_meta_items_by_name(vec[@ast::meta_item] metas,
|
|
|
|
ast::ident name) -> vec[@ast::meta_item] {
|
|
|
|
auto filter = bind fn(&@ast::meta_item m,
|
|
|
|
ast::ident name) -> option::t[@ast::meta_item] {
|
|
|
|
if (get_meta_item_name(m) == name) {
|
|
|
|
option::some(m)
|
|
|
|
} else {
|
|
|
|
option::none
|
|
|
|
}
|
|
|
|
} (_, name);
|
|
|
|
ret vec::filter_map(filter, metas);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_meta_item_name(&@ast::meta_item meta) -> ast::ident {
|
|
|
|
alt (meta.node) {
|
|
|
|
case (ast::meta_word(?n)) { n }
|
|
|
|
case (ast::meta_name_value(?n, _)) { n }
|
|
|
|
case (ast::meta_list(?n, _)) { n }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
fn get_meta_item_value_str(&@ast::meta_item meta) -> option::t[str] {
|
|
|
|
alt (meta.node) {
|
|
|
|
case (ast::meta_name_value(_, ?v)) {
|
|
|
|
alt (v.node) {
|
|
|
|
case (ast::lit_str(?s, _)) {
|
|
|
|
option::some(s)
|
|
|
|
}
|
|
|
|
case (_) { option::none }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (_) { option::none }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-28 14:53:59 -05:00
|
|
|
fn attr_meta(&ast::attribute attr) -> @ast::meta_item { @attr.node.value }
|
|
|
|
|
2011-07-05 19:01:23 -05:00
|
|
|
// Get the meta_items from inside a vector of attributes
|
2011-07-06 13:26:26 -05:00
|
|
|
fn attr_metas(&vec[ast::attribute] attrs) -> vec[@ast::meta_item] {
|
|
|
|
ret vec::map(attr_meta, attrs);
|
2011-06-28 14:53:59 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn eq(@ast::meta_item a, @ast::meta_item b) -> bool {
|
|
|
|
ret alt (a.node) {
|
|
|
|
case (ast::meta_word(?na)) {
|
|
|
|
alt (b.node) {
|
|
|
|
case(ast::meta_word(?nb)) { na == nb }
|
|
|
|
case(_) { false }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (ast::meta_name_value(?na, ?va)) {
|
|
|
|
alt (b.node) {
|
2011-07-05 19:01:23 -05:00
|
|
|
case (ast::meta_name_value(?nb, ?vb)) {
|
|
|
|
na == nb && va.node == vb.node
|
|
|
|
}
|
2011-06-28 14:53:59 -05:00
|
|
|
case (_) { false }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case (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-06 13:26:26 -05:00
|
|
|
fn contains(&vec[@ast::meta_item] haystack, @ast::meta_item needle) -> bool {
|
2011-07-05 04:48:19 -05:00
|
|
|
log #fmt("looking for %s",
|
|
|
|
syntax::print::pprust::meta_item_to_str(*needle));
|
2011-06-28 14:53:59 -05:00
|
|
|
for (@ast::meta_item 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-06-28 14:53:59 -05:00
|
|
|
if (eq(item, needle)) {
|
2011-06-30 16:12:11 -05:00
|
|
|
log "found it!";
|
2011-06-28 14:53:59 -05:00
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
}
|
2011-06-30 16:12:11 -05:00
|
|
|
log "found it not :(";
|
2011-06-28 14:53:59 -05:00
|
|
|
ret false;
|
|
|
|
}
|
|
|
|
|
2011-07-01 14:51:46 -05:00
|
|
|
// FIXME: This needs to sort by meta_item variant in addition to the item name
|
2011-06-28 17:46:09 -05:00
|
|
|
fn sort_meta_items(&vec[@ast::meta_item] items) -> vec[@ast::meta_item] {
|
|
|
|
fn lteq(&@ast::meta_item ma, &@ast::meta_item mb) -> bool {
|
|
|
|
fn key(&@ast::meta_item m) -> ast::ident {
|
|
|
|
alt (m.node) {
|
|
|
|
case (ast::meta_word(?name)) {
|
|
|
|
name
|
|
|
|
}
|
|
|
|
case (ast::meta_name_value(?name, _)) {
|
|
|
|
name
|
|
|
|
}
|
|
|
|
case (ast::meta_list(?name, _)) {
|
|
|
|
name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret key(ma) <= key(mb);
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is sort of stupid here, converting to a vec of mutables and back
|
|
|
|
let vec[mutable @ast::meta_item] v = [mutable ];
|
|
|
|
for (@ast::meta_item mi in items) {
|
|
|
|
v += [mutable mi];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::sort::quick_sort(lteq, v);
|
|
|
|
|
|
|
|
let vec[@ast::meta_item] v2 = [];
|
|
|
|
for (@ast::meta_item mi in v) {
|
|
|
|
v2 += [mi]
|
|
|
|
}
|
|
|
|
ret v2;
|
|
|
|
}
|
|
|
|
|
2011-06-29 16:17:23 -05:00
|
|
|
fn remove_meta_items_by_name(&vec[@ast::meta_item] items,
|
|
|
|
str name) -> vec[@ast::meta_item] {
|
|
|
|
|
|
|
|
auto filter = bind fn(&@ast::meta_item item,
|
|
|
|
str name) -> option::t[@ast::meta_item] {
|
|
|
|
if (get_meta_item_name(item) != name) {
|
|
|
|
option::some(item)
|
|
|
|
} else {
|
|
|
|
option::none
|
|
|
|
}
|
|
|
|
} (_, name);
|
|
|
|
|
|
|
|
ret vec::filter_map(filter, items);
|
|
|
|
}
|
|
|
|
|
2011-07-05 13:46:02 -05:00
|
|
|
fn require_unique_names(&session::session sess, &vec[@ast::meta_item] metas) {
|
|
|
|
auto map = map::mk_hashmap[str, ()](str::hash, str::eq);
|
|
|
|
for (@ast::meta_item meta in metas) {
|
|
|
|
auto name = get_meta_item_name(meta);
|
|
|
|
if (map.contains_key(name)) {
|
|
|
|
sess.span_fatal(meta.span,
|
|
|
|
#fmt("duplicate meta item `%s`", name));
|
|
|
|
}
|
|
|
|
map.insert(name, ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-05 04:48:19 -05:00
|
|
|
fn span[T](&T item) -> ast::spanned[T] {
|
2011-06-30 18:53:13 -05:00
|
|
|
ret rec(node=item, span=rec(lo=0u, hi=0u));
|
|
|
|
}
|
|
|
|
|
2011-07-05 19:01:23 -05:00
|
|
|
fn mk_name_value_item_str(ast::ident name, str value) -> @ast::meta_item {
|
|
|
|
auto value_lit = span(ast::lit_str(value, ast::sk_rc));
|
|
|
|
ret mk_name_value_item(name, value_lit);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mk_name_value_item(ast::ident name, ast::lit value) -> @ast::meta_item {
|
2011-06-30 18:53:13 -05:00
|
|
|
ret @span(ast::meta_name_value(name, value));
|
|
|
|
}
|
|
|
|
|
2011-07-06 13:26:26 -05:00
|
|
|
fn mk_list_item(ast::ident name,
|
|
|
|
&vec[@ast::meta_item] items) -> @ast::meta_item {
|
2011-06-30 18:53:13 -05:00
|
|
|
ret @span(ast::meta_list(name, items));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mk_word_item(ast::ident name) -> @ast::meta_item {
|
|
|
|
ret @span(ast::meta_word(name));
|
|
|
|
}
|
|
|
|
|
2011-06-30 19:03:08 -05:00
|
|
|
fn mk_attr(@ast::meta_item item) -> ast::attribute {
|
|
|
|
ret span(rec(style = ast::attr_inner,
|
|
|
|
value = *item));
|
|
|
|
}
|
|
|
|
|
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:
|
|
|
|
//
|