[ir] Split `TextGenerator` apart.

Currently the `TextGenerator` class contains code specific to generating
from the AST. This CL splits out the AST specific bits into an
`ASTTextGenerator` subclass and uses that in the AST writers.

Bug: tint:1718
Change-Id: Ib4b15308a065fb8f7d8915e9cf67dde9f6e6ed19
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/138680
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 3e807e9..3901d5d 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -988,6 +988,8 @@
     "writer/append_vector.h",
     "writer/array_length_from_uniform_options.cc",
     "writer/array_length_from_uniform_options.h",
+    "writer/ast_text_generator.cc",
+    "writer/ast_text_generator.h",
     "writer/binding_point.h",
     "writer/binding_remapper_options.cc",
     "writer/binding_remapper_options.h",
@@ -1894,10 +1896,10 @@
   tint_unittests_source_set("tint_unittests_writer_src") {
     sources = [
       "writer/append_vector_test.cc",
+      "writer/ast_text_generator_test.cc",
       "writer/check_supported_extensions_test.cc",
       "writer/flatten_bindings_test.cc",
       "writer/float_to_string_test.cc",
-      "writer/text_generator_test.cc",
     ]
     deps = [
       ":libtint_unittests_ast_helper",
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index 5cc2e76..a9c5a8d 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -562,6 +562,8 @@
   writer/append_vector.h
   writer/array_length_from_uniform_options.cc
   writer/array_length_from_uniform_options.h
+  writer/ast_text_generator.cc
+  writer/ast_text_generator.h
   writer/binding_point.h
   writer/binding_remapper_options.cc
   writer/binding_remapper_options.h
@@ -1110,10 +1112,10 @@
     utils/unique_vector_test.cc
     utils/vector_test.cc
     writer/append_vector_test.cc
+    writer/ast_text_generator_test.cc
     writer/check_supported_extensions_test.cc
     writer/flatten_bindings_test.cc
     writer/float_to_string_test.cc
-    writer/text_generator_test.cc
   )
 
   # Noet, the source files are included here otherwise the cmd sources would not be included in the
diff --git a/src/tint/writer/ast_text_generator.cc b/src/tint/writer/ast_text_generator.cc
new file mode 100644
index 0000000..dc0530b
--- /dev/null
+++ b/src/tint/writer/ast_text_generator.cc
@@ -0,0 +1,42 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/writer/ast_text_generator.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "src/tint/utils/map.h"
+
+namespace tint::writer {
+
+ASTTextGenerator::ASTTextGenerator(const Program* program)
+    : program_(program), builder_(ProgramBuilder::Wrap(program)) {}
+
+ASTTextGenerator::~ASTTextGenerator() = default;
+
+std::string ASTTextGenerator::UniqueIdentifier(const std::string& prefix) {
+    return builder_.Symbols().New(prefix).Name();
+}
+
+std::string ASTTextGenerator::StructName(const type::Struct* s) {
+    auto name = s->Name().Name();
+    if (name.size() > 1 && name[0] == '_' && name[1] == '_') {
+        name = utils::GetOrCreate(builtin_struct_names_, s,
+                                  [&] { return UniqueIdentifier(name.substr(2)); });
+    }
+    return name;
+}
+
+}  // namespace tint::writer
diff --git a/src/tint/writer/ast_text_generator.h b/src/tint/writer/ast_text_generator.h
new file mode 100644
index 0000000..243458c
--- /dev/null
+++ b/src/tint/writer/ast_text_generator.h
@@ -0,0 +1,71 @@
+// Copyright 2023 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_WRITER_AST_TEXT_GENERATOR_H_
+#define SRC_TINT_WRITER_AST_TEXT_GENERATOR_H_
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+#include "src/tint/program_builder.h"
+#include "src/tint/writer/text_generator.h"
+
+namespace tint::writer {
+
+/// Helper methods for generators which are creating text output
+class ASTTextGenerator : public TextGenerator {
+  public:
+    /// Constructor
+    /// @param program the program used by the generator
+    explicit ASTTextGenerator(const Program* program);
+    ~ASTTextGenerator();
+
+    /// @return a new, unique identifier with the given prefix.
+    /// @param prefix optional prefix to apply to the generated identifier. If
+    /// empty "tint_symbol" will be used.
+    std::string UniqueIdentifier(const std::string& prefix = "");
+
+    /// @param s the semantic structure
+    /// @returns the name of the structure, taking special care of builtin
+    /// structures that start with double underscores. If the structure is a
+    /// builtin, then the returned name will be a unique name without the leading
+    /// underscores.
+    std::string StructName(const type::Struct* s);
+
+  protected:
+    /// @returns the resolved type of the ast::Expression `expr`
+    /// @param expr the expression
+    const type::Type* TypeOf(const ast::Expression* expr) const { return builder_.TypeOf(expr); }
+
+    /// @returns the resolved type of the ast::TypeDecl `type_decl`
+    /// @param type_decl the type
+    const type::Type* TypeOf(const ast::TypeDecl* type_decl) const {
+        return builder_.TypeOf(type_decl);
+    }
+
+    /// The program
+    Program const* const program_;
+    /// A ProgramBuilder that thinly wraps program_
+    ProgramBuilder builder_;
+
+  private:
+    /// Map of builtin structure to unique generated name
+    std::unordered_map<const type::Struct*, std::string> builtin_struct_names_;
+};
+
+}  // namespace tint::writer
+
+#endif  // SRC_TINT_WRITER_AST_TEXT_GENERATOR_H_
diff --git a/src/tint/writer/text_generator_test.cc b/src/tint/writer/ast_text_generator_test.cc
similarity index 84%
rename from src/tint/writer/text_generator_test.cc
rename to src/tint/writer/ast_text_generator_test.cc
index 1bfa41f..d879f68 100644
--- a/src/tint/writer/text_generator_test.cc
+++ b/src/tint/writer/ast_text_generator_test.cc
@@ -12,29 +12,29 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/writer/text_generator.h"
+#include "src/tint/writer/ast_text_generator.h"
 
 #include "gtest/gtest.h"
 
 namespace tint::writer {
 namespace {
 
-TEST(TextGeneratorTest, UniqueIdentifier) {
+TEST(ASTTextGeneratorTest, UniqueIdentifier) {
     Program program(ProgramBuilder{});
 
-    TextGenerator gen(&program);
+    ASTTextGenerator gen(&program);
 
     ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident");
     ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_1");
 }
 
-TEST(TextGeneratorTest, UniqueIdentifier_ConflictWithExisting) {
+TEST(ASTTextGeneratorTest, UniqueIdentifier_ConflictWithExisting) {
     ProgramBuilder builder;
     builder.Symbols().Register("ident_1");
     builder.Symbols().Register("ident_2");
     Program program(std::move(builder));
 
-    TextGenerator gen(&program);
+    ASTTextGenerator gen(&program);
 
     ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident");
     ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_3");
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index 1bb2f85..537d328 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -254,7 +254,7 @@
 }
 
 GeneratorImpl::GeneratorImpl(const Program* program, const Version& version)
-    : TextGenerator(program), version_(version) {}
+    : ASTTextGenerator(program), version_(version) {}
 
 GeneratorImpl::~GeneratorImpl() = default;
 
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index 7f9e31c..23633ae 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -38,9 +38,9 @@
 #include "src/tint/scope_stack.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/string_stream.h"
+#include "src/tint/writer/ast_text_generator.h"
 #include "src/tint/writer/glsl/generator.h"
 #include "src/tint/writer/glsl/version.h"
-#include "src/tint/writer/text_generator.h"
 
 // Forward declarations
 namespace tint::sem {
@@ -75,7 +75,7 @@
                          const std::string& entry_point);
 
 /// Implementation class for GLSL generator
-class GeneratorImpl : public TextGenerator {
+class GeneratorImpl : public ASTTextGenerator {
   public:
     /// Constructor
     /// @param program the program to generate
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 06a4d7c..d00859c 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -328,7 +328,7 @@
     return result;
 }
 
-GeneratorImpl::GeneratorImpl(const Program* program) : TextGenerator(program) {}
+GeneratorImpl::GeneratorImpl(const Program* program) : ASTTextGenerator(program) {}
 
 GeneratorImpl::~GeneratorImpl() = default;
 
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 2ae653c..3028853 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -38,8 +38,8 @@
 #include "src/tint/sem/binding_point.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/writer/array_length_from_uniform_options.h"
+#include "src/tint/writer/ast_text_generator.h"
 #include "src/tint/writer/hlsl/generator.h"
-#include "src/tint/writer/text_generator.h"
 
 // Forward declarations
 namespace tint::sem {
@@ -74,7 +74,7 @@
 SanitizedResult Sanitize(const Program* program, const Options& options);
 
 /// Implementation class for HLSL generator
-class GeneratorImpl : public TextGenerator {
+class GeneratorImpl : public ASTTextGenerator {
   public:
     /// Constructor
     /// @param program the program to generate
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index b0799d4..3cf5b31 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -271,7 +271,7 @@
     return result;
 }
 
-GeneratorImpl::GeneratorImpl(const Program* program) : TextGenerator(program) {}
+GeneratorImpl::GeneratorImpl(const Program* program) : ASTTextGenerator(program) {}
 
 GeneratorImpl::~GeneratorImpl() = default;
 
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index 0be80be..b9bd3501 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -42,8 +42,8 @@
 #include "src/tint/sem/struct.h"
 #include "src/tint/utils/string_stream.h"
 #include "src/tint/writer/array_length_from_uniform_options.h"
+#include "src/tint/writer/ast_text_generator.h"
 #include "src/tint/writer/msl/generator.h"
-#include "src/tint/writer/text_generator.h"
 
 // Forward declarations
 namespace tint::sem {
@@ -80,7 +80,7 @@
 SanitizedResult Sanitize(const Program* program, const Options& options);
 
 /// Implementation class for MSL generator
-class GeneratorImpl : public TextGenerator {
+class GeneratorImpl : public ASTTextGenerator {
   public:
     /// Constructor
     /// @param program the program to generate
diff --git a/src/tint/writer/syntax_tree/generator_impl.cc b/src/tint/writer/syntax_tree/generator_impl.cc
index 56f7f57..e8e58a3 100644
--- a/src/tint/writer/syntax_tree/generator_impl.cc
+++ b/src/tint/writer/syntax_tree/generator_impl.cc
@@ -41,7 +41,7 @@
 
 namespace tint::writer::syntax_tree {
 
-GeneratorImpl::GeneratorImpl(const Program* program) : TextGenerator(program) {}
+GeneratorImpl::GeneratorImpl(const Program* program) : ASTTextGenerator(program) {}
 
 GeneratorImpl::~GeneratorImpl() = default;
 
diff --git a/src/tint/writer/syntax_tree/generator_impl.h b/src/tint/writer/syntax_tree/generator_impl.h
index dc2cf01..2473df2 100644
--- a/src/tint/writer/syntax_tree/generator_impl.h
+++ b/src/tint/writer/syntax_tree/generator_impl.h
@@ -36,12 +36,12 @@
 #include "src/tint/program.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/utils/string_stream.h"
-#include "src/tint/writer/text_generator.h"
+#include "src/tint/writer/ast_text_generator.h"
 
 namespace tint::writer::syntax_tree {
 
 /// Implementation class for AST generator
-class GeneratorImpl : public TextGenerator {
+class GeneratorImpl : public ASTTextGenerator {
   public:
     /// Constructor
     /// @param program the program
diff --git a/src/tint/writer/text_generator.cc b/src/tint/writer/text_generator.cc
index 4b0ab6a..89e1a6f 100644
--- a/src/tint/writer/text_generator.cc
+++ b/src/tint/writer/text_generator.cc
@@ -17,28 +17,14 @@
 #include <algorithm>
 #include <limits>
 
-#include "src/tint/utils/map.h"
+#include "src/tint/debug.h"
 
 namespace tint::writer {
 
-TextGenerator::TextGenerator(const Program* program)
-    : program_(program), builder_(ProgramBuilder::Wrap(program)) {}
+TextGenerator::TextGenerator() = default;
 
 TextGenerator::~TextGenerator() = default;
 
-std::string TextGenerator::UniqueIdentifier(const std::string& prefix) {
-    return builder_.Symbols().New(prefix).Name();
-}
-
-std::string TextGenerator::StructName(const type::Struct* s) {
-    auto name = s->Name().Name();
-    if (name.size() > 1 && name[0] == '_' && name[1] == '_') {
-        name = utils::GetOrCreate(builtin_struct_names_, s,
-                                  [&] { return UniqueIdentifier(name.substr(2)); });
-    }
-    return name;
-}
-
 TextGenerator::LineWriter::LineWriter(TextBuffer* buf) : buffer(buf) {}
 
 TextGenerator::LineWriter::LineWriter(LineWriter&& other) {
diff --git a/src/tint/writer/text_generator.h b/src/tint/writer/text_generator.h
index ad3eb80..8458db0 100644
--- a/src/tint/writer/text_generator.h
+++ b/src/tint/writer/text_generator.h
@@ -21,7 +21,6 @@
 #include <vector>
 
 #include "src/tint/diagnostic/diagnostic.h"
-#include "src/tint/program_builder.h"
 #include "src/tint/utils/string_stream.h"
 
 namespace tint::writer {
@@ -87,8 +86,7 @@
     };
 
     /// Constructor
-    /// @param program the program used by the generator
-    explicit TextGenerator(const Program* program);
+    TextGenerator();
     ~TextGenerator();
 
     /// Increment the emitter indent level
@@ -102,18 +100,6 @@
     /// @returns the list of diagnostics raised by the generator.
     const diag::List& Diagnostics() const { return diagnostics_; }
 
-    /// @return a new, unique identifier with the given prefix.
-    /// @param prefix optional prefix to apply to the generated identifier. If
-    /// empty "tint_symbol" will be used.
-    std::string UniqueIdentifier(const std::string& prefix = "");
-
-    /// @param s the semantic structure
-    /// @returns the name of the structure, taking special care of builtin
-    /// structures that start with double underscores. If the structure is a
-    /// builtin, then the returned name will be a unique name without the leading
-    /// underscores.
-    std::string StructName(const type::Struct* s);
-
   protected:
     /// LineWriter is a helper that acts as a string buffer, who's content is
     /// emitted to the TextBuffer as a single line on destruction.
@@ -183,16 +169,6 @@
         TextBuffer* buffer_;
     };
 
-    /// @returns the resolved type of the ast::Expression `expr`
-    /// @param expr the expression
-    const type::Type* TypeOf(const ast::Expression* expr) const { return builder_.TypeOf(expr); }
-
-    /// @returns the resolved type of the ast::TypeDecl `type_decl`
-    /// @param type_decl the type
-    const type::Type* TypeOf(const ast::TypeDecl* type_decl) const {
-        return builder_.TypeOf(type_decl);
-    }
-
     /// @returns a new LineWriter, used for buffering and writing a line to
     /// the end of #current_buffer_.
     LineWriter line() { return LineWriter(current_buffer_); }
@@ -202,10 +178,6 @@
     /// the end of `buffer`.
     static LineWriter line(TextBuffer* buffer) { return LineWriter(buffer); }
 
-    /// The program
-    Program const* const program_;
-    /// A ProgramBuilder that thinly wraps program_
-    ProgramBuilder builder_;
     /// Diagnostics generated by the generator
     diag::List diagnostics_;
     /// The buffer the TextGenerator is currently appending lines to
@@ -214,8 +186,6 @@
   private:
     /// The primary text buffer that the generator will emit
     TextBuffer main_buffer_;
-    /// Map of builtin structure to unique generated name
-    std::unordered_map<const type::Struct*, std::string> builtin_struct_names_;
 };
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index 0d626f2..751d16ff 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -42,7 +42,7 @@
 
 namespace tint::writer::wgsl {
 
-GeneratorImpl::GeneratorImpl(const Program* program) : TextGenerator(program) {}
+GeneratorImpl::GeneratorImpl(const Program* program) : ASTTextGenerator(program) {}
 
 GeneratorImpl::~GeneratorImpl() = default;
 
diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h
index 5d69821..6c67d79 100644
--- a/src/tint/writer/wgsl/generator_impl.h
+++ b/src/tint/writer/wgsl/generator_impl.h
@@ -36,12 +36,12 @@
 #include "src/tint/program.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/utils/string_stream.h"
-#include "src/tint/writer/text_generator.h"
+#include "src/tint/writer/ast_text_generator.h"
 
 namespace tint::writer::wgsl {
 
 /// Implementation class for WGSL generator
-class GeneratorImpl : public TextGenerator {
+class GeneratorImpl : public ASTTextGenerator {
   public:
     /// Constructor
     /// @param program the program