[parser] Start re-implementing interfaces using the stack parser. (#2412)

First change towards re-implementing interfaces using the new parser. I kept it small to make sure we are on the same page regarding stack states and how the parse tree should look like.

Co-authored-by: ergawy <kareem.ergawy@guardsquare.com>
This commit is contained in:
Kareem Ergawy
2022-11-28 12:58:41 -08:00
committed by GitHub
co-authored by ergawy
parent 5cd05efc62
commit a508390423
7 changed files with 159 additions and 0 deletions
@@ -78,6 +78,10 @@ CARBON_DIAGNOSTIC_KIND(ExpectedSemiToEndPackageDirective)
// For-specific diagnostics
CARBON_DIAGNOSTIC_KIND(ExpectedIn)
// Interface-specific diagnostics
CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceName)
CARBON_DIAGNOSTIC_KIND(ExpectedInterfaceOpenCurlyBrace)
// ============================================================================
// Semantics diagnostics
// ============================================================================
+5
View File
@@ -113,6 +113,11 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldValue, TodoFixParseNode)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldType, TodoFixParseNode)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructComma, 0)
// Interfaces
CARBON_PARSE_NODE_KIND_CHILD_COUNT(InterfaceDefinition, TodoFixParseNode)
CARBON_PARSE_NODE_KIND_CHILD_COUNT(InterfaceBodyStart, 0)
CARBON_PARSE_NODE_KIND_BRACKET(InterfaceBody, InterfaceBodyStart)
#undef CARBON_PARSE_NODE_KIND
#undef CARBON_PARSE_NODE_KIND_BRACKET
#undef CARBON_PARSE_NODE_KIND_CHILD_COUNT
+72
View File
@@ -701,6 +701,11 @@ auto Parser::HandleDeclarationLoopState() -> void {
PushState(ParserState::VarAsRequireSemicolon());
break;
}
case TokenKind::Interface(): {
PushState(ParserState::InterfaceIntroducer());
++position_;
break;
}
default: {
CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error,
"Unrecognized declaration introducer.");
@@ -1658,4 +1663,71 @@ auto Parser::HandleVarFinishAsNoSemicolonState() -> void {
HandleVarFinish(/*require_semicolon=*/false);
}
auto Parser::HandleInterfaceIntroducerState() -> void {
auto state = PopState();
if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier(),
ParseNodeKind::DeclaredName())) {
CARBON_DIAGNOSTIC(ExpectedInterfaceName, Error,
"Expected interface name after `interface` keyword.");
emitter_->Emit(*position_, ExpectedInterfaceName);
state.has_error = true;
}
bool parse_body = true;
if (!PositionIs(TokenKind::OpenCurlyBrace())) {
CARBON_DIAGNOSTIC(ExpectedInterfaceOpenCurlyBrace, Error,
"Expected `{{` to start interface definition.");
emitter_->Emit(*position_, ExpectedInterfaceOpenCurlyBrace);
state.has_error = true;
SkipPastLikelyEnd(state.token);
parse_body = false;
}
state.state = ParserState::InterfaceDefinitionFinish();
PushState(state);
if (parse_body) {
PushState(ParserState::InterfaceDefinitionLoop());
AddLeafNode(ParseNodeKind::InterfaceBodyStart(), Consume());
}
}
auto Parser::HandleInterfaceDefinitionLoopState() -> void {
// This maintains the current state unless we're at the end of the interface
// definition.
switch (PositionKind()) {
case TokenKind::CloseCurlyBrace(): {
auto state = PopState();
AddNode(ParseNodeKind::InterfaceBody(), Consume(), state.subtree_start,
state.has_error);
break;
}
// TODO: Handle possible declarations inside interface body.
default: {
CARBON_DIAGNOSTIC(UnrecognizedDeclaration, Error,
"Unrecognized declaration introducer.");
emitter_->Emit(*position_, UnrecognizedDeclaration);
if (auto semi = SkipPastLikelyEnd(*position_)) {
AddLeafNode(ParseNodeKind::EmptyDeclaration(), *semi,
/*has_error=*/true);
} else {
ReturnErrorOnState();
}
break;
}
}
}
auto Parser::HandleInterfaceDefinitionFinishState() -> void {
auto state = PopState();
AddNode(ParseNodeKind::InterfaceDefinition(), state.token,
state.subtree_start, state.has_error);
}
} // namespace Carbon
+28
View File
@@ -123,6 +123,9 @@ CARBON_PARSER_STATE(CodeBlockFinish)
// If `Var`:
// 1. Var
// 2. DeclarationLoop
// If `interface`:
// 1. InterfaceIntroducer
// 2. DeclarationLoop
// Else:
// 1. DeclarationLoop
CARBON_PARSER_STATE(DeclarationLoop)
@@ -276,6 +279,31 @@ CARBON_PARSER_STATE(FunctionSignatureFinish)
// (state done)
CARBON_PARSER_STATE(FunctionDefinitionFinish)
// Finishes an interface definition.
//
// Always:
// (state done)
CARBON_PARSER_STATE(InterfaceDefinitionFinish)
// Handles parsing the body of an interface.
//
// If `}`:
// (state done)
// Else:
// 1. InterfaceDefinitionLoop
CARBON_PARSER_STATE(InterfaceDefinitionLoop)
// Handles processing of a intefaces's `interface <name> {`.
//
// If invalid:
// 1. InterfaceDefinitionFinish
// If `{` is missing:
// 1. InterfaceDefinitionFinish
// Else:
// 1. InterfaceDefinitionLoop
// 2. InterfaceDefinitionFinish
CARBON_PARSER_STATE(InterfaceIntroducer)
// Handles `package`.
//
// Always:
@@ -0,0 +1,15 @@
// 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: 'DeclaredName', text: 'foo'},
// CHECK:STDOUT: {kind: 'InterfaceBodyStart', text: '{'},
// CHECK:STDOUT: {kind: 'InterfaceBody', text: '}', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', subtree_size: 4},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
interface foo {
}
@@ -0,0 +1,16 @@
// 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: %{not} %{carbon-run-parser}
// CHECK:STDOUT: [
// CHECK:STDOUT: {kind: 'InterfaceBodyStart', text: '{'},
// CHECK:STDOUT: {kind: 'InterfaceBody', text: '}', subtree_size: 2},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', has_error: yes, subtree_size: 3},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_missing_name.carbon:[[@LINE+1]]:11: Expected interface name after `interface` keyword.
interface {
}
@@ -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: %{not} %{carbon-run-parser}
// CHECK:STDOUT: [
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'bar'},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', has_error: yes, subtree_size: 2},
// CHECK:STDOUT: {kind: 'DeclaredName', text: 'foo'},
// CHECK:STDOUT: {kind: 'InterfaceDefinition', text: 'interface', has_error: yes, subtree_size: 2},
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
// CHECK:STDOUT: ]
// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon:[[@LINE+1]]:15: Expected `{` to start interface definition.
interface bar baz {}
// CHECK:STDERR: {{.*}}/toolchain/parser/testdata/generics/interface/fail_missing_open_curly.carbon:[[@LINE+1]]:14: Expected `{` to start interface definition.
interface foo