mirror of
https://github.com/open-goal/jak-project
synced 2026-07-07 14:13:45 -04:00
[Decompiler] Replace type hint system and improve variable types. (#320)
* get gkernel and gkernel-h at least somewhat working in the offline tests * strip comments from json * switch hints to casts. online tests passing, offline passing up to gkernel * variable retyping is added * fix up casts in lets * update
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "decompiler/analysis/final_output.h"
|
||||
#include "decompiler/analysis/insert_lets.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "common/util/json_util.h"
|
||||
#include "decompiler/IR2/Form.h"
|
||||
#include "third-party/json.hpp"
|
||||
|
||||
@@ -67,6 +68,43 @@ void FormRegressionTest::TestData::add_string_at_label(const std::string& label_
|
||||
EXPECT_TRUE(false);
|
||||
}
|
||||
|
||||
std::pair<std::vector<std::string>, std::unordered_map<std::string, LocalVarOverride>>
|
||||
parse_var_json(const std::string& str) {
|
||||
if (str.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<std::string> args;
|
||||
std::unordered_map<std::string, LocalVarOverride> var_overrides;
|
||||
|
||||
auto j = parse_commented_json(str);
|
||||
|
||||
auto arg = j.find("args");
|
||||
if (arg != j.end()) {
|
||||
for (auto& x : arg.value()) {
|
||||
args.push_back(x);
|
||||
}
|
||||
}
|
||||
|
||||
auto var = j.find("vars");
|
||||
if (var != j.end()) {
|
||||
for (auto& vkv : var->get<std::unordered_map<std::string, nlohmann::json>>()) {
|
||||
LocalVarOverride override;
|
||||
if (vkv.second.is_string()) {
|
||||
override.name = vkv.second.get<std::string>();
|
||||
} else if (vkv.second.is_array()) {
|
||||
override.name = vkv.second[0].get<std::string>();
|
||||
override.type = vkv.second[1].get<std::string>();
|
||||
} else {
|
||||
throw std::runtime_error("Invalid function var override.");
|
||||
}
|
||||
var_overrides[vkv.first] = override;
|
||||
}
|
||||
}
|
||||
|
||||
return {args, var_overrides};
|
||||
}
|
||||
|
||||
std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
const std::string& code,
|
||||
const TypeSpec& function_type,
|
||||
@@ -74,7 +112,8 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
bool allow_pairs,
|
||||
const std::string& method_name,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings,
|
||||
const std::unordered_map<int, std::vector<TypeHint>>& hints) {
|
||||
const std::unordered_map<int, std::vector<TypeCast>>& casts,
|
||||
const std::string& var_map_json) {
|
||||
dts->type_prop_settings.locked = true;
|
||||
dts->type_prop_settings.reset();
|
||||
dts->type_prop_settings.allow_pair = allow_pairs;
|
||||
@@ -112,7 +151,7 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
test->func.ir2.atomic_ops_succeeded = true;
|
||||
test->func.ir2.env.set_end_var(test->func.ir2.atomic_ops->end_op().return_var());
|
||||
|
||||
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, hints, {}));
|
||||
EXPECT_TRUE(test->func.run_type_analysis_ir2(function_type, *dts, test->file, casts, {}));
|
||||
|
||||
test->func.ir2.env.set_reg_use(analyze_ir2_register_usage(test->func));
|
||||
|
||||
@@ -133,8 +172,9 @@ std::unique_ptr<FormRegressionTest::TestData> FormRegressionTest::make_function(
|
||||
test->func.ir2.top_form->collect_vars(vars, true);
|
||||
|
||||
if (do_expressions) {
|
||||
auto config = parse_var_json(var_map_json);
|
||||
bool success = convert_to_expressions(test->func.ir2.top_form, *test->func.ir2.form_pool,
|
||||
test->func, *dts);
|
||||
test->func, config.first, config.second, *dts);
|
||||
|
||||
EXPECT_TRUE(success);
|
||||
if (!success) {
|
||||
@@ -167,9 +207,11 @@ void FormRegressionTest::test(const std::string& code,
|
||||
bool allow_pairs,
|
||||
const std::string& method_name,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings,
|
||||
const std::unordered_map<int, std::vector<TypeHint>>& hints) {
|
||||
const std::unordered_map<int, std::vector<TypeCast>>& casts,
|
||||
const std::string& var_map_json) {
|
||||
auto ts = dts->parse_type_spec(type);
|
||||
auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings, hints);
|
||||
auto test = make_function(code, ts, do_expressions, allow_pairs, method_name, strings, casts,
|
||||
var_map_json);
|
||||
ASSERT_TRUE(test);
|
||||
auto expected_form =
|
||||
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
|
||||
@@ -193,9 +235,10 @@ void FormRegressionTest::test_final_function(
|
||||
const std::string& expected,
|
||||
bool allow_pairs,
|
||||
const std::vector<std::pair<std::string, std::string>>& strings,
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeHint>>& hints) {
|
||||
const std::unordered_map<int, std::vector<decompiler::TypeCast>>& casts,
|
||||
const std::string& var_map_json) {
|
||||
auto ts = dts->parse_type_spec(type);
|
||||
auto test = make_function(code, ts, true, allow_pairs, "", strings, hints);
|
||||
auto test = make_function(code, ts, true, allow_pairs, "", strings, casts, var_map_json);
|
||||
ASSERT_TRUE(test);
|
||||
auto expected_form =
|
||||
pretty_print::get_pretty_printer_reader().read_from_string(expected, false).as_pair()->car;
|
||||
@@ -211,20 +254,22 @@ void FormRegressionTest::test_final_function(
|
||||
EXPECT_TRUE(expected_form == actual_form);
|
||||
}
|
||||
|
||||
std::unordered_map<int, std::vector<decompiler::TypeHint>> FormRegressionTest::parse_hint_json(
|
||||
std::unordered_map<int, std::vector<decompiler::TypeCast>> FormRegressionTest::parse_cast_json(
|
||||
const std::string& in) {
|
||||
std::unordered_map<int, std::vector<decompiler::TypeHint>> out;
|
||||
auto hints = nlohmann::json::parse(in);
|
||||
for (auto& hint : hints) {
|
||||
auto idx = hint.at(0).get<int>();
|
||||
for (size_t i = 1; i < hint.size(); i++) {
|
||||
auto& assignment = hint.at(i);
|
||||
TypeHint type_hint;
|
||||
type_hint.reg = Register(assignment.at(0).get<std::string>());
|
||||
type_hint.type_name = assignment.at(1).get<std::string>();
|
||||
out[idx].push_back(type_hint);
|
||||
std::unordered_map<int, std::vector<decompiler::TypeCast>> out;
|
||||
auto casts = nlohmann::json::parse(in);
|
||||
|
||||
for (auto& cast : casts) {
|
||||
auto idx_range = parse_json_optional_integer_range(cast.at(0));
|
||||
for (auto idx : idx_range) {
|
||||
TypeCast type_cast;
|
||||
type_cast.atomic_op_idx = idx;
|
||||
type_cast.reg = Register(cast.at(1));
|
||||
type_cast.type_name = cast.at(2).get<std::string>();
|
||||
out[idx].push_back(type_cast);
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user