mirror of
https://github.com/open-goal/jak-project
synced 2026-05-26 15:46:14 -04:00
[decompiler] as-type and font method support (#3855)
Add support for `as-type` macro, and detecting inline font methods. This works in all three games but I've only updated jak 3's goal_src for now. Eventually I will go back and work through the others, but I want to get more decompiler features in first.  --------- Co-authored-by: water111 <awaterford1111445@gmail.com>
This commit is contained in:
@@ -4638,6 +4638,67 @@ Form* try_rewrite_as_process_to_ppointer(CondNoElseElement* value,
|
||||
GenericOperator::make_fixed(FixedOperatorKind::PROCESS_TO_PPOINTER), repopped);
|
||||
}
|
||||
|
||||
/*!
|
||||
* (if (type? foo bar)
|
||||
* foo
|
||||
* )
|
||||
*/
|
||||
Form* try_rewrite_as_as_type(CondNoElseElement* value,
|
||||
FormStack& stack,
|
||||
FormPool& pool,
|
||||
const Env& env,
|
||||
const TypeSpec& resulting_type) {
|
||||
if (value->entries.size() != 1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto condition = value->entries.at(0).condition;
|
||||
auto body = value->entries[0].body;
|
||||
|
||||
auto condition_matcher = Matcher::op(
|
||||
GenericOpMatcher::condition(IR2_Condition::Kind::TRUTHY),
|
||||
{Matcher::func(Matcher::symbol("type?"), {Matcher::any_reg(0), Matcher::any_symbol(1)})});
|
||||
|
||||
auto condition_mr = match(condition_matcher, condition);
|
||||
if (!condition_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto body_matcher = Matcher::any_reg(0);
|
||||
auto body_mr = match(body_matcher, body);
|
||||
if (!body_mr.matched) {
|
||||
body_mr = match(Matcher::cast_to_any(1, body_matcher), body);
|
||||
if (!body_mr.matched) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
auto body_var = body_mr.maps.regs.at(0).value();
|
||||
auto condition_var = condition_mr.maps.regs.at(0).value();
|
||||
auto* menv = const_cast<Env*>(&env);
|
||||
menv->disable_use(body_var);
|
||||
auto repopped = stack.pop_reg(condition_var, {}, env, true);
|
||||
if (!repopped) {
|
||||
repopped = var_to_form(condition_var, pool);
|
||||
}
|
||||
auto new_type = condition_mr.maps.strings.at(1);
|
||||
|
||||
auto result = pool.form<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("as-type")),
|
||||
std::vector<Form*>{repopped, pool.form<ConstantTokenElement>(new_type)});
|
||||
|
||||
// silly cast situation:
|
||||
// sometimes there is something dumb like (the specific (as-type foo general))
|
||||
// we have to make sure that we keep the leading cast.
|
||||
// HACK: inserting casts more aggressively in Jak 2 because I am too lazy to fix up all the
|
||||
// slightly wrong casts that matter now.
|
||||
if (resulting_type != TypeSpec(new_type) &&
|
||||
(env.version == GameVersion::Jak2 || env.dts->ts.tc(TypeSpec(new_type), resulting_type))) {
|
||||
return pool.form<CastElement>(resulting_type, result);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// (if x (-> x 0 self)) -> (ppointer->process x)
|
||||
Form* try_rewrite_as_pppointer_to_process(CondNoElseElement* value,
|
||||
FormStack& stack,
|
||||
@@ -4810,11 +4871,18 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
|
||||
stack.push_value_to_reg(write_as_value, as_ja_group, true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
} else {
|
||||
// lg::print("func {} final destination {} type {}\n", env.func->name(),
|
||||
// final_destination.to_string(env),
|
||||
// env.get_variable_type(final_destination, false).print());
|
||||
stack.push_value_to_reg(write_as_value, pool.alloc_single_form(nullptr, this), true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
auto as_as_type = try_rewrite_as_as_type(this, stack, pool, env,
|
||||
env.get_variable_type(final_destination, true));
|
||||
if (as_as_type) {
|
||||
stack.push_value_to_reg(write_as_value, as_as_type, true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
} else {
|
||||
// lg::print("func {} final destination {} type {}\n", env.func->name(),
|
||||
// final_destination.to_string(env),
|
||||
// env.get_variable_type(final_destination, false).print());
|
||||
stack.push_value_to_reg(write_as_value, pool.alloc_single_form(nullptr, this), true,
|
||||
env.get_variable_type(final_destination, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user