From 96a159a6eaea213c2b9b9582a133a718bc967eac Mon Sep 17 00:00:00 2001 From: Marijn Haverbeke Date: Tue, 8 May 2012 23:01:38 +0200 Subject: [PATCH] Support visibility modifiers and attributes on view items Issue #1893 Tangentially, issue #2357 --- src/librustsyntax/ast.rs | 3 +- src/librustsyntax/fold.rs | 2 + src/librustsyntax/parse/attr.rs | 2 +- src/librustsyntax/parse/common.rs | 14 ++- src/librustsyntax/parse/parser.rs | 97 ++++++++----------- src/rustc/front/core_inject.rs | 10 +- src/test/compile-fail/ext-after-attrib.rs | 2 +- .../attr-before-view-item.rs | 0 .../attr-before-view-item2.rs | 0 9 files changed, 61 insertions(+), 69 deletions(-) rename src/test/{compile-fail => run-pass}/attr-before-view-item.rs (100%) rename src/test/{compile-fail => run-pass}/attr-before-view-item2.rs (100%) diff --git a/src/librustsyntax/ast.rs b/src/librustsyntax/ast.rs index cf338ad02c289..210244eca91ea 100644 --- a/src/librustsyntax/ast.rs +++ b/src/librustsyntax/ast.rs @@ -612,7 +612,8 @@ enum view_path_ { } #[auto_serialize] -type view_item = spanned; +type view_item = {node: view_item_, attrs: [attribute], + vis: visibility, span: span}; #[auto_serialize] enum view_item_ { diff --git a/src/librustsyntax/fold.rs b/src/librustsyntax/fold.rs index f538cc526519a..ebc65c9db38ea 100644 --- a/src/librustsyntax/fold.rs +++ b/src/librustsyntax/fold.rs @@ -679,6 +679,8 @@ fn make_fold(afp: ast_fold_precursor) -> ast_fold { fn f_view_item(afp: ast_fold_precursor, f: ast_fold, &&x: @view_item) -> @view_item { ret @{node: afp.fold_view_item(x.node, f), + attrs: vec::map(x.attrs, {|a| fold_attribute_(a, f)}), + vis: x.vis, span: afp.new_span(x.span)}; } fn f_native_item(afp: ast_fold_precursor, f: ast_fold, &&x: @native_item) diff --git a/src/librustsyntax/parse/attr.rs b/src/librustsyntax/parse/attr.rs index 969aa03d9026f..e8d73915577a1 100644 --- a/src/librustsyntax/parse/attr.rs +++ b/src/librustsyntax/parse/attr.rs @@ -39,7 +39,7 @@ fn parse_outer_attrs_or_ext( // Parse attributes that appear before an item fn parse_outer_attributes(p: parser) -> [ast::attribute] { let mut attrs: [ast::attribute] = []; - while p.token == token::POUND { + while p.token == token::POUND && p.look_ahead(1u) == token::LBRACKET { attrs += [parse_attribute(p, ast::attr_outer)]; } ret attrs; diff --git a/src/librustsyntax/parse/common.rs b/src/librustsyntax/parse/common.rs index 8bf388f3d4078..b50c2b7e7f3c6 100644 --- a/src/librustsyntax/parse/common.rs +++ b/src/librustsyntax/parse/common.rs @@ -58,12 +58,16 @@ fn require_keyword(p: parser, word: str) { } } -fn is_keyword(p: parser, word: str) -> bool { +fn token_is_keyword(p: parser, word: str, tok: token::token) -> bool { require_keyword(p, word); - ret alt p.token { - token::IDENT(sid, false) { str::eq(word, p.get_str(sid)) } - _ { false } - }; + alt tok { + token::IDENT(sid, false) { str::eq(word, p.get_str(sid)) } + _ { false } + } +} + +fn is_keyword(p: parser, word: str) -> bool { + token_is_keyword(p, word, p.token) } fn eat_keyword(p: parser, word: str) -> bool { diff --git a/src/librustsyntax/parse/parser.rs b/src/librustsyntax/parse/parser.rs index 1bfc6b2c6c2fe..7b1b9823a1ff8 100644 --- a/src/librustsyntax/parse/parser.rs +++ b/src/librustsyntax/parse/parser.rs @@ -1606,8 +1606,8 @@ fn parse_block_tail_(p: parser, lo: uint, s: blk_check_mode, +first_item_attrs: [attribute]) -> blk { let mut stmts = []; let mut expr = none; - let view_items = maybe_parse_view_import_only(p, first_item_attrs); - let mut initial_attrs = first_item_attrs; + let {attrs_remaining, view_items} = parse_view(p, first_item_attrs, true); + let mut initial_attrs = attrs_remaining; if p.token == token::RBRACE && !vec::is_empty(initial_attrs) { p.fatal("expected item"); @@ -2036,12 +2036,13 @@ fn parse_visibility(p: parser, def: visibility) -> visibility { fn parse_mod_items(p: parser, term: token::token, +first_item_attrs: [attribute]) -> _mod { // Shouldn't be any view items since we've already parsed an item attr - let view_items = maybe_parse_view(p, first_item_attrs); + let {attrs_remaining, view_items} = + parse_view(p, first_item_attrs, false); let mut items: [@item] = []; let mut first = true; while p.token != term { let mut attrs = parse_outer_attributes(p); - if first { attrs = first_item_attrs + attrs; first = false; } + if first { attrs = attrs_remaining + attrs; first = false; } #debug["parse_mod_items: parse_item(attrs=%?)", attrs]; let vis = parse_visibility(p, private); alt parse_item(p, attrs, vis) { @@ -2054,7 +2055,7 @@ fn parse_mod_items(p: parser, term: token::token, #debug["parse_mod_items: attrs=%?", attrs]; } - if first && first_item_attrs.len() > 0u { + if first && attrs_remaining.len() > 0u { // We parsed attributes for the first item but didn't find the item p.fatal("expected item"); } @@ -2113,12 +2114,10 @@ fn parse_native_item(p: parser, +attrs: [attribute]) -> fn parse_native_mod_items(p: parser, +first_item_attrs: [attribute]) -> native_mod { // Shouldn't be any view items since we've already parsed an item attr - let view_items = - if vec::len(first_item_attrs) == 0u { - parse_native_view(p) - } else { [] }; + let {attrs_remaining, view_items} = + parse_view(p, first_item_attrs, false); let mut items: [@native_item] = []; - let mut initial_attrs = first_item_attrs; + let mut initial_attrs = attrs_remaining; while p.token != token::RBRACE { let attrs = initial_attrs + parse_outer_attributes(p); initial_attrs = []; @@ -2378,58 +2377,38 @@ fn parse_view_paths(p: parser) -> [@view_path] { ret vp; } -fn parse_view_item(p: parser) -> @view_item { - let lo = p.span.lo; - let the_item = - if eat_keyword(p, "use") { - parse_use(p) - } else if eat_keyword(p, "import") { - view_item_import(parse_view_paths(p)) - } else if eat_keyword(p, "export") { - view_item_export(parse_view_paths(p)) - } else { - fail - }; - let mut hi = p.span.lo; - expect(p, token::SEMI); - ret @spanned(lo, hi, the_item); -} - fn is_view_item(p: parser) -> bool { - is_keyword(p, "use") || is_keyword(p, "import") || is_keyword(p, "export") -} - -fn maybe_parse_view( - p: parser, - first_item_attrs: [attribute]) -> [@view_item] { - - maybe_parse_view_while(p, first_item_attrs, is_view_item) -} - -fn maybe_parse_view_import_only( - p: parser, - first_item_attrs: [attribute]) -> [@view_item] { - - maybe_parse_view_while(p, first_item_attrs, bind is_keyword(_, "import")) + let tok = if !is_keyword(p, "pub") && !is_keyword(p, "priv") { p.token } + else { p.look_ahead(1u) }; + token_is_keyword(p, "use", tok) || token_is_keyword(p, "import", tok) || + token_is_keyword(p, "export", tok) +} + +fn parse_view_item(p: parser, +attrs: [attribute]) -> @view_item { + let lo = p.span.lo, vis = parse_visibility(p, private); + let node = if eat_keyword(p, "use") { + parse_use(p) + } else if eat_keyword(p, "import") { + view_item_import(parse_view_paths(p)) + } else if eat_keyword(p, "export") { + view_item_export(parse_view_paths(p)) + } else { fail; }; + expect(p, token::SEMI); + @{node: node, attrs: attrs, + vis: vis, span: mk_sp(lo, p.last_span.hi)} } -fn maybe_parse_view_while( - p: parser, - first_item_attrs: [attribute], - f: fn@(parser) -> bool) -> [@view_item] { - - if vec::len(first_item_attrs) == 0u { - let mut 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_view(p: parser, +first_item_attrs: [attribute], + only_imports: bool) -> {attrs_remaining: [attribute], + view_items: [@view_item]} { + let mut attrs = first_item_attrs + parse_outer_attributes(p); + let mut items = []; + while if only_imports { is_keyword(p, "import") } + else { is_view_item(p) } { + items += [parse_view_item(p, attrs)]; + attrs = parse_outer_attributes(p); } -} - -fn parse_native_view(p: parser) -> [@view_item] { - maybe_parse_view_while(p, [], is_view_item) + {attrs_remaining: attrs, view_items: items} } // Parses a source module as a crate @@ -2494,7 +2473,7 @@ fn parse_crate_directive(p: parser, first_outer_attr: [attribute]) -> _ { unexpected(p); } } } else if is_view_item(p) { - let vi = parse_view_item(p); + let vi = parse_view_item(p, outer_attrs); ret spanned(lo, vi.span.hi, cdir_view_item(vi)); } else { ret p.fatal("expected crate directive"); } } diff --git a/src/rustc/front/core_inject.rs b/src/rustc/front/core_inject.rs index 79c78e2fcc45a..590a371da07e1 100644 --- a/src/rustc/front/core_inject.rs +++ b/src/rustc/front/core_inject.rs @@ -30,10 +30,16 @@ fn inject_libcore_ref(sess: session, let n1 = sess.next_node_id(); let n2 = sess.next_node_id(); - let vi1 = spanned(ast::view_item_use("core", [], n1)); + let vi1 = @{node: ast::view_item_use("core", [], n1), + attrs: [], + vis: ast::public, + span: dummy_sp()}; let vp = spanned(ast::view_path_glob(ident_to_path(dummy_sp(), "core"), n2)); - let vi2 = spanned(ast::view_item_import([vp])); + let vi2 = @{node: ast::view_item_import([vp]), + attrs: [], + vis: ast::public, + span: dummy_sp()}; let vis = [vi1, vi2] + crate.node.module.view_items; diff --git a/src/test/compile-fail/ext-after-attrib.rs b/src/test/compile-fail/ext-after-attrib.rs index 1eea33bc2e9ff..42d93b8220893 100644 --- a/src/test/compile-fail/ext-after-attrib.rs +++ b/src/test/compile-fail/ext-after-attrib.rs @@ -1,4 +1,4 @@ -// error-pattern:expecting '[' but found 'fmt' +// error-pattern:expected item but found '#' // Don't know how to deal with a syntax extension appearing after an // item attribute. Probably could use a better error message. diff --git a/src/test/compile-fail/attr-before-view-item.rs b/src/test/run-pass/attr-before-view-item.rs similarity index 100% rename from src/test/compile-fail/attr-before-view-item.rs rename to src/test/run-pass/attr-before-view-item.rs diff --git a/src/test/compile-fail/attr-before-view-item2.rs b/src/test/run-pass/attr-before-view-item2.rs similarity index 100% rename from src/test/compile-fail/attr-before-view-item2.rs rename to src/test/run-pass/attr-before-view-item2.rs