Răsfoiți Sursa

Make stringification non-recursive. (#2804)

Jon Ross-Perkins 3 ani în urmă
părinte
comite
32ea47f068
2 a modificat fișierele cu 69 adăugiri și 54 ștergeri
  1. 68 53
      toolchain/semantics/semantics_ir.cpp
  2. 1 1
      toolchain/semantics/semantics_ir.h

+ 68 - 53
toolchain/semantics/semantics_ir.cpp

@@ -113,63 +113,78 @@ auto SemanticsIR::StringifyNode(SemanticsNodeId node_id) -> std::string {
 }
 
 auto SemanticsIR::StringifyNodeImpl(llvm::raw_ostream& out,
-                                    SemanticsNodeId node_id) -> void {
-  // Invalid node IDs will use the default invalid printing.
-  if (!node_id.is_valid()) {
-    out << node_id;
-    return;
-  }
+                                    SemanticsNodeId root_node_id) -> void {
+  struct Step {
+    // The node to print.
+    SemanticsNodeId node_id;
+    // The index into node_id to print. Not used by all types.
+    int index = 0;
+  };
+  llvm::SmallVector<Step> steps = {{.node_id = root_node_id}};
+
+  while (!steps.empty()) {
+    auto step = steps.pop_back_val();
+
+    // Invalid node IDs will use the default invalid printing.
+    if (!step.node_id.is_valid()) {
+      out << step.node_id;
+      continue;
+    }
 
-  // Builtins have designated labels.
-  if (node_id.index < SemanticsBuiltinKind::ValidCount) {
-    out << SemanticsBuiltinKind::FromInt(node_id.index).label();
-    return;
-  }
+    // Builtins have designated labels.
+    if (step.node_id.index < SemanticsBuiltinKind::ValidCount) {
+      out << SemanticsBuiltinKind::FromInt(step.node_id.index).label();
+      continue;
+    }
 
-  auto node = GetNode(node_id);
-  switch (node.kind()) {
-    case SemanticsNodeKind::StructType: {
-      out << "{";
-      auto refs = GetNodeBlock(node.GetAsStructType().second);
-      llvm::ListSeparator sep;
-      for (const auto& ref_id : refs) {
-        out << sep;
-        // TODO: Bound recursion depth or remove recursive step.
-        StringifyNodeImpl(out, ref_id);
+    auto node = GetNode(step.node_id);
+    switch (node.kind()) {
+      case SemanticsNodeKind::StructType: {
+        auto refs = GetNodeBlock(node.GetAsStructType().second);
+        if (step.index == 0) {
+          out << "{";
+        } else if (step.index < static_cast<int>(refs.size())) {
+          out << ", ";
+        } else {
+          out << "}";
+          break;
+        }
+
+        steps.push_back({.node_id = step.node_id, .index = step.index + 1});
+        steps.push_back({.node_id = refs[step.index]});
+        break;
       }
-      out << "}";
-      break;
-    }
-    case SemanticsNodeKind::StructTypeField: {
-      out << "." << GetString(node.GetAsStructTypeField()) << ": ";
-      StringifyNodeImpl(out, node.type_id());
-      break;
+      case SemanticsNodeKind::StructTypeField: {
+        out << "." << GetString(node.GetAsStructTypeField()) << ": ";
+        steps.push_back({.node_id = node.type_id()});
+        break;
+      }
+      case SemanticsNodeKind::Assign:
+      case SemanticsNodeKind::BinaryOperatorAdd:
+      case SemanticsNodeKind::BindName:
+      case SemanticsNodeKind::Builtin:
+      case SemanticsNodeKind::Call:
+      case SemanticsNodeKind::CodeBlock:
+      case SemanticsNodeKind::CrossReference:
+      case SemanticsNodeKind::FunctionDeclaration:
+      case SemanticsNodeKind::FunctionDefinition:
+      case SemanticsNodeKind::IntegerLiteral:
+      case SemanticsNodeKind::RealLiteral:
+      case SemanticsNodeKind::Return:
+      case SemanticsNodeKind::ReturnExpression:
+      case SemanticsNodeKind::StringLiteral:
+      case SemanticsNodeKind::StructMemberAccess:
+      case SemanticsNodeKind::StructValue:
+      case SemanticsNodeKind::StubReference:
+      case SemanticsNodeKind::VarStorage:
+        // We don't need to handle stringification for nodes that don't show up
+        // in errors, but make it clear what's going on so that it's clearer
+        // when stringification is needed.
+        out << "<cannot stringify " << step.node_id << ">";
+        break;
+      case SemanticsNodeKind::Invalid:
+        llvm_unreachable("SemanticsNodeKind::Invalid is never used.");
     }
-    case SemanticsNodeKind::Assign:
-    case SemanticsNodeKind::BinaryOperatorAdd:
-    case SemanticsNodeKind::BindName:
-    case SemanticsNodeKind::Builtin:
-    case SemanticsNodeKind::Call:
-    case SemanticsNodeKind::CodeBlock:
-    case SemanticsNodeKind::CrossReference:
-    case SemanticsNodeKind::FunctionDeclaration:
-    case SemanticsNodeKind::FunctionDefinition:
-    case SemanticsNodeKind::IntegerLiteral:
-    case SemanticsNodeKind::RealLiteral:
-    case SemanticsNodeKind::Return:
-    case SemanticsNodeKind::ReturnExpression:
-    case SemanticsNodeKind::StringLiteral:
-    case SemanticsNodeKind::StructMemberAccess:
-    case SemanticsNodeKind::StructValue:
-    case SemanticsNodeKind::StubReference:
-    case SemanticsNodeKind::VarStorage:
-      // We don't need to handle stringification for nodes that don't show up in
-      // errors, but make it clear what's going on so that it's clearer when
-      // stringification is needed.
-      out << "<cannot stringify " << node_id << ">";
-      return;
-    case SemanticsNodeKind::Invalid:
-      llvm_unreachable("SemanticsNodeKind::Invalid is never used.");
   }
 }
 

+ 1 - 1
toolchain/semantics/semantics_ir.h

@@ -214,7 +214,7 @@ class SemanticsIR {
   auto StringifyNode(SemanticsNodeId node_id) -> std::string;
 
   // Implements StringifyNode using streaming.
-  auto StringifyNodeImpl(llvm::raw_ostream& out, SemanticsNodeId node_id)
+  auto StringifyNodeImpl(llvm::raw_ostream& out, SemanticsNodeId root_node_id)
       -> void;
 
   bool has_errors_ = false;