[writer] Allow for out of order text generation
Add Insert() methods to TextBuffer.
Allows generators to insert helper functions at the top of the output without requiring a scan of the program before generation.
Change-Id: I05f67ad05d189f2249e35cfac99536afccb5578d
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/57140
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
diff --git a/src/writer/text_generator.cc b/src/writer/text_generator.cc
index 4dc86d4..27b2d28 100644
--- a/src/writer/text_generator.cc
+++ b/src/writer/text_generator.cc
@@ -39,17 +39,16 @@
return str;
}
-TextGenerator::LineWriter::LineWriter(TextGenerator* generator)
- : gen(generator) {}
+TextGenerator::LineWriter::LineWriter(TextBuffer* buf) : buffer(buf) {}
TextGenerator::LineWriter::LineWriter(LineWriter&& other) {
- gen = other.gen;
- other.gen = nullptr;
+ buffer = other.buffer;
+ other.buffer = nullptr;
}
TextGenerator::LineWriter::~LineWriter() {
- if (gen) {
- gen->current_buffer_->Append(os.str());
+ if (buffer) {
+ buffer->Append(os.str());
}
}
@@ -68,12 +67,47 @@
lines.emplace_back(Line{current_indent, line});
}
+void TextGenerator::TextBuffer::Insert(const std::string& line,
+ size_t before,
+ uint32_t indent) {
+ if (before >= lines.size()) {
+ diag::List d;
+ TINT_ICE(Writer, d)
+ << "TextBuffer::Insert() called with before >= lines.size()\n"
+ << " before:" << before << "\n"
+ << " lines.size(): " << lines.size();
+ return;
+ }
+ lines.insert(lines.begin() + before, Line{indent, line});
+}
+
void TextGenerator::TextBuffer::Append(const TextBuffer& tb) {
for (auto& line : tb.lines) {
+ // TODO(bclayton): inefficent, consider optimizing
lines.emplace_back(Line{current_indent + line.indent, line.content});
}
}
+void TextGenerator::TextBuffer::Insert(const TextBuffer& tb,
+ size_t before,
+ uint32_t indent) {
+ if (before >= lines.size()) {
+ diag::List d;
+ TINT_ICE(Writer, d)
+ << "TextBuffer::Insert() called with before >= lines.size()\n"
+ << " before:" << before << "\n"
+ << " lines.size(): " << lines.size();
+ return;
+ }
+ size_t idx = 0;
+ for (auto& line : tb.lines) {
+ // TODO(bclayton): inefficent, consider optimizing
+ lines.insert(lines.begin() + before + idx,
+ Line{indent + line.indent, line.content});
+ idx++;
+ }
+}
+
std::string TextGenerator::TextBuffer::String() const {
std::stringstream ss;
for (auto& line : lines) {
@@ -96,11 +130,14 @@
}
TextGenerator::ScopedIndent::ScopedIndent(TextGenerator* generator)
- : gen(generator) {
- gen->increment_indent();
+ : ScopedIndent(generator->current_buffer_) {}
+
+TextGenerator::ScopedIndent::ScopedIndent(TextBuffer* buffer)
+ : buffer_(buffer) {
+ buffer_->IncrementIndent();
}
TextGenerator::ScopedIndent::~ScopedIndent() {
- gen->decrement_indent();
+ buffer_->DecrementIndent();
}
} // namespace writer
diff --git a/src/writer/text_generator.h b/src/writer/text_generator.h
index 885c319..1e75a52 100644
--- a/src/writer/text_generator.h
+++ b/src/writer/text_generator.h
@@ -60,38 +60,6 @@
std::string TrimSuffix(std::string str, const std::string& suffix);
protected:
- /// LineWriter is a helper that acts as a string buffer, who's content is
- /// emitted to the TextGenerator as a single line on destruction.
- struct LineWriter {
- public:
- /// Constructor
- /// @param generator the TextGenerator that the LineWriter will append its
- /// content to on destruction
- explicit LineWriter(TextGenerator* generator);
- /// Move constructor
- /// @param rhs the LineWriter to move
- LineWriter(LineWriter&& rhs);
- /// Destructor
- ~LineWriter();
-
- /// @returns the ostringstream
- operator std::ostream &() { return os; }
-
- /// @param rhs the value to write to the line
- /// @returns the ostream so calls can be chained
- template <typename T>
- std::ostream& operator<<(T&& rhs) {
- return os << std::forward<T>(rhs);
- }
-
- private:
- LineWriter(const LineWriter&) = delete;
- LineWriter& operator=(const LineWriter&) = delete;
-
- std::ostringstream os;
- TextGenerator* gen;
- };
-
/// Line holds a single line of text
struct Line {
/// The indentation of the line in whitespaces
@@ -120,10 +88,23 @@
/// @param line the line to append to the TextBuffer
void Append(const std::string& line);
+ /// Inserts the line to the TextBuffer before the line with index `before`
+ /// @param line the line to append to the TextBuffer
+ /// @param before the zero-based index of the line to insert the text before
+ /// @param indent the indentation to apply to the inserted lines
+ void Insert(const std::string& line, size_t before, uint32_t indent);
+
/// Appends the lines of `tb` to the end of this TextBuffer
/// @param tb the TextBuffer to append to the end of this TextBuffer
void Append(const TextBuffer& tb);
+ /// Inserts the lines of `tb` to the TextBuffer before the line with index
+ /// `before`
+ /// @param tb the TextBuffer to insert into this TextBuffer
+ /// @param before the zero-based index of the line to insert the text before
+ /// @param indent the indentation to apply to the inserted lines
+ void Insert(const TextBuffer& tb, size_t before, uint32_t indent);
+
/// @returns the buffer's content as a single string
std::string String() const;
@@ -135,6 +116,39 @@
std::vector<Line> lines;
};
+ /// LineWriter is a helper that acts as a string buffer, who's content is
+ /// emitted to the TextBuffer as a single line on destruction.
+ struct LineWriter {
+ public:
+ /// Constructor
+ /// @param buffer the TextBuffer that the LineWriter will append its
+ /// content to on destruction, at the end of the buffer.
+ explicit LineWriter(TextBuffer* buffer);
+
+ /// Move constructor
+ /// @param rhs the LineWriter to move
+ LineWriter(LineWriter&& rhs);
+ /// Destructor
+ ~LineWriter();
+
+ /// @returns the ostringstream
+ operator std::ostream &() { return os; }
+
+ /// @param rhs the value to write to the line
+ /// @returns the ostream so calls can be chained
+ template <typename T>
+ std::ostream& operator<<(T&& rhs) {
+ return os << std::forward<T>(rhs);
+ }
+
+ private:
+ LineWriter(const LineWriter&) = delete;
+ LineWriter& operator=(const LineWriter&) = delete;
+
+ std::ostringstream os;
+ TextBuffer* buffer;
+ };
+
/// Helper for writing a '(' on construction and a ')' destruction.
struct ScopedParen {
/// Constructor
@@ -154,7 +168,11 @@
/// indentation on destruction.
struct ScopedIndent {
/// Constructor
- /// @param generator the TextGenerator that the ScopedIndent will indent
+ /// @param buffer the TextBuffer that the ScopedIndent will indent
+ explicit ScopedIndent(TextBuffer* buffer);
+ /// Constructor
+ /// @param generator ScopedIndent will indent the generator's
+ /// `current_buffer_`
explicit ScopedIndent(TextGenerator* generator);
/// Destructor
~ScopedIndent();
@@ -163,7 +181,7 @@
ScopedIndent(ScopedIndent&& rhs) = delete;
ScopedIndent(const ScopedIndent&) = delete;
ScopedIndent& operator=(const ScopedIndent&) = delete;
- TextGenerator* gen;
+ TextBuffer* buffer_;
};
/// @returns the resolved type of the ast::Expression `expr`
@@ -184,8 +202,14 @@
return builder_.TypeOf(type_decl);
}
- /// @returns a new LineWriter, used for buffering and writing a line to out_
- LineWriter line() { return LineWriter(this); }
+ /// @returns a new LineWriter, used for buffering and writing a line to
+ /// the end of #current_buffer_.
+ LineWriter line() { return LineWriter(current_buffer_); }
+
+ /// @param buffer the TextBuffer to write the line to
+ /// @returns a new LineWriter, used for buffering and writing a line to
+ /// the end of `buffer`.
+ LineWriter line(TextBuffer* buffer) { return LineWriter(buffer); }
/// The program
Program const* const program_;