From 9aab3c77467073e5d7d10c64b76de7649213ab0d Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Fri, 14 Oct 2022 20:14:20 +0000 Subject: [PATCH] Patterns parsing: add support for guards. Bug: https://github.com/dart-lang/sdk/issues/50035 Change-Id: I21db09c9d8c1d359e1b125eea2bae2749cdb72fd Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/264101 Reviewed-by: Jens Johansen Reviewed-by: Konstantin Shcheglov Commit-Queue: Paul Berry --- .../lib/src/parser/parser_impl.dart | 18 +- .../lib/src/scanner/token.dart | 11 +- pkg/analyzer/lib/src/dart/ast/ast.dart | 1 + pkg/analyzer/lib/src/fasta/ast_builder.dart | 15 +- .../test/generated/patterns_parser_test.dart | 232 ++++++++++++++++++ .../src/summary/resolved_ast_printer.dart | 8 + .../lib/src/fasta/kernel/body_builder.dart | 44 ++++ ...ssicPattern_guarded_insideIfStatement.dart | 3 + ...tern_guarded_insideIfStatement.dart.expect | 37 +++ ..._insideIfStatement.dart.intertwined.expect | 89 +++++++ ...arded_insideIfStatement.dart.parser.expect | 9 + ...rded_insideIfStatement.dart.scanner.expect | 9 + ...Pattern_guarded_insideSwitchStatement.dart | 6 + ..._guarded_insideSwitchStatement.dart.expect | 41 ++++ ...ideSwitchStatement.dart.intertwined.expect | 102 ++++++++ ...d_insideSwitchStatement.dart.parser.expect | 15 ++ ..._insideSwitchStatement.dart.scanner.expect | 15 ++ ...icPattern_unguarded_insideIfStatement.dart | 3 + ...rn_unguarded_insideIfStatement.dart.expect | 36 +++ ..._insideIfStatement.dart.intertwined.expect | 83 +++++++ ...arded_insideIfStatement.dart.parser.expect | 9 + ...rded_insideIfStatement.dart.scanner.expect | 9 + ...ttern_unguarded_insideSwitchStatement.dart | 6 + ...nguarded_insideSwitchStatement.dart.expect | 40 +++ ...ideSwitchStatement.dart.intertwined.expect | 96 ++++++++ ...d_insideSwitchStatement.dart.parser.expect | 15 ++ ..._insideSwitchStatement.dart.scanner.expect | 15 ++ ...hNewPattern_guarded_insideIfStatement.dart | 3 + ...tern_guarded_insideIfStatement.dart.expect | 43 ++++ ..._insideIfStatement.dart.intertwined.expect | 96 ++++++++ ...arded_insideIfStatement.dart.parser.expect | 9 + ...rded_insideIfStatement.dart.scanner.expect | 9 + ...Pattern_guarded_insideSwitchStatement.dart | 6 + ..._guarded_insideSwitchStatement.dart.expect | 47 ++++ ...ideSwitchStatement.dart.intertwined.expect | 109 ++++++++ ...d_insideSwitchStatement.dart.parser.expect | 15 ++ ..._insideSwitchStatement.dart.scanner.expect | 15 ++ ...ewPattern_unguarded_insideIfStatement.dart | 3 + ...rn_unguarded_insideIfStatement.dart.expect | 42 ++++ ..._insideIfStatement.dart.intertwined.expect | 90 +++++++ ...arded_insideIfStatement.dart.parser.expect | 9 + ...rded_insideIfStatement.dart.scanner.expect | 9 + ...ttern_unguarded_insideSwitchStatement.dart | 6 + ...nguarded_insideSwitchStatement.dart.expect | 46 ++++ ...ideSwitchStatement.dart.intertwined.expect | 103 ++++++++ ...d_insideSwitchStatement.dart.parser.expect | 15 ++ ..._insideSwitchStatement.dart.scanner.expect | 15 ++ pkg/front_end/test/token_test.dart | 1 + 48 files changed, 1649 insertions(+), 9 deletions(-) create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideIfStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideIfStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideIfStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideIfStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideIfStatement.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideSwitchStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideSwitchStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideSwitchStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideSwitchStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_guarded_insideSwitchStatement.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideIfStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideIfStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideIfStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideIfStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideIfStatement.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideSwitchStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideSwitchStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideSwitchStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideSwitchStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withClassicPattern_unguarded_insideSwitchStatement.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideIfStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideIfStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideIfStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideIfStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideIfStatement.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideSwitchStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideSwitchStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideSwitchStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideSwitchStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_guarded_insideSwitchStatement.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideIfStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideIfStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideIfStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideIfStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideIfStatement.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideSwitchStatement.dart create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideSwitchStatement.dart.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideSwitchStatement.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideSwitchStatement.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/patterns/caseHead_withNewPattern_unguarded_insideSwitchStatement.dart.scanner.expect diff --git a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart index 807a3a6446f3..3ad19539f46c 100644 --- a/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart +++ b/pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart @@ -6240,8 +6240,14 @@ class Parser { if (allowPatterns && optional('case', next)) { Token case_ = token = next; token = parsePattern(token); + next = token.next!; + Token? when; + if (optional('when', next)) { + when = token = next; + token = parseExpression(token); + } token = ensureCloseParen(token, begin); - listener.handleParenthesizedCondition(begin, case_, null); + listener.handleParenthesizedCondition(begin, case_, when); } else { token = ensureCloseParen(token, begin); listener.handleParenthesizedCondition( @@ -8258,9 +8264,15 @@ class Parser { } else { token = parseExpression(caseKeyword); } + Token? next = token.next!; + Token? when; + if (optional('when', next)) { + when = token = next; + token = parseExpression(token); + } token = ensureColon(token); - listener.endCaseExpression(null, token); - listener.handleCaseMatch(caseKeyword, null, token); + listener.endCaseExpression(when, token); + listener.handleCaseMatch(caseKeyword, when, token); expressionCount++; peek = peekPastLabels(token.next!); } else if (expressionCount > 0) { diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart index ccbb40f1f024..a3afcf2fa23a 100644 --- a/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart +++ b/pkg/_fe_analyzer_shared/lib/src/scanner/token.dart @@ -327,14 +327,17 @@ class Keyword extends TokenType { static const Keyword VOID = const Keyword(/* index = */ 145, "void", "VOID", KeywordStyle.reserved); + static const Keyword WHEN = + const Keyword(/* index = */ 146, "when", 'WHEN', KeywordStyle.pseudo); + static const Keyword WHILE = - const Keyword(/* index = */ 146, "while", "WHILE", KeywordStyle.reserved); + const Keyword(/* index = */ 147, "while", "WHILE", KeywordStyle.reserved); static const Keyword WITH = - const Keyword(/* index = */ 147, "with", "WITH", KeywordStyle.reserved); + const Keyword(/* index = */ 148, "with", "WITH", KeywordStyle.reserved); static const Keyword YIELD = - const Keyword(/* index = */ 148, "yield", "YIELD", KeywordStyle.pseudo); + const Keyword(/* index = */ 149, "yield", "YIELD", KeywordStyle.pseudo); static const List values = const [ ABSTRACT, @@ -404,6 +407,7 @@ class Keyword extends TokenType { TYPEDEF, VAR, VOID, + WHEN, WHILE, WITH, YIELD, @@ -1978,6 +1982,7 @@ const List _tokenTypesByIndex = [ Keyword.TYPEDEF, Keyword.VAR, Keyword.VOID, + Keyword.WHEN, Keyword.WHILE, Keyword.WITH, Keyword.YIELD, diff --git a/pkg/analyzer/lib/src/dart/ast/ast.dart b/pkg/analyzer/lib/src/dart/ast/ast.dart index 365fed943e73..d94417324a3b 100644 --- a/pkg/analyzer/lib/src/dart/ast/ast.dart +++ b/pkg/analyzer/lib/src/dart/ast/ast.dart @@ -1483,6 +1483,7 @@ class CaseClauseImpl extends AstNodeImpl implements CaseClause { required this.whenClause, }) { _becomeParentOf(pattern); + _becomeParentOf(whenClause); } @override diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart index 7b841436b8d8..95467fe19c86 100644 --- a/pkg/analyzer/lib/src/fasta/ast_builder.dart +++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart @@ -3282,12 +3282,17 @@ class AstBuilder extends StackListener { debugEvent("CaseMatch"); if (_featureSet.isEnabled(Feature.patterns)) { + WhenClauseImpl? whenClause; + if (when != null) { + var expression = pop() as ExpressionImpl; + whenClause = WhenClauseImpl(whenKeyword: when, expression: expression); + } var pattern = pop() as DartPatternImpl; push(SwitchPatternCaseImpl( labels: