mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 13:31:06 +01:00
Extend deduced and regular parameter handling to types. (#2684)
This makes it possible to specify both deduced and regular parameters on types. It reorganizes the handling of parameter lists in order to allow more reuse of code in this approach. Both functions and types use the new DeclarationNameAndParams handling. Overall the goal here is to take advantage of commonality in structure. Regarding destructors, the likely approach would be to use ParameterListAsDeduced directly because `destructor` is a keyword with no declaration name and no regular parameters.
This commit is contained in:
+185
-134
@@ -22,9 +22,6 @@ CARBON_DIAGNOSTIC(
|
||||
OperatorRequiresParentheses, Error,
|
||||
"Parentheses are required to disambiguate operator precedence.");
|
||||
|
||||
CARBON_DIAGNOSTIC(ExpectedParenAfter, Error, "Expected `(` after `{0}`.",
|
||||
TokenKind);
|
||||
|
||||
CARBON_DIAGNOSTIC(ExpectedSemiAfterExpression, Error,
|
||||
"Expected `;` after expression.");
|
||||
|
||||
@@ -127,6 +124,8 @@ auto Parser::ConsumeAndAddOpenParen(TokenizedBuffer::Token default_token,
|
||||
if (auto open_paren = ConsumeIf(TokenKind::OpenParen)) {
|
||||
AddLeafNode(start_kind, *open_paren, /*has_error=*/false);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(ExpectedParenAfter, Error, "Expected `(` after `{0}`.",
|
||||
TokenKind);
|
||||
emitter_->Emit(*position_, ExpectedParenAfter,
|
||||
tokens_->GetKind(default_token));
|
||||
AddLeafNode(start_kind, default_token, /*has_error=*/true);
|
||||
@@ -766,6 +765,53 @@ auto Parser::HandleCodeBlockFinishState() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleDeclarationNameAndParams(bool params_required) -> void {
|
||||
auto state = PopState();
|
||||
|
||||
if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier,
|
||||
ParseNodeKind::DeclaredName)) {
|
||||
emitter_->Emit(*position_, ExpectedDeclarationName,
|
||||
tokens_->GetKind(state.token));
|
||||
ReturnErrorOnState();
|
||||
return;
|
||||
}
|
||||
|
||||
if (PositionIs(TokenKind::OpenSquareBracket)) {
|
||||
PushState(ParserState::DeclarationNameAndParamsAfterDeduced);
|
||||
PushState(ParserState::ParameterListAsDeduced);
|
||||
} else if (PositionIs(TokenKind::OpenParen)) {
|
||||
PushState(ParserState::ParameterListAsRegular);
|
||||
} else if (params_required) {
|
||||
CARBON_DIAGNOSTIC(ParametersRequiredByIntroducer, Error,
|
||||
"`{0}` requires a `(` for parameters.", TokenKind);
|
||||
emitter_->Emit(*position_, ParametersRequiredByIntroducer,
|
||||
tokens_->GetKind(state.token));
|
||||
ReturnErrorOnState();
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleDeclarationNameAndParamsAsOptionalState() -> void {
|
||||
HandleDeclarationNameAndParams(/*params_required=*/false);
|
||||
}
|
||||
|
||||
auto Parser::HandleDeclarationNameAndParamsAsRequiredState() -> void {
|
||||
HandleDeclarationNameAndParams(/*params_required=*/true);
|
||||
}
|
||||
|
||||
auto Parser::HandleDeclarationNameAndParamsAfterDeducedState() -> void {
|
||||
PopAndDiscardState();
|
||||
|
||||
if (PositionIs(TokenKind::OpenParen)) {
|
||||
PushState(ParserState::ParameterListAsRegular);
|
||||
} else {
|
||||
CARBON_DIAGNOSTIC(
|
||||
ParametersRequiredByDeduced, Error,
|
||||
"A `(` for parameters is required after deduced parameters.");
|
||||
emitter_->Emit(*position_, ParametersRequiredByDeduced);
|
||||
ReturnErrorOnState();
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleDeclarationScopeLoopState() -> void {
|
||||
// This maintains the current state unless we're at the end of the scope.
|
||||
|
||||
@@ -807,35 +853,6 @@ auto Parser::HandleDeclarationScopeLoopState() -> void {
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleDeducedParameterState() -> void {
|
||||
PopAndDiscardState();
|
||||
|
||||
PushState(ParserState::DeducedParameterFinish);
|
||||
PushState(ParserState::PatternAsDeducedParameter);
|
||||
}
|
||||
|
||||
auto Parser::HandleDeducedParameterFinishState() -> void {
|
||||
auto state = PopState();
|
||||
|
||||
if (state.has_error) {
|
||||
ReturnErrorOnState();
|
||||
}
|
||||
|
||||
if (ConsumeListToken(ParseNodeKind::ParameterListComma,
|
||||
TokenKind::CloseSquareBracket,
|
||||
state.has_error) == ListTokenKind::Comma) {
|
||||
PushState(ParserState::DeducedParameter);
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleDeducedParameterListFinishState() -> void {
|
||||
auto state = PopState();
|
||||
|
||||
AddNode(ParseNodeKind::DeducedParameterList,
|
||||
ConsumeChecked(TokenKind::CloseSquareBracket), state.subtree_start,
|
||||
state.has_error);
|
||||
}
|
||||
|
||||
auto Parser::HandleDesignator(bool as_struct) -> void {
|
||||
auto state = PopState();
|
||||
|
||||
@@ -1084,87 +1101,13 @@ auto Parser::HandleFunctionIntroducerState() -> void {
|
||||
|
||||
AddLeafNode(ParseNodeKind::FunctionIntroducer, Consume());
|
||||
|
||||
if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier,
|
||||
ParseNodeKind::DeclaredName)) {
|
||||
emitter_->Emit(*position_, ExpectedDeclarationName, TokenKind::Fn);
|
||||
// TODO: We could change the lexer to allow us to synthesize certain
|
||||
// kinds of tokens and try to "recover" here, but unclear that this is
|
||||
// really useful.
|
||||
HandleDeclarationError(state, ParseNodeKind::FunctionDeclaration,
|
||||
/*skip_past_likely_end=*/true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Proceed to the same state regardless of whether there's a deduced
|
||||
// parameter list.
|
||||
state.state = ParserState::FunctionAfterDeducedParameterList;
|
||||
state.state = ParserState::FunctionAfterParameters;
|
||||
PushState(state);
|
||||
|
||||
if (!PositionIs(TokenKind::OpenSquareBracket)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the deduced parameter list as its own subtree.
|
||||
PushState(ParserState::DeducedParameterListFinish);
|
||||
AddLeafNode(ParseNodeKind::DeducedParameterListStart, Consume());
|
||||
|
||||
if (!PositionIs(TokenKind::CloseSquareBracket)) {
|
||||
PushState(ParserState::DeducedParameter);
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleFunctionAfterDeducedParameterListState() -> void {
|
||||
auto state = PopState();
|
||||
|
||||
if (!PositionIs(TokenKind::OpenParen)) {
|
||||
CARBON_DIAGNOSTIC(ExpectedFunctionParams, Error,
|
||||
"Expected `(` after function name.");
|
||||
emitter_->Emit(*position_, ExpectedFunctionParams);
|
||||
HandleDeclarationError(state, ParseNodeKind::FunctionDeclaration,
|
||||
/*skip_past_likely_end=*/true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the parameter list as its own subtree; once that pops, resume
|
||||
// function parsing.
|
||||
state.state = ParserState::FunctionAfterParameterList;
|
||||
state.state = ParserState::DeclarationNameAndParamsAsRequired;
|
||||
PushState(state);
|
||||
PushState(ParserState::FunctionParameterListFinish);
|
||||
AddLeafNode(ParseNodeKind::ParameterListStart, Consume());
|
||||
|
||||
if (!PositionIs(TokenKind::CloseParen)) {
|
||||
PushState(ParserState::FunctionParameter);
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleFunctionParameterState() -> void {
|
||||
PopAndDiscardState();
|
||||
|
||||
PushState(ParserState::FunctionParameterFinish);
|
||||
PushState(ParserState::PatternAsFunctionParameter);
|
||||
}
|
||||
|
||||
auto Parser::HandleFunctionParameterFinishState() -> void {
|
||||
auto state = PopState();
|
||||
|
||||
if (state.has_error) {
|
||||
ReturnErrorOnState();
|
||||
}
|
||||
|
||||
if (ConsumeListToken(ParseNodeKind::ParameterListComma, TokenKind::CloseParen,
|
||||
state.has_error) == ListTokenKind::Comma) {
|
||||
PushState(ParserState::FunctionParameter);
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleFunctionParameterListFinishState() -> void {
|
||||
auto state = PopState();
|
||||
|
||||
AddNode(ParseNodeKind::ParameterList, ConsumeChecked(TokenKind::CloseParen),
|
||||
state.subtree_start, state.has_error);
|
||||
}
|
||||
|
||||
auto Parser::HandleFunctionAfterParameterListState() -> void {
|
||||
auto Parser::HandleFunctionAfterParametersState() -> void {
|
||||
auto state = PopState();
|
||||
|
||||
// Regardless of whether there's a return type, we'll finish the signature.
|
||||
@@ -1219,8 +1162,10 @@ auto Parser::HandleFunctionSignatureFinishState() -> void {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
emitter_->Emit(*position_, ExpectedDeclarationSemiOrDefinition,
|
||||
TokenKind::Fn);
|
||||
if (!state.has_error) {
|
||||
emitter_->Emit(*position_, ExpectedDeclarationSemiOrDefinition,
|
||||
TokenKind::Fn);
|
||||
}
|
||||
// Only need to skip if we've not already found a new line.
|
||||
bool skip_past_likely_end =
|
||||
tokens_->GetLine(*position_) == tokens_->GetLine(state.token);
|
||||
@@ -1316,6 +1261,93 @@ auto Parser::HandlePackageState() -> void {
|
||||
/*has_error=*/false);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameter(ParserState pattern_state,
|
||||
ParserState finish_state) -> void {
|
||||
PopAndDiscardState();
|
||||
|
||||
PushState(finish_state);
|
||||
PushState(pattern_state);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterAsDeducedState() -> void {
|
||||
HandleParameter(ParserState::PatternAsDeducedParameter,
|
||||
ParserState::ParameterFinishAsDeduced);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterAsRegularState() -> void {
|
||||
HandleParameter(ParserState::PatternAsParameter,
|
||||
ParserState::ParameterFinishAsRegular);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterFinish(TokenKind close_token,
|
||||
ParserState param_state) -> void {
|
||||
auto state = PopState();
|
||||
|
||||
if (state.has_error) {
|
||||
ReturnErrorOnState();
|
||||
}
|
||||
|
||||
if (ConsumeListToken(ParseNodeKind::ParameterListComma, close_token,
|
||||
state.has_error) == ListTokenKind::Comma) {
|
||||
PushState(param_state);
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterFinishAsDeducedState() -> void {
|
||||
HandleParameterFinish(TokenKind::CloseSquareBracket,
|
||||
ParserState::ParameterAsDeduced);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterFinishAsRegularState() -> void {
|
||||
HandleParameterFinish(TokenKind::CloseParen, ParserState::ParameterAsRegular);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterList(ParseNodeKind parse_node_kind,
|
||||
TokenKind open_token_kind,
|
||||
TokenKind close_token_kind,
|
||||
ParserState param_state,
|
||||
ParserState finish_state) -> void {
|
||||
PopAndDiscardState();
|
||||
|
||||
PushState(finish_state);
|
||||
AddLeafNode(parse_node_kind, ConsumeChecked(open_token_kind));
|
||||
|
||||
if (!PositionIs(close_token_kind)) {
|
||||
PushState(param_state);
|
||||
}
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterListAsDeducedState() -> void {
|
||||
HandleParameterList(
|
||||
ParseNodeKind::DeducedParameterListStart, TokenKind::OpenSquareBracket,
|
||||
TokenKind::CloseSquareBracket, ParserState::ParameterAsDeduced,
|
||||
ParserState::ParameterListFinishAsDeduced);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterListAsRegularState() -> void {
|
||||
HandleParameterList(ParseNodeKind::ParameterListStart, TokenKind::OpenParen,
|
||||
TokenKind::CloseParen, ParserState::ParameterAsRegular,
|
||||
ParserState::ParameterListFinishAsRegular);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterListFinish(ParseNodeKind parse_node_kind,
|
||||
TokenKind token_kind) -> void {
|
||||
auto state = PopState();
|
||||
|
||||
AddNode(parse_node_kind, ConsumeChecked(token_kind), state.subtree_start,
|
||||
state.has_error);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterListFinishAsDeducedState() -> void {
|
||||
HandleParameterListFinish(ParseNodeKind::DeducedParameterList,
|
||||
TokenKind::CloseSquareBracket);
|
||||
}
|
||||
|
||||
auto Parser::HandleParameterListFinishAsRegularState() -> void {
|
||||
HandleParameterListFinish(ParseNodeKind::ParameterList,
|
||||
TokenKind::CloseParen);
|
||||
}
|
||||
|
||||
auto Parser::HandleParenCondition(ParseNodeKind start_kind,
|
||||
ParserState finish_state) -> void {
|
||||
auto state = PopState();
|
||||
@@ -1489,7 +1521,7 @@ auto Parser::HandlePatternAsDeducedParameterState() -> void {
|
||||
HandlePattern(PatternKind::DeducedParameter);
|
||||
}
|
||||
|
||||
auto Parser::HandlePatternAsFunctionParameterState() -> void {
|
||||
auto Parser::HandlePatternAsParameterState() -> void {
|
||||
HandlePattern(PatternKind::Parameter);
|
||||
}
|
||||
|
||||
@@ -1733,17 +1765,39 @@ auto Parser::HandleStatementWhileBlockFinishState() -> void {
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeIntroducer(ParseNodeKind introducer_kind,
|
||||
ParseNodeKind declaration_kind,
|
||||
ParseNodeKind definition_start_kind,
|
||||
ParserState definition_finish_state) -> void {
|
||||
ParserState after_params_state) -> void {
|
||||
auto state = PopState();
|
||||
|
||||
AddLeafNode(introducer_kind, Consume());
|
||||
|
||||
if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier,
|
||||
ParseNodeKind::DeclaredName)) {
|
||||
emitter_->Emit(*position_, ExpectedDeclarationName,
|
||||
tokens_->GetKind(state.token));
|
||||
state.state = after_params_state;
|
||||
PushState(state);
|
||||
state.state = ParserState::DeclarationNameAndParamsAsOptional;
|
||||
PushState(state);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeIntroducerAsClassState() -> void {
|
||||
HandleTypeIntroducer(ParseNodeKind::ClassIntroducer,
|
||||
ParserState::TypeAfterParamsAsClass);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeIntroducerAsInterfaceState() -> void {
|
||||
HandleTypeIntroducer(ParseNodeKind::InterfaceIntroducer,
|
||||
ParserState::TypeAfterParamsAsInterface);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeIntroducerAsNamedConstraintState() -> void {
|
||||
HandleTypeIntroducer(ParseNodeKind::NamedConstraintIntroducer,
|
||||
ParserState::TypeAfterParamsAsNamedConstraint);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeAfterParams(ParseNodeKind declaration_kind,
|
||||
ParseNodeKind definition_start_kind,
|
||||
ParserState definition_finish_state)
|
||||
-> void {
|
||||
auto state = PopState();
|
||||
|
||||
if (state.has_error) {
|
||||
HandleDeclarationError(state, declaration_kind,
|
||||
/*skip_past_likely_end=*/true);
|
||||
return;
|
||||
@@ -1769,25 +1823,22 @@ auto Parser::HandleTypeIntroducer(ParseNodeKind introducer_kind,
|
||||
state.has_error);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeIntroducerAsClassState() -> void {
|
||||
HandleTypeIntroducer(ParseNodeKind::ClassIntroducer,
|
||||
ParseNodeKind::ClassDeclaration,
|
||||
ParseNodeKind::ClassDefinitionStart,
|
||||
ParserState::TypeDefinitionFinishAsClass);
|
||||
auto Parser::HandleTypeAfterParamsAsClassState() -> void {
|
||||
HandleTypeAfterParams(ParseNodeKind::ClassDeclaration,
|
||||
ParseNodeKind::ClassDefinitionStart,
|
||||
ParserState::TypeDefinitionFinishAsClass);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeIntroducerAsInterfaceState() -> void {
|
||||
HandleTypeIntroducer(ParseNodeKind::InterfaceIntroducer,
|
||||
ParseNodeKind::InterfaceDeclaration,
|
||||
ParseNodeKind::InterfaceDefinitionStart,
|
||||
ParserState::TypeDefinitionFinishAsInterface);
|
||||
auto Parser::HandleTypeAfterParamsAsInterfaceState() -> void {
|
||||
HandleTypeAfterParams(ParseNodeKind::InterfaceDeclaration,
|
||||
ParseNodeKind::InterfaceDefinitionStart,
|
||||
ParserState::TypeDefinitionFinishAsInterface);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeIntroducerAsNamedConstraintState() -> void {
|
||||
HandleTypeIntroducer(ParseNodeKind::NamedConstraintIntroducer,
|
||||
ParseNodeKind::NamedConstraintDeclaration,
|
||||
ParseNodeKind::NamedConstraintDefinitionStart,
|
||||
ParserState::TypeDefinitionFinishAsNamedConstraint);
|
||||
auto Parser::HandleTypeAfterParamsAsNamedConstraintState() -> void {
|
||||
HandleTypeAfterParams(ParseNodeKind::NamedConstraintDeclaration,
|
||||
ParseNodeKind::NamedConstraintDefinitionStart,
|
||||
ParserState::TypeDefinitionFinishAsNamedConstraint);
|
||||
}
|
||||
|
||||
auto Parser::HandleTypeDefinitionFinish(ParseNodeKind definition_kind) -> void {
|
||||
|
||||
Reference in New Issue
Block a user