// Copyright 2026 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_REGEXP_REGEXP_PRINTER_H_ #define V8_REGEXP_REGEXP_PRINTER_H_ #ifdef V8_ENABLE_REGEXP_DIAGNOSTICS #include #include #include #include "irregexp/RegExpShim.h" namespace v8 { namespace internal { class Zone; namespace regexp { class GraphPrinter; class Node; template class NodePrinter; class TraceTreeScope; class Tree; template class GraphLabeller { public: auto RegisterNode(const T* node) { auto result = nodes_.emplace(node, next_node_label_); if (result.second) { next_node_label_++; } return result.first; } int NodeId(const T* node) { auto it = nodes_.find(node); if (it == nodes_.end()) { it = RegisterNode(node); DCHECK_NE(it, nodes_.end()); } return it->second; } int NodeId(const T* node) const { auto it = nodes_.find(node); if (it == nodes_.end()) { return -1; } return it->second; } private: std::map nodes_; int next_node_label_ = 1; }; class PrinterBase { public: enum class Color : int { kDefault = 0, kRed = 31, kGreen = 32, kYellow = 33, kBlue = 34, kMagenta = 35, kCyan = 36, kWhite = 37 }; PrinterBase(std::ostream& os, Zone* zone) : os_(os), zone_(zone) {} PrinterBase(const PrinterBase& other) V8_NOEXCEPT = default; int color() const { return color_; } void set_color(Color color) { if (!v8_flags.log_colour) return; color_ = static_cast(color); os() << "\033[" << color_ << "m"; } void set_bold(bool bold) { if (!v8_flags.log_colour) return; os() << "\033[" << (bold ? "1" : "0") << ";" << color() << "m"; } std::ostream& os() { return os_; } Zone* zone() { return zone_; } private: std::ostream& os_; Zone* zone_; int color_ = 0; }; template class NodePrinterBase : public PrinterBase { public: NodePrinterBase(std::ostream& os, GraphLabeller* labeller, Zone* zone, char prefix) : PrinterBase(os, zone), labeller_(labeller), prefix_(prefix) {} NodePrinterBase(const PrinterBase& other, GraphLabeller* labeller, char prefix) : PrinterBase(other), labeller_(labeller), prefix_(prefix) {} GraphLabeller* labeller() { return labeller_; } const GraphLabeller* labeller() const { return labeller_; } void PrintNodeLabel(const T* node) { if (!labeller_) return; int id = labeller_->NodeId(node); DCHECK_NE(id, 0); set_bold(true); os() << prefix_ << id; set_bold(false); } void RegisterNode(const T* node) { if (!labeller_) return; labeller_->RegisterNode(node); } protected: GraphLabeller* labeller_; const char prefix_; }; class Diagnostics { public: Diagnostics(std::ostream& os, Zone* zone); ~Diagnostics(); std::ostream& os() const { return os_; } Zone* zone() const { return zone_; } bool has_graph_labeller() const { return !!graph_labeller_; } GraphLabeller* graph_labeller() const { DCHECK(has_graph_labeller()); return graph_labeller_.get(); } void set_graph_labeller(std::unique_ptr> graph_labeller); bool has_tree_labeller() const { return !!tree_labeller_; } GraphLabeller* tree_labeller() const { DCHECK(has_tree_labeller()); return tree_labeller_.get(); } void set_tree_labeller(std::unique_ptr> tree_labeller); bool has_graph_printer() const { return !!graph_printer_; } GraphPrinter* graph_printer() const { DCHECK(has_graph_printer()); return graph_printer_.get(); } void set_graph_printer(std::unique_ptr graph_printer); bool has_ast_printer() const { return !!ast_printer_; } NodePrinter* ast_printer() const { DCHECK(has_ast_printer()); return ast_printer_.get(); } void set_ast_printer(std::unique_ptr> ast_printer); TraceTreeScope* trace_tree_scope() { return trace_tree_scope_; } void set_trace_tree_scope(TraceTreeScope* scope) { trace_tree_scope_ = scope; } private: std::unique_ptr> graph_labeller_; std::unique_ptr> tree_labeller_; std::unique_ptr graph_printer_; std::unique_ptr> ast_printer_; TraceTreeScope* trace_tree_scope_ = nullptr; std::ostream& os_; Zone* zone_; }; } // namespace regexp } // namespace internal } // namespace v8 #endif // V8_ENABLE_REGEXP_DIAGNOSTICS #endif // V8_REGEXP_REGEXP_PRINTER_H_