瀏覽代碼

Replace ParseContext with an examination of state_stack_. (#2645)

Per [discussion](https://discord.com/channels/655572317891461132/655578254970716160/1078427629427904563), there's a preference for having the support this enables in the parser. For example, that the parser should detect and error on a non-default interface function's definition.

However, we do need to handle nesting of declarations. We could do that by making this a stack. I think though that it'll be more efficient to keep using state_stack_, since it'll be called in places which are a limited number of steps from the actual state. That may already be in cache since we frequently look at state_stack_, so I'm uncertain that maintaining an additional stack would be a net benefit.
Jon Ross-Perkins 3 年之前
父節點
當前提交
28327a00a9
共有 2 個文件被更改,包括 25 次插入13 次删除
  1. 17 7
      toolchain/parser/parser.cpp
  2. 8 6
      toolchain/parser/parser.h

+ 17 - 7
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 {

+ 8 - 6
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<StateStackEntry> state_stack_;
-  // TODO: This can be a mini-stack of contexts rather than a simple variable.
-  ParseContext stack_context_;
 };
 
 }  // namespace Carbon