diff --git a/src/parser/event_parser/grammar/items.rs b/src/parser/event_parser/grammar/items.rs index 5b0180b8106..7ae48b5db6a 100644 --- a/src/parser/event_parser/grammar/items.rs +++ b/src/parser/event_parser/grammar/items.rs @@ -2,93 +2,90 @@ use super::*; pub(super) fn mod_contents(p: &mut Parser) { attributes::inner_attributes(p); - repeat(p, |p| { - skip_to_first( - p, item_first, mod_contents_item, - "expected item", - ) - }); -} - -fn item_first(p: &Parser) -> bool { - match p.current() { - STRUCT_KW | FN_KW | EXTERN_KW | MOD_KW | USE_KW | POUND | PUB_KW => true, - _ => false, + while !p.at(EOF) { + item(p); } } -fn mod_contents_item(p: &mut Parser) { - if item(p) { - if p.current() == SEMI { - node(p, ERROR, |p| { - p.error() - .message("expected item, found `;`\n\ - consider removing this semicolon") - .emit(); - p.bump(); - }) - } - } -} - -fn item(p: &mut Parser) -> bool { +fn item(p: &mut Parser){ let attrs_start = p.mark(); attributes::outer_attributes(p); visibility(p); - // node_if(p, USE_KW, USE_ITEM, use_item) - // || extern crate_fn - // || node_if(p, STATIC_KW, STATIC_ITEM, static_item) - // || node_if(p, CONST_KW, CONST_ITEM, const_item) or const FN! - // || unsafe trait, impl - // || node_if(p, FN_KW, FN_ITEM, fn_item) - // || node_if(p, TYPE_KW, TYPE_ITEM, type_item) + let la = p.raw_lookahead(1); let item_start = p.mark(); - let item_parsed = node_if(p, [EXTERN_KW, CRATE_KW], EXTERN_CRATE_ITEM, extern_crate_item) - || node_if(p, MOD_KW, MOD_ITEM, mod_item) - || node_if(p, USE_KW, USE_ITEM, use_item) - || node_if(p, STRUCT_KW, STRUCT_ITEM, struct_item) - || node_if(p, FN_KW, FN_ITEM, fn_item); - + match p.current() { + EXTERN_KW if la == CRATE_KW => extern_crate_item(p), + MOD_KW => mod_item(p), + USE_KW => use_item(p), + STRUCT_KW => struct_item(p), + FN_KW => fn_item(p), + err_token => { + p.start(ERROR); + let message = if err_token == SEMI { + //TODO: if the item is incomplete, this messsage is misleading + "expected item, found `;`\n\ + consider removing this semicolon" + } else { + "expected item" + }; + p.error() + .message(message) + .emit(); + p.bump(); + p.finish(); + return; + } + }; p.forward_parent(attrs_start, item_start); - item_parsed } fn struct_item(p: &mut Parser) { - if !p.expect(IDENT) { - return - } - generic_parameters(p); - match p.current() { - WHERE_KW => { - where_clause(p); - match p.current() { - SEMI => { - p.bump(); - return - } - L_CURLY => named_fields(p), - _ => { //TODO: special case `(` error message - p.error() - .message("expected `;` or `{`") - .emit(); - return + p.start(STRUCT_ITEM); + + assert!(p.at(STRUCT_KW)); + p.bump(); + + struct_inner(p); + p.finish(); + + fn struct_inner(p: &mut Parser) { + if !p.expect(IDENT) { + p.finish(); + return + } + generic_parameters(p); + match p.current() { + WHERE_KW => { + where_clause(p); + match p.current() { + SEMI => { + p.bump(); + return + } + L_CURLY => named_fields(p), + _ => { //TODO: special case `(` error message + p.error() + .message("expected `;` or `{`") + .emit(); + return + } } } - } - SEMI => { - p.bump(); - return - } - L_CURLY => named_fields(p), - L_PAREN => { - tuple_fields(p); - p.expect(SEMI); - }, - _ => { - p.error() - .message("expected `;`, `{`, or `(`") - .emit(); - return + SEMI => { + p.bump(); + return + } + L_CURLY => named_fields(p), + L_PAREN => { + tuple_fields(p); + p.expect(SEMI); + }, + _ => { + p.error() + .message("expected `;`, `{`, or `(`") + .emit(); + return + } } } } @@ -135,17 +132,28 @@ fn where_clause(_: &mut Parser) { } fn extern_crate_item(p: &mut Parser) { + p.start(EXTERN_CRATE_ITEM); + + assert!(p.at(EXTERN_KW)); + p.bump(); + + assert!(p.at(CRATE_KW)); + p.bump(); + p.expect(IDENT) && alias(p) && p.expect(SEMI); + p.finish(); } fn mod_item(p: &mut Parser) { - if !p.expect(IDENT) { - return; + p.start(MOD_ITEM); + + assert!(p.at(MOD_KW)); + p.bump(); + + if p.expect(IDENT) && !p.eat(SEMI) { + p.curly_block(mod_contents); } - if p.eat(SEMI) { - return; - } - p.curly_block(mod_contents); + p.finish() } pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool { @@ -153,8 +161,13 @@ pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool { } fn use_item(p: &mut Parser) { + p.start(USE_ITEM); + + assert!(p.at(USE_KW)); + p.bump(); use_tree(p); p.expect(SEMI); + p.finish(); fn use_tree(p: &mut Parser) -> bool{ if node_if(p, STAR, USE_TREE, |_| ()) { @@ -210,8 +223,14 @@ fn use_item(p: &mut Parser) { fn fn_item(p: &mut Parser) { + p.start(FN_ITEM); + + assert!(p.at(FN_KW)); + p.bump(); + p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN) && p.curly_block(|_| ()); + p.finish(); } diff --git a/src/parser/event_parser/grammar/mod.rs b/src/parser/event_parser/grammar/mod.rs index 1097344c01d..0c775bb257d 100644 --- a/src/parser/event_parser/grammar/mod.rs +++ b/src/parser/event_parser/grammar/mod.rs @@ -10,37 +10,39 @@ mod types; mod paths; pub(crate) fn file(p: &mut Parser) { - node(p, FILE, |p| { - p.eat(SHEBANG); - items::mod_contents(p); - }) + p.start(FILE); + p.eat(SHEBANG); + items::mod_contents(p); + p.finish() } fn visibility(p: &mut Parser) { - node_if(p, PUB_KW, VISIBILITY, |p| { - if p.current() != L_PAREN { - return - } - match p.raw_lookahead(1) { - CRATE_KW | SELF_KW | SUPER_KW => { - p.bump(); - p.bump(); + if p.at(PUB_KW) { + p.start(VISIBILITY); + p.bump(); + if p.at(L_PAREN) { + match p.raw_lookahead(1) { + CRATE_KW | SELF_KW | SUPER_KW | IN_KW => { + p.bump(); + if p.bump() == IN_KW { + paths::use_path(p); + } + p.expect(R_PAREN); + } + _ => () } - IN_KW => { - p.bump(); - p.bump(); - paths::use_path(p); - } - _ => return } - p.expect(R_PAREN); - }); + p.finish(); + } } fn alias(p: &mut Parser) -> bool { - node_if(p, AS_KW, ALIAS, |p| { + if p.at(AS_KW) { + p.start(ALIAS); + p.bump(); p.expect(IDENT); - }); + p.finish(); + } true //FIXME: return false if three are errors } @@ -92,40 +94,13 @@ fn comma_list bool>(p: &mut Parser, end: SyntaxKind, f: F) } -fn skip_to_first(p: &mut Parser, cond: C, f: F, message: &str) -> bool -where - C: Fn(&Parser) -> bool, - F: FnOnce(&mut Parser), -{ - let mut skipped = false; - loop { - if cond(p) { - if skipped { - p.finish(); - } - f(p); - return true; - } - if p.current() == EOF { - if skipped { - p.finish(); - } - return false; - } - if !skipped { - p.start(ERROR); - p.error() - .message(message) - .emit(); - } - p.bump(); - skipped = true; - } -} - impl<'p> Parser<'p> { + fn at(&self, kind: SyntaxKind) -> bool { + self.current() == kind + } + pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool { - if self.current() == kind { + if self.at(kind) { self.bump(); true } else { @@ -195,4 +170,4 @@ impl<'a> Lookahead for AnyOf<'a> { p.bump(); } -} \ No newline at end of file +} diff --git a/tests/data/parser/err/0001_item_recovery_in_file.txt b/tests/data/parser/err/0001_item_recovery_in_file.txt index 730367694b3..0ac741aa85a 100644 --- a/tests/data/parser/err/0001_item_recovery_in_file.txt +++ b/tests/data/parser/err/0001_item_recovery_in_file.txt @@ -1,8 +1,10 @@ FILE@[0; 21) - ERROR@[0; 10) + ERROR@[0; 3) err: `expected item` IDENT@[0; 2) WHITESPACE@[2; 3) + ERROR@[3; 10) + err: `expected item` IDENT@[3; 8) WHITESPACE@[8; 10) STRUCT_ITEM@[10; 21) diff --git a/tests/data/parser/err/0004_use_path_bad_segment.txt b/tests/data/parser/err/0004_use_path_bad_segment.txt index cd7e86d681a..adc0496832d 100644 --- a/tests/data/parser/err/0004_use_path_bad_segment.txt +++ b/tests/data/parser/err/0004_use_path_bad_segment.txt @@ -11,7 +11,10 @@ FILE@[0; 12) PATH_SEGMENT@[9; 9) err: `expected identifier` err: `expected SEMI` - ERROR@[9; 12) + ERROR@[9; 11) err: `expected item` INT_NUMBER@[9; 11) + ERROR@[11; 12) + err: `expected item, found `;` +consider removing this semicolon` SEMI@[11; 12)