about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2012-04-15 01:07:47 -0700
committerBrian Anderson <banderson@mozilla.com>2012-04-15 01:43:38 -0700
commit4f576275be8473a17052300aabb811a767ad7b1b (patch)
treebbd4e2cefeedfee9bcf4b78bc694b5a0df4ab2e2
parent4f4a468e84537b38648bc9591e0f5a385be593e0 (diff)
syntax: Cleanup attr module. Closes #1545
-rw-r--r--src/librustsyntax/ast_util.rs4
-rw-r--r--src/librustsyntax/attr.rs401
-rw-r--r--src/librustsyntax/parse/eval.rs2
-rw-r--r--src/rustc/driver/session.rs2
-rw-r--r--src/rustc/front/test.rs2
-rw-r--r--src/rustc/metadata/creader.rs11
-rw-r--r--src/rustc/metadata/decoder.rs2
-rw-r--r--src/rustc/middle/trans/native.rs4
-rw-r--r--src/rustdoc/attr_parser.rs2
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")
     }
 }