forked from axilmar/parserlib
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbatch_test.cpp
More file actions
244 lines (190 loc) · 6.82 KB
/
Copy pathbatch_test.cpp
File metadata and controls
244 lines (190 loc) · 6.82 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <algorithm>
#include <iostream>
#include <vector>
#include <sstream>
#include <memory>
#include <cassert>
#include <string>
#include <unordered_map>
#include <algorithm>
#include <stdexcept>
#include "parserlib.hpp"
using namespace parserlib;
#include "cpp_lexer_grammar.h"
#include "cpp_parser_grammar.h"
#include "ast_visitor.h"
// --- Source type ---
using source_type = line_counting_string<>;
//-----------------------------------------------------
// Expected hierarchy structures (from previous logic)
//-----------------------------------------------------
struct Expected {
std::string type;
std::string name;
std::vector<Expected> children;
Expected(std::string t = {}, std::string n = {})
: type(std::move(t)), name(std::move(n)) {}
};
struct AnnotatedLine {
std::string code;
std::string type;
std::string name;
int brace_diff = 0; // +1 for '{', -1 for '}'
};
//-----------------------------------------------------
// Parse annotated source comments like "// CLASS_DEF Foo"
//-----------------------------------------------------
std::vector<AnnotatedLine> parse_annotated_source(const std::string& src) {
std::vector<AnnotatedLine> result;
std::istringstream in(src);
std::string line;
while (std::getline(in, line)) {
AnnotatedLine l;
// detect braces
for (char c : line) {
if (c == '{') l.brace_diff++;
else if (c == '}') l.brace_diff--;
}
// find comment
auto pos = line.find("//");
if (pos != std::string::npos) {
std::string comment = line.substr(pos + 2);
auto first = comment.find_first_not_of(" \t");
if (first != std::string::npos)
comment = comment.substr(first);
std::istringstream ws(comment);
ws >> l.type; // e.g. CLASS_DEF
ws >> l.name; // e.g. Foo
}
if (!l.type.empty())
result.push_back(std::move(l));
}
return result;
}
//-----------------------------------------------------
// Build expected tree (supports multiple top-levels)
//-----------------------------------------------------
Expected build_expected_tree(const std::vector<AnnotatedLine>& lines) {
Expected root("ROOT", "");
std::vector<Expected*> stack = { &root };
int current_depth = 0;
for (const auto& line : lines) {
Expected node(line.type, line.name);
stack.back()->children.push_back(node);
Expected* node_ptr = &stack.back()->children.back();
if (line.brace_diff > 0) {
stack.push_back(node_ptr);
current_depth += line.brace_diff;
}
else if (line.brace_diff < 0) {
for (int i = 0; i < -line.brace_diff && stack.size() > 1; ++i) {
stack.pop_back();
current_depth--;
}
}
}
return root;
}
//-----------------------------------------------------
// Print tree for debug
//-----------------------------------------------------
void print_expected(const Expected& node, int indent = 0) {
if (node.type != "ROOT") {
std::cout << std::string(indent * 4, ' ')
<< node.type;
if (!node.name.empty())
std::cout << " " << node.name;
std::cout << "\n";
}
for (const auto& c : node.children)
print_expected(c, indent + 1);
}
//-----------------------------------------------------
// Compare two Expected trees recursively
//-----------------------------------------------------
bool compare_expected(const Expected& a, const Expected& b, int depth = 0) {
bool type_match = (a.type == b.type);
// Allow name to be skipped if one side is empty
bool name_match = (a.name == b.name) || a.name.empty() || b.name.empty();
if (!type_match || !name_match) {
std::cout << std::string(depth * 4, ' ')
<< "Mismatch: expected (" << a.type << " " << a.name
<< ") got (" << b.type << " " << b.name << ")\n";
return false;
}
if (a.type == b.type && a.name != b.name && (a.name.empty() || b.name.empty())) {
std::cout << std::string(depth * 4, ' ')
<< "(note: matched by type only, name missing)\n";
}
if (a.children.size() != b.children.size()) {
std::cout << std::string(depth * 4, ' ')
<< "Child count mismatch for " << a.type << " " << a.name
<< ": expected " << a.children.size()
<< ", got " << b.children.size() << "\n";
return false;
}
for (size_t i = 0; i < a.children.size(); ++i) {
if (!compare_expected(a.children[i], b.children[i], depth + 1))
return false;
}
return true;
}
//-----------------------------------------------------
// Integrate with your parser test
//-----------------------------------------------------
bool test_cpp_source_annotated(const std::string& source_str) {
// Build expected tree from comments
auto lines = parse_annotated_source(source_str);
Expected expected_root = build_expected_tree(lines);
std::cout << "Expected parse structure:\n";
print_expected(expected_root);
std::cout << "------------------------------------------------------------\n";
// === your existing parser logic ===
source_type source(source_str.c_str());
using parser_type = parser<source_type, cpp_lexer_grammar, cpp_parser_grammar>;
auto result = parser_type::parse(source);
if (!result.success) {
std::cout << "Parser failed. Return! \n";
return false;
}
else
std::cout << "Parser success!\n";
std::cout << "------------------------------------------------------------\n";
std::cout << "Parsing result print:\n";
if (!result.ast_nodes.empty()) // result.success &&
{
for (auto &node : result.ast_nodes)
cpp_parser_grammar::print_ast(node);
}
// Convert parser matches to Expected tree
Expected actual_root("ROOT", "");
for (const auto& node : result.ast_nodes) {
actual_root.children.emplace_back(
cpp_parser_grammar::match_id_to_string(node->id()), ""
);
}
std::cout << "Actual parser matches:\n";
print_expected(actual_root);
std::cout << "------------------------------------------------------------\n";
// Compare
return compare_expected(expected_root, actual_root);
}
//-----------------------------------------------------
// Example test driver
//-----------------------------------------------------
void test_cpp_parser_with_comments() {
const std::string src = R"(
class Foo // CLASS_DEF Foo
{
};
abc x; // VAR_DECL x
)";
if (test_cpp_source_annotated(src))
std::cout << " Test Passed\n";
else
std::cout << " Test Failed\n";
}