rustc: Parse fn inner attributes. Closes #1506
This commit is contained in:
parent
17585cc47e
commit
3466c9b4be
|
@ -1531,14 +1531,23 @@ fn parse_let(p: parser) -> @ast::decl {
|
||||||
ret @spanned(lo, p.last_span.hi, ast::decl_local(locals));
|
ret @spanned(lo, p.last_span.hi, ast::decl_local(locals));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(p: parser) -> @ast::stmt {
|
fn parse_stmt(p: parser, first_item_attrs: [ast::attribute]) -> @ast::stmt {
|
||||||
|
fn check_expected_item(p: parser, current_attrs: [ast::attribute]) {
|
||||||
|
// If we have attributes then we should have an item
|
||||||
|
if vec::is_not_empty(current_attrs) {
|
||||||
|
p.fatal("expected item");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let lo = p.span.lo;
|
let lo = p.span.lo;
|
||||||
if eat_word(p, "let") {
|
if is_word(p, "let") {
|
||||||
|
check_expected_item(p, first_item_attrs);
|
||||||
|
expect_word(p, "let");
|
||||||
let decl = parse_let(p);
|
let decl = parse_let(p);
|
||||||
ret @spanned(lo, decl.span.hi, ast::stmt_decl(decl, p.get_id()));
|
ret @spanned(lo, decl.span.hi, ast::stmt_decl(decl, p.get_id()));
|
||||||
} else {
|
} else {
|
||||||
let item_attrs;
|
let item_attrs;
|
||||||
alt parse_outer_attrs_or_ext(p) {
|
alt parse_outer_attrs_or_ext(p, first_item_attrs) {
|
||||||
none. { item_attrs = []; }
|
none. { item_attrs = []; }
|
||||||
some(left(attrs)) { item_attrs = attrs; }
|
some(left(attrs)) { item_attrs = attrs; }
|
||||||
some(right(ext)) {
|
some(right(ext)) {
|
||||||
|
@ -1546,6 +1555,8 @@ fn parse_stmt(p: parser) -> @ast::stmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let item_attrs = first_item_attrs + item_attrs;
|
||||||
|
|
||||||
alt parse_item(p, item_attrs) {
|
alt parse_item(p, item_attrs) {
|
||||||
some(i) {
|
some(i) {
|
||||||
let hi = i.span.hi;
|
let hi = i.span.hi;
|
||||||
|
@ -1555,10 +1566,7 @@ fn parse_stmt(p: parser) -> @ast::stmt {
|
||||||
none() { /* fallthrough */ }
|
none() { /* fallthrough */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have attributes then we should have an item
|
check_expected_item(p, item_attrs);
|
||||||
if vec::len(item_attrs) > 0u {
|
|
||||||
ret p.fatal("expected item");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remainder are line-expr stmts.
|
// Remainder are line-expr stmts.
|
||||||
let e = parse_expr_res(p, RESTRICT_STMT_EXPR);
|
let e = parse_expr_res(p, RESTRICT_STMT_EXPR);
|
||||||
|
@ -1605,16 +1613,37 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(p: parser) -> ast::blk {
|
fn parse_block(p: parser) -> ast::blk {
|
||||||
|
let (attrs, blk) = parse_inner_attrs_and_block(p, false);
|
||||||
|
assert vec::is_empty(attrs);
|
||||||
|
ret blk;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_inner_attrs_and_block(
|
||||||
|
p: parser, parse_attrs: bool) -> ([ast::attribute], ast::blk) {
|
||||||
|
|
||||||
|
fn maybe_parse_inner_attrs_and_next(
|
||||||
|
p: parser, parse_attrs: bool) ->
|
||||||
|
{inner: [ast::attribute], next: [ast::attribute]} {
|
||||||
|
if parse_attrs {
|
||||||
|
parse_inner_attrs_and_next(p)
|
||||||
|
} else {
|
||||||
|
{inner: [], next: []}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let lo = p.span.lo;
|
let lo = p.span.lo;
|
||||||
if eat_word(p, "unchecked") {
|
if eat_word(p, "unchecked") {
|
||||||
expect(p, token::LBRACE);
|
expect(p, token::LBRACE);
|
||||||
be parse_block_tail(p, lo, ast::unchecked_blk);
|
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
|
||||||
|
ret (inner, parse_block_tail_(p, lo, ast::unchecked_blk, next));
|
||||||
} else if eat_word(p, "unsafe") {
|
} else if eat_word(p, "unsafe") {
|
||||||
expect(p, token::LBRACE);
|
expect(p, token::LBRACE);
|
||||||
be parse_block_tail(p, lo, ast::unsafe_blk);
|
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
|
||||||
|
ret (inner, parse_block_tail_(p, lo, ast::unsafe_blk, next));
|
||||||
} else {
|
} else {
|
||||||
expect(p, token::LBRACE);
|
expect(p, token::LBRACE);
|
||||||
be parse_block_tail(p, lo, ast::default_blk);
|
let {inner, next} = maybe_parse_inner_attrs_and_next(p, parse_attrs);
|
||||||
|
ret (inner, parse_block_tail_(p, lo, ast::default_blk, next));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1630,15 +1659,28 @@ fn parse_block_no_value(p: parser) -> ast::blk {
|
||||||
// necessary, and this should take a qualifier.
|
// necessary, and this should take a qualifier.
|
||||||
// some blocks start with "#{"...
|
// some blocks start with "#{"...
|
||||||
fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
|
fn parse_block_tail(p: parser, lo: uint, s: ast::blk_check_mode) -> ast::blk {
|
||||||
let stmts = [], expr = none;
|
parse_block_tail_(p, lo, s, [])
|
||||||
let view_items = parse_view_import_only(p);
|
}
|
||||||
|
|
||||||
|
fn parse_block_tail_(p: parser, lo: uint, s: ast::blk_check_mode,
|
||||||
|
first_item_attrs: [ast::attribute]) -> ast::blk {
|
||||||
|
let stmts = [];
|
||||||
|
let expr = none;
|
||||||
|
let view_items = maybe_parse_view_import_only(p, first_item_attrs);
|
||||||
|
let initial_attrs = first_item_attrs;
|
||||||
|
|
||||||
|
if p.token == token::RBRACE && !vec::is_empty(initial_attrs) {
|
||||||
|
p.fatal("expected item");
|
||||||
|
}
|
||||||
|
|
||||||
while p.token != token::RBRACE {
|
while p.token != token::RBRACE {
|
||||||
alt p.token {
|
alt p.token {
|
||||||
token::SEMI. {
|
token::SEMI. {
|
||||||
p.bump(); // empty
|
p.bump(); // empty
|
||||||
}
|
}
|
||||||
_ {
|
_ {
|
||||||
let stmt = parse_stmt(p);
|
let stmt = parse_stmt(p, initial_attrs);
|
||||||
|
initial_attrs = [];
|
||||||
alt stmt.node {
|
alt stmt.node {
|
||||||
ast::stmt_expr(e, stmt_id) { // Expression without semicolon:
|
ast::stmt_expr(e, stmt_id) { // Expression without semicolon:
|
||||||
alt p.token {
|
alt p.token {
|
||||||
|
@ -1751,7 +1793,8 @@ fn parse_item_fn(p: parser, purity: ast::purity,
|
||||||
let lo = p.last_span.lo;
|
let lo = p.last_span.lo;
|
||||||
let t = parse_fn_header(p);
|
let t = parse_fn_header(p);
|
||||||
let decl = parse_fn_decl(p, purity);
|
let decl = parse_fn_decl(p, purity);
|
||||||
let body = parse_block(p);
|
let (inner_attrs, body) = parse_inner_attrs_and_block(p, true);
|
||||||
|
let attrs = attrs + inner_attrs;
|
||||||
ret mk_item(p, lo, body.span.hi, t.ident,
|
ret mk_item(p, lo, body.span.hi, t.ident,
|
||||||
ast::item_fn(decl, t.tps, body), attrs);
|
ast::item_fn(decl, t.tps, body), attrs);
|
||||||
}
|
}
|
||||||
|
@ -1832,8 +1875,7 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item {
|
||||||
fn parse_mod_items(p: parser, term: token::token,
|
fn parse_mod_items(p: parser, term: token::token,
|
||||||
first_item_attrs: [ast::attribute]) -> ast::_mod {
|
first_item_attrs: [ast::attribute]) -> ast::_mod {
|
||||||
// Shouldn't be any view items since we've already parsed an item attr
|
// Shouldn't be any view items since we've already parsed an item attr
|
||||||
let view_items =
|
let view_items = maybe_parse_view(p, first_item_attrs);
|
||||||
if vec::len(first_item_attrs) == 0u { parse_view(p) } else { [] };
|
|
||||||
let items: [@ast::item] = [];
|
let items: [@ast::item] = [];
|
||||||
let initial_attrs = first_item_attrs;
|
let initial_attrs = first_item_attrs;
|
||||||
while p.token != term {
|
while p.token != term {
|
||||||
|
@ -2134,14 +2176,20 @@ fn parse_item(p: parser, attrs: [ast::attribute]) -> option::t<@ast::item> {
|
||||||
// extensions, which both begin with token.POUND
|
// extensions, which both begin with token.POUND
|
||||||
type attr_or_ext = option::t<either::t<[ast::attribute], @ast::expr>>;
|
type attr_or_ext = option::t<either::t<[ast::attribute], @ast::expr>>;
|
||||||
|
|
||||||
fn parse_outer_attrs_or_ext(p: parser) -> attr_or_ext {
|
fn parse_outer_attrs_or_ext(
|
||||||
|
p: parser,
|
||||||
|
first_item_attrs: [ast::attribute]) -> attr_or_ext {
|
||||||
|
let expect_item_next = vec::is_not_empty(first_item_attrs);
|
||||||
if p.token == token::POUND {
|
if p.token == token::POUND {
|
||||||
let lo = p.span.lo;
|
let lo = p.span.lo;
|
||||||
p.bump();
|
if p.look_ahead(1u) == token::LBRACKET {
|
||||||
if p.token == token::LBRACKET {
|
p.bump();
|
||||||
let first_attr = parse_attribute_naked(p, ast::attr_outer, lo);
|
let first_attr = parse_attribute_naked(p, ast::attr_outer, lo);
|
||||||
ret some(left([first_attr] + parse_outer_attributes(p)));
|
ret some(left([first_attr] + parse_outer_attributes(p)));
|
||||||
} else if !(p.token == token::LT || p.token == token::LBRACKET) {
|
} else if !(p.look_ahead(1u) == token::LT
|
||||||
|
|| p.look_ahead(1u) == token::LBRACKET
|
||||||
|
|| expect_item_next) {
|
||||||
|
p.bump();
|
||||||
ret some(right(parse_syntax_ext_naked(p, lo)));
|
ret some(right(parse_syntax_ext_naked(p, lo)));
|
||||||
} else { ret none; }
|
} else { ret none; }
|
||||||
} else { ret none; }
|
} else { ret none; }
|
||||||
|
@ -2182,6 +2230,10 @@ fn parse_inner_attrs_and_next(p: parser) ->
|
||||||
let inner_attrs: [ast::attribute] = [];
|
let inner_attrs: [ast::attribute] = [];
|
||||||
let next_outer_attrs: [ast::attribute] = [];
|
let next_outer_attrs: [ast::attribute] = [];
|
||||||
while p.token == token::POUND {
|
while p.token == token::POUND {
|
||||||
|
if p.look_ahead(1u) != token::LBRACKET {
|
||||||
|
// This is an extension
|
||||||
|
break;
|
||||||
|
}
|
||||||
let attr = parse_attribute(p, ast::attr_inner);
|
let attr = parse_attribute(p, ast::attr_inner);
|
||||||
if p.token == token::SEMI {
|
if p.token == token::SEMI {
|
||||||
p.bump();
|
p.bump();
|
||||||
|
@ -2377,22 +2429,37 @@ fn is_view_item(p: parser) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_view(p: parser) -> [@ast::view_item] {
|
fn maybe_parse_view(
|
||||||
parse_view_while(p, is_view_item)
|
p: parser,
|
||||||
|
first_item_attrs: [ast::attribute]) -> [@ast::view_item] {
|
||||||
|
|
||||||
|
maybe_parse_view_while(p, first_item_attrs, is_view_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_view_import_only(p: parser) -> [@ast::view_item] {
|
fn maybe_parse_view_import_only(
|
||||||
parse_view_while(p, bind is_word(_, "import"))
|
p: parser,
|
||||||
|
first_item_attrs: [ast::attribute]) -> [@ast::view_item] {
|
||||||
|
|
||||||
|
maybe_parse_view_while(p, first_item_attrs, bind is_word(_, "import"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_view_while(p: parser, f: fn@(parser) -> bool) -> [@ast::view_item] {
|
fn maybe_parse_view_while(
|
||||||
let items = [];
|
p: parser,
|
||||||
while f(p) { items += [parse_view_item(p)]; }
|
first_item_attrs: [ast::attribute],
|
||||||
ret items;
|
f: fn@(parser) -> bool) -> [@ast::view_item] {
|
||||||
|
|
||||||
|
if vec::len(first_item_attrs) == 0u {
|
||||||
|
let items = [];
|
||||||
|
while f(p) { items += [parse_view_item(p)]; }
|
||||||
|
ret items;
|
||||||
|
} else {
|
||||||
|
// Shouldn't be any view items since we've already parsed an item attr
|
||||||
|
ret [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_native_view(p: parser) -> [@ast::view_item] {
|
fn parse_native_view(p: parser) -> [@ast::view_item] {
|
||||||
parse_view_while(p, is_view_item)
|
maybe_parse_view_while(p, [], is_view_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
|
fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
|
||||||
|
|
|
@ -366,7 +366,7 @@ fn print_item(s: ps, &&item: @ast::item) {
|
||||||
ast::item_fn(decl, typarams, body) {
|
ast::item_fn(decl, typarams, body) {
|
||||||
print_fn(s, decl, item.ident, typarams);
|
print_fn(s, decl, item.ident, typarams);
|
||||||
word(s.s, " ");
|
word(s.s, " ");
|
||||||
print_block(s, body);
|
print_block_with_attrs(s, body, item.attrs);
|
||||||
}
|
}
|
||||||
ast::item_mod(_mod) {
|
ast::item_mod(_mod) {
|
||||||
head(s, "mod");
|
head(s, "mod");
|
||||||
|
@ -551,10 +551,20 @@ fn print_block(s: ps, blk: ast::blk) {
|
||||||
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
|
print_possibly_embedded_block(s, blk, block_normal, indent_unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_block_with_attrs(s: ps, blk: ast::blk, attrs: [ast::attribute]) {
|
||||||
|
print_possibly_embedded_block_(s, blk, block_normal, indent_unit, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
tag embed_type { block_macro; block_block_fn; block_normal; }
|
tag embed_type { block_macro; block_block_fn; block_normal; }
|
||||||
|
|
||||||
fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type,
|
fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type,
|
||||||
indented: uint) {
|
indented: uint) {
|
||||||
|
print_possibly_embedded_block_(
|
||||||
|
s, blk, embedded, indented, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_possibly_embedded_block_(s: ps, blk: ast::blk, embedded: embed_type,
|
||||||
|
indented: uint, attrs: [ast::attribute]) {
|
||||||
alt blk.node.rules {
|
alt blk.node.rules {
|
||||||
ast::unchecked_blk. { word(s.s, "unchecked"); }
|
ast::unchecked_blk. { word(s.s, "unchecked"); }
|
||||||
ast::unsafe_blk. { word(s.s, "unsafe"); }
|
ast::unsafe_blk. { word(s.s, "unsafe"); }
|
||||||
|
@ -570,6 +580,8 @@ fn print_possibly_embedded_block(s: ps, blk: ast::blk, embedded: embed_type,
|
||||||
block_normal. { bopen(s); }
|
block_normal. { bopen(s); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_inner_attributes(s, attrs);
|
||||||
|
|
||||||
for vi in blk.node.view_items { print_view_item(s, vi); }
|
for vi in blk.node.view_items { print_view_item(s, vi); }
|
||||||
for st: @ast::stmt in blk.node.stmts {
|
for st: @ast::stmt in blk.node.stmts {
|
||||||
print_stmt(s, *st);
|
print_stmt(s, *st);
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
#[attr]
|
||||||
|
#debug("hi"); //! ERROR expected item
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
fn main() {
|
||||||
|
#[attr]
|
||||||
|
let _i = 0; //! ERROR expected item
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
// pp-exact
|
||||||
|
// Testing that both the inner item and next outer item are
|
||||||
|
// preserved, and that the first outer item parsed in main is not
|
||||||
|
// accidentally carried over to each inner function
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
#[inner_attr];
|
||||||
|
#[outer_attr]
|
||||||
|
fn f() { }
|
||||||
|
|
||||||
|
#[outer_attr]
|
||||||
|
fn g() { }
|
||||||
|
}
|
|
@ -183,6 +183,10 @@ mod test_literals {
|
||||||
mod m { }
|
mod m { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_fn_inner() {
|
||||||
|
#[inner_fn_attr];
|
||||||
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in New Issue