2021-10-12 20:33:26 -04:00
|
|
|
#include <string>
|
|
|
|
#include <unordered_set>
|
|
|
|
#include <vector>
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
#include "third-party/fmt/format.h"
|
2021-03-03 15:42:55 -05:00
|
|
|
#include "common/log/log.h"
|
2021-10-12 20:33:26 -04:00
|
|
|
#include "common/common_types.h"
|
|
|
|
#include "common/util/FileUtil.h"
|
|
|
|
#include "common/util/json_util.h"
|
2021-03-03 15:42:55 -05:00
|
|
|
#include "decompiler/ObjectFile/ObjectFileDB.h"
|
2021-10-12 20:33:26 -04:00
|
|
|
#include "common/util/diff.h"
|
2021-03-03 15:42:55 -05:00
|
|
|
#include "goalc/compiler/Compiler.h"
|
2021-03-24 19:16:31 -04:00
|
|
|
#include "common/util/Timer.h"
|
2021-05-09 17:03:58 -04:00
|
|
|
|
|
|
|
namespace fs = std::filesystem;
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
// command line arguments
|
|
|
|
struct OfflineTestArgs {
|
|
|
|
bool dump_current_output = false;
|
|
|
|
std::string iso_data_path;
|
|
|
|
s32 max_files = INT32_MAX;
|
2021-10-10 19:53:19 -04:00
|
|
|
};
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
/*!
|
|
|
|
* Parse command line arguments.
|
|
|
|
*/
|
|
|
|
OfflineTestArgs parse_args(int argc, char* argv[]) {
|
|
|
|
OfflineTestArgs result;
|
2021-07-25 15:30:37 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
for (int i = 1; i < argc; i++) {
|
|
|
|
auto arg = std::string(argv[i]);
|
|
|
|
if (arg == "--dump-mode") {
|
|
|
|
result.dump_current_output = true;
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-26 20:02:16 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
if (arg == "--max-files") {
|
|
|
|
i++;
|
|
|
|
if (i >= argc) {
|
|
|
|
fmt::print("--max-files must be followed by an integer\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
result.max_files = atoi(argv[i]);
|
|
|
|
fmt::print("Limiting to {} files\n", result.max_files);
|
|
|
|
continue;
|
|
|
|
}
|
2021-07-30 22:18:35 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
result.iso_data_path = arg;
|
|
|
|
fmt::print("Using {} for ISO data\n", result.iso_data_path);
|
|
|
|
}
|
2021-09-21 18:40:38 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
return result;
|
|
|
|
}
|
2021-10-10 19:53:19 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
// json config file data (previously was in source of offline_test_main.cpp)
|
|
|
|
struct OfflineTestConfig {
|
|
|
|
std::vector<std::string> dgos;
|
|
|
|
std::unordered_set<std::string> skip_compile_files;
|
|
|
|
std::unordered_set<std::string> skip_compile_functions;
|
|
|
|
std::unordered_map<std::string, std::unordered_set<std::string>> skip_compile_states;
|
2021-10-10 19:53:19 -04:00
|
|
|
};
|
2021-03-03 20:52:25 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
/*!
|
|
|
|
* Read and parse the json config file, config.json, located in test/offline
|
|
|
|
*/
|
|
|
|
OfflineTestConfig parse_config() {
|
2022-04-03 19:17:03 -04:00
|
|
|
auto json_file_path = file_util::get_jak_project_dir() / "test" / "offline" / "config.jsonc";
|
|
|
|
auto json = parse_commented_json(file_util::read_text_file(json_file_path.string()),
|
|
|
|
json_file_path.string());
|
2021-10-12 20:33:26 -04:00
|
|
|
OfflineTestConfig result;
|
|
|
|
result.dgos = json["dgos"].get<std::vector<std::string>>();
|
|
|
|
result.skip_compile_files = json["skip_compile_files"].get<std::unordered_set<std::string>>();
|
|
|
|
result.skip_compile_functions =
|
|
|
|
json["skip_compile_functions"].get<std::unordered_set<std::string>>();
|
|
|
|
result.skip_compile_states =
|
|
|
|
json["skip_compile_states"]
|
|
|
|
.get<std::unordered_map<std::string, std::unordered_set<std::string>>>();
|
|
|
|
return result;
|
|
|
|
}
|
2021-05-06 00:42:49 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
struct DecompilerFile {
|
|
|
|
std::filesystem::path path;
|
|
|
|
std::string name_in_dgo;
|
|
|
|
std::string unique_name;
|
|
|
|
std::string reference;
|
2021-09-06 21:10:19 -04:00
|
|
|
};
|
|
|
|
|
2021-05-09 17:03:58 -04:00
|
|
|
std::string replaceFirstOccurrence(std::string& s,
|
|
|
|
const std::string& toReplace,
|
|
|
|
const std::string& replaceWith) {
|
|
|
|
std::size_t pos = s.find(toReplace);
|
|
|
|
if (pos == std::string::npos)
|
|
|
|
return s;
|
|
|
|
return s.replace(pos, toReplace.length(), replaceWith);
|
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
std::vector<DecompilerFile> find_files(const std::vector<std::string>& dgos) {
|
|
|
|
std::vector<DecompilerFile> result;
|
2021-03-03 20:52:25 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
std::unordered_map<std::string, fs::path> files_with_ref;
|
2022-04-03 19:17:03 -04:00
|
|
|
for (auto& p : fs::recursive_directory_iterator(file_util::get_jak_project_dir() / "test" /
|
|
|
|
"decompiler" / "reference")) {
|
2021-05-09 17:03:58 -04:00
|
|
|
if (p.is_regular_file()) {
|
|
|
|
std::string file_name = fs::path(p.path()).replace_extension().filename().string();
|
|
|
|
if (file_name.find("_REF") == std::string::npos) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
std::string object_name = replaceFirstOccurrence(file_name, "_REF", "");
|
2021-10-12 20:33:26 -04:00
|
|
|
files_with_ref.insert({object_name, p.path()});
|
2021-05-09 17:03:58 -04:00
|
|
|
}
|
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
|
|
|
|
fmt::print(" Found {} reference files\n", files_with_ref.size());
|
|
|
|
|
2021-05-09 17:03:58 -04:00
|
|
|
// use the all_objs.json file to place them in the correct build order
|
|
|
|
auto j = parse_commented_json(
|
2022-04-03 19:17:03 -04:00
|
|
|
file_util::read_text_file(
|
|
|
|
(file_util::get_jak_project_dir() / "goal_src" / "build" / "all_objs.json").string()),
|
2021-05-11 21:57:05 -04:00
|
|
|
"all_objs.json");
|
2021-10-12 20:33:26 -04:00
|
|
|
|
|
|
|
std::unordered_set<std::string> matched_files;
|
2021-05-09 17:03:58 -04:00
|
|
|
for (auto& x : j) {
|
2021-10-12 20:33:26 -04:00
|
|
|
auto unique_name = x[0].get<std::string>();
|
|
|
|
|
2021-09-06 21:10:19 -04:00
|
|
|
std::vector<std::string> dgoList = x[3].get<std::vector<std::string>>();
|
2021-10-12 20:33:26 -04:00
|
|
|
// for (auto& p : reference_files_rough_order) {
|
|
|
|
auto it = files_with_ref.find(unique_name);
|
|
|
|
if (it != files_with_ref.end()) {
|
|
|
|
// Check to see if we've included atleast one of the DGO/CGOs in our hardcoded list
|
|
|
|
// If not BLOW UP
|
|
|
|
bool dgoValidated = false;
|
|
|
|
for (int i = 0; i < (int)dgoList.size(); i++) {
|
|
|
|
std::string& dgo = dgoList.at(i);
|
|
|
|
// can either be in the DGO or CGO folder, and can either end with .CGO or .DGO
|
|
|
|
if (std::find(dgos.begin(), dgos.end(), fmt::format("DGO/{}.DGO", dgo)) != dgos.end() ||
|
|
|
|
std::find(dgos.begin(), dgos.end(), fmt::format("DGO/{}.CGO", dgo)) != dgos.end() ||
|
|
|
|
std::find(dgos.begin(), dgos.end(), fmt::format("CGO/{}.DGO", dgo)) != dgos.end() ||
|
|
|
|
std::find(dgos.begin(), dgos.end(), fmt::format("CGO/{}.CGO", dgo)) != dgos.end()) {
|
|
|
|
dgoValidated = true;
|
2021-09-06 21:10:19 -04:00
|
|
|
}
|
2021-05-09 17:03:58 -04:00
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
if (!dgoValidated) {
|
|
|
|
fmt::print(
|
|
|
|
"File [{}] is in the following DGOs [{}], and not one of these is in our list! Add "
|
|
|
|
"it!\n",
|
|
|
|
unique_name, fmt::join(dgoList, ", "));
|
|
|
|
exit(1);
|
|
|
|
}
|
2021-05-09 17:03:58 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
DecompilerFile file;
|
|
|
|
file.path = it->second;
|
|
|
|
file.unique_name = it->first;
|
|
|
|
file.name_in_dgo = x[1];
|
|
|
|
result.push_back(file);
|
|
|
|
matched_files.insert(unique_name);
|
2021-03-03 20:52:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
if (matched_files.size() != files_with_ref.size()) {
|
|
|
|
fmt::print("Error: some REF files were not matched to files in all_objs.json:\n");
|
|
|
|
for (auto& f : files_with_ref) {
|
|
|
|
if (matched_files.count(f.first) == 0) {
|
|
|
|
fmt::print(" {}\n", f.first);
|
|
|
|
}
|
2021-08-29 11:13:06 -04:00
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
exit(1);
|
2021-08-29 11:13:06 -04:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
return result;
|
2021-03-03 20:52:25 -05:00
|
|
|
}
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
struct Decompiler {
|
|
|
|
std::unique_ptr<decompiler::ObjectFileDB> db;
|
|
|
|
std::unique_ptr<decompiler::Config> config;
|
|
|
|
};
|
2021-07-11 16:35:25 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
Decompiler setup_decompiler(const std::vector<DecompilerFile>& files,
|
|
|
|
const OfflineTestArgs& args,
|
|
|
|
const OfflineTestConfig& offline_config) {
|
|
|
|
Decompiler dc;
|
|
|
|
file_util::init_crc();
|
|
|
|
decompiler::init_opcode_info();
|
|
|
|
dc.config = std::make_unique<decompiler::Config>(decompiler::read_config_file(
|
2022-04-03 19:17:03 -04:00
|
|
|
(file_util::get_jak_project_dir() / "decompiler" / "config" / "jak1_ntsc_black_label.jsonc")
|
|
|
|
.string(),
|
|
|
|
{}));
|
2021-10-12 20:33:26 -04:00
|
|
|
|
|
|
|
// modify the config
|
|
|
|
std::unordered_set<std::string> object_files;
|
|
|
|
for (auto& file : files) {
|
|
|
|
object_files.insert(file.name_in_dgo); // todo, make this work with unique_name
|
|
|
|
}
|
2021-07-11 16:35:25 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
dc.config->allowed_objects = object_files;
|
|
|
|
// don't try to do this because we can't write the file
|
|
|
|
dc.config->generate_symbol_definition_map = false;
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
std::vector<std::string> dgo_paths;
|
|
|
|
if (args.iso_data_path.empty()) {
|
|
|
|
for (auto& x : offline_config.dgos) {
|
2022-04-09 11:46:56 -04:00
|
|
|
dgo_paths.push_back((file_util::get_jak_project_dir() / "iso_data" / "jak1" / x).string());
|
2021-05-09 17:03:58 -04:00
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
} else {
|
|
|
|
for (auto& x : offline_config.dgos) {
|
|
|
|
dgo_paths.push_back(file_util::combine_path(args.iso_data_path, x));
|
2021-03-03 20:52:25 -05:00
|
|
|
}
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
dc.db = std::make_unique<decompiler::ObjectFileDB>(dgo_paths, dc.config->obj_file_name_map_file,
|
|
|
|
std::vector<std::string>{},
|
|
|
|
std::vector<std::string>{}, *dc.config);
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
std::unordered_set<std::string> db_files;
|
|
|
|
for (auto& files_by_name : dc.db->obj_files_by_name) {
|
|
|
|
for (auto& f : files_by_name.second) {
|
|
|
|
db_files.insert(f.to_unique_name());
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
}
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
if (db_files.size() != files.size()) {
|
|
|
|
fmt::print("DB file error.\n");
|
|
|
|
for (auto& f : files) {
|
|
|
|
if (!db_files.count(f.unique_name)) {
|
|
|
|
fmt::print("didn't find {}\n", f.unique_name);
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
return dc;
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
void disassemble(Decompiler& dc) {
|
|
|
|
dc.db->process_link_data(*dc.config);
|
|
|
|
dc.db->find_code(*dc.config);
|
|
|
|
dc.db->process_labels();
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
void decompile(Decompiler& dc, const OfflineTestConfig& config) {
|
2021-10-16 21:01:23 -04:00
|
|
|
dc.db->analyze_functions_ir2({}, *dc.config, config.skip_compile_functions,
|
|
|
|
config.skip_compile_states);
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
std::string strip_trailing_newlines(const std::string& in) {
|
|
|
|
std::string out = in;
|
|
|
|
while (!out.empty() && out.back() == '\n') {
|
|
|
|
out.pop_back();
|
|
|
|
}
|
|
|
|
return out;
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
decompiler::ObjectFileData& get_data(Decompiler& dc,
|
|
|
|
const std::string& unique_name,
|
|
|
|
const std::string& name_in_dgo) {
|
|
|
|
auto& files = dc.db->obj_files_by_name.at(name_in_dgo);
|
|
|
|
auto it = std::find_if(files.begin(), files.end(), [&](const decompiler::ObjectFileData& data) {
|
|
|
|
return data.to_unique_name() == unique_name;
|
2021-03-03 15:42:55 -05:00
|
|
|
});
|
2022-02-08 19:02:47 -05:00
|
|
|
ASSERT(it != files.end());
|
2021-10-12 20:33:26 -04:00
|
|
|
return *it;
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
int line_count(const std::string& str) {
|
|
|
|
int result = 0;
|
|
|
|
for (auto& c : str) {
|
|
|
|
if (c == '\n') {
|
|
|
|
result++;
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
return result;
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
2021-07-11 16:35:25 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
struct CompareResult {
|
|
|
|
std::vector<std::string> failing_files;
|
|
|
|
int total_files = 0;
|
|
|
|
int ok_files = 0;
|
|
|
|
int total_lines = 0;
|
2021-07-11 16:35:25 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
bool total_pass = true;
|
|
|
|
};
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
CompareResult compare(Decompiler& dc, const std::vector<DecompilerFile>& refs, bool dump_mode) {
|
|
|
|
CompareResult compare_result;
|
|
|
|
|
|
|
|
for (const auto& file : refs) {
|
|
|
|
auto& data = get_data(dc, file.unique_name, file.name_in_dgo);
|
|
|
|
std::string result = strip_trailing_newlines(data.full_output);
|
|
|
|
std::string ref = strip_trailing_newlines(file_util::read_text_file(file.path.string()));
|
|
|
|
compare_result.total_files++;
|
|
|
|
compare_result.total_lines += line_count(result);
|
|
|
|
if (result != ref) {
|
|
|
|
compare_result.failing_files.push_back(file.unique_name);
|
|
|
|
compare_result.total_pass = false;
|
|
|
|
fmt::print("Reference test failure on {}:\n", file.unique_name);
|
2021-10-15 21:31:22 -04:00
|
|
|
fmt::print("{}\n", diff_strings(ref, result));
|
2021-10-12 20:33:26 -04:00
|
|
|
|
|
|
|
if (dump_mode) {
|
2021-05-12 19:46:17 -04:00
|
|
|
file_util::create_dir_if_needed("./failures");
|
2021-10-12 20:33:26 -04:00
|
|
|
file_util::write_text_file("./failures/" + file.unique_name + "_REF.gc", result);
|
2021-05-06 00:42:49 -04:00
|
|
|
}
|
|
|
|
} else {
|
2021-10-12 20:33:26 -04:00
|
|
|
compare_result.ok_files++;
|
2021-05-06 00:42:49 -04:00
|
|
|
}
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
return compare_result;
|
2021-03-24 19:16:31 -04:00
|
|
|
}
|
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
bool compile(Decompiler& dc,
|
|
|
|
const std::vector<DecompilerFile>& refs,
|
|
|
|
const OfflineTestConfig& config) {
|
|
|
|
fmt::print("Setting up compiler...\n");
|
2021-03-03 15:42:55 -05:00
|
|
|
Compiler compiler;
|
|
|
|
|
2021-06-19 15:50:52 -04:00
|
|
|
compiler.run_front_end_on_file({"decompiler", "config", "all-types.gc"});
|
|
|
|
compiler.run_front_end_on_file({"test", "decompiler", "reference", "decompiler-macros.gc"});
|
2021-03-05 18:48:01 -05:00
|
|
|
|
2021-03-24 19:16:31 -04:00
|
|
|
Timer timer;
|
|
|
|
int total_lines = 0;
|
2021-10-12 20:33:26 -04:00
|
|
|
for (const auto& file : refs) {
|
|
|
|
if (config.skip_compile_files.count(file.name_in_dgo)) {
|
|
|
|
fmt::print("Skipping {}\n", file.name_in_dgo);
|
2021-05-01 15:51:53 -04:00
|
|
|
continue;
|
|
|
|
}
|
2021-05-03 08:54:49 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
fmt::print("Compiling {}...\n", file.unique_name);
|
2021-05-03 08:54:49 -04:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
auto& data = get_data(dc, file.unique_name, file.name_in_dgo);
|
2021-03-03 15:42:55 -05:00
|
|
|
|
2021-10-12 20:33:26 -04:00
|
|
|
try {
|
|
|
|
const auto& src = data.output_with_skips;
|
2021-07-11 16:35:25 -04:00
|
|
|
total_lines += line_count(src);
|
2022-01-15 23:31:07 -05:00
|
|
|
compiler.run_full_compiler_on_string_no_save(src, file.name_in_dgo);
|
2021-10-12 20:33:26 -04:00
|
|
|
} catch (const std::exception& e) {
|
|
|
|
fmt::print("Compiler exception: {}\n", e.what());
|
|
|
|
return false;
|
2021-07-11 16:35:25 -04:00
|
|
|
}
|
2021-03-03 15:42:55 -05:00
|
|
|
}
|
2021-03-24 19:16:31 -04:00
|
|
|
auto time = timer.getSeconds();
|
2021-10-12 20:33:26 -04:00
|
|
|
fmt::print("Total Lines Compiled: {}. Lines/second: {:.1f}\n", total_lines,
|
|
|
|
(float)total_lines / time);
|
|
|
|
|
|
|
|
return true;
|
2021-04-10 21:17:36 -04:00
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
|
|
|
|
int main(int argc, char* argv[]) {
|
|
|
|
fmt::print("Offline Decompiler Test 2\n");
|
|
|
|
lg::initialize();
|
2022-04-03 19:17:03 -04:00
|
|
|
if (!file_util::setup_project_path()) {
|
|
|
|
return 1;
|
|
|
|
}
|
2021-10-12 20:33:26 -04:00
|
|
|
|
|
|
|
fmt::print("Reading config...\n");
|
|
|
|
auto args = parse_args(argc, argv);
|
|
|
|
auto config = parse_config();
|
|
|
|
|
|
|
|
fmt::print("Finding files...\n");
|
|
|
|
auto files = find_files(config.dgos);
|
|
|
|
if (args.max_files < (int)files.size()) {
|
|
|
|
files.erase(files.begin() + args.max_files, files.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
fmt::print("Setting up decompiler and loading files...\n");
|
|
|
|
auto decompiler = setup_decompiler(files, args, config);
|
|
|
|
|
|
|
|
fmt::print("Disassembling files...\n");
|
|
|
|
disassemble(decompiler);
|
|
|
|
|
|
|
|
fmt::print("Decompiling...\n");
|
|
|
|
decompile(decompiler, config);
|
|
|
|
|
|
|
|
fmt::print("Comparing...\n");
|
|
|
|
auto compare_result = compare(decompiler, files, args.dump_current_output);
|
|
|
|
fmt::print("Compared {} lines. {}/{} files passed.\n", compare_result.total_lines,
|
|
|
|
compare_result.ok_files, compare_result.total_files);
|
|
|
|
|
|
|
|
if (!compare_result.failing_files.empty()) {
|
|
|
|
fmt::print("Failing files:\n");
|
|
|
|
for (auto& f : compare_result.failing_files) {
|
|
|
|
fmt::print(" {}\n", f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool compile_result = compile(decompiler, files, config);
|
|
|
|
|
|
|
|
if (compare_result.total_pass && compile_result) {
|
|
|
|
fmt::print("Pass!\n");
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
if (!compile_result) {
|
|
|
|
fmt::print("Compilation failed.\n");
|
|
|
|
}
|
|
|
|
if (!compare_result.total_pass) {
|
|
|
|
fmt::print("Comparison failed.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
2021-10-16 21:01:23 -04:00
|
|
|
}
|