From 9671d214082016e61b59bd67bb6d4e295188a2a4 Mon Sep 17 00:00:00 2001
From: Graydon Hoare <graydon@mozilla.com>
Date: Fri, 10 Jun 2011 15:54:41 -0700
Subject: [PATCH] Implement meta tag matching in creader. Start using it in
 rustc.rc. Close #459. Close #457.

---
 src/comp/front/creader.rs              | 50 ++++++++++++++++++++++++--
 src/comp/front/eval.rs                 |  3 --
 src/comp/rustc.rc                      |  4 ++-
 src/test/run-pass/use-import-export.rs |  4 +--
 src/test/run-pass/use.rs               |  4 +--
 5 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs
index 6abae3c61b7..7b92a6d6641 100644
--- a/src/comp/front/creader.rs
+++ b/src/comp/front/creader.rs
@@ -505,9 +505,54 @@ fn get_metadata_section(str filename) -> option::t[vec[u8]] {
     ret option::none[vec[u8]];
 }
 
+fn get_exported_metadata(&session::session sess,
+                         &str path,
+                         &vec[u8] data) -> hashmap[str,str] {
+    auto meta_items = ebml::get_doc(ebml::new_doc(data),
+                                    metadata::tag_meta_export);
+    auto mm = common::new_str_hash[str]();
 
-fn metadata_matches(&vec[u8] data,
+    for each (ebml::doc m in ebml::tagged_docs(meta_items,
+                                               metadata::tag_meta_item)) {
+
+        auto kd = ebml::get_doc(m, metadata::tag_meta_item_key);
+        auto vd = ebml::get_doc(m, metadata::tag_meta_item_value);
+
+        auto k = str::unsafe_from_bytes(ebml::doc_data(kd));
+        auto v = str::unsafe_from_bytes(ebml::doc_data(vd));
+
+        log #fmt("metadata in %s: %s = %s", path, k, v);
+
+        if (!mm.insert(k,v)) {
+            sess.warn(#fmt("Duplicate metadata item in %s: %s", path, k));
+        }
+    }
+    ret mm;
+}
+
+fn metadata_matches(hashmap[str,str] mm,
                     &vec[@ast::meta_item] metas) -> bool {
+    log #fmt("matching %u metadata requirements against %u metadata items",
+             vec::len(metas), mm.size());
+    for (@ast::meta_item mi in metas) {
+        alt (mm.find(mi.node.key)) {
+            case (some(?v)) {
+                if (v == mi.node.value) {
+                    log #fmt("matched '%s': '%s'",
+                             mi.node.key, mi.node.value);
+                } else {
+                    log #fmt("missing '%s': '%s' (got '%s')",
+                             mi.node.key, mi.node.value, v);
+                    ret false;
+                }
+            }
+            case (none) {
+                    log #fmt("missing '%s': '%s'",
+                             mi.node.key, mi.node.value);
+                    ret false;
+            }
+        }
+    }
     ret true;
 }
 
@@ -547,7 +592,8 @@ fn find_library_crate(&session::session sess,
 
             alt (get_metadata_section(path)) {
                 case (option::some(?cvec)) {
-                    if (!metadata_matches(cvec, metas)) {
+                    auto mm = get_exported_metadata(sess, path, cvec);
+                    if (!metadata_matches(mm, metas)) {
                         log #fmt("skipping %s, metadata doesn't match", path);
                         cont;
                     }
diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs
index 567066436e4..b311c56b884 100644
--- a/src/comp/front/eval.rs
+++ b/src/comp/front/eval.rs
@@ -419,9 +419,6 @@ fn eval_crate_directive(ctx cx,
         }
 
         case (ast::cdir_meta(?vi, ?mi)) {
-            // FIXME: we should actually record, for documentation-sake,
-            // the metadata that's not exported. It would be nice to have
-            // compiled-in to the target crate, not just in theh AST.
             if (vi == ast::export_meta) {
                 cx.sess.add_metadata(mi);
             }
diff --git a/src/comp/rustc.rc b/src/comp/rustc.rc
index ebd62b99fc3..39879894753 100644
--- a/src/comp/rustc.rc
+++ b/src/comp/rustc.rc
@@ -10,7 +10,9 @@ meta (desc = "The Rust compiler",
       license = "BSD");
 
 
-use std;
+use std (name = "std",
+         vers = "0.1",
+         url = "http://rust-lang.org/src/std");
 
 mod middle {
     mod trans;
diff --git a/src/test/run-pass/use-import-export.rs b/src/test/run-pass/use-import-export.rs
index b467828bcea..8b15a620db2 100644
--- a/src/test/run-pass/use-import-export.rs
+++ b/src/test/run-pass/use-import-export.rs
@@ -1,11 +1,11 @@
 mod foo {
   export x;
-  use std (ver="0.0.1");
+  use std (vers="0.1");
   fn x() -> int { ret 1; }
 }
 
 mod bar {
-  use std (ver="0.0.1");
+  use std (vers="0.1");
   export y;
   fn y() -> int { ret 1; }
 }
diff --git a/src/test/run-pass/use.rs b/src/test/run-pass/use.rs
index ee8ae10ad87..cb78a23acc3 100644
--- a/src/test/run-pass/use.rs
+++ b/src/test/run-pass/use.rs
@@ -4,7 +4,7 @@
 use std;
 use libc();
 use zed(name = "std");
-use bar(name = "std", ver = "0.0.1");
+use bar(name = "std", vers = "0.1");
 
 // FIXME: commented out since resolve doesn't know how to handle crates yet.
 // import std::str;
@@ -14,7 +14,7 @@ mod baz {
   use std;
   use libc();
   use zed(name = "std");
-  use bar(name = "std", ver = "0.0.1");
+  use bar(name = "std", vers = "0.0.1");
 
   // import std::str;
   // import x = std::str;