From 50a02eb3593591a02677e1b56f24d7ff0459b9d0 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 12 Aug 2020 17:06:49 +0200 Subject: Rename ra_parser -> parser --- crates/parser/src/grammar/items.rs | 432 +++++++++++++++++++++++++++++++++++++ 1 file changed, 432 insertions(+) create mode 100644 crates/parser/src/grammar/items.rs (limited to 'crates/parser/src/grammar/items.rs') diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs new file mode 100644 index 000000000..d091b0fbb --- /dev/null +++ b/crates/parser/src/grammar/items.rs @@ -0,0 +1,432 @@ +//! FIXME: write short doc here + +mod consts; +mod adt; +mod traits; +mod use_item; + +pub(crate) use self::{ + adt::{enum_variant_list, record_field_def_list}, + expressions::{match_arm_list, record_field_list}, + traits::{impl_item_list, trait_item_list}, + use_item::use_tree_list, +}; +use super::*; + +// test mod_contents +// fn foo() {} +// macro_rules! foo {} +// foo::bar!(); +// super::baz! {} +// struct S; +pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { + attributes::inner_attributes(p); + while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) { + item_or_macro(p, stop_on_r_curly) + } +} + +pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ + FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, + CRATE_KW, USE_KW, MACRO_KW +]; + +pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) { + let m = p.start(); + attributes::outer_attributes(p); + let m = match maybe_item(p, m) { + Ok(()) => { + if p.at(T![;]) { + p.err_and_bump( + "expected item, found `;`\n\ + consider removing this semicolon", + ); + } + return; + } + Err(m) => m, + }; + if paths::is_use_path_start(p) { + match macro_call(p) { + BlockLike::Block => (), + BlockLike::NotBlock => { + p.expect(T![;]); + } + } + m.complete(p, MACRO_CALL); + } else { + m.abandon(p); + if p.at(T!['{']) { + error_block(p, "expected an item"); + } else if p.at(T!['}']) && !stop_on_r_curly { + let e = p.start(); + p.error("unmatched `}`"); + p.bump(T!['}']); + e.complete(p, ERROR); + } else if !p.at(EOF) && !p.at(T!['}']) { + p.err_and_bump("expected an item"); + } else { + p.error("expected an item"); + } + } +} + +pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { + // test_err pub_expr + // fn foo() { pub 92; } + let has_visibility = opt_visibility(p); + + let m = match items_without_modifiers(p, m) { + Ok(()) => return Ok(()), + Err(m) => m, + }; + + let mut has_mods = false; + + // modifiers + has_mods |= p.eat(T![const]); + + // test_err async_without_semicolon + // fn foo() { let _ = async {} } + if p.at(T![async]) && p.nth(1) != T!['{'] && p.nth(1) != T![move] && p.nth(1) != T![|] { + p.eat(T![async]); + has_mods = true; + } + + // test_err unsafe_block_in_mod + // fn foo(){} unsafe { } fn bar(){} + if p.at(T![unsafe]) && p.nth(1) != T!['{'] { + p.eat(T![unsafe]); + has_mods = true; + } + + if p.at(T![extern]) { + has_mods = true; + abi(p); + } + if p.at(IDENT) && p.at_contextual_kw("auto") && p.nth(1) == T![trait] { + p.bump_remap(T![auto]); + has_mods = true; + } + + // test default_item + // default impl T for Foo {} + if p.at(IDENT) && p.at_contextual_kw("default") { + match p.nth(1) { + T![fn] | T![type] | T![const] | T![impl] => { + p.bump_remap(T![default]); + has_mods = true; + } + T![unsafe] => { + // test default_unsafe_item + // default unsafe impl T for Foo { + // default unsafe fn foo() {} + // } + if matches!(p.nth(2), T![impl] | T![fn]) { + p.bump_remap(T![default]); + p.bump(T![unsafe]); + has_mods = true; + } + } + _ => (), + } + } + + // test existential_type + // existential type Foo: Fn() -> usize; + if p.at(IDENT) && p.at_contextual_kw("existential") && p.nth(1) == T![type] { + p.bump_remap(T![existential]); + has_mods = true; + } + + // items + match p.current() { + // test fn + // fn foo() {} + T![fn] => { + fn_def(p); + m.complete(p, FN); + } + + // test trait + // trait T {} + T![trait] => { + traits::trait_def(p); + m.complete(p, TRAIT); + } + + T![const] => { + consts::const_def(p, m); + } + + // test impl + // impl T for S {} + T![impl] => { + traits::impl_def(p); + m.complete(p, IMPL); + } + + T![type] => { + type_def(p, m); + } + _ => { + if !has_visibility && !has_mods { + return Err(m); + } else { + if has_mods { + p.error("expected existential, fn, trait or impl"); + } else { + p.error("expected an item"); + } + m.complete(p, ERROR); + } + } + } + Ok(()) +} + +fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { + let la = p.nth(1); + match p.current() { + // test extern_crate + // extern crate foo; + T![extern] if la == T![crate] => extern_crate_item(p, m), + T![type] => { + type_def(p, m); + } + T![mod] => mod_item(p, m), + T![struct] => { + // test struct_items + // struct Foo; + // struct Foo {} + // struct Foo(); + // struct Foo(String, usize); + // struct Foo { + // a: i32, + // b: f32, + // } + adt::struct_def(p, m); + } + // test pub_macro_def + // pub macro m($:ident) {} + T![macro] => { + macro_def(p, m); + } + IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => { + // test union_items + // union Foo {} + // union Foo { + // a: i32, + // b: f32, + // } + adt::union_def(p, m); + } + T![enum] => adt::enum_def(p, m), + T![use] => use_item::use_item(p, m), + T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::const_def(p, m), + T![static] => consts::static_def(p, m), + // test extern_block + // extern {} + T![extern] + if la == T!['{'] || ((la == STRING || la == RAW_STRING) && p.nth(2) == T!['{']) => + { + abi(p); + extern_item_list(p); + m.complete(p, EXTERN_BLOCK); + } + _ => return Err(m), + }; + Ok(()) +} + +fn extern_crate_item(p: &mut Parser, m: Marker) { + assert!(p.at(T![extern])); + p.bump(T![extern]); + assert!(p.at(T![crate])); + p.bump(T![crate]); + + if p.at(T![self]) { + p.bump(T![self]); + } else { + name_ref(p); + } + + opt_alias(p); + p.expect(T![;]); + m.complete(p, EXTERN_CRATE); +} + +pub(crate) fn extern_item_list(p: &mut Parser) { + assert!(p.at(T!['{'])); + let m = p.start(); + p.bump(T!['{']); + mod_contents(p, true); + p.expect(T!['}']); + m.complete(p, EXTERN_ITEM_LIST); +} + +fn fn_def(p: &mut Parser) { + assert!(p.at(T![fn])); + p.bump(T![fn]); + + name_r(p, ITEM_RECOVERY_SET); + // test function_type_params + // fn foo(){} + type_params::opt_type_param_list(p); + + if p.at(T!['(']) { + params::param_list_fn_def(p); + } else { + p.error("expected function arguments"); + } + // test function_ret_type + // fn foo() {} + // fn bar() -> () {} + opt_fn_ret_type(p); + + // test function_where_clause + // fn foo() where T: Copy {} + type_params::opt_where_clause(p); + + // test fn_decl + // trait T { fn foo(); } + if p.at(T![;]) { + p.bump(T![;]); + } else { + expressions::block_expr(p) + } +} + +// test type_item +// type Foo = Bar; +fn type_def(p: &mut Parser, m: Marker) { + assert!(p.at(T![type])); + p.bump(T![type]); + + name(p); + + // test type_item_type_params + // type Result = (); + type_params::opt_type_param_list(p); + + if p.at(T![:]) { + type_params::bounds(p); + } + + // test type_item_where_clause + // type Foo where Foo: Copy = (); + type_params::opt_where_clause(p); + if p.eat(T![=]) { + types::type_(p); + } + p.expect(T![;]); + m.complete(p, TYPE_ALIAS); +} + +pub(crate) fn mod_item(p: &mut Parser, m: Marker) { + assert!(p.at(T![mod])); + p.bump(T![mod]); + + name(p); + if p.at(T!['{']) { + mod_item_list(p); + } else if !p.eat(T![;]) { + p.error("expected `;` or `{`"); + } + m.complete(p, MODULE); +} + +pub(crate) fn mod_item_list(p: &mut Parser) { + assert!(p.at(T!['{'])); + let m = p.start(); + p.bump(T!['{']); + mod_contents(p, true); + p.expect(T!['}']); + m.complete(p, ITEM_LIST); +} + +// test macro_def +// macro m { ($i:ident) => {} } +// macro m($i:ident) {} +fn macro_def(p: &mut Parser, m: Marker) { + p.expect(T![macro]); + name_r(p, ITEM_RECOVERY_SET); + if p.at(T!['{']) { + token_tree(p); + } else if !p.at(T!['(']) { + p.error("unmatched `(`"); + } else { + let m = p.start(); + token_tree(p); + match p.current() { + T!['{'] | T!['['] | T!['('] => token_tree(p), + _ => p.error("expected `{`, `[`, `(`"), + } + m.complete(p, TOKEN_TREE); + } + + m.complete(p, MACRO_DEF); +} + +fn macro_call(p: &mut Parser) -> BlockLike { + assert!(paths::is_use_path_start(p)); + paths::use_path(p); + macro_call_after_excl(p) +} + +pub(super) fn macro_call_after_excl(p: &mut Parser) -> BlockLike { + p.expect(T![!]); + if p.at(IDENT) { + name(p); + } + // Special-case `macro_rules! try`. + // This is a hack until we do proper edition support + + // test try_macro_rules + // macro_rules! try { () => {} } + if p.at(T![try]) { + let m = p.start(); + p.bump_remap(IDENT); + m.complete(p, NAME); + } + + match p.current() { + T!['{'] => { + token_tree(p); + BlockLike::Block + } + T!['('] | T!['['] => { + token_tree(p); + BlockLike::NotBlock + } + _ => { + p.error("expected `{`, `[`, `(`"); + BlockLike::NotBlock + } + } +} + +pub(crate) fn token_tree(p: &mut Parser) { + let closing_paren_kind = match p.current() { + T!['{'] => T!['}'], + T!['('] => T![')'], + T!['['] => T![']'], + _ => unreachable!(), + }; + let m = p.start(); + p.bump_any(); + while !p.at(EOF) && !p.at(closing_paren_kind) { + match p.current() { + T!['{'] | T!['('] | T!['['] => token_tree(p), + T!['}'] => { + p.error("unmatched `}`"); + m.complete(p, TOKEN_TREE); + return; + } + T![')'] | T![']'] => p.err_and_bump("unmatched brace"), + _ => p.bump_any(), + } + } + p.expect(closing_paren_kind); + m.complete(p, TOKEN_TREE); +} -- cgit v1.2.3 From 6bc2633c90cedad057c5201d1ab7f67b57247004 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 17:58:35 +0200 Subject: Align parser names with grammar --- crates/parser/src/grammar/items.rs | 54 +++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'crates/parser/src/grammar/items.rs') diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index d091b0fbb..b2f7cc21f 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -6,9 +6,9 @@ mod traits; mod use_item; pub(crate) use self::{ - adt::{enum_variant_list, record_field_def_list}, - expressions::{match_arm_list, record_field_list}, - traits::{impl_item_list, trait_item_list}, + adt::{record_field_list, variant_list}, + expressions::{match_arm_list, record_expr_field_list}, + traits::assoc_item_list, use_item::use_tree_list, }; use super::*; @@ -20,7 +20,7 @@ use super::*; // super::baz! {} // struct S; pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { - attributes::inner_attributes(p); + attributes::inner_attrs(p); while !(stop_on_r_curly && p.at(T!['}']) || p.at(EOF)) { item_or_macro(p, stop_on_r_curly) } @@ -33,7 +33,7 @@ pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) { let m = p.start(); - attributes::outer_attributes(p); + attributes::outer_attrs(p); let m = match maybe_item(p, m) { Ok(()) => { if p.at(T![;]) { @@ -144,30 +144,30 @@ pub(super) fn maybe_item(p: &mut Parser, m: Marker) -> Result<(), Marker> { // test fn // fn foo() {} T![fn] => { - fn_def(p); + fn_(p); m.complete(p, FN); } // test trait // trait T {} T![trait] => { - traits::trait_def(p); + traits::trait_(p); m.complete(p, TRAIT); } T![const] => { - consts::const_def(p, m); + consts::konst(p, m); } // test impl // impl T for S {} T![impl] => { - traits::impl_def(p); + traits::impl_(p); m.complete(p, IMPL); } T![type] => { - type_def(p, m); + type_alias(p, m); } _ => { if !has_visibility && !has_mods { @@ -190,9 +190,9 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { match p.current() { // test extern_crate // extern crate foo; - T![extern] if la == T![crate] => extern_crate_item(p, m), + T![extern] if la == T![crate] => extern_crate(p, m), T![type] => { - type_def(p, m); + type_alias(p, m); } T![mod] => mod_item(p, m), T![struct] => { @@ -205,7 +205,7 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { // a: i32, // b: f32, // } - adt::struct_def(p, m); + adt::strukt(p, m); } // test pub_macro_def // pub macro m($:ident) {} @@ -219,12 +219,12 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { // a: i32, // b: f32, // } - adt::union_def(p, m); + adt::union(p, m); } - T![enum] => adt::enum_def(p, m), - T![use] => use_item::use_item(p, m), - T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::const_def(p, m), - T![static] => consts::static_def(p, m), + T![enum] => adt::enum_(p, m), + T![use] => use_item::use_(p, m), + T![const] if (la == IDENT || la == T![_] || la == T![mut]) => consts::konst(p, m), + T![static] => consts::static_(p, m), // test extern_block // extern {} T![extern] @@ -239,7 +239,7 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { Ok(()) } -fn extern_crate_item(p: &mut Parser, m: Marker) { +fn extern_crate(p: &mut Parser, m: Marker) { assert!(p.at(T![extern])); p.bump(T![extern]); assert!(p.at(T![crate])); @@ -251,7 +251,7 @@ fn extern_crate_item(p: &mut Parser, m: Marker) { name_ref(p); } - opt_alias(p); + opt_rename(p); p.expect(T![;]); m.complete(p, EXTERN_CRATE); } @@ -265,14 +265,14 @@ pub(crate) fn extern_item_list(p: &mut Parser) { m.complete(p, EXTERN_ITEM_LIST); } -fn fn_def(p: &mut Parser) { +fn fn_(p: &mut Parser) { assert!(p.at(T![fn])); p.bump(T![fn]); name_r(p, ITEM_RECOVERY_SET); // test function_type_params // fn foo(){} - type_params::opt_type_param_list(p); + type_params::opt_generic_param_list(p); if p.at(T!['(']) { params::param_list_fn_def(p); @@ -282,7 +282,7 @@ fn fn_def(p: &mut Parser) { // test function_ret_type // fn foo() {} // fn bar() -> () {} - opt_fn_ret_type(p); + opt_ret_type(p); // test function_where_clause // fn foo() where T: Copy {} @@ -299,7 +299,7 @@ fn fn_def(p: &mut Parser) { // test type_item // type Foo = Bar; -fn type_def(p: &mut Parser, m: Marker) { +fn type_alias(p: &mut Parser, m: Marker) { assert!(p.at(T![type])); p.bump(T![type]); @@ -307,7 +307,7 @@ fn type_def(p: &mut Parser, m: Marker) { // test type_item_type_params // type Result = (); - type_params::opt_type_param_list(p); + type_params::opt_generic_param_list(p); if p.at(T![:]) { type_params::bounds(p); @@ -329,14 +329,14 @@ pub(crate) fn mod_item(p: &mut Parser, m: Marker) { name(p); if p.at(T!['{']) { - mod_item_list(p); + item_list(p); } else if !p.eat(T![;]) { p.error("expected `;` or `{`"); } m.complete(p, MODULE); } -pub(crate) fn mod_item_list(p: &mut Parser) { +pub(crate) fn item_list(p: &mut Parser) { assert!(p.at(T!['{'])); let m = p.start(); p.bump(T!['{']); -- cgit v1.2.3 From ef462ed6af7ae8e0d30894baefe6ba1ff49aab8f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 13 Aug 2020 18:28:23 +0200 Subject: Better recovery in `use foo::;` --- crates/parser/src/grammar/items.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'crates/parser/src/grammar/items.rs') diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index b2f7cc21f..8fd8f3b80 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -27,8 +27,20 @@ pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) { } pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ - FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, - CRATE_KW, USE_KW, MACRO_KW + FN_KW, + STRUCT_KW, + ENUM_KW, + IMPL_KW, + TRAIT_KW, + CONST_KW, + STATIC_KW, + LET_KW, + MOD_KW, + PUB_KW, + CRATE_KW, + USE_KW, + MACRO_KW, + T![;], ]; pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool) { -- cgit v1.2.3