From f53c4f79d75cd70264f54c1384daa9e653adbefe Mon Sep 17 00:00:00 2001
From: Brian Anderson <banderson@mozilla.com>
Date: Mon, 27 Jun 2011 19:41:48 -0700
Subject: [PATCH] Write metadata for crate attributes. Issue #487

---
 src/comp/metadata/decoder.rs | 37 ++++++++++++++++++++++++---
 src/comp/metadata/encoder.rs | 48 +++++++++++++++++++++++-------------
 src/comp/metadata/tags.rs    |  7 +++++-
 src/comp/pretty/pprust.rs    |  4 +++
 4 files changed, 74 insertions(+), 22 deletions(-)

diff --git a/src/comp/metadata/decoder.rs b/src/comp/metadata/decoder.rs
index 1da65b97e34..500b3f31137 100644
--- a/src/comp/metadata/decoder.rs
+++ b/src/comp/metadata/decoder.rs
@@ -259,7 +259,7 @@ fn item_kind_to_str(u8 kind) -> str {
 fn get_meta_items(&ebml::doc md) -> vec[ast::meta_item] {
     let vec[ast::meta_item] items = [];
     for each (ebml::doc meta_item_doc in
-              ebml::tagged_docs(md, tag_meta_item)) {
+              ebml::tagged_docs(md, tag_meta_item_key_value)) {
         auto kd = ebml::get_doc(meta_item_doc, tag_meta_item_key);
         auto vd = ebml::get_doc(meta_item_doc, tag_meta_item_value);
         auto k = str::unsafe_from_bytes(ebml::doc_data(kd));
@@ -270,6 +270,27 @@ fn get_meta_items(&ebml::doc md) -> vec[ast::meta_item] {
     ret items;
 }
 
+fn get_attributes(&ebml::doc md) -> vec[ast::attribute] {
+    let vec[ast::attribute] attrs = [];
+    alt (ebml::maybe_get_doc(md, tag_attributes)) {
+        case (option::some(?attrs_d)) {
+            for each (ebml::doc attr_doc in
+                      ebml::tagged_docs(attrs_d, tag_attribute)) {
+                auto meta_items = get_meta_items(attr_doc);
+                // Currently it's only possible to have a single meta item on
+                // an attribute
+                assert (vec::len(meta_items) == 1u);
+                auto meta_item = meta_items.(0);
+                attrs += [rec(node=rec(style=ast::attr_outer,
+                                       value=meta_item),
+                              span=rec(lo=0u, hi=0u))];
+            }
+        }
+        case (option::none) { }
+    }
+    ret attrs;
+}
+
 fn list_meta_items(&ebml::doc meta_items, io::writer out) {
     for (ast::meta_item mi in get_meta_items(meta_items)) {
         out.write_str(#fmt("%s\n", pprust::meta_item_to_str(mi)));
@@ -277,10 +298,18 @@ fn list_meta_items(&ebml::doc meta_items, io::writer out) {
 }
 
 fn list_crate_attributes(&ebml::doc md, io::writer out) {
-    out.write_str("=Crate=\n");
+    out.write_str("=Crate=");
+
+    // FIXME: This is transitional until attributes are snapshotted
+    out.write_str("old-style:\n");
     auto meta_items = ebml::get_doc(md, tag_meta_export);
     list_meta_items(meta_items, out);
-    out.write_str("\n");
+
+    for (ast::attribute attr in get_attributes(md)) {
+        out.write_str(#fmt("%s", pprust::attribute_to_str(attr)));
+    }
+
+    out.write_str("\n\n");
 }
 
 fn list_crate_items(vec[u8] bytes, &ebml::doc md, io::writer out) {
@@ -316,7 +345,7 @@ fn get_exported_metadata(&session::session sess, &str path, &vec[u8] data) ->
         ebml::get_doc(ebml::new_doc(data), tag_meta_export);
     auto mm = common::new_str_hash[str]();
     for each (ebml::doc m in
-             ebml::tagged_docs(meta_items, tag_meta_item)) {
+             ebml::tagged_docs(meta_items, tag_meta_item_key_value)) {
         auto kd = ebml::get_doc(m, tag_meta_item_key);
         auto vd = ebml::get_doc(m, tag_meta_item_value);
         auto k = str::unsafe_from_bytes(ebml::doc_data(kd));
diff --git a/src/comp/metadata/encoder.rs b/src/comp/metadata/encoder.rs
index 3b74f79ab88..da3b5bcb1b2 100644
--- a/src/comp/metadata/encoder.rs
+++ b/src/comp/metadata/encoder.rs
@@ -416,25 +416,36 @@ fn write_int(&io::writer writer, &int n) {
     writer.write_be_uint(n as uint, 4u);
 }
 
-fn encode_meta_items(&ebml::writer ebml_w, &crate crate) {
-    fn encode_meta_item(&ebml::writer ebml_w, &meta_item mi) {
-        // FIXME (#487): Support all forms of meta item
-        ebml::start_tag(ebml_w, tag_meta_item);
-        alt (mi.node) {
-            case (meta_key_value(?key, ?value)) {
-                ebml::start_tag(ebml_w, tag_meta_item_key);
-                ebml_w.writer.write(str::bytes(key));
-                ebml::end_tag(ebml_w);
-                ebml::start_tag(ebml_w, tag_meta_item_value);
-                ebml_w.writer.write(str::bytes(value));
-                ebml::end_tag(ebml_w);
-            }
-            case (_) {
-                log_err "unimplemented meta_item type";
-            }
+fn encode_meta_item(&ebml::writer ebml_w, &meta_item mi) {
+    // FIXME (#487): Support all forms of meta item
+    ebml::start_tag(ebml_w, tag_meta_item_key_value);
+    alt (mi.node) {
+        case (meta_key_value(?key, ?value)) {
+            ebml::start_tag(ebml_w, tag_meta_item_key);
+            ebml_w.writer.write(str::bytes(key));
+            ebml::end_tag(ebml_w);
+            ebml::start_tag(ebml_w, tag_meta_item_value);
+            ebml_w.writer.write(str::bytes(value));
+            ebml::end_tag(ebml_w);
         }
+        case (_) {
+            log_err "unimplemented meta_item type";
+        }
+    }
+    ebml::end_tag(ebml_w);
+}
+
+fn encode_attributes(&ebml::writer ebml_w, &vec[attribute] attrs) {
+    ebml::start_tag(ebml_w, tag_attributes);
+    for (attribute attr in attrs) {
+        ebml::start_tag(ebml_w, tag_attribute);
+        encode_meta_item(ebml_w, attr.node.value);
         ebml::end_tag(ebml_w);
     }
+    ebml::end_tag(ebml_w);
+}
+
+fn encode_meta_items(&ebml::writer ebml_w, &crate crate) {
     ebml::start_tag(ebml_w, tag_meta_export);
     for each (@meta_item mi in crate_export_metas(crate)) {
         encode_meta_item(ebml_w, *mi);
@@ -451,9 +462,12 @@ fn encode_metadata(&@crate_ctxt cx, &@crate crate) -> str {
     auto string_w = io::string_writer();
     auto buf_w = string_w.get_writer().get_buf_writer();
     auto ebml_w = ebml::create_writer(buf_w);
-    // Encode the meta items
 
+    // FIXME: This is the old way of encoding crate meta items
+    // Remove after going through a snapshot cycle
     encode_meta_items(ebml_w, *crate);
+    // Encode crate attributes
+    encode_attributes(ebml_w, crate.node.attrs);
     // Encode and index the paths.
 
     ebml::start_tag(ebml_w, tag_paths);
diff --git a/src/comp/metadata/tags.rs b/src/comp/metadata/tags.rs
index 9ce5a7947f5..856023b0b90 100644
--- a/src/comp/metadata/tags.rs
+++ b/src/comp/metadata/tags.rs
@@ -44,8 +44,13 @@ const uint tag_meta_export = 0x16u;
 
 const uint tag_meta_local = 0x17u;
 
-const uint tag_meta_item = 0x18u;
+const uint tag_meta_item_key_value = 0x18u;
 
 const uint tag_meta_item_key = 0x19u;
 
 const uint tag_meta_item_value = 0x20u;
+
+const uint tag_attributes = 0x21u;
+
+const uint tag_attribute = 0x22u;
+
diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs
index 1e4d89cddcb..a092dc86ddd 100644
--- a/src/comp/pretty/pprust.rs
+++ b/src/comp/pretty/pprust.rs
@@ -84,6 +84,10 @@ fn meta_item_to_str(&ast::meta_item mi) -> str {
     ret to_str(@mi, print_meta_item);
 }
 
+fn attribute_to_str(&ast::attribute attr) -> str {
+    be to_str(attr, print_attribute);
+}
+
 fn cbox(&ps s, uint u) {
     vec::push(s.boxes, pp::consistent);
     pp::cbox(s.s, u);