1 // Copyright 2020 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 "src/regexp/experimental/experimental-bytecode.h"
6 
7 #include <cctype>
8 #include <iomanip>
9 
10 namespace v8 {
11 namespace internal {
12 
13 namespace {
14 
PrintAsciiOrHex(std::ostream& os, base::uc16 c)15 std::ostream& PrintAsciiOrHex(std::ostream& os, base::uc16 c) {
16   if (c < 128 && std::isprint(c)) {
17     os << static_cast<char>(c);
18   } else {
19     os << "0x" << std::hex << static_cast<int>(c);
20   }
21   return os;
22 }
23 
24 }  // namespace
25 
operator <<(std::ostream& os, const RegExpInstruction& inst)26 std::ostream& operator<<(std::ostream& os, const RegExpInstruction& inst) {
27   switch (inst.opcode) {
28     case RegExpInstruction::CONSUME_RANGE: {
29       os << "CONSUME_RANGE [";
30       PrintAsciiOrHex(os, inst.payload.consume_range.min);
31       os << ", ";
32       PrintAsciiOrHex(os, inst.payload.consume_range.max);
33       os << "]";
34       break;
35     }
36     case RegExpInstruction::ASSERTION:
37       os << "ASSERTION ";
38       switch (inst.payload.assertion_type) {
39         case RegExpAssertion::Type::START_OF_INPUT:
40           os << "START_OF_INPUT";
41           break;
42         case RegExpAssertion::Type::END_OF_INPUT:
43           os << "END_OF_INPUT";
44           break;
45         case RegExpAssertion::Type::START_OF_LINE:
46           os << "START_OF_LINE";
47           break;
48         case RegExpAssertion::Type::END_OF_LINE:
49           os << "END_OF_LINE";
50           break;
51         case RegExpAssertion::Type::BOUNDARY:
52           os << "BOUNDARY";
53           break;
54         case RegExpAssertion::Type::NON_BOUNDARY:
55           os << "NON_BOUNDARY";
56           break;
57       }
58       break;
59     case RegExpInstruction::FORK:
60       os << "FORK " << inst.payload.pc;
61       break;
62     case RegExpInstruction::JMP:
63       os << "JMP " << inst.payload.pc;
64       break;
65     case RegExpInstruction::ACCEPT:
66       os << "ACCEPT";
67       break;
68     case RegExpInstruction::SET_REGISTER_TO_CP:
69       os << "SET_REGISTER_TO_CP " << inst.payload.register_index;
70       break;
71     case RegExpInstruction::CLEAR_REGISTER:
72       os << "CLEAR_REGISTER " << inst.payload.register_index;
73       break;
74   }
75   return os;
76 }
77 
78 namespace {
79 
80 // The maximum number of digits required to display a non-negative number < n
81 // in base 10.
DigitsRequiredBelow(int n)82 int DigitsRequiredBelow(int n) {
83   DCHECK_GE(n, 0);
84 
85   int result = 1;
86   for (int i = 10; i < n; i *= 10) {
87     result += 1;
88   }
89   return result;
90 }
91 
92 }  // namespace
93 
operator <<(std::ostream& os, base::Vector<const RegExpInstruction> insts)94 std::ostream& operator<<(std::ostream& os,
95                          base::Vector<const RegExpInstruction> insts) {
96   int inst_num = insts.length();
97   int line_digit_num = DigitsRequiredBelow(inst_num);
98 
99   for (int i = 0; i != inst_num; ++i) {
100     const RegExpInstruction& inst = insts[i];
101     os << std::setfill('0') << std::setw(line_digit_num) << i << ": " << inst
102        << std::endl;
103   }
104   return os;
105 }
106 
107 }  // namespace internal
108 }  // namespace v8
109