Parsing for generic and template parameters. (#2685)

Also cleans up some comments about related parse nodes. Currently basic and not heavily validated.

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
Jon Ross-Perkins
2023-03-16 10:50:35 -07:00
committed by GitHub
co-authored by Richard Smith
parent 7d553107dd
commit d7ab71ba7d
9 changed files with 153 additions and 44 deletions
+2
View File
@@ -45,6 +45,7 @@ CARBON_SYMBOL_TOKEN(LessLessEqual, "<<=")
CARBON_SYMBOL_TOKEN(AmpEqual, "&=")
CARBON_SYMBOL_TOKEN(CaretEqual, "^=")
CARBON_SYMBOL_TOKEN(ColonEqual, ":=")
CARBON_SYMBOL_TOKEN(ColonExclaim, ":!")
CARBON_SYMBOL_TOKEN(EqualEqual, "==")
CARBON_SYMBOL_TOKEN(EqualGreater, "=>")
CARBON_SYMBOL_TOKEN(ExclaimEqual, "!=")
@@ -161,6 +162,7 @@ CARBON_KEYWORD_TOKEN(SelfParameter, "self")
CARBON_KEYWORD_TOKEN(SelfType, "Self")
// TODO: Although we provide a String type literal, it's not standardized.
CARBON_KEYWORD_TOKEN(StringTypeLiteral, "String")
CARBON_KEYWORD_TOKEN(Template, "template")
CARBON_KEYWORD_TOKEN(Then, "then")
// Underscore is tokenized as a keyword because it's part of identifiers.
CARBON_KEYWORD_TOKEN(Underscore, "_")
+16 -23
View File
@@ -88,23 +88,30 @@ CARBON_PARSE_NODE_KIND_BRACKET(FunctionDefinitionStart, FunctionIntroducer)
CARBON_PARSE_NODE_KIND_BRACKET(FunctionDefinition, FunctionDefinitionStart)
CARBON_PARSE_NODE_KIND_BRACKET(FunctionDeclaration, FunctionIntroducer)
// A parameter list:
// ParamertListStart
// _external_: expression
// A parameter list, possibly deduced:
// [Deduced]ParamertListStart
// _external_: [Generic]PatternBinding
// ParameterListComma
// ParameterList
// [Deduced]ParameterList
//
// Expressions and ParameterListComma may repeat with ParameterListComma as a
// separator.
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ParameterListStart, 0)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(DeducedParameterListStart, 0)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(ParameterListComma, 0)
CARBON_PARSE_NODE_KIND_BRACKET(ParameterList, ParameterListStart)
CARBON_PARSE_NODE_KIND_BRACKET(DeducedParameterList, DeducedParameterListStart)
// A pattern binding, such as `name: Type`:
// DeclaredName
// _external_: type expression
// PatternBinding
// [Generic]PatternBinding
//
// Address and Template may be parents to [Generic]PatternBinding, in that order.
CARBON_PARSE_NODE_KIND_CHILD_COUNT(PatternBinding, 2)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(GenericPatternBinding, 2)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(Address, 1)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(Template, 1)
// `var`:
// VariableIntroducer
@@ -330,27 +337,13 @@ CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDefinition,
CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDeclaration,
NamedConstraintIntroducer)
// A pattern binding for `self` deduced parameter:
// `self`
// _external_: type expression
// SelfDeducedParameter
// The `self` name and `Self` type keywords. Typically of the form `self: Self`:
// SelfDeducedParameter
// SelfType
// PatternBinding
CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfDeducedParameter, 0)
// A pattern binding for `addr self` deduced parameter:
// `addr self`
// _external_: type expression
// SelfDeducedParameter
// CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfDeducedParameterAddress, 1)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(Address, 1)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfType, 0)
// Deduced parameters, such as `[self: Self]`:
// DeducedParameterListStart
// _external_: Address or PatternBinding
// DeducedParameterList
CARBON_PARSE_NODE_KIND_CHILD_COUNT(DeducedParameterListStart, 0)
CARBON_PARSE_NODE_KIND_BRACKET(DeducedParameterList, DeducedParameterListStart)
#undef CARBON_PARSE_NODE_KIND
#undef CARBON_PARSE_NODE_KIND_BRACKET
#undef CARBON_PARSE_NODE_KIND_CHILD_COUNT
+47 -19
View File
@@ -1451,23 +1451,26 @@ auto Parser::HandleParenExpressionFinishAsTupleState() -> void {
state.has_error);
}
auto Parser::ConsumeIfPatternKeyword(TokenKind keyword_token,
ParserState keyword_state,
int subtree_start) -> void {
if (auto token = ConsumeIf(keyword_token)) {
PushState(StateStackEntry(
keyword_state, PrecedenceGroup::ForTopLevelExpression(),
PrecedenceGroup::ForTopLevelExpression(), *token, subtree_start));
}
}
auto Parser::HandlePattern(PatternKind pattern_kind) -> void {
auto state = PopState();
// Ensure the finish state always follows, including for errors.
state.state = ParserState::PatternFinish;
// Parameters may have an `addr` keyword prefixing the pattern. This becomes
// the parent for the full PatternBinding.
// Parameters may have keywords prefixing the pattern. They become the parent
// for the full PatternBinding.
if (pattern_kind != PatternKind::Variable) {
if (auto addr = ConsumeIf(TokenKind::Addr)) {
// Mirror information including subtree_size, but we need to change a copy
// to avoid affecting the token.
auto addr_state = state;
addr_state.state = ParserState::PatternAddress;
addr_state.token = *addr;
PushState(addr_state);
}
ConsumeIfPatternKeyword(TokenKind::Template, ParserState::PatternTemplate,
state.subtree_start);
ConsumeIfPatternKeyword(TokenKind::Addr, ParserState::PatternAddress,
state.subtree_start);
}
// Handle an invalid pattern introducer for parameters and variables.
@@ -1487,6 +1490,8 @@ auto Parser::HandlePattern(PatternKind pattern_kind) -> void {
break;
}
}
// Still use the finish state for errors.
state.state = ParserState::PatternFinishAsRegular;
state.has_error = true;
PushState(state);
};
@@ -1506,9 +1511,13 @@ auto Parser::HandlePattern(PatternKind pattern_kind) -> void {
return;
}
if (auto colon = ConsumeIf(TokenKind::Colon)) {
// Use the colon for the root node.
state.token = *colon;
if (auto kind = PositionKind();
kind == TokenKind::Colon || kind == TokenKind::ColonExclaim) {
state.state = kind == TokenKind::Colon
? ParserState::PatternFinishAsRegular
: ParserState::PatternFinishAsGeneric;
// Use the `:` or `:!` for the root node.
state.token = Consume();
PushState(state);
PushStateForExpression(PrecedenceGroup::ForType());
} else {
@@ -1529,7 +1538,7 @@ auto Parser::HandlePatternAsVariableState() -> void {
HandlePattern(PatternKind::Variable);
}
auto Parser::HandlePatternFinishState() -> void {
auto Parser::HandlePatternFinish(ParseNodeKind node_kind) -> void {
auto state = PopState();
// If an error was encountered, propagate it without adding a node.
@@ -1539,8 +1548,15 @@ auto Parser::HandlePatternFinishState() -> void {
}
// TODO: may need to mark has_error if !type.
AddNode(ParseNodeKind::PatternBinding, state.token, state.subtree_start,
/*has_error=*/false);
AddNode(node_kind, state.token, state.subtree_start, /*has_error=*/false);
}
auto Parser::HandlePatternFinishAsGenericState() -> void {
HandlePatternFinish(ParseNodeKind::GenericPatternBinding);
}
auto Parser::HandlePatternFinishAsRegularState() -> void {
HandlePatternFinish(ParseNodeKind::PatternBinding);
}
auto Parser::HandlePatternAddressState() -> void {
@@ -1555,6 +1571,18 @@ auto Parser::HandlePatternAddressState() -> void {
}
}
auto Parser::HandlePatternTemplateState() -> void {
auto state = PopState();
AddNode(ParseNodeKind::Template, state.token, state.subtree_start,
state.has_error);
// If an error was encountered, propagate it while adding a node.
if (state.has_error) {
ReturnErrorOnState();
}
}
auto Parser::HandleStatementState() -> void {
PopAndDiscardState();
+8
View File
@@ -339,6 +339,14 @@ class Parser {
// Handles PatternAs(DeducedParameter|FunctionParameter|Variable).
auto HandlePattern(PatternKind pattern_kind) -> void;
// Handles PatternFinishAs(Generic|Regular).
auto HandlePatternFinish(ParseNodeKind node_kind) -> void;
// For HandlePattern, tries to consume a wrapping keyword.
auto ConsumeIfPatternKeyword(TokenKind keyword_token,
ParserState keyword_state, int subtree_start)
-> void;
// Handles the `;` after a keyword statement.
auto HandleStatementKeywordFinish(ParseNodeKind node_kind) -> void;
+8 -2
View File
@@ -380,7 +380,7 @@ CARBON_PARSER_STATE_VARIANTS2(ParenExpressionFinish, Normal, Tuple)
//
// If valid:
// 1. Expression
// 2. PatternFinish
// 2. PatternFinishAs(Generic|Regular)
// Else:
// 1. PatternFinish
CARBON_PARSER_STATE_VARIANTS3(Pattern, DeducedParameter, Parameter, Variable)
@@ -391,11 +391,17 @@ CARBON_PARSER_STATE_VARIANTS3(Pattern, DeducedParameter, Parameter, Variable)
// (state done)
CARBON_PARSER_STATE(PatternAddress)
// Handles `template` in a pattern.
//
// Always:
// (state done)
CARBON_PARSER_STATE(PatternTemplate)
// Finishes pattern processing.
//
// Always:
// (state done)
CARBON_PARSER_STATE(PatternFinish)
CARBON_PARSER_STATE_VARIANTS2(PatternFinish, Generic, Regular)
// Handles a single statement. While typically within a statement block, this
// can also be used for error recovery where we expect a statement block and
@@ -0,0 +1,19 @@
// 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
// RUN: %{carbon-run-parser}
// CHECK:STDOUT: [
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'},
// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'},
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'GenericPatternBinding', text: ':!', subtree_size: 3},
// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 5},
// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 8},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
fn foo(a:! i32);
@@ -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
// RUN: %{carbon-run-parser}
// CHECK:STDOUT: [
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'},
// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'},
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'GenericPatternBinding', text: ':!', subtree_size: 3},
// CHECK:STDOUT: {kind: 'Template', text: 'template', subtree_size: 4},
// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 6},
// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 9},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
fn foo(template a:! i32);
@@ -0,0 +1,21 @@
// 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
// RUN: %{carbon-run-parser}
// CHECK:STDOUT: [
// CHECK:STDOUT: {kind: 'FunctionIntroducer', text: 'fn'},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'},
// CHECK:STDOUT: {kind: 'ParameterListStart', text: '('},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'a'},
// CHECK:STDOUT: {kind: 'Literal', text: 'i32'},
// CHECK:STDOUT: {kind: 'GenericPatternBinding', text: ':!', subtree_size: 3},
// CHECK:STDOUT: {kind: 'Address', text: 'addr', subtree_size: 4},
// CHECK:STDOUT: {kind: 'Template', text: 'template', subtree_size: 5},
// CHECK:STDOUT: {kind: 'ParameterList', text: ')', subtree_size: 7},
// CHECK:STDOUT: {kind: 'FunctionDeclaration', text: ';', subtree_size: 10},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
fn foo(template addr a:! i32);
@@ -553,6 +553,12 @@ auto SemanticsParseTreeHandler::HandleFunctionIntroducer(
return true;
}
auto SemanticsParseTreeHandler::HandleGenericPatternBinding(
ParseTree::Node parse_node) -> bool {
emitter_->Emit(parse_node, SemanticsTodo, "GenericPatternBinding");
return false;
}
auto SemanticsParseTreeHandler::HandleIfCondition(ParseTree::Node parse_node)
-> bool {
emitter_->Emit(parse_node, SemanticsTodo, "HandleIfCondition");
@@ -977,6 +983,12 @@ auto SemanticsParseTreeHandler::HandleStructTypeLiteral(
return false;
}
auto SemanticsParseTreeHandler::HandleTemplate(ParseTree::Node parse_node)
-> bool {
emitter_->Emit(parse_node, SemanticsTodo, "HandleTemplate");
return false;
}
auto SemanticsParseTreeHandler::HandleTupleLiteral(ParseTree::Node parse_node)
-> bool {
emitter_->Emit(parse_node, SemanticsTodo, "HandleTupleLiteral");