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
10namespace v8 {
11namespace internal {
12
13namespace {
14
15std::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
26std::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
78namespace {
79
80// The maximum number of digits required to display a non-negative number < n
81// in base 10.
82int 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
94std::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