/src/serenity/Userland/Libraries/LibRegex/RegexDebug.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com> |
3 | | * |
4 | | * SPDX-License-Identifier: BSD-2-Clause |
5 | | */ |
6 | | |
7 | | #pragma once |
8 | | |
9 | | #include <AK/StringBuilder.h> |
10 | | #include <LibRegex/RegexMatcher.h> |
11 | | |
12 | | namespace regex { |
13 | | |
14 | | class RegexDebug { |
15 | | public: |
16 | | RegexDebug(FILE* file = stdout) |
17 | 0 | : m_file(file) |
18 | 0 | { |
19 | 0 | } |
20 | | |
21 | 0 | virtual ~RegexDebug() = default; |
22 | | |
23 | | template<typename T> |
24 | | void print_raw_bytecode(Regex<T>& regex) const |
25 | | { |
26 | | auto& bytecode = regex.parser_result.bytecode; |
27 | | size_t index { 0 }; |
28 | | for (auto& value : bytecode) { |
29 | | outln(m_file, "OpCode i={:3} [{:#02X}]", index, (u32)value); |
30 | | ++index; |
31 | | } |
32 | | } |
33 | | |
34 | | template<typename T> |
35 | | void print_bytecode(Regex<T> const& regex) const |
36 | | { |
37 | | print_bytecode(regex.parser_result.bytecode); |
38 | | } |
39 | | |
40 | | void print_bytecode(ByteCode const& bytecode) const |
41 | 0 | { |
42 | 0 | MatchState state; |
43 | 0 | for (;;) { |
44 | 0 | auto& opcode = bytecode.get_opcode(state); |
45 | 0 | print_opcode("PrintBytecode", opcode, state); |
46 | 0 | out(m_file, "{}", m_debug_stripline); |
47 | |
|
48 | 0 | if (is<OpCode_Exit>(opcode)) |
49 | 0 | break; |
50 | | |
51 | 0 | state.instruction_position += opcode.size(); |
52 | 0 | } |
53 | |
|
54 | 0 | fflush(m_file); |
55 | 0 | } |
56 | | |
57 | | void print_opcode(ByteString const& system, OpCode& opcode, MatchState& state, size_t recursion = 0, bool newline = true) const |
58 | 0 | { |
59 | 0 | out(m_file, "{:15} | {:5} | {:9} | {:35} | {:30} | {:20}", |
60 | 0 | system.characters(), |
61 | 0 | state.instruction_position, |
62 | 0 | recursion, |
63 | 0 | opcode.to_byte_string().characters(), |
64 | 0 | opcode.arguments_string().characters(), |
65 | 0 | ByteString::formatted("ip: {:3}, sp: {:3}", state.instruction_position, state.string_position)); |
66 | 0 | if (newline) |
67 | 0 | outln(); |
68 | 0 | if (newline && is<OpCode_Compare>(opcode)) { |
69 | 0 | for (auto& line : to<OpCode_Compare>(opcode).variable_arguments_to_byte_string()) |
70 | 0 | outln(m_file, "{:15} | {:5} | {:9} | {:35} | {:30} | {:20}", "", "", "", "", line, ""); |
71 | 0 | } |
72 | 0 | } |
73 | | |
74 | | void print_result(OpCode const& opcode, ByteCode const& bytecode, MatchInput const& input, MatchState& state, ExecutionResult result) const |
75 | 0 | { |
76 | 0 | StringBuilder builder; |
77 | 0 | builder.append(execution_result_name(result)); |
78 | 0 | builder.appendff(", fc: {}, ss: {}", input.fail_counter, input.saved_positions.size()); |
79 | 0 | if (result == ExecutionResult::Succeeded) { |
80 | 0 | builder.appendff(", ip: {}/{}, sp: {}/{}", state.instruction_position, bytecode.size() - 1, state.string_position, input.view.length() - 1); |
81 | 0 | } else if (result == ExecutionResult::Fork_PrioHigh) { |
82 | 0 | builder.appendff(", next ip: {}", state.fork_at_position + opcode.size()); |
83 | 0 | } else if (result != ExecutionResult::Failed) { |
84 | 0 | builder.appendff(", next ip: {}", state.instruction_position + opcode.size()); |
85 | 0 | } |
86 | 0 |
|
87 | 0 | outln(m_file, " | {:20}", builder.to_byte_string()); |
88 | 0 |
|
89 | 0 | if (is<OpCode_Compare>(opcode)) { |
90 | 0 | for (auto& line : to<OpCode_Compare>(opcode).variable_arguments_to_byte_string(input)) { |
91 | 0 | outln(m_file, "{:15} | {:5} | {:9} | {:35} | {:30} | {:20}", "", "", "", "", line, ""); |
92 | 0 | } |
93 | 0 | } |
94 | 0 |
|
95 | 0 | out(m_file, "{}", m_debug_stripline); |
96 | 0 | } |
97 | | |
98 | | void print_header() |
99 | 0 | { |
100 | 0 | StringBuilder builder; |
101 | 0 | builder.appendff("{:15} | {:5} | {:9} | {:35} | {:30} | {:20} | {:20}\n", "System", "Index", "Recursion", "OpCode", "Arguments", "State", "Result"); |
102 | 0 | auto length = builder.length(); |
103 | 0 | for (size_t i = 0; i < length; ++i) { |
104 | 0 | builder.append('='); |
105 | 0 | } |
106 | 0 | auto str = builder.to_byte_string(); |
107 | 0 | VERIFY(!str.is_empty()); |
108 | 0 |
|
109 | 0 | outln(m_file, "{}", str); |
110 | 0 | fflush(m_file); |
111 | 0 |
|
112 | 0 | builder.clear(); |
113 | 0 | for (size_t i = 0; i < length; ++i) { |
114 | 0 | builder.append('-'); |
115 | 0 | } |
116 | 0 | builder.append('\n'); |
117 | 0 | m_debug_stripline = builder.to_byte_string(); |
118 | 0 | } |
119 | | |
120 | | private: |
121 | | ByteString m_debug_stripline; |
122 | | FILE* m_file; |
123 | | }; |
124 | | |
125 | | } |
126 | | |
127 | | using regex::RegexDebug; |