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