Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse support for tuple patterns in var and let #3448

Merged
merged 7 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions toolchain/check/handle_binding_pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ auto HandleBindingPattern(Context& context, Parse::NodeId parse_node) -> bool {
}

auto HandleTemplate(Context& context, Parse::NodeId parse_node) -> bool {
// TODO: diagnose if this occurs in a `var` context.
return context.TODO(parse_node, "HandleTemplate");
}

Expand Down
3 changes: 3 additions & 0 deletions toolchain/check/handle_let.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ namespace Carbon::Check {

auto HandleLetDecl(Context& context, Parse::NodeId parse_node) -> bool {
auto value_id = context.node_stack().PopExpr();
if (context.node_stack().PeekIs<Parse::NodeKind::ParamList>()) {
return context.TODO(parse_node, "tuple pattern in let");
}
SemIR::InstId pattern_id =
context.node_stack().Pop<Parse::NodeKind::BindingPattern>();
context.node_stack()
Expand Down
14 changes: 11 additions & 3 deletions toolchain/check/handle_variable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,23 @@ auto HandleVariableInitializer(Context& context, Parse::NodeId parse_node)
auto HandleVariableDecl(Context& context, Parse::NodeId parse_node) -> bool {
// Handle the optional initializer.
auto init_id = SemIR::InstId::Invalid;
bool has_init =
context.parse_tree().node_kind(context.node_stack().PeekParseNode()) !=
Parse::NodeKind::BindingPattern;
Parse::NodeKind next_kind =
context.parse_tree().node_kind(context.node_stack().PeekParseNode());
if (next_kind == Parse::NodeKind::ParamList) {
return context.TODO(parse_node, "tuple pattern in var");
}
// TODO: find a more robust way to determine if there was an initializer.
bool has_init = next_kind != Parse::NodeKind::BindingPattern;
if (has_init) {
init_id = context.node_stack().PopExpr();
context.node_stack()
.PopAndDiscardSoloParseNode<Parse::NodeKind::VariableInitializer>();
}

if (context.node_stack().PeekIs<Parse::NodeKind::ParamList>()) {
return context.TODO(parse_node, "tuple pattern in var");
}

// Extract the name binding.
auto value_id = context.node_stack().Pop<Parse::NodeKind::BindingPattern>();
if (auto bind_name = context.insts().Get(value_id).TryAs<SemIR::BindName>()) {
Expand Down
4 changes: 1 addition & 3 deletions toolchain/diagnostics/diagnostic_kind.def
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,13 @@ CARBON_DIAGNOSTIC_KIND(ExpectedCloseSymbol)
CARBON_DIAGNOSTIC_KIND(ExpectedCodeBlock)
CARBON_DIAGNOSTIC_KIND(ExpectedExpr)
CARBON_DIAGNOSTIC_KIND(ExpectedIdentifierAfterDotOrArrow)
CARBON_DIAGNOSTIC_KIND(ExpectedLetBindingName)
CARBON_DIAGNOSTIC_KIND(ExpectedParamName)
CARBON_DIAGNOSTIC_KIND(ExpectedBindingPattern)
CARBON_DIAGNOSTIC_KIND(ExpectedParenAfter)
CARBON_DIAGNOSTIC_KIND(ExpectedExprSemi)
CARBON_DIAGNOSTIC_KIND(ExpectedStatementSemi)
CARBON_DIAGNOSTIC_KIND(ExpectedStructLiteralField)
CARBON_DIAGNOSTIC_KIND(ExpectedVarAfterReturned)
CARBON_DIAGNOSTIC_KIND(ExpectedVariableDecl)
CARBON_DIAGNOSTIC_KIND(ExpectedVariableName)
CARBON_DIAGNOSTIC_KIND(OperatorRequiresParentheses)
CARBON_DIAGNOSTIC_KIND(StatementOperatorAsSubExpr)
CARBON_DIAGNOSTIC_KIND(UnaryOperatorRequiresParentheses)
Expand Down
10 changes: 0 additions & 10 deletions toolchain/parse/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,16 +166,6 @@ auto Context::ConsumeIf(Lex::TokenKind kind) -> std::optional<Lex::TokenIndex> {
return Consume();
}

auto Context::ConsumeIfBindingPatternKeyword(Lex::TokenKind keyword_token,
State keyword_state,
int subtree_start) -> void {
if (auto token = ConsumeIf(keyword_token)) {
PushState(Context::StateStackEntry(
keyword_state, PrecedenceGroup::ForTopLevelExpr(),
PrecedenceGroup::ForTopLevelExpr(), *token, subtree_start));
}
}

auto Context::FindNextOf(std::initializer_list<Lex::TokenKind> desired_kinds)
-> std::optional<Lex::TokenIndex> {
auto new_position = position_;
Expand Down
13 changes: 0 additions & 13 deletions toolchain/parse/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,6 @@ class Context {
// Possible return values for FindListToken.
enum class ListTokenKind : int8_t { Comma, Close, CommaClose };

// Supported kinds for HandleBindingPattern.
enum class BindingPatternKind : int8_t {
ImplicitParam,
Param,
Variable,
Let
};

// Used for restricting ordering of `package` and `import` directives.
enum class PackagingState : int8_t {
FileStart,
Expand Down Expand Up @@ -295,11 +287,6 @@ class Context {
// Propagates an error up the state stack, to the parent state.
auto ReturnErrorOnState() -> void { state_stack_.back().has_error = true; }

// For HandleBindingPattern, tries to consume a wrapping keyword.
auto ConsumeIfBindingPatternKeyword(Lex::TokenKind keyword_token,
State keyword_state, int subtree_start)
-> void;

// Emits a diagnostic for a declaration missing a semi.
auto EmitExpectedDeclSemi(Lex::TokenKind expected_kind) -> void;

Expand Down
62 changes: 14 additions & 48 deletions toolchain/parse/handle_binding_pattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,28 @@

namespace Carbon::Parse {

// Handles BindingPatternAs(ImplicitParam|FunctionParam|Variable|Let).
static auto HandleBindingPattern(Context& context,
Context::BindingPatternKind pattern_kind)
-> void {
auto HandleBindingPattern(Context& context) -> void {
auto state = context.PopState();

// Parameters may have keywords prefixing the pattern. They become the parent
// for the full BindingPattern.
if (pattern_kind != Context::BindingPatternKind::Variable) {
context.ConsumeIfBindingPatternKeyword(Lex::TokenKind::Template,
State::BindingPatternTemplate,
state.subtree_start);
context.ConsumeIfBindingPatternKeyword(Lex::TokenKind::Addr,
State::BindingPatternAddress,
state.subtree_start);
if (auto token = context.ConsumeIf(Lex::TokenKind::Template)) {
context.PushState(Context::StateStackEntry(
State::BindingPatternTemplate, PrecedenceGroup::ForTopLevelExpr(),
PrecedenceGroup::ForTopLevelExpr(), *token, state.subtree_start));
}

if (auto token = context.ConsumeIf(Lex::TokenKind::Addr)) {
context.PushState(Context::StateStackEntry(
State::BindingPatternAddress, PrecedenceGroup::ForTopLevelExpr(),
PrecedenceGroup::ForTopLevelExpr(), *token, state.subtree_start));
}

// Handle an invalid pattern introducer for parameters and variables.
auto on_error = [&]() {
switch (pattern_kind) {
case Context::BindingPatternKind::ImplicitParam:
case Context::BindingPatternKind::Param: {
CARBON_DIAGNOSTIC(ExpectedParamName, Error,
"Expected parameter declaration.");
context.emitter().Emit(*context.position(), ExpectedParamName);
break;
}
case Context::BindingPatternKind::Variable: {
CARBON_DIAGNOSTIC(ExpectedVariableName, Error,
"Expected pattern in `var` declaration.");
context.emitter().Emit(*context.position(), ExpectedVariableName);
break;
}
case Context::BindingPatternKind::Let: {
CARBON_DIAGNOSTIC(ExpectedLetBindingName, Error,
"Expected pattern in `let` declaration.");
context.emitter().Emit(*context.position(), ExpectedLetBindingName);
break;
}
}
CARBON_DIAGNOSTIC(ExpectedBindingPattern, Error,
"Expected binding pattern.");
context.emitter().Emit(*context.position(), ExpectedBindingPattern);
// Add a placeholder for the type.
context.AddLeafNode(NodeKind::InvalidParse, *context.position(),
/*has_error=*/true);
Expand Down Expand Up @@ -89,22 +71,6 @@ static auto HandleBindingPattern(Context& context,
}
}

auto HandleBindingPatternAsImplicitParam(Context& context) -> void {
HandleBindingPattern(context, Context::BindingPatternKind::ImplicitParam);
}

auto HandleBindingPatternAsParam(Context& context) -> void {
HandleBindingPattern(context, Context::BindingPatternKind::Param);
}

auto HandleBindingPatternAsVariable(Context& context) -> void {
HandleBindingPattern(context, Context::BindingPatternKind::Variable);
}

auto HandleBindingPatternAsLet(Context& context) -> void {
HandleBindingPattern(context, Context::BindingPatternKind::Let);
}

// Handles BindingPatternFinishAs(Generic|Regular).
static auto HandleBindingPatternFinish(Context& context, NodeKind node_kind)
-> void {
Expand Down
2 changes: 1 addition & 1 deletion toolchain/parse/handle_let.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ auto HandleLet(Context& context) -> void {
context.PushState(state);

// This will start at the pattern.
context.PushState(State::BindingPatternAsLet);
context.PushState(State::Pattern);
}

auto HandleLetAfterPattern(Context& context) -> void {
Expand Down
6 changes: 2 additions & 4 deletions toolchain/parse/handle_param.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@ static auto HandleParam(Context& context, State pattern_state,
}

auto HandleParamAsImplicit(Context& context) -> void {
HandleParam(context, State::BindingPatternAsImplicitParam,
State::ParamFinishAsImplicit);
HandleParam(context, State::BindingPattern, State::ParamFinishAsImplicit);
}

auto HandleParamAsRegular(Context& context) -> void {
HandleParam(context, State::BindingPatternAsParam,
State::ParamFinishAsRegular);
HandleParam(context, State::BindingPattern, State::ParamFinishAsRegular);
}

// Handles ParamFinishAs(Implicit|Regular).
Expand Down
18 changes: 18 additions & 0 deletions toolchain/parse/handle_pattern.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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 HandlePattern(Context& context) -> void {
context.PopAndDiscardState();
if (context.PositionKind() == Lex::TokenKind::OpenParen) {
context.PushState(State::ParamListAsRegular);
} else {
context.PushState(State::BindingPattern);
}
}

} // namespace Carbon::Parse
2 changes: 1 addition & 1 deletion toolchain/parse/handle_var.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ static auto HandleVar(Context& context, State finish_state,
context.AddLeafNode(NodeKind::ReturnedModifier, returned_token);
}

context.PushState(State::BindingPatternAsVariable);
context.PushState(State::Pattern);
}

auto HandleVarAsDecl(Context& context) -> void {
Expand Down
6 changes: 4 additions & 2 deletions toolchain/parse/node_kind.def
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ CARBON_PARSE_NODE_KIND_BRACKET(FunctionDecl, FunctionIntroducer,
//
// [Generic]PatternBinding and ParamListComma may repeat with ParamListComma
// as a separator.
//
// TODO: rename ParamList to TuplePattern to reflect wider usage.
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ParamListStart, 0, CARBON_TOKEN(OpenParen))
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplicitParamListStart, 0,
CARBON_TOKEN(OpenSquareBracket))
Expand Down Expand Up @@ -285,7 +287,7 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(Template, 1, CARBON_TOKEN(Template))
// `let`:
// LetIntroducer
// _repeated_ _external_: modifier
// _external_: BindingPattern
// _external_: BindingPattern or ParamList
// LetInitializer
// _external_: expression
// LetDecl
Expand All @@ -301,7 +303,7 @@ CARBON_PARSE_NODE_KIND_BRACKET(LetDecl, LetIntroducer,
// VariableIntroducer
// _repeated_ _external_: modifier
// _optional_ ReturnedModifier
// _external_: BindingPattern
// _external_: BindingPattern or ParamList
// VariableInitializer
// _external_: expression
// _optional_
Expand Down
42 changes: 36 additions & 6 deletions toolchain/parse/state.def
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ CARBON_PARSE_STATE(Package)
//
// ...
// ^
// 1. BindingPatternAs(ImplicitParam|Param)
// 1. BindingPattern
// 2. ParamFinishAs(Implicit|Regular)
CARBON_PARSE_STATE_VARIANTS2(Param, Implicit, Regular)

Expand All @@ -671,6 +671,8 @@ CARBON_PARSE_STATE_VARIANTS2(ParamFinish, Implicit, Regular)

// Handles processing of a parameter list `[` or `(`.
//
// TODO: Rename this to TuplePattern to reflect wider usage.
//
// ( ) (variant is Regular)
// ^
// [ ] (variant is Implicit)
Expand Down Expand Up @@ -759,6 +761,17 @@ CARBON_PARSE_STATE_VARIANTS2(ParenExprParamFinish, Unknown, Tuple)
// (state done)
CARBON_PARSE_STATE_VARIANTS2(ParenExprFinish, Normal, Tuple)

// Handles processing of a pattern.
//
// ( ... )
// ^
// 1. ParamListAsRegular
//
// ...
// ^
// 1. BindingPattern
CARBON_PARSE_STATE(Pattern)

// Handles the initial part of a binding pattern, enqueuing type expression
// processing.
//
Expand Down Expand Up @@ -791,8 +804,7 @@ CARBON_PARSE_STATE_VARIANTS2(ParenExprFinish, Normal, Tuple)
// ???
// ^
// 1. BindingPatternFinishAsRegular
CARBON_PARSE_STATE_VARIANTS4(BindingPattern, ImplicitParam, Param, Variable,
Let)
CARBON_PARSE_STATE(BindingPattern)

// Handles `addr` in a binding pattern.
//
Expand Down Expand Up @@ -1056,13 +1068,25 @@ CARBON_PARSE_STATE(BaseDecl)
//
// var ... (variant is not Returned)
// ^
// 1. BindingPatternAsVariable
// 1. BindingPattern
// 2. VarAfterPattern
// 3. VarFinishAs(Decl|For)
//
// var (...)
// ^
// 1. ParamListAsRegular
// 2. VarAfterPattern
// 3. VarFinishAs(Decl|For)
//
// returned var ... (variant is Returned)
// ^~~~~~~~~~~~
// 1. BindingPatternAsVariable
// 1. BindingPattern
// 2. VarAfterPattern
// 3. VarFinishAsDecl
//
// returned var ... (variant is Returned)
// ^~~~~~~~~~~~
// 1. ParamListAsRegular
// 2. VarAfterPattern
// 3. VarFinishAsDecl
//
Expand Down Expand Up @@ -1102,9 +1126,15 @@ CARBON_PARSE_STATE_VARIANTS2(VarFinish, Decl, For)

// Handles the start of a `let`.
//
// let (...)
// ^~~
// 1. ParamListAsRegular
// 2. LetAfterPattern
// 3. LetFinish
//
// let ...
// ^
// 1. BindingPatternAsLet
// 1. BindingPattern
// 2. LetAfterPattern
// 3. LetFinish
CARBON_PARSE_STATE(Let)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// AUTOUPDATE

// CHECK:STDERR: fail_paren_match_regression.carbon:[[@LINE+6]]:5: ERROR: Expected pattern in `var` declaration.
// CHECK:STDERR: fail_paren_match_regression.carbon:[[@LINE+6]]:5: ERROR: Expected binding pattern.
// CHECK:STDERR: var = (foo {})
// CHECK:STDERR: ^
// CHECK:STDERR: fail_paren_match_regression.carbon:[[@LINE+3]]:12: ERROR: Expected `,` or `)`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// CHECK:STDERR: fail_missing_implicit_close.carbon:[[@LINE+6]]:7: ERROR: Closing symbol does not match most recent opening symbol.
// CHECK:STDERR: fn Div[();
// CHECK:STDERR: ^
// CHECK:STDERR: fail_missing_implicit_close.carbon:[[@LINE+3]]:8: ERROR: Expected parameter declaration.
// CHECK:STDERR: fail_missing_implicit_close.carbon:[[@LINE+3]]:8: ERROR: Expected binding pattern.
// CHECK:STDERR: fn Div[();
// CHECK:STDERR: ^
fn Div[();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// AUTOUPDATE

// CHECK:STDERR: fail_with_identifier_as_param.carbon:[[@LINE+3]]:11: ERROR: Expected parameter declaration.
// CHECK:STDERR: fail_with_identifier_as_param.carbon:[[@LINE+3]]:11: ERROR: Expected binding pattern.
// CHECK:STDERR: fn foo(bar);
// CHECK:STDERR: ^
fn foo(bar);
Expand Down
Loading
Loading