diff options
| author | Brian Anderson <banderson@mozilla.com> | 2012-04-15 01:07:47 -0700 |
|---|---|---|
| committer | Brian Anderson <banderson@mozilla.com> | 2012-04-15 01:43:38 -0700 |
| commit | 4f576275be8473a17052300aabb811a767ad7b1b (patch) | |
| tree | bbd4e2cefeedfee9bcf4b78bc694b5a0df4ab2e2 | |
| parent | 4f4a468e84537b38648bc9591e0f5a385be593e0 (diff) | |
syntax: Cleanup attr module. Closes #1545
| -rw-r--r-- | src/librustsyntax/ast_util.rs | 4 | ||||
| -rw-r--r-- | src/librustsyntax/attr.rs | 401 | ||||
| -rw-r--r-- | src/librustsyntax/parse/eval.rs | 2 | ||||
| -rw-r--r-- | src/rustc/driver/session.rs | 2 | ||||
| -rw-r--r-- | src/rustc/front/test.rs | 2 | ||||
| -rw-r--r-- | src/rustc/metadata/creader.rs | 11 | ||||
| -rw-r--r-- | src/rustc/metadata/decoder.rs | 2 | ||||
| -rw-r--r-- | src/rustc/middle/trans/native.rs | 4 | ||||
| -rw-r--r-- | src/rustdoc/attr_parser.rs | 2 |
9 files changed, 237 insertions, 193 deletions
diff --git a/src/librustsyntax/ast_util.rs b/src/librustsyntax/ast_util.rs index 69c24d1e549..db7d753fffd 100644 --- a/src/librustsyntax/ast_util.rs +++ b/src/librustsyntax/ast_util.rs @@ -5,6 +5,10 @@ fn respan<T: copy>(sp: span, t: T) -> spanned<T> { ret {node: t, span: sp}; } +fn dummy_spanned<T: copy>(t: T) -> spanned<T> { + ret respan(dummy_sp(), t); +} + /* assuming that we're not in macro expansion */ fn mk_sp(lo: uint, hi: uint) -> span { ret {lo: lo, hi: hi, expn_info: none}; diff --git a/src/librustsyntax/attr.rs b/src/librustsyntax/attr.rs index 861e86ec0ee..81c465c2839 100644 --- a/src/librustsyntax/attr.rs +++ b/src/librustsyntax/attr.rs @@ -4,112 +4,89 @@ import std::map; import std::map::hashmap; import either::either; import diagnostic::span_handler; +import ast_util::dummy_spanned; +// Constructors +export mk_name_value_item_str; +export mk_name_value_item; +export mk_list_item; +export mk_word_item; +export mk_attr; + +// Conversion export attr_meta; export attr_metas; -export find_linkage_attrs; -export find_linkage_metas; -export inline_attr; -export find_inline_attr; + +// Accessors +export get_attr_name; +export get_meta_item_name; +export get_meta_item_value_str; +export get_meta_item_list; +export get_name_value_str_pair; + +// Searching export find_attrs_by_name; -export attrs_contains_name; export find_meta_items_by_name; export contains; export contains_name; +export attrs_contains_name; +export first_attr_value_str_by_name; +export last_meta_item_value_str_by_name; +export last_meta_item_list_by_name; + +// Higher-level applications export sort_meta_items; export remove_meta_items_by_name; -export require_unique_names; -export get_attr_name; -export get_meta_item_name; -export get_meta_item_value_str; -export get_meta_item_value_str_by_name; -export get_meta_item_list; -export meta_item_value_from_list; -export meta_item_list_from_list; -export name_value_str_pair; -export mk_name_value_item_str; -export mk_name_value_item; -export mk_list_item; -export mk_word_item; -export mk_attr; +export find_linkage_attrs; +export find_linkage_metas; export native_abi; +export inline_attr; +export find_inline_attr; +export require_unique_names; -// From a list of crate attributes get only the meta_items that impact crate -// linkage -fn find_linkage_metas(attrs: [ast::attribute]) -> [@ast::meta_item] { - find_linkage_attrs(attrs).flat_map {|attr| - alt check attr.node.value.node { - ast::meta_list(_, items) { items } - } - } +/* Constructors */ + +fn mk_name_value_item_str(name: ast::ident, value: str) -> @ast::meta_item { + let value_lit = dummy_spanned(ast::lit_str(value)); + ret mk_name_value_item(name, value_lit); } -fn find_linkage_attrs(attrs: [ast::attribute]) -> [ast::attribute] { - let mut found = []; - for find_attrs_by_name(attrs, "link").each {|attr| - alt attr.node.value.node { - ast::meta_list(_, _) { found += [attr] } - _ { #debug("ignoring link attribute that has incorrect type"); } - } - } - ret found; +fn mk_name_value_item(name: ast::ident, value: ast::lit) -> @ast::meta_item { + ret @dummy_spanned(ast::meta_name_value(name, value)); } -enum inline_attr { - ia_none, - ia_hint, - ia_always +fn mk_list_item(name: ast::ident, items: [@ast::meta_item]) -> + @ast::meta_item { + ret @dummy_spanned(ast::meta_list(name, items)); } -// True if something like #[inline] is found in the list of attrs. -fn find_inline_attr(attrs: [ast::attribute]) -> inline_attr { - // TODO---validate the usage of #[inline] and #[inline(always)] - vec::foldl(ia_none, attrs) {|ia,attr| - alt attr.node.value.node { - ast::meta_word("inline") { ia_hint } - ast::meta_list("inline", items) { - if !vec::is_empty(find_meta_items_by_name(items, "always")) { - ia_always - } else { - ia_hint - } - } - _ { ia } - } - } +fn mk_word_item(name: ast::ident) -> @ast::meta_item { + ret @dummy_spanned(ast::meta_word(name)); } -// Search a list of attributes and return only those with a specific name -fn find_attrs_by_name(attrs: [ast::attribute], name: ast::ident) -> - [ast::attribute] { - let filter = ( - fn@(a: ast::attribute) -> option<ast::attribute> { - if get_attr_name(a) == name { - option::some(a) - } else { option::none } - } - ); - ret vec::filter_map(attrs, filter); +fn mk_attr(item: @ast::meta_item) -> ast::attribute { + ret dummy_spanned({style: ast::attr_inner, value: *item}); } -fn attrs_contains_name(attrs: [ast::attribute], name: ast::ident) -> bool { - vec::is_not_empty(find_attrs_by_name(attrs, name)) + +/* Conversion */ + +fn attr_meta(attr: ast::attribute) -> @ast::meta_item { @attr.node.value } + +// Get the meta_items from inside a vector of attributes +fn attr_metas(attrs: [ast::attribute]) -> [@ast::meta_item] { + let mut mitems = []; + for attrs.each {|a| mitems += [attr_meta(a)]; } + ret mitems; } + +/* Accessors */ + fn get_attr_name(attr: ast::attribute) -> ast::ident { get_meta_item_name(@attr.node.value) } -fn find_meta_items_by_name(metas: [@ast::meta_item], name: ast::ident) -> - [@ast::meta_item] { - let filter = fn@(&&m: @ast::meta_item) -> option<@ast::meta_item> { - if get_meta_item_name(m) == name { - option::some(m) - } else { option::none } - }; - ret vec::filter_map(metas, filter); -} - fn get_meta_item_name(meta: @ast::meta_item) -> ast::ident { alt meta.node { ast::meta_word(n) { n } @@ -118,8 +95,10 @@ fn get_meta_item_name(meta: @ast::meta_item) -> ast::ident { } } -// Gets the string value if the meta_item is a meta_name_value variant -// containing a string, otherwise none +#[doc = " +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(meta: @ast::meta_item) -> option<str> { alt meta.node { ast::meta_name_value(_, v) { @@ -129,15 +108,7 @@ fn get_meta_item_value_str(meta: @ast::meta_item) -> option<str> { } } -fn get_meta_item_value_str_by_name(attrs: [ast::attribute], name: ast::ident) - -> option<str> { - let mattrs = find_attrs_by_name(attrs, name); - if vec::len(mattrs) > 0u { - ret get_meta_item_value_str(attr_meta(mattrs[0])); - } - ret option::none; -} - +#[doc = "Gets a list of inner meta items from a list meta_item type"] fn get_meta_item_list(meta: @ast::meta_item) -> option<[@ast::meta_item]> { alt meta.node { ast::meta_list(_, l) { option::some(l) } @@ -145,13 +116,67 @@ fn get_meta_item_list(meta: @ast::meta_item) -> option<[@ast::meta_item]> { } } -fn attr_meta(attr: ast::attribute) -> @ast::meta_item { @attr.node.value } +#[doc = " +If the meta item is a nam-value type with a string value then returns +a tuple containing the name and string value, otherwise `none` +"] +fn get_name_value_str_pair( + item: @ast::meta_item +) -> option<(str, str)> { + alt attr::get_meta_item_value_str(item) { + some(value) { + let name = attr::get_meta_item_name(item); + some((name, value)) + } + none { none } + } +} -// Get the meta_items from inside a vector of attributes -fn attr_metas(attrs: [ast::attribute]) -> [@ast::meta_item] { - let mut mitems = []; - for attrs.each {|a| mitems += [attr_meta(a)]; } - ret mitems; + +/* Searching */ + +#[doc = " +Search a list of attributes and return only those with a specific name +"] +fn find_attrs_by_name(attrs: [ast::attribute], name: ast::ident) -> + [ast::attribute] { + let filter = ( + fn@(a: ast::attribute) -> option<ast::attribute> { + if get_attr_name(a) == name { + option::some(a) + } else { option::none } + } + ); + ret vec::filter_map(attrs, filter); +} + +#[doc = " +Searcha list of meta items and return only those with a specific name +"] +fn find_meta_items_by_name(metas: [@ast::meta_item], name: ast::ident) -> + [@ast::meta_item] { + let filter = fn@(&&m: @ast::meta_item) -> option<@ast::meta_item> { + if get_meta_item_name(m) == name { + option::some(m) + } else { option::none } + }; + ret vec::filter_map(metas, filter); +} + +#[doc = " +Returns true if a list of meta items contains another meta item. The +comparison is performed structurally. +"] +fn contains(haystack: [@ast::meta_item], needle: @ast::meta_item) -> bool { + #debug("looking for %s", + print::pprust::meta_item_to_str(*needle)); + for haystack.each {|item| + #debug("looking in %s", + print::pprust::meta_item_to_str(*item)); + if eq(item, needle) { #debug("found it!"); ret true; } + } + #debug("found it not :("); + ret false; } fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool { @@ -175,23 +200,62 @@ fn eq(a: @ast::meta_item, b: @ast::meta_item) -> bool { } } -fn contains(haystack: [@ast::meta_item], needle: @ast::meta_item) -> bool { - #debug("looking for %s", - print::pprust::meta_item_to_str(*needle)); - for haystack.each {|item| - #debug("looking in %s", - print::pprust::meta_item_to_str(*item)); - if eq(item, needle) { #debug("found it!"); ret true; } - } - #debug("found it not :("); - ret false; -} - fn contains_name(metas: [@ast::meta_item], name: ast::ident) -> bool { let matches = find_meta_items_by_name(metas, name); ret vec::len(matches) > 0u; } +fn attrs_contains_name(attrs: [ast::attribute], name: ast::ident) -> bool { + vec::is_not_empty(find_attrs_by_name(attrs, name)) +} + +fn first_attr_value_str_by_name(attrs: [ast::attribute], name: ast::ident) + -> option<str> { + let mattrs = find_attrs_by_name(attrs, name); + if vec::len(mattrs) > 0u { + ret get_meta_item_value_str(attr_meta(mattrs[0])); + } + ret option::none; +} + +fn last_meta_item_by_name( + items: [@ast::meta_item], + name: str +) -> option<@ast::meta_item> { + let items = attr::find_meta_items_by_name(items, name); + vec::last_opt(items) +} + +fn last_meta_item_value_str_by_name( + items: [@ast::meta_item], + name: str +) -> option<str> { + alt last_meta_item_by_name(items, name) { + some(item) { + alt attr::get_meta_item_value_str(item) { + some(value) { some(value) } + none { none } + } + } + none { none } + } +} + +fn last_meta_item_list_by_name( + items: [@ast::meta_item], + name: str +) -> option<[@ast::meta_item]> { + alt last_meta_item_by_name(items, name) { + some(item) { + attr::get_meta_item_list(item) + } + none { none } + } +} + + +/* Higher-level applications */ + // FIXME: This needs to sort by meta_item variant in addition to the item name fn sort_meta_items(items: [@ast::meta_item]) -> [@ast::meta_item] { fn lteq(&&ma: @ast::meta_item, &&mb: @ast::meta_item) -> bool { @@ -228,21 +292,31 @@ fn remove_meta_items_by_name(items: [@ast::meta_item], name: str) -> ret vec::filter_map(items, filter); } -fn require_unique_names(diagnostic: span_handler, - metas: [@ast::meta_item]) { - let map = map::str_hash(); - for metas.each {|meta| - let name = get_meta_item_name(meta); - if map.contains_key(name) { - diagnostic.span_fatal(meta.span, - #fmt["duplicate meta item `%s`", name]); +fn find_linkage_attrs(attrs: [ast::attribute]) -> [ast::attribute] { + let mut found = []; + for find_attrs_by_name(attrs, "link").each {|attr| + alt attr.node.value.node { + ast::meta_list(_, _) { found += [attr] } + _ { #debug("ignoring link attribute that has incorrect type"); } + } + } + ret found; +} + +#[doc = " +From a list of crate attributes get only the meta_items that impact crate +linkage +"] +fn find_linkage_metas(attrs: [ast::attribute]) -> [@ast::meta_item] { + find_linkage_attrs(attrs).flat_map {|attr| + alt check attr.node.value.node { + ast::meta_list(_, items) { items } } - map.insert(name, ()); } } fn native_abi(attrs: [ast::attribute]) -> either<str, ast::native_abi> { - ret alt attr::get_meta_item_value_str_by_name(attrs, "abi") { + ret alt attr::first_attr_value_str_by_name(attrs, "abi") { option::none { either::right(ast::native_abi_cdecl) } @@ -261,79 +335,44 @@ fn native_abi(attrs: [ast::attribute]) -> either<str, ast::native_abi> { }; } -fn meta_item_from_list( - items: [@ast::meta_item], - name: str -) -> option<@ast::meta_item> { - let items = attr::find_meta_items_by_name(items, name); - vec::last_opt(items) +enum inline_attr { + ia_none, + ia_hint, + ia_always } -fn meta_item_value_from_list( - items: [@ast::meta_item], - name: str -) -> option<str> { - alt meta_item_from_list(items, name) { - some(item) { - alt attr::get_meta_item_value_str(item) { - some(value) { some(value) } - none { none } +#[doc = "True if something like #[inline] is found in the list of attrs."] +fn find_inline_attr(attrs: [ast::attribute]) -> inline_attr { + // TODO---validate the usage of #[inline] and #[inline(always)] + vec::foldl(ia_none, attrs) {|ia,attr| + alt attr.node.value.node { + ast::meta_word("inline") { ia_hint } + ast::meta_list("inline", items) { + if !vec::is_empty(find_meta_items_by_name(items, "always")) { + ia_always + } else { + ia_hint + } + } + _ { ia } } - } - none { none } } } -fn meta_item_list_from_list( - items: [@ast::meta_item], - name: str -) -> option<[@ast::meta_item]> { - alt meta_item_from_list(items, name) { - some(item) { - attr::get_meta_item_list(item) - } - none { none } - } -} -fn name_value_str_pair( - item: @ast::meta_item -) -> option<(str, str)> { - alt attr::get_meta_item_value_str(item) { - some(value) { - let name = attr::get_meta_item_name(item); - some((name, value)) - } - none { none } +fn require_unique_names(diagnostic: span_handler, + metas: [@ast::meta_item]) { + let map = map::str_hash(); + for metas.each {|meta| + let name = get_meta_item_name(meta); + if map.contains_key(name) { + diagnostic.span_fatal(meta.span, + #fmt["duplicate meta item `%s`", name]); + } + map.insert(name, ()); } } -fn span<T: copy>(item: T) -> ast::spanned<T> { - ret {node: item, span: ast_util::dummy_sp()}; -} - -fn mk_name_value_item_str(name: ast::ident, value: str) -> @ast::meta_item { - let value_lit = span(ast::lit_str(value)); - ret mk_name_value_item(name, value_lit); -} - -fn mk_name_value_item(name: ast::ident, value: ast::lit) -> @ast::meta_item { - ret @span(ast::meta_name_value(name, value)); -} - -fn mk_list_item(name: ast::ident, items: [@ast::meta_item]) -> - @ast::meta_item { - ret @span(ast::meta_list(name, items)); -} - -fn mk_word_item(name: ast::ident) -> @ast::meta_item { - ret @span(ast::meta_word(name)); -} - -fn mk_attr(item: @ast::meta_item) -> ast::attribute { - ret span({style: ast::attr_inner, value: *item}); -} - // // Local Variables: // mode: rust diff --git a/src/librustsyntax/parse/eval.rs b/src/librustsyntax/parse/eval.rs index d01667d1029..75824152f5d 100644 --- a/src/librustsyntax/parse/eval.rs +++ b/src/librustsyntax/parse/eval.rs @@ -81,7 +81,7 @@ fn parse_companion_mod(cx: ctx, prefix: str, suffix: option<str>) } fn cdir_path_opt(id: str, attrs: [ast::attribute]) -> str { - alt attr::get_meta_item_value_str_by_name(attrs, "path") { + alt attr::first_attr_value_str_by_name(attrs, "path") { some(d) { ret d; } diff --git a/src/rustc/driver/session.rs b/src/rustc/driver/session.rs index af978db1a77..f452500d873 100644 --- a/src/rustc/driver/session.rs +++ b/src/rustc/driver/session.rs @@ -129,7 +129,7 @@ fn building_library(req_crate_type: crate_type, crate: @ast::crate, if testing { false } else { - alt syntax::attr::get_meta_item_value_str_by_name( + alt syntax::attr::first_attr_value_str_by_name( crate.node.attrs, "crate_type") { option::some("lib") { true } diff --git a/src/rustc/front/test.rs b/src/rustc/front/test.rs index aa1090cb2ae..11010dade08 100644 --- a/src/rustc/front/test.rs +++ b/src/rustc/front/test.rs @@ -238,7 +238,7 @@ fn mk_path(cx: test_ctxt, path: [ast::ident]) -> [ast::ident] { // the paths with std:: let is_std = { let items = attr::find_linkage_metas(cx.crate.node.attrs); - alt attr::meta_item_value_from_list(items, "name") { + alt attr::last_meta_item_value_str_by_name(items, "name") { some("std") { true } _ { false } } diff --git a/src/rustc/metadata/creader.rs b/src/rustc/metadata/creader.rs index a24180238b7..1f4bc2cdcf7 100644 --- a/src/rustc/metadata/creader.rs +++ b/src/rustc/metadata/creader.rs @@ -115,7 +115,7 @@ fn visit_item(e: env, i: @ast::item) { let cstore = e.sess.cstore; let native_name = - alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") { + alt attr::first_attr_value_str_by_name(i.attrs, "link_name") { some(nn) { if nn == "" { e.sess.span_fatal( @@ -387,10 +387,11 @@ fn resolve_crate(e: env, ident: ast::ident, metas: [@ast::meta_item], // Now resolve the crates referenced by this crate let cnum_map = resolve_crate_deps(e, cdata); - let cname = alt attr::meta_item_value_from_list(metas, "name") { - option::some(v) { v } - option::none { ident } - }; + let cname = + alt attr::last_meta_item_value_str_by_name(metas, "name") { + option::some(v) { v } + option::none { ident } + }; let cmeta = @{name: cname, data: cdata, cnum_map: cnum_map, cnum: cnum}; diff --git a/src/rustc/metadata/decoder.rs b/src/rustc/metadata/decoder.rs index 015f9d27258..ab33355dee2 100644 --- a/src/rustc/metadata/decoder.rs +++ b/src/rustc/metadata/decoder.rs @@ -620,7 +620,7 @@ fn get_crate_hash(data: @[u8]) -> str { fn get_crate_vers(data: @[u8]) -> str { let attrs = decoder::get_crate_attributes(data); - ret alt attr::meta_item_value_from_list( + ret alt attr::last_meta_item_value_str_by_name( attr::find_linkage_metas(attrs), "vers") { some(ver) { ver } none { "0.0" } diff --git a/src/rustc/middle/trans/native.rs b/src/rustc/middle/trans/native.rs index d8ab88e04ee..5f98915b3c7 100644 --- a/src/rustc/middle/trans/native.rs +++ b/src/rustc/middle/trans/native.rs @@ -395,7 +395,7 @@ fn decl_x86_64_fn(tys: x86_64_tys, } fn link_name(i: @ast::native_item) -> str { - alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") { + alt attr::first_attr_value_str_by_name(i.attrs, "link_name") { none { ret i.ident; } option::some(ln) { ret ln; } } @@ -989,7 +989,7 @@ fn register_crust_fn(ccx: @crate_ctxt, sp: span, fn abi_of_native_fn(ccx: @crate_ctxt, i: @ast::native_item) -> ast::native_abi { - alt attr::get_meta_item_value_str_by_name(i.attrs, "abi") { + alt attr::first_attr_value_str_by_name(i.attrs, "abi") { none { alt check ccx.tcx.items.get(i.id) { ast_map::node_native_item(_, abi, _) { abi } diff --git a/src/rustdoc/attr_parser.rs b/src/rustdoc/attr_parser.rs index dd5c9ade7a2..60da58b83b6 100644 --- a/src/rustdoc/attr_parser.rs +++ b/src/rustdoc/attr_parser.rs @@ -65,7 +65,7 @@ fn parse_crate(attrs: [ast::attribute]) -> crate_attrs { let link_metas = attr::find_linkage_metas(attrs); { - name: attr::meta_item_value_from_list(link_metas, "name") + name: attr::last_meta_item_value_str_by_name(link_metas, "name") } } |
