From e1c0bdaf75f8d88a5c28b3e44def17d91d4f46b3 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 25 Nov 2019 16:55:09 +0300 Subject: Introduce dedicated AST node for union Although structs and unions have the same syntax and differ only in the keyword, re-using the single syntax node for both of them leads to confusion in practice, and propagates further down the hir in an upleasent way. Moreover, static and consts also share syntax, but we use different nodes for them. --- crates/ra_parser/src/grammar/items.rs | 10 +- crates/ra_parser/src/grammar/items/adt.rs | 176 +++++++++++++++++++++ crates/ra_parser/src/grammar/items/nominal.rs | 167 ------------------- crates/ra_parser/src/syntax_kind/generated.rs | 1 + crates/ra_syntax/src/ast/generated.rs | 28 ++++ crates/ra_syntax/src/grammar.ron | 10 ++ .../parser/inline/ok/0068_union_items.txt | 4 +- .../test_data/parser/ok/0035_weird_exprs.txt | 2 +- 8 files changed, 223 insertions(+), 175 deletions(-) create mode 100644 crates/ra_parser/src/grammar/items/adt.rs delete mode 100644 crates/ra_parser/src/grammar/items/nominal.rs (limited to 'crates') diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs index 85f7eeb00..630e6ce64 100644 --- a/crates/ra_parser/src/grammar/items.rs +++ b/crates/ra_parser/src/grammar/items.rs @@ -1,13 +1,13 @@ //! FIXME: write short doc here mod consts; -mod nominal; +mod adt; mod traits; mod use_item; pub(crate) use self::{ expressions::{match_arm_list, record_field_list}, - nominal::{enum_variant_list, record_field_def_list}, + adt::{enum_variant_list, record_field_def_list}, traits::{impl_item_list, trait_item_list}, use_item::use_tree_list, }; @@ -247,7 +247,7 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { // a: i32, // b: f32, // } - nominal::struct_def(p, m, T![struct]); + adt::struct_def(p, m); } IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => { // test union_items @@ -256,9 +256,9 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> { // a: i32, // b: f32, // } - nominal::struct_def(p, m, T![union]); + adt::union_def(p, m); } - T![enum] => nominal::enum_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), diff --git a/crates/ra_parser/src/grammar/items/adt.rs b/crates/ra_parser/src/grammar/items/adt.rs new file mode 100644 index 000000000..c777bc9d0 --- /dev/null +++ b/crates/ra_parser/src/grammar/items/adt.rs @@ -0,0 +1,176 @@ +//! FIXME: write short doc here + +use super::*; + +pub(super) fn struct_def(p: &mut Parser, m: Marker) { + assert!(p.at(T![struct])); + p.bump(T![struct]); + struct_or_union(p, m, T![struct], STRUCT_DEF); +} + +pub(super) fn union_def(p: &mut Parser, m: Marker) { + assert!(p.at_contextual_kw("union")); + p.bump_remap(T![union]); + struct_or_union(p, m, T![union], UNION_DEF); +} + +fn struct_or_union(p: &mut Parser, m: Marker, kw: SyntaxKind, def: SyntaxKind) { + name_r(p, ITEM_RECOVERY_SET); + type_params::opt_type_param_list(p); + match p.current() { + T![where] => { + type_params::opt_where_clause(p); + match p.current() { + T![;] => { + p.bump(T![;]); + } + T!['{'] => record_field_def_list(p), + _ => { + //FIXME: special case `(` error message + p.error("expected `;` or `{`"); + } + } + } + T![;] if kw == T![struct] => { + p.bump(T![;]); + } + T!['{'] => record_field_def_list(p), + T!['('] if kw == T![struct] => { + tuple_field_def_list(p); + // test tuple_struct_where + // struct Test(T) where T: Clone; + // struct Test(T); + type_params::opt_where_clause(p); + p.expect(T![;]); + } + _ if kw == T![struct] => { + p.error("expected `;`, `{`, or `(`"); + } + _ => { + p.error("expected `{`"); + } + } + m.complete(p, def); +} + +pub(super) fn enum_def(p: &mut Parser, m: Marker) { + assert!(p.at(T![enum])); + p.bump(T![enum]); + name_r(p, ITEM_RECOVERY_SET); + type_params::opt_type_param_list(p); + type_params::opt_where_clause(p); + if p.at(T!['{']) { + enum_variant_list(p); + } else { + p.error("expected `{`") + } + m.complete(p, ENUM_DEF); +} + +pub(crate) fn enum_variant_list(p: &mut Parser) { + assert!(p.at(T!['{'])); + let m = p.start(); + p.bump(T!['{']); + while !p.at(EOF) && !p.at(T!['}']) { + if p.at(T!['{']) { + error_block(p, "expected enum variant"); + continue; + } + let var = p.start(); + attributes::outer_attributes(p); + if p.at(IDENT) { + name(p); + match p.current() { + T!['{'] => record_field_def_list(p), + T!['('] => tuple_field_def_list(p), + T![=] => { + p.bump(T![=]); + expressions::expr(p); + } + _ => (), + } + var.complete(p, ENUM_VARIANT); + } else { + var.abandon(p); + p.err_and_bump("expected enum variant"); + } + if !p.at(T!['}']) { + p.expect(T![,]); + } + } + p.expect(T!['}']); + m.complete(p, ENUM_VARIANT_LIST); +} + +pub(crate) fn record_field_def_list(p: &mut Parser) { + assert!(p.at(T!['{'])); + let m = p.start(); + p.bump(T!['{']); + while !p.at(T!['}']) && !p.at(EOF) { + if p.at(T!['{']) { + error_block(p, "expected field"); + continue; + } + record_field_def(p); + if !p.at(T!['}']) { + p.expect(T![,]); + } + } + p.expect(T!['}']); + m.complete(p, RECORD_FIELD_DEF_LIST); + + fn record_field_def(p: &mut Parser) { + let m = p.start(); + // test record_field_attrs + // struct S { + // #[serde(with = "url_serde")] + // pub uri: Uri, + // } + attributes::outer_attributes(p); + opt_visibility(p); + if p.at(IDENT) { + name(p); + p.expect(T![:]); + types::type_(p); + m.complete(p, RECORD_FIELD_DEF); + } else { + m.abandon(p); + p.err_and_bump("expected field declaration"); + } + } +} + +fn tuple_field_def_list(p: &mut Parser) { + assert!(p.at(T!['('])); + let m = p.start(); + if !p.expect(T!['(']) { + return; + } + while !p.at(T![')']) && !p.at(EOF) { + let m = p.start(); + // test tuple_field_attrs + // struct S ( + // #[serde(with = "url_serde")] + // pub Uri, + // ); + // + // enum S { + // Uri(#[serde(with = "url_serde")] Uri), + // } + attributes::outer_attributes(p); + opt_visibility(p); + if !p.at_ts(types::TYPE_FIRST) { + p.error("expected a type"); + m.complete(p, ERROR); + break; + } + types::type_(p); + m.complete(p, TUPLE_FIELD_DEF); + + if !p.at(T![')']) { + p.expect(T![,]); + } + } + p.expect(T![')']); + m.complete(p, TUPLE_FIELD_DEF_LIST); +} diff --git a/crates/ra_parser/src/grammar/items/nominal.rs b/crates/ra_parser/src/grammar/items/nominal.rs deleted file mode 100644 index 9d8fb8486..000000000 --- a/crates/ra_parser/src/grammar/items/nominal.rs +++ /dev/null @@ -1,167 +0,0 @@ -//! FIXME: write short doc here - -use super::*; - -pub(super) fn struct_def(p: &mut Parser, m: Marker, kind: SyntaxKind) { - assert!(p.at(T![struct]) || p.at_contextual_kw("union")); - p.bump_remap(kind); - - name_r(p, ITEM_RECOVERY_SET); - type_params::opt_type_param_list(p); - match p.current() { - T![where] => { - type_params::opt_where_clause(p); - match p.current() { - T![;] => { - p.bump(T![;]); - } - T!['{'] => record_field_def_list(p), - _ => { - //FIXME: special case `(` error message - p.error("expected `;` or `{`"); - } - } - } - T![;] if kind == T![struct] => { - p.bump(T![;]); - } - T!['{'] => record_field_def_list(p), - T!['('] if kind == T![struct] => { - tuple_field_def_list(p); - // test tuple_struct_where - // struct Test(T) where T: Clone; - // struct Test(T); - type_params::opt_where_clause(p); - p.expect(T![;]); - } - _ if kind == T![struct] => { - p.error("expected `;`, `{`, or `(`"); - } - _ => { - p.error("expected `{`"); - } - } - m.complete(p, STRUCT_DEF); -} - -pub(super) fn enum_def(p: &mut Parser, m: Marker) { - assert!(p.at(T![enum])); - p.bump(T![enum]); - name_r(p, ITEM_RECOVERY_SET); - type_params::opt_type_param_list(p); - type_params::opt_where_clause(p); - if p.at(T!['{']) { - enum_variant_list(p); - } else { - p.error("expected `{`") - } - m.complete(p, ENUM_DEF); -} - -pub(crate) fn enum_variant_list(p: &mut Parser) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - while !p.at(EOF) && !p.at(T!['}']) { - if p.at(T!['{']) { - error_block(p, "expected enum variant"); - continue; - } - let var = p.start(); - attributes::outer_attributes(p); - if p.at(IDENT) { - name(p); - match p.current() { - T!['{'] => record_field_def_list(p), - T!['('] => tuple_field_def_list(p), - T![=] => { - p.bump(T![=]); - expressions::expr(p); - } - _ => (), - } - var.complete(p, ENUM_VARIANT); - } else { - var.abandon(p); - p.err_and_bump("expected enum variant"); - } - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); - m.complete(p, ENUM_VARIANT_LIST); -} - -pub(crate) fn record_field_def_list(p: &mut Parser) { - assert!(p.at(T!['{'])); - let m = p.start(); - p.bump(T!['{']); - while !p.at(T!['}']) && !p.at(EOF) { - if p.at(T!['{']) { - error_block(p, "expected field"); - continue; - } - record_field_def(p); - if !p.at(T!['}']) { - p.expect(T![,]); - } - } - p.expect(T!['}']); - m.complete(p, RECORD_FIELD_DEF_LIST); - - fn record_field_def(p: &mut Parser) { - let m = p.start(); - // test record_field_attrs - // struct S { - // #[serde(with = "url_serde")] - // pub uri: Uri, - // } - attributes::outer_attributes(p); - opt_visibility(p); - if p.at(IDENT) { - name(p); - p.expect(T![:]); - types::type_(p); - m.complete(p, RECORD_FIELD_DEF); - } else { - m.abandon(p); - p.err_and_bump("expected field declaration"); - } - } -} - -fn tuple_field_def_list(p: &mut Parser) { - assert!(p.at(T!['('])); - let m = p.start(); - if !p.expect(T!['(']) { - return; - } - while !p.at(T![')']) && !p.at(EOF) { - let m = p.start(); - // test tuple_field_attrs - // struct S ( - // #[serde(with = "url_serde")] - // pub Uri, - // ); - // - // enum S { - // Uri(#[serde(with = "url_serde")] Uri), - // } - attributes::outer_attributes(p); - opt_visibility(p); - if !p.at_ts(types::TYPE_FIRST) { - p.error("expected a type"); - m.complete(p, ERROR); - break; - } - types::type_(p); - m.complete(p, TUPLE_FIELD_DEF); - - if !p.at(T![')']) { - p.expect(T![,]); - } - } - p.expect(T![')']); - m.complete(p, TUPLE_FIELD_DEF_LIST); -} diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs index 96b5bce88..fe0fcdb33 100644 --- a/crates/ra_parser/src/syntax_kind/generated.rs +++ b/crates/ra_parser/src/syntax_kind/generated.rs @@ -122,6 +122,7 @@ pub enum SyntaxKind { R_DOLLAR, SOURCE_FILE, STRUCT_DEF, + UNION_DEF, ENUM_DEF, FN_DEF, RET_TYPE, diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index de506d7cd..1a03ae56c 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -3789,6 +3789,34 @@ impl AstNode for TypeRef { } impl TypeRef {} #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct UnionDef { + pub(crate) syntax: SyntaxNode, +} +impl AstNode for UnionDef { + fn can_cast(kind: SyntaxKind) -> bool { + match kind { + UNION_DEF => true, + _ => false, + } + } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { + &self.syntax + } +} +impl ast::VisibilityOwner for UnionDef {} +impl ast::NameOwner for UnionDef {} +impl ast::TypeParamsOwner for UnionDef {} +impl ast::AttrsOwner for UnionDef {} +impl ast::DocCommentsOwner for UnionDef {} +impl UnionDef {} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct UseItem { pub(crate) syntax: SyntaxNode, } diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 88d1dc109..c16bed891 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -126,6 +126,7 @@ Grammar( "SOURCE_FILE", "STRUCT_DEF", + "UNION_DEF", "ENUM_DEF", "FN_DEF", "RET_TYPE", @@ -285,6 +286,15 @@ Grammar( "DocCommentsOwner" ] ), + "UnionDef": ( + traits: [ + "VisibilityOwner", + "NameOwner", + "TypeParamsOwner", + "AttrsOwner", + "DocCommentsOwner" + ] + ), "RecordFieldDefList": (collections: [("fields", "RecordFieldDef")]), "RecordFieldDef": ( traits: [ diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.txt b/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.txt index f9ace02ee..9d7982684 100644 --- a/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.txt +++ b/crates/ra_syntax/test_data/parser/inline/ok/0068_union_items.txt @@ -1,5 +1,5 @@ SOURCE_FILE@[0; 51) - STRUCT_DEF@[0; 12) + UNION_DEF@[0; 12) UNION_KW@[0; 5) "union" WHITESPACE@[5; 6) " " NAME@[6; 9) @@ -9,7 +9,7 @@ SOURCE_FILE@[0; 51) L_CURLY@[10; 11) "{" R_CURLY@[11; 12) "}" WHITESPACE@[12; 13) "\n" - STRUCT_DEF@[13; 50) + UNION_DEF@[13; 50) UNION_KW@[13; 18) "union" WHITESPACE@[18; 19) " " NAME@[19; 22) diff --git a/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.txt b/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.txt index 3260cc589..90538b90d 100644 --- a/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.txt +++ b/crates/ra_syntax/test_data/parser/ok/0035_weird_exprs.txt @@ -1592,7 +1592,7 @@ SOURCE_FILE@[0; 3813) BLOCK@[2845; 2906) L_CURLY@[2845; 2846) "{" WHITESPACE@[2846; 2851) "\n " - STRUCT_DEF@[2851; 2904) + UNION_DEF@[2851; 2904) UNION_KW@[2851; 2856) "union" WHITESPACE@[2856; 2857) " " NAME@[2857; 2862) -- cgit v1.2.3