From eb8e9043e227682e6e7db2711091dc74d847e766 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 8 Aug 2018 19:26:38 +0300 Subject: Where clauses --- src/grammar.ron | 1 + src/grammar/type_params.rs | 60 ++++++++++++++----- src/grammar/types.rs | 2 +- src/syntax_kinds/generated.rs | 2 + .../parser/inline/0016_type_item_where_clause.txt | 17 ++++-- tests/data/parser/inline/0056_trait_item.txt | 16 +++-- .../parser/inline/0059_fn_item_where_clause.txt | 16 +++-- tests/data/parser/inline/0098_where_clause.rs | 6 ++ tests/data/parser/inline/0098_where_clause.txt | 69 ++++++++++++++++++++++ 9 files changed, 162 insertions(+), 27 deletions(-) create mode 100644 tests/data/parser/inline/0098_where_clause.rs create mode 100644 tests/data/parser/inline/0098_where_clause.txt diff --git a/src/grammar.ron b/src/grammar.ron index df1dfe050..0443dd798 100644 --- a/src/grammar.ron +++ b/src/grammar.ron @@ -192,6 +192,7 @@ Grammar( "ALIAS", "VISIBILITY", "WHERE_CLAUSE", + "WHERE_PRED", "ABI", "NAME", "NAME_REF", diff --git a/src/grammar/type_params.rs b/src/grammar/type_params.rs index 1227482ad..0a3e8fd07 100644 --- a/src/grammar/type_params.rs +++ b/src/grammar/type_params.rs @@ -24,13 +24,8 @@ pub(super) fn type_param_list(p: &mut Parser) { assert!(p.at(LIFETIME)); let m = p.start(); p.bump(); - if p.eat(COLON) { - while p.at(LIFETIME) { - p.bump(); - if !p.eat(PLUS) { - break; - } - } + if p.at(COLON) { + lifetime_bounds(p); } m.complete(p, LIFETIME_PARAM); } @@ -60,6 +55,17 @@ pub(super) fn bounds(p: &mut Parser) { bounds_without_colon(p); } +fn lifetime_bounds(p: &mut Parser) { + assert!(p.at(COLON)); + p.bump(); + while p.at(LIFETIME) { + p.bump(); + if !p.eat(PLUS) { + break; + } + } +} + pub(super) fn bounds_without_colon(p: &mut Parser) { loop { let has_paren = p.eat(L_PAREN); @@ -83,13 +89,39 @@ pub(super) fn bounds_without_colon(p: &mut Parser) { } } +// test where_clause +// fn foo() +// where +// 'a: 'b + 'c, +// T: Clone + Copy + 'static, +// Iterator::Item: 'a, +// {} pub(super) fn where_clause(p: &mut Parser) { - if p.at(WHERE_KW) { - let m = p.start(); - p.bump(); - p.expect(IDENT); - p.expect(COLON); - p.expect(IDENT); - m.complete(p, WHERE_CLAUSE); + if !p.at(WHERE_KW) { + return; + } + let m = p.start(); + p.bump(); + loop { + if !(paths::is_path_start(p) || p.current() == LIFETIME) { + break + } + where_predicate(p); + if p.current() != L_CURLY && p.current() != SEMI { + p.expect(COMMA); + } + } + m.complete(p, WHERE_CLAUSE); +} + +fn where_predicate(p: &mut Parser) { + let m = p.start(); + if p.at(LIFETIME) { + p.eat(LIFETIME); + lifetime_bounds(p) + } else { + types::path_type(p); + bounds(p); } + m.complete(p, WHERE_PRED); } diff --git a/src/grammar/types.rs b/src/grammar/types.rs index c8ced3d28..0d8c6bfba 100644 --- a/src/grammar/types.rs +++ b/src/grammar/types.rs @@ -199,7 +199,7 @@ fn impl_trait_type(p: &mut Parser) { // type B = ::Foo; // type C = self::Foo; // type D = super::Foo; -fn path_type(p: &mut Parser) { +pub(super) fn path_type(p: &mut Parser) { assert!(paths::is_path_start(p)); let m = p.start(); paths::type_path(p); diff --git a/src/syntax_kinds/generated.rs b/src/syntax_kinds/generated.rs index a74acf6eb..9a9c1f223 100644 --- a/src/syntax_kinds/generated.rs +++ b/src/syntax_kinds/generated.rs @@ -175,6 +175,7 @@ pub enum SyntaxKind { ALIAS, VISIBILITY, WHERE_CLAUSE, + WHERE_PRED, ABI, NAME, NAME_REF, @@ -415,6 +416,7 @@ impl SyntaxKind { ALIAS => &SyntaxInfo { name: "ALIAS" }, VISIBILITY => &SyntaxInfo { name: "VISIBILITY" }, WHERE_CLAUSE => &SyntaxInfo { name: "WHERE_CLAUSE" }, + WHERE_PRED => &SyntaxInfo { name: "WHERE_PRED" }, ABI => &SyntaxInfo { name: "ABI" }, NAME => &SyntaxInfo { name: "NAME" }, NAME_REF => &SyntaxInfo { name: "NAME_REF" }, diff --git a/tests/data/parser/inline/0016_type_item_where_clause.txt b/tests/data/parser/inline/0016_type_item_where_clause.txt index 5879edc42..2f3c52960 100644 --- a/tests/data/parser/inline/0016_type_item_where_clause.txt +++ b/tests/data/parser/inline/0016_type_item_where_clause.txt @@ -8,10 +8,19 @@ FILE@[0; 31) WHERE_CLAUSE@[9; 24) WHERE_KW@[9; 14) WHITESPACE@[14; 15) - IDENT@[15; 18) "Foo" - COLON@[18; 19) - WHITESPACE@[19; 20) - IDENT@[20; 24) "Copy" + WHERE_PRED@[15; 24) + PATH_TYPE@[15; 18) + PATH@[15; 18) + PATH_SEGMENT@[15; 18) + NAME_REF@[15; 18) + IDENT@[15; 18) "Foo" + COLON@[18; 19) + WHITESPACE@[19; 20) + PATH@[20; 24) + PATH_SEGMENT@[20; 24) + NAME_REF@[20; 24) + IDENT@[20; 24) "Copy" + err: `expected COMMA` WHITESPACE@[24; 25) EQ@[25; 26) WHITESPACE@[26; 27) diff --git a/tests/data/parser/inline/0056_trait_item.txt b/tests/data/parser/inline/0056_trait_item.txt index b2d36afe7..ba4e0ebc8 100644 --- a/tests/data/parser/inline/0056_trait_item.txt +++ b/tests/data/parser/inline/0056_trait_item.txt @@ -27,10 +27,18 @@ FILE@[0; 42) WHERE_CLAUSE@[25; 38) WHERE_KW@[25; 30) WHITESPACE@[30; 31) - IDENT@[31; 32) "U" - COLON@[32; 33) - WHITESPACE@[33; 34) - IDENT@[34; 38) "Copy" + WHERE_PRED@[31; 38) + PATH_TYPE@[31; 32) + PATH@[31; 32) + PATH_SEGMENT@[31; 32) + NAME_REF@[31; 32) + IDENT@[31; 32) "U" + COLON@[32; 33) + WHITESPACE@[33; 34) + PATH@[34; 38) + PATH_SEGMENT@[34; 38) + NAME_REF@[34; 38) + IDENT@[34; 38) "Copy" WHITESPACE@[38; 39) L_CURLY@[39; 40) R_CURLY@[40; 41) diff --git a/tests/data/parser/inline/0059_fn_item_where_clause.txt b/tests/data/parser/inline/0059_fn_item_where_clause.txt index 8614d1597..afedf983e 100644 --- a/tests/data/parser/inline/0059_fn_item_where_clause.txt +++ b/tests/data/parser/inline/0059_fn_item_where_clause.txt @@ -17,10 +17,18 @@ FILE@[0; 29) WHERE_CLAUSE@[12; 25) WHERE_KW@[12; 17) WHITESPACE@[17; 18) - IDENT@[18; 19) "T" - COLON@[19; 20) - WHITESPACE@[20; 21) - IDENT@[21; 25) "Copy" + WHERE_PRED@[18; 25) + PATH_TYPE@[18; 19) + PATH@[18; 19) + PATH_SEGMENT@[18; 19) + NAME_REF@[18; 19) + IDENT@[18; 19) "T" + COLON@[19; 20) + WHITESPACE@[20; 21) + PATH@[21; 25) + PATH_SEGMENT@[21; 25) + NAME_REF@[21; 25) + IDENT@[21; 25) "Copy" WHITESPACE@[25; 26) BLOCK_EXPR@[26; 28) L_CURLY@[26; 27) diff --git a/tests/data/parser/inline/0098_where_clause.rs b/tests/data/parser/inline/0098_where_clause.rs new file mode 100644 index 000000000..592a005f9 --- /dev/null +++ b/tests/data/parser/inline/0098_where_clause.rs @@ -0,0 +1,6 @@ +fn foo() +where + 'a: 'b + 'c, + T: Clone + Copy + 'static, + Iterator::Item: 'a, +{} diff --git a/tests/data/parser/inline/0098_where_clause.txt b/tests/data/parser/inline/0098_where_clause.txt new file mode 100644 index 000000000..a1180b554 --- /dev/null +++ b/tests/data/parser/inline/0098_where_clause.txt @@ -0,0 +1,69 @@ +FILE@[0; 87) + FN_ITEM@[0; 86) + FN_KW@[0; 2) + WHITESPACE@[2; 3) + NAME@[3; 6) + IDENT@[3; 6) "foo" + PARAM_LIST@[6; 8) + L_PAREN@[6; 7) + R_PAREN@[7; 8) + WHITESPACE@[8; 9) + WHERE_CLAUSE@[9; 83) + WHERE_KW@[9; 14) + WHITESPACE@[14; 18) + WHERE_PRED@[18; 29) + LIFETIME@[18; 20) "'a" + COLON@[20; 21) + WHITESPACE@[21; 22) + LIFETIME@[22; 24) "'b" + WHITESPACE@[24; 25) + PLUS@[25; 26) + WHITESPACE@[26; 27) + LIFETIME@[27; 29) "'c" + COMMA@[29; 30) + WHITESPACE@[30; 34) + WHERE_PRED@[34; 59) + PATH_TYPE@[34; 35) + PATH@[34; 35) + PATH_SEGMENT@[34; 35) + NAME_REF@[34; 35) + IDENT@[34; 35) "T" + COLON@[35; 36) + WHITESPACE@[36; 37) + PATH@[37; 42) + PATH_SEGMENT@[37; 42) + NAME_REF@[37; 42) + IDENT@[37; 42) "Clone" + WHITESPACE@[42; 43) + PLUS@[43; 44) + WHITESPACE@[44; 45) + PATH@[45; 49) + PATH_SEGMENT@[45; 49) + NAME_REF@[45; 49) + IDENT@[45; 49) "Copy" + WHITESPACE@[49; 50) + PLUS@[50; 51) + WHITESPACE@[51; 52) + LIFETIME@[52; 59) "'static" + COMMA@[59; 60) + WHITESPACE@[60; 64) + WHERE_PRED@[64; 82) + PATH_TYPE@[64; 78) + PATH@[64; 78) + PATH@[64; 72) + PATH_SEGMENT@[64; 72) + NAME_REF@[64; 72) + IDENT@[64; 72) "Iterator" + COLONCOLON@[72; 74) + PATH_SEGMENT@[74; 78) + NAME_REF@[74; 78) + IDENT@[74; 78) "Item" + COLON@[78; 79) + WHITESPACE@[79; 80) + LIFETIME@[80; 82) "'a" + COMMA@[82; 83) + WHITESPACE@[83; 84) + BLOCK_EXPR@[84; 86) + L_CURLY@[84; 85) + R_CURLY@[85; 86) + WHITESPACE@[86; 87) -- cgit v1.2.3