diff --git a/toolchain/check/handle_match_first.cpp b/toolchain/check/handle_match_first.cpp new file mode 100644 index 000000000000..9c4d10b5a691 --- /dev/null +++ b/toolchain/check/handle_match_first.cpp @@ -0,0 +1,25 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/check/context.h" +#include "toolchain/check/convert.h" +#include "toolchain/check/handle.h" + +namespace Carbon::Check { + +auto HandleParseNode(Context& context, Parse::MatchFirstIntroducerId node_id) + -> bool { + return context.TODO(node_id, "HandleMatchFirstIntroducer"); +} + +auto HandleParseNode(Context& context, + Parse::MatchFirstDefinitionStartId node_id) -> bool { + return context.TODO(node_id, "HandleMatchFirstDefinitionStart"); +} + +auto HandleParseNode(Context& context, Parse::MatchFirstId node_id) -> bool { + return context.TODO(node_id, "HandleMatchFirst"); +} + +} // namespace Carbon::Check diff --git a/toolchain/check/node_stack.h b/toolchain/check/node_stack.h index 31260c657fdb..6d07266f08ce 100644 --- a/toolchain/check/node_stack.h +++ b/toolchain/check/node_stack.h @@ -521,6 +521,8 @@ class NodeStack { case Parse::NodeKind::MatchConditionStart: case Parse::NodeKind::MatchDefault: case Parse::NodeKind::MatchDefaultIntroducer: + case Parse::NodeKind::MatchFirstIntroducer: + case Parse::NodeKind::MatchFirstDefinitionStart: case Parse::NodeKind::MatchHandlerStart: case Parse::NodeKind::MatchHandler: case Parse::NodeKind::MatchIntroducer: diff --git a/toolchain/lex/token_kind.def b/toolchain/lex/token_kind.def index 96e2ce32f255..84bc1c27ab87 100644 --- a/toolchain/lex/token_kind.def +++ b/toolchain/lex/token_kind.def @@ -164,6 +164,7 @@ CARBON_DECL_INTRODUCER_TOKEN(Import, "import") CARBON_DECL_INTRODUCER_TOKEN(Interface, "interface") CARBON_DECL_INTRODUCER_TOKEN(Let, "let") CARBON_DECL_INTRODUCER_TOKEN(Library, "library") +CARBON_DECL_INTRODUCER_TOKEN(MatchFirst, "match_first") CARBON_DECL_INTRODUCER_TOKEN(Namespace, "namespace") CARBON_DECL_INTRODUCER_TOKEN(Package, "package") CARBON_DECL_INTRODUCER_TOKEN(Require, "require") diff --git a/toolchain/parse/handle_decl_scope_loop.cpp b/toolchain/parse/handle_decl_scope_loop.cpp index 85c5fbcbfb18..acb7bc5e682b 100644 --- a/toolchain/parse/handle_decl_scope_loop.cpp +++ b/toolchain/parse/handle_decl_scope_loop.cpp @@ -129,6 +129,8 @@ static constexpr auto DeclIntroducers = [] { StateKind::ImplAfterIntroducer); set(Lex::TokenKind::Interface, NodeKind::InterfaceIntroducer, StateKind::TypeAfterIntroducerAsInterface); + set(Lex::TokenKind::MatchFirst, NodeKind::MatchFirstIntroducer, + StateKind::MatchFirst); set(Lex::TokenKind::Namespace, NodeKind::NamespaceStart, StateKind::Namespace); set(Lex::TokenKind::Observe, NodeKind::ObserveIntroducer, diff --git a/toolchain/parse/handle_match_first.cpp b/toolchain/parse/handle_match_first.cpp new file mode 100644 index 000000000000..7929485c0982 --- /dev/null +++ b/toolchain/parse/handle_match_first.cpp @@ -0,0 +1,24 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include "toolchain/parse/context.h" +#include "toolchain/parse/handle.h" + +namespace Carbon::Parse { + +auto HandleMatchFirst(Context& context) -> void { + auto state = context.PopState(); + // MatchFirstIntroducer node is automatically added for the MatchFirst state. + context.AddNode(NodeKind::MatchFirstDefinitionStart, context.Consume(), + state.has_error); + context.PushState(state, StateKind::MatchFirstFinish); + context.PushState(StateKind::DeclScopeLoopAsRegular); +} + +auto HandleMatchFirstFinish(Context& context) -> void { + auto state = context.PopState(); + context.AddNode(NodeKind::MatchFirst, context.Consume(), state.has_error); +} + +} // namespace Carbon::Parse diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index 812cb19c039e..885109894162 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -142,6 +142,10 @@ CARBON_PARSE_NODE_KIND(ExportDecl) CARBON_PARSE_NODE_KIND(NamespaceStart) CARBON_PARSE_NODE_KIND(Namespace) +CARBON_PARSE_NODE_KIND(MatchFirstIntroducer) +CARBON_PARSE_NODE_KIND(MatchFirstDefinitionStart) +CARBON_PARSE_NODE_KIND(MatchFirst) + CARBON_PARSE_NODE_KIND(CodeBlockStart) CARBON_PARSE_NODE_KIND(CodeBlock) diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index 7c2e865e6afc..c33260d05a14 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -388,6 +388,10 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterParams) // ^~~~~~~ // 1. Library // +// match_first ... +// ^~~~~~~~~ +// 1. MatchFirst +// // namespace ... // ^~~~~~~~~ // 1. Namespace @@ -919,6 +923,21 @@ CARBON_PARSE_STATE(Import) // (state done) CARBON_PARSE_STATE(Library) +// Handles `match_first` and opens the block. +// +// match_first { ... +// ^~~~~~~~~~~~~ +// 1. DeclScopeLoopAsRegular +// 2. MatchFirstFinish +CARBON_PARSE_STATE(MatchFirst) + +// Handles closing the `match_first` block. +// +// match_first { ... } +// ^ +// (state done) +CARBON_PARSE_STATE(MatchFirstFinish) + // Handles `namespace`. // // namespace ... diff --git a/toolchain/parse/testdata/generics/impl/final_match_first.carbon b/toolchain/parse/testdata/generics/impl/final_match_first.carbon new file mode 100644 index 000000000000..7a16f7081cbc --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/final_match_first.carbon @@ -0,0 +1,83 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/generics/impl/final_match_first.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/generics/impl/final_match_first.carbon + +final match_first { + +impl forall [T:! I] T as Interface { + fn Add(self, b: Self) -> Self; +} + +impl forall [T:! J] T as Interface { + fn Add(self, b: Self) -> Self; +} + +} + +// CHECK:STDOUT: - filename: final_match_first.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'MatchFirstIntroducer', text: 'match_first'}, +// CHECK:STDOUT: {kind: 'FinalModifier', text: 'final'}, +// CHECK:STDOUT: {kind: 'MatchFirstDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'Forall', text: 'forall'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':!', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'Add'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'SelfValueName', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfBindingPattern', text: 'self', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'b'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'Forall', text: 'forall'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':!', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'J'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'Add'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'SelfValueName', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfBindingPattern', text: 'self', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'b'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'MatchFirst', text: '}', subtree_size: 56}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/generics/impl/match_first.carbon b/toolchain/parse/testdata/generics/impl/match_first.carbon new file mode 100644 index 000000000000..19835deee0e9 --- /dev/null +++ b/toolchain/parse/testdata/generics/impl/match_first.carbon @@ -0,0 +1,82 @@ +// Part of the Carbon Language project, under the Apache License v2.0 with LLVM +// Exceptions. See /LICENSE for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/parse/testdata/generics/impl/match_first.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/parse/testdata/generics/impl/match_first.carbon + +match_first { + +impl forall [T:! I] T as Interface { + fn Add(self, b: Self) -> Self; +} + +impl forall [T:! J] T as Interface { + fn Add(self, b: Self) -> Self; +} + +} + +// CHECK:STDOUT: - filename: match_first.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'MatchFirstIntroducer', text: 'match_first'}, +// CHECK:STDOUT: {kind: 'MatchFirstDefinitionStart', text: '{', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'Forall', text: 'forall'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':!', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'I'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'Add'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'SelfValueName', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfBindingPattern', text: 'self', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'b'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'ImplIntroducer', text: 'impl'}, +// CHECK:STDOUT: {kind: 'Forall', text: 'forall'}, +// CHECK:STDOUT: {kind: 'ImplicitParamListStart', text: '['}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'T'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPatternStart', text: ':!', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'J'}, +// CHECK:STDOUT: {kind: 'CompileTimeBindingPattern', text: ':!', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'ImplicitParamList', text: ']', subtree_size: 6}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'ImplTypeAs', text: 'as', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'Interface'}, +// CHECK:STDOUT: {kind: 'ImplDefinitionStart', text: '{', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'}, +// CHECK:STDOUT: {kind: 'IdentifierNameMaybeBeforeSignature', text: 'Add'}, +// CHECK:STDOUT: {kind: 'ExplicitParamListStart', text: '('}, +// CHECK:STDOUT: {kind: 'SelfValueName', text: 'self'}, +// CHECK:STDOUT: {kind: 'SelfBindingPattern', text: 'self', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'PatternListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierNameNotBeforeSignature', text: 'b'}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'LetBindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ExplicitParamList', text: ')', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'SelfTypeNameExpr', text: 'Self'}, +// CHECK:STDOUT: {kind: 'ReturnType', text: '->', subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FunctionDecl', text: ';', subtree_size: 13}, +// CHECK:STDOUT: {kind: 'ImplDefinition', text: '}', subtree_size: 26}, +// CHECK:STDOUT: {kind: 'MatchFirst', text: '}', subtree_size: 55}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index 653b41829378..cc3c86aad038 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -319,6 +319,31 @@ struct ExportDecl { Lex::SemiTokenIndex token; }; +// MatchFirst nodes +// --------------- + +using MatchFirstIntroducer = + LeafNode; + +struct MatchFirstDefinitionStart { + static constexpr auto Kind = NodeKind::MatchFirstDefinitionStart.Define( + {.bracketed_by = MatchFirstIntroducer::Kind}); + MatchFirstIntroducerId introducer; + llvm::SmallVector modifiers; + Lex::OpenCurlyBraceTokenIndex token; +}; + +// A match_first block: `match_first { ... }`. +struct MatchFirst { + static constexpr auto Kind = NodeKind::MatchFirst.Define( + {.category = NodeCategory::Decl, + .bracketed_by = MatchFirstDefinitionStart::Kind}); + + MatchFirstDefinitionStartId start; + llvm::SmallVector members; + Lex::CloseCurlyBraceTokenIndex token; +}; + // Namespace nodes // ---------------