diff --git a/src/comp/front/eval.rs b/src/comp/front/eval.rs index 67be27d4cb6..44a6e1abb5d 100644 --- a/src/comp/front/eval.rs +++ b/src/comp/front/eval.rs @@ -287,7 +287,7 @@ fn eval_crate_directive(ctx cx, env e, @ast::crate_directive cdir, str prefix, auto p0 = new_parser(cx.sess, e, start_id, full_path, cx.chpos, cx.next_ann); - auto m0 = parse_mod_items(p0, token::EOF); + auto m0 = parse_mod_items(p0, token::EOF, []); auto next_id = p0.next_def_id(); // Thread defids and chpos through the parsers diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index 01cff9d81aa..39ceb7a6540 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -955,10 +955,10 @@ fn parse_bottom_expr(&parser p) -> @ast::expr { fn parse_syntax_ext(&parser p) -> @ast::expr { auto lo = p.get_lo_pos(); expect(p, token::POUND); - ret parse_syntax_ext_inner(p, lo); + ret parse_syntax_ext_naked(p, lo); } -fn parse_syntax_ext_inner(&parser p, uint lo) -> @ast::expr { +fn parse_syntax_ext_naked(&parser p, uint lo) -> @ast::expr { auto pth = parse_path(p); auto es = parse_seq(token::LPAREN, token::RPAREN, some(token::COMMA), parse_expr, p); @@ -1496,7 +1496,7 @@ fn parse_source_stmt(&parser p) -> @ast::stmt { } else { auto item_attrs; - alt (parse_attrs_or_ext(p)) { + alt (parse_outer_attrs_or_ext(p)) { case (none) { item_attrs = []; } @@ -1799,11 +1799,14 @@ fn parse_item_obj(&parser p, ast::layer lyr, vec[ast::attribute] attrs) -> p.next_def_id()), attrs); } -fn parse_mod_items(&parser p, token::token term) -> ast::_mod { +fn parse_mod_items(&parser p, token::token term, + vec[ast::attribute] first_item_attrs) -> ast::_mod { auto view_items = parse_view(p); let vec[@ast::item] items = []; + auto initial_attrs = first_item_attrs; while (p.peek() != term) { - auto attrs = parse_attributes(p); + auto attrs = initial_attrs + parse_outer_attributes(p); + initial_attrs = []; alt (parse_item(p, attrs)) { case (got_item(?i)) { vec::push(items, i); } case (_) { @@ -1830,10 +1833,13 @@ fn parse_item_mod(&parser p, vec[ast::attribute] attrs) -> @ast::item { auto lo = p.get_last_lo_pos(); auto id = parse_ident(p); expect(p, token::LBRACE); - auto m = parse_mod_items(p, token::RBRACE); + auto inner_attrs = parse_inner_attributes(p); + auto first_item_outer_attrs = inner_attrs._1; + auto m = parse_mod_items(p, token::RBRACE, + first_item_outer_attrs); auto hi = p.get_hi_pos(); expect(p, token::RBRACE); - ret mk_item(p, lo, hi, id, ast::item_mod(m), attrs); + ret mk_item(p, lo, hi, id, ast::item_mod(m), attrs + inner_attrs._0); } fn parse_item_native_type(&parser p) -> @ast::native_item { @@ -2039,34 +2045,37 @@ fn parse_item(&parser p, vec[ast::attribute] attrs) -> parsed_item { type attr_or_ext = option::t[either::t[vec[ast::attribute], @ast::expr]]; -fn parse_attrs_or_ext(&parser p) -> attr_or_ext { +fn parse_outer_attrs_or_ext(&parser p) -> attr_or_ext { if (p.peek() == token::POUND) { auto lo = p.get_lo_pos(); p.bump(); if (p.peek() == token::LBRACKET) { - auto first_attr = parse_attribute_inner(p, lo); - ret some(left([first_attr] + parse_attributes(p))); + auto first_attr = parse_attribute_naked(p, lo); + ret some(left([first_attr] + parse_outer_attributes(p))); } else { - ret some(right(parse_syntax_ext_inner(p, lo))); + ret some(right(parse_syntax_ext_naked(p, lo))); } } else { ret none; } } -fn parse_attributes(&parser p) -> vec[ast::attribute] { +// Parse attributes that appear before an item +fn parse_outer_attributes(&parser p) -> vec[ast::attribute] { let vec[ast::attribute] attrs = []; - while (p.peek() == token::POUND) { attrs += [parse_attribute(p)]; } + while (p.peek() == token::POUND) { + attrs += [parse_attribute(p)]; + } ret attrs; } fn parse_attribute(&parser p) -> ast::attribute { auto lo = p.get_lo_pos(); expect(p, token::POUND); - ret parse_attribute_inner(p, lo); + ret parse_attribute_naked(p, lo); } -fn parse_attribute_inner(&parser p, uint lo) -> ast::attribute { +fn parse_attribute_naked(&parser p, uint lo) -> ast::attribute { expect(p, token::LBRACKET); auto meta_item = parse_meta_item(p); expect(p, token::RBRACKET); @@ -2074,6 +2083,29 @@ fn parse_attribute_inner(&parser p, uint lo) -> ast::attribute { ret spanned(lo, hi, rec(style=ast::attr_outer, value=*meta_item)); } +// Parse attributes that appear after the opening of an item, each terminated +// by a semicolon. In addition to a vector of inner attributes, this function +// also returns a vector that may contain the first outer attribute of the +// next item (since we can't know whether the attribute is an inner attribute +// of the containing item or an outer attribute of the first contained item +// until we see the semi). +fn parse_inner_attributes(&parser p) -> tup(vec[ast::attribute], + vec[ast::attribute]) { + let vec[ast::attribute] inner_attrs = []; + let vec[ast::attribute] next_outer_attrs = []; + while (p.peek() == token::POUND) { + auto attr = parse_attribute(p); + if (p.peek() == token::SEMI) { + p.bump(); + inner_attrs += [attr]; + } else { + next_outer_attrs += [attr]; + break; + } + } + ret tup(inner_attrs, next_outer_attrs); +} + fn parse_meta_item(&parser p) -> @ast::meta_item { auto lo = p.get_lo_pos(); auto ident = parse_ident(p); @@ -2234,7 +2266,7 @@ fn parse_native_view(&parser p) -> vec[@ast::view_item] { fn parse_crate_from_source_file(&parser p) -> @ast::crate { auto lo = p.get_lo_pos(); - auto m = parse_mod_items(p, token::EOF); + auto m = parse_mod_items(p, token::EOF, []); let vec[@ast::crate_directive] cdirs = []; ret @spanned(lo, p.get_lo_pos(), rec(directives=cdirs, module=m)); } diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index c407a386d60..39f96499e92 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -116,5 +116,49 @@ mod test_stmt_multi_attr_outer { } } +mod test_attr_inner { + + mod m { + // This is an attribute of mod m + #[attr = "val"]; + } +} + +mod test_attr_inner_then_outer { + + mod m { + // This is an attribute of mod m + #[attr = "val"]; + // This is an attribute of fn f + #[attr = "val"] + fn f() { + } + } +} + +mod test_attr_inner_then_outer_multi { + mod m { + // This is an attribute of mod m + #[attr1 = "val"]; + #[attr2 = "val"]; + // This is an attribute of fn f + #[attr1 = "val"] + #[attr2 = "val"] + fn f() { + } + } +} + fn main() { } + +// +// Local Variables: +// mode: rust +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'"; +// End: +//