1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "irregexp/imported/regexp-dotprinter.h"
6
7 #include "irregexp/imported/regexp-compiler.h"
8
9 namespace v8 {
10 namespace internal {
11
12 // -------------------------------------------------------------------
13 // Dot/dotty output
14
15 class DotPrinterImpl : public NodeVisitor {
16 public:
DotPrinterImpl(std::ostream & os)17 explicit DotPrinterImpl(std::ostream& os) : os_(os) {}
18 void PrintNode(const char* label, RegExpNode* node);
19 void Visit(RegExpNode* node);
20 void PrintAttributes(RegExpNode* from);
21 void PrintOnFailure(RegExpNode* from, RegExpNode* to);
22 #define DECLARE_VISIT(Type) virtual void Visit##Type(Type##Node* that);
23 FOR_EACH_NODE_TYPE(DECLARE_VISIT)
24 #undef DECLARE_VISIT
25 private:
26 std::ostream& os_;
27 };
28
PrintNode(const char * label,RegExpNode * node)29 void DotPrinterImpl::PrintNode(const char* label, RegExpNode* node) {
30 os_ << "digraph G {\n graph [label=\"";
31 for (int i = 0; label[i]; i++) {
32 switch (label[i]) {
33 case '\\':
34 os_ << "\\\\";
35 break;
36 case '"':
37 os_ << "\"";
38 break;
39 default:
40 os_ << label[i];
41 break;
42 }
43 }
44 os_ << "\"];\n";
45 Visit(node);
46 os_ << "}" << std::endl;
47 }
48
Visit(RegExpNode * node)49 void DotPrinterImpl::Visit(RegExpNode* node) {
50 if (node->info()->visited) return;
51 node->info()->visited = true;
52 node->Accept(this);
53 }
54
PrintOnFailure(RegExpNode * from,RegExpNode * on_failure)55 void DotPrinterImpl::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) {
56 os_ << " n" << from << " -> n" << on_failure << " [style=dotted];\n";
57 Visit(on_failure);
58 }
59
60 class AttributePrinter {
61 public:
AttributePrinter(std::ostream & os)62 explicit AttributePrinter(std::ostream& os) : os_(os), first_(true) {}
PrintSeparator()63 void PrintSeparator() {
64 if (first_) {
65 first_ = false;
66 } else {
67 os_ << "|";
68 }
69 }
PrintBit(const char * name,bool value)70 void PrintBit(const char* name, bool value) {
71 if (!value) return;
72 PrintSeparator();
73 os_ << "{" << name << "}";
74 }
PrintPositive(const char * name,int value)75 void PrintPositive(const char* name, int value) {
76 if (value < 0) return;
77 PrintSeparator();
78 os_ << "{" << name << "|" << value << "}";
79 }
80
81 private:
82 std::ostream& os_;
83 bool first_;
84 };
85
PrintAttributes(RegExpNode * that)86 void DotPrinterImpl::PrintAttributes(RegExpNode* that) {
87 os_ << " a" << that << " [shape=Mrecord, color=grey, fontcolor=grey, "
88 << "margin=0.1, fontsize=10, label=\"{";
89 AttributePrinter printer(os_);
90 NodeInfo* info = that->info();
91 printer.PrintBit("NI", info->follows_newline_interest);
92 printer.PrintBit("WI", info->follows_word_interest);
93 printer.PrintBit("SI", info->follows_start_interest);
94 Label* label = that->label();
95 if (label->is_bound()) printer.PrintPositive("@", label->pos());
96 os_ << "}\"];\n"
97 << " a" << that << " -> n" << that
98 << " [style=dashed, color=grey, arrowhead=none];\n";
99 }
100
VisitChoice(ChoiceNode * that)101 void DotPrinterImpl::VisitChoice(ChoiceNode* that) {
102 os_ << " n" << that << " [shape=Mrecord, label=\"?\"];\n";
103 for (int i = 0; i < that->alternatives()->length(); i++) {
104 GuardedAlternative alt = that->alternatives()->at(i);
105 os_ << " n" << that << " -> n" << alt.node();
106 }
107 for (int i = 0; i < that->alternatives()->length(); i++) {
108 GuardedAlternative alt = that->alternatives()->at(i);
109 alt.node()->Accept(this);
110 }
111 }
112
VisitLoopChoice(LoopChoiceNode * that)113 void DotPrinterImpl::VisitLoopChoice(LoopChoiceNode* that) {
114 VisitChoice(that);
115 }
116
VisitNegativeLookaroundChoice(NegativeLookaroundChoiceNode * that)117 void DotPrinterImpl::VisitNegativeLookaroundChoice(
118 NegativeLookaroundChoiceNode* that) {
119 VisitChoice(that);
120 }
121
VisitText(TextNode * that)122 void DotPrinterImpl::VisitText(TextNode* that) {
123 Zone* zone = that->zone();
124 os_ << " n" << that << " [label=\"";
125 for (int i = 0; i < that->elements()->length(); i++) {
126 if (i > 0) os_ << " ";
127 TextElement elm = that->elements()->at(i);
128 switch (elm.text_type()) {
129 case TextElement::ATOM: {
130 Vector<const uc16> data = elm.atom()->data();
131 for (int i = 0; i < data.length(); i++) {
132 os_ << static_cast<char>(data[i]);
133 }
134 break;
135 }
136 case TextElement::CHAR_CLASS: {
137 RegExpCharacterClass* node = elm.char_class();
138 os_ << "[";
139 if (node->is_negated()) os_ << "^";
140 for (int j = 0; j < node->ranges(zone)->length(); j++) {
141 CharacterRange range = node->ranges(zone)->at(j);
142 os_ << AsUC32(range.from()) << "-" << AsUC32(range.to());
143 }
144 os_ << "]";
145 break;
146 }
147 default:
148 UNREACHABLE();
149 }
150 }
151 os_ << "\", shape=box, peripheries=2];\n";
152 PrintAttributes(that);
153 os_ << " n" << that << " -> n" << that->on_success() << ";\n";
154 Visit(that->on_success());
155 }
156
VisitBackReference(BackReferenceNode * that)157 void DotPrinterImpl::VisitBackReference(BackReferenceNode* that) {
158 os_ << " n" << that << " [label=\"$" << that->start_register() << "..$"
159 << that->end_register() << "\", shape=doubleoctagon];\n";
160 PrintAttributes(that);
161 os_ << " n" << that << " -> n" << that->on_success() << ";\n";
162 Visit(that->on_success());
163 }
164
VisitEnd(EndNode * that)165 void DotPrinterImpl::VisitEnd(EndNode* that) {
166 os_ << " n" << that << " [style=bold, shape=point];\n";
167 PrintAttributes(that);
168 }
169
VisitAssertion(AssertionNode * that)170 void DotPrinterImpl::VisitAssertion(AssertionNode* that) {
171 os_ << " n" << that << " [";
172 switch (that->assertion_type()) {
173 case AssertionNode::AT_END:
174 os_ << "label=\"$\", shape=septagon";
175 break;
176 case AssertionNode::AT_START:
177 os_ << "label=\"^\", shape=septagon";
178 break;
179 case AssertionNode::AT_BOUNDARY:
180 os_ << "label=\"\\b\", shape=septagon";
181 break;
182 case AssertionNode::AT_NON_BOUNDARY:
183 os_ << "label=\"\\B\", shape=septagon";
184 break;
185 case AssertionNode::AFTER_NEWLINE:
186 os_ << "label=\"(?<=\\n)\", shape=septagon";
187 break;
188 }
189 os_ << "];\n";
190 PrintAttributes(that);
191 RegExpNode* successor = that->on_success();
192 os_ << " n" << that << " -> n" << successor << ";\n";
193 Visit(successor);
194 }
195
VisitAction(ActionNode * that)196 void DotPrinterImpl::VisitAction(ActionNode* that) {
197 os_ << " n" << that << " [";
198 switch (that->action_type_) {
199 case ActionNode::SET_REGISTER_FOR_LOOP:
200 os_ << "label=\"$" << that->data_.u_store_register.reg
201 << ":=" << that->data_.u_store_register.value << "\", shape=octagon";
202 break;
203 case ActionNode::INCREMENT_REGISTER:
204 os_ << "label=\"$" << that->data_.u_increment_register.reg
205 << "++\", shape=octagon";
206 break;
207 case ActionNode::STORE_POSITION:
208 os_ << "label=\"$" << that->data_.u_position_register.reg
209 << ":=$pos\", shape=octagon";
210 break;
211 case ActionNode::BEGIN_POSITIVE_SUBMATCH:
212 os_ << "label=\"$" << that->data_.u_submatch.current_position_register
213 << ":=$pos,begin-positive\", shape=septagon";
214 break;
215 case ActionNode::BEGIN_NEGATIVE_SUBMATCH:
216 os_ << "label=\"$" << that->data_.u_submatch.current_position_register
217 << ":=$pos,begin-negative\", shape=septagon";
218 break;
219 case ActionNode::POSITIVE_SUBMATCH_SUCCESS:
220 os_ << "label=\"escape\", shape=septagon";
221 break;
222 case ActionNode::EMPTY_MATCH_CHECK:
223 os_ << "label=\"$" << that->data_.u_empty_match_check.start_register
224 << "=$pos?,$" << that->data_.u_empty_match_check.repetition_register
225 << "<" << that->data_.u_empty_match_check.repetition_limit
226 << "?\", shape=septagon";
227 break;
228 case ActionNode::CLEAR_CAPTURES: {
229 os_ << "label=\"clear $" << that->data_.u_clear_captures.range_from
230 << " to $" << that->data_.u_clear_captures.range_to
231 << "\", shape=septagon";
232 break;
233 }
234 }
235 os_ << "];\n";
236 PrintAttributes(that);
237 RegExpNode* successor = that->on_success();
238 os_ << " n" << that << " -> n" << successor << ";\n";
239 Visit(successor);
240 }
241
DotPrint(const char * label,RegExpNode * node)242 void DotPrinter::DotPrint(const char* label, RegExpNode* node) {
243 StdoutStream os;
244 DotPrinterImpl printer(os);
245 printer.PrintNode(label, node);
246 }
247
248 } // namespace internal
249 } // namespace v8
250