diff --git a/toolchain/check/handle_choice.cpp b/toolchain/check/handle_choice.cpp new file mode 100644 index 000000000000..d11142d938f3 --- /dev/null +++ b/toolchain/check/handle_choice.cpp @@ -0,0 +1,30 @@ +// 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" + +namespace Carbon::Check { + +auto HandleChoiceDefinition(Context& context, + Parse::ChoiceDefinitionId parse_node) -> bool { + return context.TODO(parse_node, "HandleChoiceDefinition"); +} + +auto HandleChoiceIntroducer(Context& context, + Parse::ChoiceIntroducerId parse_node) -> bool { + return context.TODO(parse_node, "HandleChoiceIntroducer"); +} + +auto HandleChoiceDefinitionStart(Context& context, + Parse::ChoiceDefinitionStartId parse_node) + -> bool { + return context.TODO(parse_node, "HandleChoiceDefinitionStart"); +} + +auto HandleChoiceAlternativeListComma( + Context& context, Parse::ChoiceAlternativeListCommaId parse_node) -> bool { + return context.TODO(parse_node, "HandleChoiceAlternativeListComma"); +} + +} // namespace Carbon::Check diff --git a/toolchain/diagnostics/diagnostic_kind.def b/toolchain/diagnostics/diagnostic_kind.def index a114f9da7b32..a7e2454c654a 100644 --- a/toolchain/diagnostics/diagnostic_kind.def +++ b/toolchain/diagnostics/diagnostic_kind.def @@ -71,6 +71,8 @@ CARBON_DIAGNOSTIC_KIND(ExpectedStatementSemi) CARBON_DIAGNOSTIC_KIND(ExpectedStructLiteralField) CARBON_DIAGNOSTIC_KIND(ExpectedVarAfterReturned) CARBON_DIAGNOSTIC_KIND(ExpectedVariableDecl) +CARBON_DIAGNOSTIC_KIND(ExpectedChoiceDefinition) +CARBON_DIAGNOSTIC_KIND(ExpectedChoiceAlternativeName) CARBON_DIAGNOSTIC_KIND(OperatorRequiresParentheses) CARBON_DIAGNOSTIC_KIND(StatementOperatorAsSubExpr) CARBON_DIAGNOSTIC_KIND(UnaryOperatorRequiresParentheses) diff --git a/toolchain/parse/handle_choice.cpp b/toolchain/parse/handle_choice.cpp new file mode 100644 index 000000000000..e8983e748360 --- /dev/null +++ b/toolchain/parse/handle_choice.cpp @@ -0,0 +1,98 @@ +// 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" + +namespace Carbon::Parse { +auto HandleChoiceIntroducer(Context& context) -> void { + auto state = context.PopState(); + + context.PushState(state, State::ChoiceDefinitionStart); + context.PushState(State::DeclNameAndParamsAsOptional, state.token); +} + +auto HandleChoiceDefinitionStart(Context& context) -> void { + auto state = context.PopState(); + + if (!context.PositionIs(Lex::TokenKind::OpenCurlyBrace)) { + if (!state.has_error) { + CARBON_DIAGNOSTIC(ExpectedChoiceDefinition, Error, + "Choice definition expected."); + context.emitter().Emit(*context.position(), ExpectedChoiceDefinition); + } + + context.AddNode(NodeKind::ChoiceDefinitionStart, *context.position(), + state.subtree_start, /*has_error=*/true); + + context.AddNode(NodeKind::ChoiceDefinition, *context.position(), + state.subtree_start, /*has_error=*/true); + + context.SkipPastLikelyEnd(*context.position()); + return; + } + + context.AddNode(NodeKind::ChoiceDefinitionStart, context.Consume(), + state.subtree_start, state.has_error); + + state.has_error = false; + state.state = State::ChoiceDefinitionFinish; + context.PushState(state); + + if (!context.PositionIs(Lex::TokenKind::CloseCurlyBrace)) { + context.PushState(State::ChoiceAlternative); + } +} + +auto HandleChoiceAlternative(Context& context) -> void { + auto state = context.PopState(); + + context.PushState(State::ChoiceAlternativeFinish); + + if (!context.ConsumeAndAddLeafNodeIf(Lex::TokenKind::Identifier, + NodeKind::IdentifierName)) { + if (!state.has_error) { + CARBON_DIAGNOSTIC(ExpectedChoiceAlternativeName, Error, + "Expected choice alternative name."); + context.emitter().Emit(*context.position(), + ExpectedChoiceAlternativeName); + } + + context.SkipPastLikelyEnd(*context.position()); + + context.ReturnErrorOnState(); + + return; + } + + if (context.PositionIs(Lex::TokenKind::OpenParen)) { + context.PushState(State::PatternListAsTuple); + } +} + +auto HandleChoiceAlternativeFinish(Context& context) -> void { + const auto state = context.PopState(); + + if (state.has_error) { + context.ReturnErrorOnState(); + if (!context.PositionIs(Lex::TokenKind::CloseCurlyBrace)) { + context.PushState(State::ChoiceAlternative); + } + return; + } + + if (context.ConsumeListToken( + NodeKind::ChoiceAlternativeListComma, Lex::TokenKind::CloseCurlyBrace, + state.has_error) == Context::ListTokenKind::Comma) { + context.PushState(State::ChoiceAlternative); + } +} + +auto HandleChoiceDefinitionFinish(Context& context) -> void { + const auto state = context.PopState(); + + context.AddNode(NodeKind::ChoiceDefinition, + context.ConsumeChecked(Lex::TokenKind::CloseCurlyBrace), + state.subtree_start, state.has_error); +} +} // namespace Carbon::Parse diff --git a/toolchain/parse/handle_decl_scope_loop.cpp b/toolchain/parse/handle_decl_scope_loop.cpp index b30d9944ca87..7827a7c38191 100644 --- a/toolchain/parse/handle_decl_scope_loop.cpp +++ b/toolchain/parse/handle_decl_scope_loop.cpp @@ -158,6 +158,11 @@ static auto TryHandleAsDecl(Context& context, Context::StateStackEntry state, State::VarAsDecl); return true; } + case Lex::TokenKind::Choice: { + ApplyIntroducer(context, state, NodeKind::ChoiceIntroducer, + State::ChoiceIntroducer); + return true; + } case Lex::TokenKind::Semi: { if (saw_modifier) { @@ -201,6 +206,7 @@ static auto ResolveAmbiguousTokenAsDeclaration(Context& context, #define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name, ...) \ case Lex::TokenKind::Name: #include "toolchain/parse/node_kind.def" + return false; default: diff --git a/toolchain/parse/node_kind.def b/toolchain/parse/node_kind.def index facb3023e015..6c1c930dd0c7 100644 --- a/toolchain/parse/node_kind.def +++ b/toolchain/parse/node_kind.def @@ -711,6 +711,26 @@ CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDefinition, CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDecl, NamedConstraintIntroducer, CARBON_IF_VALID(Semi)) +// `choice`: +// ChoiceIntroducer +// _external_: IdentifierName or QualifiedDecl +// ChoiceDefinitionStart +// _optional_ _external_: ChoiceAlternativeList +// ChoiceDefinition +CARBON_PARSE_NODE_KIND_CHILD_COUNT(ChoiceIntroducer, 0, Choice) +CARBON_PARSE_NODE_KIND_BRACKET(ChoiceDefinitionStart, ChoiceIntroducer, + CARBON_IF_VALID(OpenCurlyBrace)) +CARBON_PARSE_NODE_KIND_BRACKET(ChoiceDefinition, ChoiceDefinitionStart, + CARBON_IF_VALID(CloseCurlyBrace)) + +// Choice alternative list: +// _external_: IdentifierName +// _optional_ _external_ : TuplePattern +// _optional_: ChoiceAlternativeListComma +// _repeated_ +// ChoiceAlternativeList +CARBON_PARSE_NODE_KIND_CHILD_COUNT(ChoiceAlternativeListComma, 0, Comma) + #undef CARBON_PARSE_NODE_KIND #undef CARBON_PARSE_NODE_KIND_BRACKET #undef CARBON_PARSE_NODE_KIND_CHILD_COUNT diff --git a/toolchain/parse/state.def b/toolchain/parse/state.def index ba455560eeca..ce3e064973c8 100644 --- a/toolchain/parse/state.def +++ b/toolchain/parse/state.def @@ -357,6 +357,11 @@ CARBON_PARSE_STATE(DeclNameAndParamsAfterImplicit) // 1. Let // 2. DeclScopeLoop // +// choice ... +// ^ +// 1. ChoiceIntroducer +// 2. DeclScopeLoop +// // ??? ; // ^~~~~ // (state done) @@ -1241,4 +1246,62 @@ CARBON_PARSE_STATE(LetAfterPattern) // (state done) CARBON_PARSE_STATE(LetFinish) +// Handles a choice's introducer. +// +// choice ... +// ^~~~~~ +// 1. DeclNameAndParamsAsOptional +// 2. ChoiceAlternativeListStart +// 3. ChoiceDefinitionFinish +CARBON_PARSE_STATE(ChoiceIntroducer) + +// Handles processing of a choice after its optional parameters. +// +// choice name ... {} +// ^ +// (state done) +// +// choice name ... { ... } +// ^ +// 1. ChoiceAlternative +// +// choice name ... ??? +// ^ +// (state done) +CARBON_PARSE_STATE(ChoiceDefinitionStart) + +// Starts alternative parsing. +// +// name( ... ) +// ^~~~ +// 1. ParamListAsRegular +// 2. ChoiceAlternativeFinish +// name ... +// ^~~~ +// 1. ChoiceAlternativeFinish +CARBON_PARSE_STATE(ChoiceAlternative) + +// Finishes parsing a choice's alternative, including the optional trailing `,`. If there +// are more alternatives, enqueues another alternative parsing state. +// +// ... , } +// ^ +// (state done) +// +// ... , ... +// ^ +// 1. ChoiceAlternative +// +// ... +// ^ +// (state done) +CARBON_PARSE_STATE(ChoiceAlternativeFinish) + +// Finishes a choice definition. +// +// choice ... } +// ^ +// (state done) +CARBON_PARSE_STATE(ChoiceDefinitionFinish) + #undef CARBON_PARSE_STATE diff --git a/toolchain/parse/testdata/choice/basic.carbon b/toolchain/parse/testdata/choice/basic.carbon new file mode 100644 index 000000000000..52715941e2e9 --- /dev/null +++ b/toolchain/parse/testdata/choice/basic.carbon @@ -0,0 +1,29 @@ +// 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 + +choice Ordering { + Less, + Equivalent, + Greater, + Incomparable +} + +// CHECK:STDOUT: - filename: basic.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Ordering'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Less'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Equivalent'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Greater'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Incomparable'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', subtree_size: 11}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/fail_alternative_with_implicit_params.carbon b/toolchain/parse/testdata/choice/fail_alternative_with_implicit_params.carbon new file mode 100644 index 000000000000..f6cc977dd79b --- /dev/null +++ b/toolchain/parse/testdata/choice/fail_alternative_with_implicit_params.carbon @@ -0,0 +1,23 @@ +// 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 + +choice X { + // CHECK:STDERR: fail_alternative_with_implicit_params.carbon:[[@LINE+3]]:4: ERROR: Expected `,` or `}`. + // CHECK:STDERR: A[T:! type](value: T) + // CHECK:STDERR: ^ + A[T:! type](value: T) +} + +// CHECK:STDOUT: - filename: fail_alternative_with_implicit_params.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'X'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'A'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/fail_invalid_alternative_identifier.carbon b/toolchain/parse/testdata/choice/fail_invalid_alternative_identifier.carbon new file mode 100644 index 000000000000..0714ef5ad316 --- /dev/null +++ b/toolchain/parse/testdata/choice/fail_invalid_alternative_identifier.carbon @@ -0,0 +1,28 @@ +// 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 + +choice InvalidAlternativeIdentifier { + // CHECK:STDERR: fail_invalid_alternative_identifier.carbon:[[@LINE+3]]:5: ERROR: Expected choice alternative name. + // CHECK:STDERR: ,Some, + // CHECK:STDERR: ^ + ,Some, + // CHECK:STDERR: fail_invalid_alternative_identifier.carbon:[[@LINE+3]]:5: ERROR: Expected choice alternative name. + // CHECK:STDERR: 42, + // CHECK:STDERR: ^~ + 42, + Other +} + +// CHECK:STDOUT: - filename: fail_invalid_alternative_identifier.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'InvalidAlternativeIdentifier'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Other'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/fail_invalid_braces.carbon b/toolchain/parse/testdata/choice/fail_invalid_braces.carbon new file mode 100644 index 000000000000..5971d040f659 --- /dev/null +++ b/toolchain/parse/testdata/choice/fail_invalid_braces.carbon @@ -0,0 +1,27 @@ +// 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 + +// CHECK:STDERR: fail_invalid_braces.carbon:[[@LINE+3]]:22: ERROR: Choice definition expected. +// CHECK:STDERR: choice InvalidBraces | +// CHECK:STDERR: ^ +choice InvalidBraces | + Some +// CHECK:STDERR: fail_invalid_braces.carbon:[[@LINE+3]]:1: ERROR: Unrecognized declaration introducer. +// CHECK:STDERR: | +// CHECK:STDERR: ^ +| + +// CHECK:STDOUT: - filename: fail_invalid_braces.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'InvalidBraces'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '|', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '|', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'InvalidParseStart', text: '|', has_error: yes}, +// CHECK:STDOUT: {kind: 'InvalidParseSubtree', text: '|', has_error: yes, subtree_size: 2}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/fail_missing_definition.carbon b/toolchain/parse/testdata/choice/fail_missing_definition.carbon new file mode 100644 index 000000000000..50f3f2ddb08d --- /dev/null +++ b/toolchain/parse/testdata/choice/fail_missing_definition.carbon @@ -0,0 +1,20 @@ +// 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 + +// CHECK:STDERR: fail_missing_definition.carbon:[[@LINE+3]]:25: ERROR: Choice definition expected. +// CHECK:STDERR: choice MissingDefinition; +// CHECK:STDERR: ^ +choice MissingDefinition; + +// CHECK:STDOUT: - filename: fail_missing_definition.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'MissingDefinition'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: ';', has_error: yes, subtree_size: 3}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: ';', has_error: yes, subtree_size: 4}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/fail_missing_definition_parameterized.carbon b/toolchain/parse/testdata/choice/fail_missing_definition_parameterized.carbon new file mode 100644 index 000000000000..8606ac080e6a --- /dev/null +++ b/toolchain/parse/testdata/choice/fail_missing_definition_parameterized.carbon @@ -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 +// +// AUTOUPDATE + +// CHECK:STDERR: fail_missing_definition_parameterized.carbon:[[@LINE+3]]:35: ERROR: Choice definition expected. +// CHECK:STDERR: choice MissingDefinition(T:! type); +// CHECK:STDERR: ^ +choice MissingDefinition(T:! type); + +// CHECK:STDOUT: - filename: fail_missing_definition_parameterized.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'MissingDefinition'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'T'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: ';', has_error: yes, subtree_size: 8}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: ';', has_error: yes, subtree_size: 9}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/fail_qualified_alternative_name.carbon b/toolchain/parse/testdata/choice/fail_qualified_alternative_name.carbon new file mode 100644 index 000000000000..64bdd0523c53 --- /dev/null +++ b/toolchain/parse/testdata/choice/fail_qualified_alternative_name.carbon @@ -0,0 +1,23 @@ +// 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 + +choice X { + // CHECK:STDERR: fail_qualified_alternative_name.carbon:[[@LINE+3]]:4: ERROR: Expected `,` or `}`. + // CHECK:STDERR: A.B + // CHECK:STDERR: ^ + A.B +} + +// CHECK:STDOUT: - filename: fail_qualified_alternative_name.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'X'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'A'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', has_error: yes, subtree_size: 5}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/modifiers.carbon b/toolchain/parse/testdata/choice/modifiers.carbon new file mode 100644 index 000000000000..729900968ab6 --- /dev/null +++ b/toolchain/parse/testdata/choice/modifiers.carbon @@ -0,0 +1,30 @@ +// 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 + +private choice Ordering { + Less, + Equivalent, + Greater, + Incomparable +} + +// CHECK:STDOUT: - filename: modifiers.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'PrivateModifier', text: 'private'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Ordering'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 4}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Less'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Equivalent'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Greater'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Incomparable'}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', subtree_size: 12}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/testdata/choice/parameterized.carbon b/toolchain/parse/testdata/choice/parameterized.carbon new file mode 100644 index 000000000000..6a83e3f0d2f1 --- /dev/null +++ b/toolchain/parse/testdata/choice/parameterized.carbon @@ -0,0 +1,34 @@ +// 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 + +choice OptionalElement(T:! type) { + Element(value: T), + None, +} + +// CHECK:STDOUT: - filename: parameterized.carbon +// CHECK:STDOUT: parse_tree: [ +// CHECK:STDOUT: {kind: 'FileStart', text: ''}, +// CHECK:STDOUT: {kind: 'ChoiceIntroducer', text: 'choice'}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'OptionalElement'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'T'}, +// CHECK:STDOUT: {kind: 'TypeTypeLiteral', text: 'type'}, +// CHECK:STDOUT: {kind: 'GenericBindingPattern', text: ':!', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ChoiceDefinitionStart', text: '{', subtree_size: 8}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'Element'}, +// CHECK:STDOUT: {kind: 'TuplePatternStart', text: '('}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'value'}, +// CHECK:STDOUT: {kind: 'IdentifierNameExpr', text: 'T'}, +// CHECK:STDOUT: {kind: 'BindingPattern', text: ':', subtree_size: 3}, +// CHECK:STDOUT: {kind: 'TuplePattern', text: ')', subtree_size: 5}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'IdentifierName', text: 'None'}, +// CHECK:STDOUT: {kind: 'ChoiceAlternativeListComma', text: ','}, +// CHECK:STDOUT: {kind: 'ChoiceDefinition', text: '}', subtree_size: 18}, +// CHECK:STDOUT: {kind: 'FileEnd', text: ''}, +// CHECK:STDOUT: ] diff --git a/toolchain/parse/typed_nodes.h b/toolchain/parse/typed_nodes.h index 81e4cb00c196..9e17770c82fc 100644 --- a/toolchain/parse/typed_nodes.h +++ b/toolchain/parse/typed_nodes.h @@ -677,6 +677,39 @@ struct IfExprElse { AnyExprId else_result; }; +// Choice nodes +// ------------ + +using ChoiceIntroducer = LeafNode; + +struct ChoiceSignature { + static constexpr auto Kind = + NodeKind::ChoiceDefinitionStart.Define(NodeCategory::None); + + ChoiceIntroducerId introducer; + llvm::SmallVector modifiers; + AnyNameComponentId name; + std::optional implicit_params; + std::optional params; +}; + +using ChoiceDefinitionStart = ChoiceSignature; + +using ChoiceAlternativeListComma = + LeafNode; + +struct ChoiceDefinition { + static constexpr auto Kind = + NodeKind::ChoiceDefinition.Define(NodeCategory::Decl); + + ChoiceDefinitionStartId signature; + struct Alternative { + IdentifierNameId name; + std::optional parameters; + }; + CommaSeparatedList alternatives; +}; + // Struct literals and struct type literals // ----------------------------------------