diff --git a/toolchain/parser/parser.cpp b/toolchain/parser/parser.cpp index 08ff10392ff6..6287e8b54883 100644 --- a/toolchain/parser/parser.cpp +++ b/toolchain/parser/parser.cpp @@ -91,8 +91,7 @@ Parser::Parser(ParseTree& tree, TokenizedBuffer& tokens, emitter_(&emitter), vlog_stream_(vlog_stream), position_(tokens_->tokens().begin()), - end_(tokens_->tokens().end()), - stack_context_(ParseContext::File) { + end_(tokens_->tokens().end()) { CARBON_CHECK(position_ != end_) << "Empty TokenizedBuffer"; --end_; CARBON_CHECK(tokens_->GetKind(*end_) == TokenKind::EndOfFile) @@ -451,6 +450,21 @@ auto Parser::Parse() -> void { AddLeafNode(ParseNodeKind::FileEnd, *position_); } +auto Parser::GetDeclarationContext() -> DeclarationContext { + for (auto entry : llvm::reverse(state_stack_)) { + switch (entry.state) { + case ParserState::InterfaceDefinitionLoop: + return DeclarationContext::Interface; + case ParserState::DeclarationLoop: + return DeclarationContext::File; + default: + // Continue checking. + break; + } + } + llvm_unreachable("Should always be able to find DeclarationLoop"); +} + auto Parser::HandleBraceExpressionState() -> void { auto state = PopState(); @@ -1135,7 +1149,7 @@ auto Parser::HandleFunctionSignatureFinishState() -> void { break; } case TokenKind::OpenCurlyBrace: { - if (stack_context_ == ParseContext::Interface) { + if (GetDeclarationContext() == DeclarationContext::Interface) { CARBON_DIAGNOSTIC( MethodImplNotAllowed, Error, "Method implementations are not allowed in interfaces."); @@ -1175,9 +1189,6 @@ auto Parser::HandleFunctionDefinitionFinishState() -> void { auto Parser::HandleInterfaceIntroducerState() -> void { auto state = PopState(); - CARBON_CHECK(stack_context_ == ParseContext::File) - << "TODO: Support nesting."; - stack_context_ = ParseContext::Interface; if (!ConsumeAndAddLeafNodeIf(TokenKind::Identifier, ParseNodeKind::DeclaredName)) { @@ -1249,7 +1260,6 @@ auto Parser::HandleInterfaceDefinitionFinishState() -> void { auto state = PopState(); AddNode(ParseNodeKind::InterfaceDefinition, state.token, state.subtree_start, state.has_error); - stack_context_ = ParseContext::File; } auto Parser::HandlePackageState() -> void { diff --git a/toolchain/parser/parser.h b/toolchain/parser/parser.h index 8bd8f013e32b..6bbfe3486b11 100644 --- a/toolchain/parser/parser.h +++ b/toolchain/parser/parser.h @@ -46,10 +46,8 @@ class Parser { // Supported kinds for HandlePattern. enum class PatternKind { Parameter, Variable }; - // Gives information about the language construct/context being parsed. For - // now, a simple enum but can be extended later to provide more information as - // necessary. - enum class ParseContext { + // Supported return values for GetDeclarationContext. + enum class DeclarationContext { File, // Top-level context. Interface, }; @@ -258,6 +256,12 @@ class Parser { << "Excessive stack size: likely infinite loop"; } + // Returns the current declaration context according to state_stack_. + // This is expected to be called in cases which are close to a context. + // Although it looks like it could be O(n) for state_stack_'s depth, valid + // parses should only need to look down a couple steps. + auto GetDeclarationContext() -> DeclarationContext; + // Propagates an error up the state stack, to the parent state. auto ReturnErrorOnState() -> void { state_stack_.back().has_error = true; } @@ -328,8 +332,6 @@ class Parser { TokenizedBuffer::TokenIterator end_; llvm::SmallVector state_stack_; - // TODO: This can be a mini-stack of contexts rather than a simple variable. - ParseContext stack_context_; }; } // namespace Carbon