regexp-dotprinter.cc (8353B)
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: 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 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 if (i > 40) { 44 os_ << "..."; 45 break; 46 } 47 } 48 os_ << "\"];\n"; 49 Visit(node); 50 os_ << "}" << std::endl; 51 } 52 53 void DotPrinterImpl::Visit(RegExpNode* node) { 54 if (node->info()->visited) return; 55 node->info()->visited = true; 56 node->Accept(this); 57 } 58 59 void DotPrinterImpl::PrintOnFailure(RegExpNode* from, RegExpNode* on_failure) { 60 os_ << " n" << from << " -> n" << on_failure << " [style=dotted];\n"; 61 Visit(on_failure); 62 } 63 64 class AttributePrinter { 65 public: 66 explicit AttributePrinter(std::ostream& os) : os_(os), first_(true) {} 67 void PrintSeparator() { 68 if (first_) { 69 first_ = false; 70 } else { 71 os_ << "|"; 72 } 73 } 74 void PrintBit(const char* name, bool value) { 75 if (!value) return; 76 PrintSeparator(); 77 os_ << "{"; 78 for (const char* p = name; *p; p++) { 79 os_ << AsUC16(static_cast<unsigned char>(*p)); 80 } 81 os_ << name << "}"; 82 } 83 void PrintPositive(const char* name, int value) { 84 if (value < 0) return; 85 PrintSeparator(); 86 os_ << "{" << name << "|" << value << "}"; 87 } 88 89 private: 90 std::ostream& os_; 91 bool first_; 92 }; 93 94 void DotPrinterImpl::PrintAttributes(RegExpNode* that) { 95 os_ << " a" << that << " [shape=Mrecord, color=grey, fontcolor=grey, " 96 << "margin=0.1, fontsize=10, label=\"{"; 97 AttributePrinter printer(os_); 98 NodeInfo* info = that->info(); 99 printer.PrintBit("NI", info->follows_newline_interest); 100 printer.PrintBit("WI", info->follows_word_interest); 101 printer.PrintBit("SI", info->follows_start_interest); 102 Label* label = that->label(); 103 if (label->is_bound()) printer.PrintPositive("@", label->pos()); 104 os_ << "}\"];\n" 105 << " a" << that << " -> n" << that 106 << " [style=dashed, color=grey, arrowhead=none];\n"; 107 } 108 109 void DotPrinterImpl::VisitChoice(ChoiceNode* that) { 110 os_ << " n" << that << " [shape=Mrecord, label=\"?"; 111 if (that->AsNegativeLookaroundChoiceNode()) os_ << " neg"; 112 os_ << "\"];\n"; 113 for (int i = 0; i < that->alternatives()->length(); i++) { 114 GuardedAlternative alt = that->alternatives()->at(i); 115 os_ << " n" << that << " -> n" << alt.node(); 116 } 117 for (int i = 0; i < that->alternatives()->length(); i++) { 118 GuardedAlternative alt = that->alternatives()->at(i); 119 alt.node()->Accept(this); 120 } 121 PrintAttributes(that); 122 } 123 124 void DotPrinterImpl::VisitLoopChoice(LoopChoiceNode* that) { 125 VisitChoice(that); 126 } 127 128 void DotPrinterImpl::VisitNegativeLookaroundChoice( 129 NegativeLookaroundChoiceNode* that) { 130 VisitChoice(that); 131 } 132 133 void DotPrinterImpl::VisitText(TextNode* that) { 134 Zone* zone = that->zone(); 135 os_ << " n" << that << " [label=\""; 136 for (int i = 0; i < that->elements()->length(); i++) { 137 if (i > 0) os_ << " "; 138 TextElement elm = that->elements()->at(i); 139 switch (elm.text_type()) { 140 case TextElement::ATOM: { 141 base::Vector<const base::uc16> data = elm.atom()->data(); 142 for (int j = 0; j < data.length(); j++) { 143 os_ << AsUC32(data[j]); 144 } 145 break; 146 } 147 case TextElement::CLASS_RANGES: { 148 RegExpClassRanges* node = elm.class_ranges(); 149 os_ << "["; 150 if (node->is_negated()) os_ << "^"; 151 for (int j = 0; j < node->ranges(zone)->length(); j++) { 152 CharacterRange range = node->ranges(zone)->at(j); 153 os_ << AsUC32(range.from()) << "-" << AsUC32(range.to()); 154 if (j > 5) { 155 os_ << "..."; 156 break; 157 } 158 } 159 os_ << "]"; 160 break; 161 } 162 default: 163 UNREACHABLE(); 164 } 165 if (i > 40) { 166 os_ << "..."; 167 break; 168 } 169 } 170 os_ << "\", shape=box, peripheries=2];\n"; 171 PrintAttributes(that); 172 os_ << " n" << that << " -> n" << that->on_success() << ";\n"; 173 Visit(that->on_success()); 174 } 175 176 void DotPrinterImpl::VisitBackReference(BackReferenceNode* that) { 177 os_ << " n" << that << " [label=\"$" << that->start_register() << "..$" 178 << that->end_register() << "\", shape=doubleoctagon];\n"; 179 PrintAttributes(that); 180 os_ << " n" << that << " -> n" << that->on_success() << ";\n"; 181 Visit(that->on_success()); 182 } 183 184 void DotPrinterImpl::VisitEnd(EndNode* that) { 185 os_ << " n" << that << " [style=bold, shape=point];\n"; 186 PrintAttributes(that); 187 } 188 189 void DotPrinterImpl::VisitAssertion(AssertionNode* that) { 190 os_ << " n" << that << " ["; 191 switch (that->assertion_type()) { 192 case AssertionNode::AT_END: 193 os_ << "label=\"$\", shape=septagon"; 194 break; 195 case AssertionNode::AT_START: 196 os_ << "label=\"^\", shape=septagon"; 197 break; 198 case AssertionNode::AT_BOUNDARY: 199 os_ << "label=\"\\b\", shape=septagon"; 200 break; 201 case AssertionNode::AT_NON_BOUNDARY: 202 os_ << "label=\"\\B\", shape=septagon"; 203 break; 204 case AssertionNode::AFTER_NEWLINE: 205 os_ << "label=\"(?<=\\n)\", shape=septagon"; 206 break; 207 } 208 os_ << "];\n"; 209 PrintAttributes(that); 210 RegExpNode* successor = that->on_success(); 211 os_ << " n" << that << " -> n" << successor << ";\n"; 212 Visit(successor); 213 } 214 215 void DotPrinterImpl::VisitAction(ActionNode* that) { 216 os_ << " n" << that << " ["; 217 switch (that->action_type_) { 218 case ActionNode::SET_REGISTER_FOR_LOOP: 219 os_ << "label=\"$" << that->register_from() << ":=" << that->value() 220 << "\", shape=octagon"; 221 break; 222 case ActionNode::INCREMENT_REGISTER: 223 os_ << "label=\"$" << that->register_from() << "++\", shape=octagon"; 224 break; 225 case ActionNode::CLEAR_POSITION: 226 os_ << "label=\"$" << that->register_from() 227 << ":=$pos c\", shape=octagon"; 228 break; 229 case ActionNode::RESTORE_POSITION: 230 os_ << "label=\"$" << that->register_from() 231 << ":=$pos r\", shape=octagon"; 232 break; 233 case ActionNode::BEGIN_POSITIVE_SUBMATCH: 234 os_ << "label=\"$" << that->data_.u_submatch.current_position_register 235 << ":=$pos,begin-positive\", shape=septagon"; 236 break; 237 case ActionNode::BEGIN_NEGATIVE_SUBMATCH: 238 os_ << "label=\"$" << that->data_.u_submatch.current_position_register 239 << ":=$pos,begin-negative\", shape=septagon"; 240 break; 241 case ActionNode::POSITIVE_SUBMATCH_SUCCESS: 242 os_ << "label=\"escape\", shape=septagon"; 243 break; 244 case ActionNode::EMPTY_MATCH_CHECK: 245 os_ << "label=\"$" << that->data_.u_empty_match_check.start_register 246 << "=$pos?,$" << that->data_.u_empty_match_check.repetition_register 247 << "<" << that->data_.u_empty_match_check.repetition_limit 248 << "?\", shape=septagon"; 249 break; 250 case ActionNode::CLEAR_CAPTURES: { 251 os_ << "label=\"clear $" << that->register_from() << " to $" 252 << that->register_to() << "\", shape=septagon"; 253 break; 254 } 255 case ActionNode::MODIFY_FLAGS: { 256 os_ << "label=\"flags $" << that->flags() << "\", shape=septagon"; 257 break; 258 } 259 } 260 os_ << "];\n"; 261 PrintAttributes(that); 262 RegExpNode* successor = that->on_success(); 263 os_ << " n" << that << " -> n" << successor << ";\n"; 264 Visit(successor); 265 } 266 267 void DotPrinter::DotPrint(const char* label, RegExpNode* node) { 268 StdoutStream os; 269 DotPrinterImpl printer(os); 270 printer.PrintNode(label, node); 271 } 272 273 } // namespace internal 274 } // namespace v8