Source code
Revision control
Copy as Markdown
Other Tools
// 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.
#ifdef V8_ENABLE_REGEXP_DIAGNOSTICS
#include "irregexp/imported/regexp-ast-printer.h"
#include "irregexp/imported/regexp-ast.h"
#include "irregexp/imported/regexp-graph-printer.h"
namespace v8 {
namespace internal {
namespace regexp {
void AstNodePrinter::VisitCharacterRange(CharacterRange that) {
os() << AsUC32(that.from());
if (!that.IsSingleton()) {
os() << "-" << AsUC32(that.to());
}
}
void* AstNodePrinter::VisitDisjunction(Disjunction* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "(|";
for (int i = 0; i < that->alternatives()->length(); i++) {
os() << " ";
that->alternatives()->at(i)->Accept(this, data);
}
os() << ")";
return nullptr;
}
void* AstNodePrinter::VisitAlternative(Alternative* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "(:";
for (int i = 0; i < that->nodes()->length(); i++) {
os() << " ";
that->nodes()->at(i)->Accept(this, data);
}
os() << ")";
return nullptr;
}
void* AstNodePrinter::VisitClassRanges(ClassRanges* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
if (that->is_negated()) os() << "^";
os() << "[";
for (int i = 0; i < that->ranges(zone())->length(); i++) {
if (i > 0) os() << " ";
VisitCharacterRange(that->ranges(zone())->at(i));
}
os() << "]";
return nullptr;
}
void* AstNodePrinter::VisitClassSetOperand(ClassSetOperand* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "![";
for (int i = 0; i < that->ranges()->length(); i++) {
if (i > 0) os() << " ";
VisitCharacterRange(that->ranges()->at(i));
}
if (that->has_strings()) {
for (auto iter : *that->strings()) {
os() << " '";
os() << std::string(iter.first.begin(), iter.first.end());
os() << "'";
}
}
os() << "]";
return nullptr;
}
void* AstNodePrinter::VisitClassSetExpression(ClassSetExpression* that,
void* data) {
RegisterNode(that);
PrintNodeLabel(that);
switch (that->operation()) {
case ClassSetExpression::OperationType::kUnion:
os() << "++";
break;
case ClassSetExpression::OperationType::kIntersection:
os() << "&&";
break;
case ClassSetExpression::OperationType::kSubtraction:
os() << "--";
break;
}
if (that->is_negated()) os() << "^";
os() << "[";
for (int i = 0; i < that->operands()->length(); i++) {
if (i > 0) os() << " ";
that->operands()->at(i)->Accept(this, data);
}
os() << "]";
return nullptr;
}
void* AstNodePrinter::VisitAssertion(Assertion* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
switch (that->assertion_type()) {
case Assertion::Type::START_OF_INPUT:
os() << "@^i";
break;
case Assertion::Type::END_OF_INPUT:
os() << "@$i";
break;
case Assertion::Type::START_OF_LINE:
os() << "@^l";
break;
case Assertion::Type::END_OF_LINE:
os() << "@$l";
break;
case Assertion::Type::BOUNDARY:
os() << "@b";
break;
case Assertion::Type::NON_BOUNDARY:
os() << "@B";
break;
}
return nullptr;
}
void* AstNodePrinter::VisitAtom(Atom* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "'";
base::Vector<const base::uc16> chardata = that->data();
for (int i = 0; i < chardata.length(); i++) {
os() << AsUC16(chardata[i]);
}
os() << "'";
return nullptr;
}
void* AstNodePrinter::VisitText(Text* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
if (that->elements()->length() == 1) {
that->elements()->at(0).tree()->Accept(this, data);
} else {
os() << "(!";
for (int i = 0; i < that->elements()->length(); i++) {
os() << " ";
that->elements()->at(i).tree()->Accept(this, data);
}
os() << ")";
}
return nullptr;
}
void* AstNodePrinter::VisitQuantifier(Quantifier* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "(# " << that->min() << " ";
if (that->max() == Tree::kInfinity) {
os() << "- ";
} else {
os() << that->max() << " ";
}
os() << (that->is_greedy() ? "g " : that->is_possessive() ? "p " : "n ");
that->body()->Accept(this, data);
os() << ")";
return nullptr;
}
void* AstNodePrinter::VisitCapture(Capture* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "(^ ";
that->body()->Accept(this, data);
os() << ")";
return nullptr;
}
void* AstNodePrinter::VisitGroup(Group* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "(?" << that->flags() << ": ";
that->body()->Accept(this, data);
os() << ")";
return nullptr;
}
void* AstNodePrinter::VisitLookaround(Lookaround* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "(";
os() << (that->type() == Lookaround::LOOKAHEAD ? "->" : "<-");
os() << (that->is_positive() ? " + " : " - ");
that->body()->Accept(this, data);
os() << ")";
return nullptr;
}
void* AstNodePrinter::VisitBackReference(BackReference* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << "(<- " << that->captures()->first()->index();
for (int i = 1; i < that->captures()->length(); ++i) {
os() << "," << that->captures()->at(i)->index();
}
os() << ")";
return nullptr;
}
void* AstNodePrinter::VisitEmpty(Empty* that, void* data) {
RegisterNode(that);
PrintNodeLabel(that);
os() << '%';
return nullptr;
}
void AstNodePrinter::Print(Tree* tree) { tree->Accept(this, nullptr); }
TraceTreeScope::TraceTreeScope(Diagnostics* diagnostics)
: parent_(diagnostics ? diagnostics->trace_tree_scope() : nullptr),
depth_(parent_ != nullptr ? parent_->depth_ + 1 : -1),
diagnostics_(diagnostics) {
if (diagnostics_) {
diagnostics_->set_trace_tree_scope(this);
}
}
TraceTreeScope::~TraceTreeScope() {
if (diagnostics_) {
diagnostics_->set_trace_tree_scope(parent_);
}
}
void TraceTreeScope::PrintTree(Tree* tree) {
std::ostream& o = os();
AstNodePrinter* printer = diagnostics_->ast_printer();
printer->set_color(PrinterBase::Color::kRed);
o << "- ";
printer->Print(tree);
printer->set_color(PrinterBase::Color::kDefault);
o << std::endl;
}
std::ostream& TraceTreeScope::os() {
std::ostream& os = diagnostics_->os();
for (int i = 0; i < depth_; i++) os << " ";
return os;
}
} // namespace regexp
} // namespace internal
} // namespace v8
#endif // V8_ENABLE_REGEXP_DIAGNOSTICS