From adc18bb24ae6dacf6bfd9ca9742d47e6d4187a6b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 21 Jun 2011 14:23:16 -0700 Subject: [PATCH] rustc: Introduce and parse additional meta_item forms Examples: #[test], #[link(name = "vers")] Issue #487 --- src/comp/back/link.rs | 55 ++++++++++++++++++++++---- src/comp/front/ast.rs | 6 ++- src/comp/front/creader.rs | 46 +++++++++++++++------ src/comp/front/parser.rs | 31 +++++++++++---- src/comp/middle/metadata.rs | 20 +++++++--- src/comp/pretty/pprust.rs | 15 +++++-- src/test/compile-fail/attr-bad-meta.rs | 6 +++ src/test/run-pass/item-attributes.rs | 11 ++++++ 8 files changed, 153 insertions(+), 37 deletions(-) create mode 100644 src/test/compile-fail/attr-bad-meta.rs diff --git a/src/comp/back/link.rs b/src/comp/back/link.rs index addcc7afb8e..388ae97a102 100644 --- a/src/comp/back/link.rs +++ b/src/comp/back/link.rs @@ -291,7 +291,15 @@ fn get_crate_meta_export(&session::session sess, &ast::crate c, str k, str default, bool warn_default) -> str { let vec[@ast::meta_item] v = []; for each (@ast::meta_item mi in crate_export_metas(c)) { - if (mi.node.key == k) { v += [mi]; } + // FIXME (#487): Support all variants of meta_item + alt (mi.node) { + case (ast::meta_key_value(?key, ?value)) { + if (key == k) { v += [mi]; } + } + case (_) { + sess.unimpl("meta_item variant"); + } + } } alt (vec::len(v)) { case (0u) { @@ -301,7 +309,16 @@ fn get_crate_meta_export(&session::session sess, &ast::crate c, str k, } ret default; } - case (1u) { ret v.(0).node.value; } + case (1u) { + alt (v.(0).node) { + case (ast::meta_key_value(_, ?value)) { + ret value; + } + case (_) { + sess.unimpl("meta_item variant"); + } + } + } case (_) { sess.span_fatal(v.(1).span, #fmt("duplicate meta '%s'", k)); } @@ -312,21 +329,45 @@ fn get_crate_meta_export(&session::session sess, &ast::crate c, str k, // This calculates CMH as defined above fn crate_meta_extras_hash(sha1 sha, &ast::crate crate) -> str { fn lteq(&@ast::meta_item ma, &@ast::meta_item mb) -> bool { - ret ma.node.key <= mb.node.key; + fn key(&@ast::meta_item m) -> ast::ident { + alt (m.node) { + case (ast::meta_word(?name)) { + name + } + case (ast::meta_key_value(?key, _)) { + key + } + } + } + ret key(ma) <= key(mb); } fn len_and_str(&str s) -> str { ret #fmt("%u_%s", str::byte_len(s), s); } let vec[mutable @ast::meta_item] v = [mutable ]; for each (@ast::meta_item mi in crate_export_metas(crate)) { - if (mi.node.key != "name" && mi.node.key != "vers") { - v += [mutable mi]; + alt (mi.node) { + case (ast::meta_key_value(?key, _)) { + if (key != "name" && key != "vers") { + v += [mutable mi]; + } + } + case (_) { + v += [mutable mi]; + } } } sort::quick_sort(lteq, v); sha.reset(); for (@ast::meta_item m_ in v) { auto m = m_; - sha.input_str(len_and_str(m.node.key)); - sha.input_str(len_and_str(m.node.value)); + alt (m.node) { + case (ast::meta_key_value(?key, ?value)) { + sha.input_str(len_and_str(key)); + sha.input_str(len_and_str(value)); + } + case (ast::meta_word(?name)) { + sha.input_str(len_and_str(name)); + } + } } ret truncated_sha1_result(sha); } diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index 14bc0e8532e..31556c66b54 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -97,7 +97,11 @@ type crate_directive = spanned[crate_directive_]; type meta_item = spanned[meta_item_]; -type meta_item_ = rec(ident key, str value); +tag meta_item_ { + meta_word(ident); + meta_list(ident, vec[@meta_item]); + meta_key_value(ident, str); +} type block = spanned[block_]; diff --git a/src/comp/front/creader.rs b/src/comp/front/creader.rs index b297f062de9..e91f514deee 100644 --- a/src/comp/front/creader.rs +++ b/src/comp/front/creader.rs @@ -548,19 +548,30 @@ fn metadata_matches(hashmap[str, str] mm, &vec[@ast::meta_item] metas) -> 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; + alt (mi.node) { + case (ast::meta_key_value(?key, ?value)) { + alt (mm.find(key)) { + case (some(?v)) { + if (v == value) { + log #fmt("matched '%s': '%s'", key, + value); + } else { + log #fmt("missing '%s': '%s' (got '%s')", + key, + value, v); + ret false; + } + } + case (none) { + log #fmt("missing '%s': '%s'", + key, value); + ret false; + } } } - case (none) { - log #fmt("missing '%s': '%s'", mi.node.key, mi.node.value); + case (_) { + // FIXME (#487): Support all forms of meta_item + log_err "unimplemented meta_item variant in metadata_matches"; ret false; } } @@ -574,7 +585,18 @@ fn find_library_crate(&session::session sess, &ast::ident ident, option::t[tup(str, vec[u8])] { let str crate_name = ident; for (@ast::meta_item mi in metas) { - if (mi.node.key == "name") { crate_name = mi.node.value; break; } + alt (mi.node) { + case (ast::meta_key_value(?key, ?value)) { + if (key == "name") { + crate_name = value; + break; + } + } + case (_) { + // FIXME (#487) + sess.unimpl("meta_item variant") + } + } } auto nn = parser::default_native_lib_naming(sess); let str prefix = nn.prefix + crate_name; diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 94ea7e7b69c..c6e256ac03f 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -2113,26 +2113,41 @@ fn parse_inner_attrs(&parser p) -> vec[ast::attribute] { fn parse_meta_item(&parser p) -> @ast::meta_item { auto lo = p.get_lo_pos(); auto ident = parse_ident(p); - expect(p, token::EQ); alt (p.peek()) { - case (token::LIT_STR(?s)) { - auto hi = p.get_hi_pos(); + case (token::EQ) { p.bump(); - ret @spanned(lo, hi, rec(key=ident, value=p.get_str(s))); + alt (p.peek()) { + case (token::LIT_STR(?s)) { + p.bump(); + auto value = p.get_str(s); + auto hi = p.get_hi_pos(); + ret @spanned(lo, hi, ast::meta_key_value(ident, value)); + } + case (_) { + p.fatal("Metadata items must be string literals"); + } + } + } + case (token::LPAREN) { + auto inner_items = parse_meta_seq(p); + auto hi = p.get_hi_pos(); + ret @spanned(lo, hi, ast::meta_list(ident, inner_items)); + } + case (_) { + auto hi = p.get_hi_pos(); + ret @spanned(lo, hi, ast::meta_word(ident)); } - case (_) { p.fatal("Metadata items must be string literals"); } } - fail; } -fn parse_meta(&parser p) -> vec[@ast::meta_item] { +fn parse_meta_seq(&parser p) -> vec[@ast::meta_item] { ret parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_meta_item, p).node; } fn parse_optional_meta(&parser p) -> vec[@ast::meta_item] { alt (p.peek()) { - case (token::LPAREN) { ret parse_meta(p); } + case (token::LPAREN) { ret parse_meta_seq(p); } case (_) { let vec[@ast::meta_item] v = []; ret v; } } } diff --git a/src/comp/middle/metadata.rs b/src/comp/middle/metadata.rs index ef3ddcf016c..f8cb1e8fb9a 100644 --- a/src/comp/middle/metadata.rs +++ b/src/comp/middle/metadata.rs @@ -669,13 +669,21 @@ fn write_int(&io::writer writer, &int n) { 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); - ebml::start_tag(ebml_w, tag_meta_item_key); - ebml_w.writer.write(str::bytes(mi.node.key)); - ebml::end_tag(ebml_w); - ebml::start_tag(ebml_w, tag_meta_item_value); - ebml_w.writer.write(str::bytes(mi.node.value)); - ebml::end_tag(ebml_w); + 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); } ebml::start_tag(ebml_w, tag_meta_export); diff --git a/src/comp/pretty/pprust.rs b/src/comp/pretty/pprust.rs index ea82213cac4..2d8d6382f8c 100644 --- a/src/comp/pretty/pprust.rs +++ b/src/comp/pretty/pprust.rs @@ -1018,9 +1018,18 @@ fn print_type_params(&ps s, &vec[ast::ty_param] params) { fn print_meta_item(&ps s, &@ast::meta_item item) { ibox(s, indent_unit); - word_space(s, item.node.key); - word_space(s, "="); - print_string(s, item.node.value); + // FIXME (#487): Print other meta item variants + alt (item.node) { + case (ast::meta_key_value(?key, ?value)) { + word_space(s, key); + word_space(s, "="); + print_string(s, value); + } + case (_) { + log_err "unimplemented meta_item variant"; + fail; + } + } end(s); } diff --git a/src/test/compile-fail/attr-bad-meta.rs b/src/test/compile-fail/attr-bad-meta.rs new file mode 100644 index 00000000000..01ca127553d --- /dev/null +++ b/src/test/compile-fail/attr-bad-meta.rs @@ -0,0 +1,6 @@ +// xfail-stage0 +// error-pattern:expecting \] + +// asterisk is bogus +#[attr*] +mod m { } \ No newline at end of file diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index 00e419bc0b9..35e578bf26c 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -173,6 +173,17 @@ mod test_distinguish_syntax_ext { } } +mod test_other_forms { + #[attr] + #[attr(word)] + #[attr(attr(word))] + #[attr(key1 = "val", + key2 = "val", + attr)] + fn f() { + } +} + fn main() { }