mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
Optimize TypeGen
This commit is contained in:
parent
cb9d6f212a
commit
c3878b8a20
9 changed files with 313 additions and 208 deletions
|
@ -39,14 +39,23 @@ target_sources(${PROJECT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/entry.cpp)
|
|||
|
||||
add_subdirectory(codegen)
|
||||
|
||||
add_custom_target(CodegenRun ALL
|
||||
message(STATUS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp)
|
||||
add_custom_command(
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bindings/GeometryDash.bro
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bindings/Cocos2d.bro
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/bindings/Entry.bro
|
||||
COMMAND Codegen ${GEODE_TARGET_PLATFORM} bindings ${GEODE_CODEGEN_PATH}
|
||||
COMMAND echo codegen > ${GEODE_CODEGEN_PATH}/.stamp
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
COMMENT "Run Codegen"
|
||||
BYPRODUCTS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp
|
||||
OUTPUT ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp ${GEODE_CODEGEN_PATH}/.stamp
|
||||
)
|
||||
|
||||
add_custom_target(CodegenRun
|
||||
DEPENDS ${GEODE_CODEGEN_PATH}/.stamp
|
||||
)
|
||||
|
||||
add_dependencies(${PROJECT_NAME} CodegenRun)
|
||||
add_dependencies(CodegenRun Codegen)
|
||||
|
||||
# Hacky way to supress the not generated error
|
||||
if (NOT EXISTS ${GEODE_CODEGEN_PATH}/Geode/GeneratedSource.cpp)
|
||||
|
|
|
@ -17,6 +17,7 @@ class AchievementManager : cocos2d::CCNode {
|
|||
PAD = win 0x4;
|
||||
}
|
||||
|
||||
|
||||
class AchievementNotifier : cocos2d::CCNode {
|
||||
void notifyAchievement(const char* title, const char* desc, const char* icon, bool quest) {
|
||||
m_queue->addObject(AchievementBar::create(title, desc, icon, quest));
|
||||
|
|
|
@ -32,9 +32,9 @@ int main(int argc, char** argv) try {
|
|||
}
|
||||
|
||||
writeFile(writeDir / "GeneratedAddress.hpp", generateAddressHeader(root));
|
||||
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify")); // pretty much obsolete with a custom compiler
|
||||
writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root)); // pretty much obsolete with a custom compiler
|
||||
writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(root)); // pretty much obsolete with a custom compiler
|
||||
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify"));
|
||||
writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root));
|
||||
writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(root));
|
||||
writeFile(writeDir / "GeneratedBinding.hpp", generateBindingHeader(root, writeDir / "binding"));
|
||||
writeFile(writeDir / "GeneratedPredeclare.hpp", generatePredeclareHeader(root));
|
||||
writeFile(writeDir / "GeneratedSource.cpp", generateBindingSource(root));
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
|
@ -36,7 +37,7 @@ namespace geode::modifier {{
|
|||
|
||||
// requires: index, class_name, arg_types, function_name, raw_arg_types, non_virtual
|
||||
char const* apply_function = R"GEN(
|
||||
GEODE_APPLY_MODIFY_FOR_FUNCTION({index}, {function_convention}, {class_name}, {function_name}))GEN";
|
||||
GEODE_APPLY_MODIFY_FOR_FUNCTION({addr_index}, {pure_index}, {function_convention}, {class_name}, {function_name}))GEN";
|
||||
|
||||
char const* modify_end = R"GEN(
|
||||
}
|
||||
|
@ -52,6 +53,9 @@ namespace geode::modifier {{
|
|||
std::string generateModifyHeader(Root& root, ghc::filesystem::path const& singleFolder) {
|
||||
std::string output;
|
||||
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
|
||||
for (auto c : root.classes) {
|
||||
if (c.name == "cocos2d")
|
||||
continue;
|
||||
|
@ -104,7 +108,8 @@ std::string generateModifyHeader(Root& root, ghc::filesystem::path const& single
|
|||
}
|
||||
|
||||
single_output += fmt::format(format_strings::apply_function,
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("addr_index", f.field_id),
|
||||
fmt::arg("pure_index", bank.getPure(*begin, c.name)),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("function_name", function_name),
|
||||
fmt::arg("function_convention", codegen::getConvention(f))
|
||||
|
|
|
@ -175,113 +175,4 @@ namespace codegen {
|
|||
if (index == std::string::npos) return s;
|
||||
return s.substr(index + 2);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// defined : we have a symbol that is usable
|
||||
inline bool isFunctionDefined(Function const& f) {
|
||||
// basically this is true for
|
||||
// fmod for all platforms
|
||||
// cocos for windows
|
||||
// all funcs without stl parameter for android
|
||||
// destructors for no platforms
|
||||
if (f.function_type == kDestructor) return false;
|
||||
if (f.function_type == kConstructor) return false;
|
||||
if (f.parent_class->name.rfind("fmod::", 0) == 0) return true;
|
||||
if (f.parent_class->name.rfind("cocos2d::", 0) == 0 && codegen::platform == kWindows) return true;
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return false;
|
||||
if (codegen::platform == kAndroid) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// definable : we can define it and hook it
|
||||
inline bool isFunctionDefinable(Function const& f) {
|
||||
// basically this is true for
|
||||
// all funcs that we have the offset for
|
||||
// all funcs with stl parameter for android
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return true;
|
||||
if (getBind(f) != "") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string getUnqualifiedClassName(Function const& f) {
|
||||
auto index = f.parent_class->name.rfind("::");
|
||||
if (index == std::string::npos) return f.parent_class->name;
|
||||
return f.parent_class->name.substr(index + 2);
|
||||
}
|
||||
|
||||
inline std::string getFunctionName(Function const& f) {
|
||||
return f.name;
|
||||
}
|
||||
|
||||
inline std::string getConst(Function const& f) {
|
||||
return f.is_const ? "const" : "";
|
||||
}
|
||||
|
||||
inline std::string getConstWhitespace(Function const& f) {
|
||||
return f.is_const ? " " : "";
|
||||
}
|
||||
|
||||
inline std::string getParameterTypes(Function const& f) { //int, float
|
||||
return fmt::format("{}", fmt::join(f.args, ", "));
|
||||
}
|
||||
|
||||
inline std::string getArguments(Function const& f) { // p0, p1
|
||||
return fmt::format("{}", fmt::join(f.argnames, ", "));
|
||||
}
|
||||
|
||||
inline std::string getParameterComma(Function const& f) { // int p0, float p1
|
||||
return f.args.size() > 0 ? ", " : "";
|
||||
}
|
||||
|
||||
inline std::string getParameterTypeComma(Function const& f) { //int, float
|
||||
return f.args.size() > 0 ? ", " : "";
|
||||
}
|
||||
|
||||
inline std::string getArgumentComma(Function const& f) { // p0, p1
|
||||
return f.argnames.size() > 0 ? ", " : "";
|
||||
}
|
||||
|
||||
// defined : we have a symbol that is usable
|
||||
inline bool isFunctionDefined(Function const& f) {
|
||||
// basically this is true for
|
||||
// fmod for all platforms
|
||||
// cocos for windows
|
||||
// all funcs without stl parameter for android
|
||||
// destructors for no platforms
|
||||
if (f.function_type == kDestructor) return false;
|
||||
if (f.function_type == kConstructor) return false;
|
||||
if (f.parent_class->name.rfind("fmod::", 0) == 0) return true;
|
||||
if (f.parent_class->name.rfind("cocos2d::", 0) == 0 && codegen::platform == kWindows) return true;
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return false;
|
||||
if (codegen::platform == kAndroid) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// definable : we can define it and hook it
|
||||
inline bool isFunctionDefinable(Function const& f) {
|
||||
// basically this is true for
|
||||
// all funcs that we have the offset for
|
||||
// all funcs with stl parameter for android
|
||||
if (getParameterTypes(f).find("gd::", 0) != string::npos && codegen::platform == kAndroid) return true;
|
||||
if (getBind(f) != "") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string getConvention(Function const& f) {
|
||||
if (codegen::platform != kWindows) return "DefaultConv";
|
||||
switch (f.function_type) {
|
||||
case kConstructor: [[fallthrough]];
|
||||
case kDestructor: [[fallthrough]];
|
||||
case kRegularFunction:
|
||||
if (isFunctionDefined(f)) return "x86::Thiscall";
|
||||
return "x86::Membercall";
|
||||
case kVirtualFunction:
|
||||
return "x86::Thiscall";
|
||||
case kStaticFunction:
|
||||
if (isFunctionDefined(f)) return "x86::Cdecl";
|
||||
return "x86::Optcall";
|
||||
}
|
||||
return "x86::Membercall";
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
|
||||
namespace { namespace format_strings {
|
||||
char const* source_start = R"CAC(
|
||||
|
@ -16,23 +17,23 @@ using namespace geode::modifier; // types
|
|||
)CAC";
|
||||
|
||||
char const* declare_member = R"GEN(
|
||||
types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
return func(this{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
char const* declare_virtual = R"GEN(
|
||||
types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto self = addresser::thunkAdjust((types::member{index})(&{class_name}::{function_name}), this);
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto self = addresser::thunkAdjust((types::member{member_index})(&{class_name}::{function_name}), this);
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
return func(self{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
||||
char const* declare_static = R"GEN(
|
||||
types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
types::ret{ret_index} {class_name}::{function_name}({parameters}){const} {{
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
return func({arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
@ -42,7 +43,7 @@ types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
|||
// basically we destruct it once by calling the gd function,
|
||||
// then lock it, so that other gd destructors dont get called
|
||||
if (CCDestructor::lock(this)) return;
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
func(this{parameter_comma}{arguments});
|
||||
// we need to construct it back so that it uhhh ummm doesnt crash
|
||||
// while going to the child destructors
|
||||
|
@ -58,7 +59,7 @@ types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
|||
// no crashes :pray:
|
||||
CCDestructor::lock(this) = true;
|
||||
{class_name}::~{unqualified_class_name}();
|
||||
auto func = Function<types::meta{index}, {convention}>({{addresses::address{index}()}});
|
||||
auto func = Function<types::meta{meta_index}, {convention}>({{addresses::address{addr_index}()}});
|
||||
func(this{parameter_comma}{arguments});
|
||||
}}
|
||||
)GEN";
|
||||
|
@ -75,6 +76,9 @@ types::ret{index} {class_name}::{function_name}({parameters}){const} {{
|
|||
std::string generateBindingSource(Root& root) {
|
||||
std::string output(format_strings::source_start);
|
||||
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
|
||||
for (auto& c : root.classes) {
|
||||
|
||||
for (auto& f : c.fields) {
|
||||
|
@ -100,7 +104,6 @@ std::string generateBindingSource(Root& root) {
|
|||
fmt::arg("const", str_if(" const ", fn->beginning.is_const)),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("parameters", codegen::getParameters(fn->beginning)),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("definition", fn->inner)
|
||||
);
|
||||
break;
|
||||
|
@ -110,7 +113,6 @@ std::string generateBindingSource(Root& root) {
|
|||
fmt::arg("const", str_if(" const ", fn->beginning.is_const)),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("parameters", codegen::getParameters(fn->beginning)),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("definition", fn->inner),
|
||||
fmt::arg("return", fn->beginning.ret.name)
|
||||
);
|
||||
|
@ -140,13 +142,18 @@ std::string generateBindingSource(Root& root) {
|
|||
if (fn->beginning.is_virtual && fn->beginning.type != FunctionType::Dtor)
|
||||
used_declare_format = format_strings::declare_virtual;
|
||||
|
||||
auto ids = bank.getIDs(fn->beginning, c.name);
|
||||
|
||||
output += fmt::format(used_declare_format,
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("unqualified_class_name", codegen::getUnqualifiedClassName(c.name)),
|
||||
fmt::arg("const", str_if(" const ", fn->beginning.is_const)),
|
||||
fmt::arg("convention", codegen::getConvention(f)),
|
||||
fmt::arg("function_name", fn->beginning.name),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("meta_index", ids.meta),
|
||||
fmt::arg("member_index", ids.member),
|
||||
fmt::arg("ret_index", ids.ret),
|
||||
fmt::arg("addr_index", f.field_id),
|
||||
fmt::arg("parameters", codegen::getParameters(fn->beginning)),
|
||||
fmt::arg("parameter_types", codegen::getParameterTypes(fn->beginning)),
|
||||
fmt::arg("arguments", codegen::getParameterNames(fn->beginning)),
|
||||
|
|
|
@ -1,84 +1,95 @@
|
|||
#include "Shared.hpp"
|
||||
#include "TypeOpt.hpp"
|
||||
#include <set>
|
||||
|
||||
namespace { namespace format_strings {
|
||||
|
||||
char const* declare_member_type = R"GEN(
|
||||
using ret{index} = {return};
|
||||
using func{index} = ret{index}(*)({const}{class_name}*{parameter_type_comma}{parameter_types});
|
||||
using pure{index} = ret{index}({parameter_types});
|
||||
using meta{index} = ret{index}({const}{class_name}*{parameter_type_comma}{parameter_types});
|
||||
using member{index} = ret{index}({class_name}::*)({parameter_types}){const};
|
||||
)GEN";
|
||||
|
||||
char const* declare_static_type = R"GEN(
|
||||
using ret{index} = {return};
|
||||
using func{index} = ret{index}(*)({parameter_types});
|
||||
using pure{index} = ret{index}({parameter_types});
|
||||
using meta{index} = ret{index}({parameter_types});
|
||||
using member{index} = func{index};
|
||||
)GEN";
|
||||
|
||||
char const* declare_structor_type = R"GEN(
|
||||
using ret{index} = void;
|
||||
using func{index} = ret{index}(*)({class_name}*{parameter_type_comma}{parameter_types});
|
||||
using pure{index} = ret{index}({parameter_types});
|
||||
using meta{index} = ret{index}({const}{class_name}*{parameter_type_comma}{parameter_types});
|
||||
using member{index} = func{index};
|
||||
)GEN";
|
||||
|
||||
}}
|
||||
|
||||
static std::string getReturn(FunctionBegin const& fn, std::string const& parent) {
|
||||
if (fn.type != FunctionType::Normal)
|
||||
return "void";
|
||||
|
||||
if (fn.ret.name == "auto") {
|
||||
std::vector<std::string> declvals;
|
||||
|
||||
for (auto& [t, n] : fn.args) {
|
||||
declvals.push_back(fmt::format("std::declval<{}>()", t.name));
|
||||
}
|
||||
|
||||
return fmt::format(
|
||||
fn.is_static ? "decltype({}::{}({}))" : "decltype(std::declval<{}>().{}({}))",
|
||||
parent,
|
||||
fn.name,
|
||||
fmt::join(declvals, ", ")
|
||||
);
|
||||
}
|
||||
|
||||
return fn.ret.name;
|
||||
}
|
||||
|
||||
std::string generateTypeHeader(Root& root) {
|
||||
std::string output;
|
||||
|
||||
for (auto& c : root.classes) {
|
||||
for (auto& f : c.fields) {
|
||||
if (codegen::getStatus(f) == BindStatus::Unbindable)
|
||||
continue;
|
||||
auto fn = f.get_fn();
|
||||
TypeBank bank;
|
||||
bank.loadFrom(root);
|
||||
|
||||
char const* used_format = format_strings::declare_member_type;
|
||||
std::map<std::string, int> used_returns;
|
||||
std::map<std::string, int> used_funcs;
|
||||
std::map<std::string, int> used_pures;
|
||||
|
||||
if (fn->type != FunctionType::Normal) {
|
||||
used_format = format_strings::declare_structor_type;
|
||||
}
|
||||
int i = 0;
|
||||
for (auto& f : bank.typeList()) {
|
||||
|
||||
if (fn->is_static) {
|
||||
used_format = format_strings::declare_static_type;
|
||||
}
|
||||
char const* return_fmt = "using ret{index} = {return};";
|
||||
char const* func_fmt;
|
||||
char const* pure_fmt = "ret{ret_index}({parameter_types});";
|
||||
char const* meta_fmt;
|
||||
char const* member_fmt;
|
||||
|
||||
output += fmt::format(used_format,
|
||||
fmt::arg("parameter_types", codegen::getParameterTypes(*fn)),
|
||||
fmt::arg("parameter_type_comma", str_if(", ", !fn->args.empty())),
|
||||
fmt::arg("class_name", c.name),
|
||||
fmt::arg("const", str_if(" const ", fn->is_const)),
|
||||
fmt::arg("index", f.field_id),
|
||||
fmt::arg("return", getReturn(*fn, c.name))
|
||||
);
|
||||
switch (f.type) {
|
||||
case FuncType::Member:
|
||||
func_fmt = "ret{ret_index}(*)( {const}{class_name}*{parameter_type_comma}{parameter_types});";
|
||||
meta_fmt = "ret{ret_index}({const}{class_name}*{parameter_type_comma}{parameter_types});";
|
||||
member_fmt = "ret{ret_index}({class_name}::*)({parameter_types}){const};";
|
||||
break;
|
||||
case FuncType::Static:
|
||||
func_fmt = "ret{ret_index}(*)({parameter_types});";
|
||||
meta_fmt = "ret{ret_index}({parameter_types});";
|
||||
member_fmt = "func{index};";
|
||||
break;
|
||||
case FuncType::Structor:
|
||||
func_fmt = "ret{ret_index}(*)({class_name}*{parameter_type_comma}{parameter_types});";
|
||||
meta_fmt = "ret{ret_index}({const}{class_name}*{parameter_type_comma}{parameter_types});";
|
||||
member_fmt = "func{index};";
|
||||
break;
|
||||
}
|
||||
|
||||
if (used_returns.count(f.return_type) == 0) {
|
||||
output += fmt::format(return_fmt,
|
||||
fmt::arg("index", i),
|
||||
fmt::arg("return", f.return_type)
|
||||
) + "\n";
|
||||
used_returns[f.return_type] = i;
|
||||
}
|
||||
int ret_index = used_returns[f.return_type];
|
||||
|
||||
std::string pure_val = fmt::format(pure_fmt,
|
||||
fmt::arg("ret_index", ret_index),
|
||||
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", "))
|
||||
);
|
||||
if (used_pures.count(pure_val) == 0) {
|
||||
output += fmt::format("using pure{} = {}\n", i, pure_val);
|
||||
used_pures[pure_val] = i;
|
||||
}
|
||||
|
||||
std::string func_val = fmt::format(func_fmt,
|
||||
fmt::arg("ret_index", ret_index),
|
||||
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", ")),
|
||||
fmt::arg("parameter_type_comma", str_if(", ", !f.parameter_types.empty())),
|
||||
fmt::arg("class_name", f.class_name),
|
||||
fmt::arg("const", str_if(" const ", f.is_const))
|
||||
);
|
||||
std::string meta_val = fmt::format(meta_fmt,
|
||||
fmt::arg("ret_index", ret_index),
|
||||
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", ")),
|
||||
fmt::arg("parameter_type_comma", str_if(", ", !f.parameter_types.empty())),
|
||||
fmt::arg("class_name", f.class_name),
|
||||
fmt::arg("const", str_if(" const ", f.is_const))
|
||||
);
|
||||
std::string member_val = fmt::format(member_fmt,
|
||||
fmt::arg("ret_index", ret_index),
|
||||
fmt::arg("parameter_types", fmt::join(f.parameter_types, ", ")),
|
||||
fmt::arg("class_name", f.class_name),
|
||||
fmt::arg("const", str_if(" const ", f.is_const)),
|
||||
fmt::arg("index", i)
|
||||
);
|
||||
|
||||
if (used_funcs.count(func_val) == 0) {
|
||||
output += fmt::format("using func{index} = {func}\nusing meta{index} = {meta}\nusing member{index} = {member}\n",
|
||||
fmt::arg("index", i),
|
||||
fmt::arg("func", func_val),
|
||||
fmt::arg("meta", meta_val),
|
||||
fmt::arg("member", member_val)
|
||||
);
|
||||
used_funcs[func_val] = i;
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
return output;
|
||||
|
|
180
codegen/src/TypeOpt.hpp
Normal file
180
codegen/src/TypeOpt.hpp
Normal file
|
@ -0,0 +1,180 @@
|
|||
#include "Shared.hpp"
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
enum class FuncType : int {
|
||||
Structor,
|
||||
Static,
|
||||
Member
|
||||
};
|
||||
struct Func {
|
||||
std::string return_type;
|
||||
bool is_const;
|
||||
std::string class_name;
|
||||
std::vector<std::string> parameter_types;
|
||||
FuncType type;
|
||||
|
||||
std::string toStr() const {
|
||||
return fmt::format("{}{}{}{}{}",
|
||||
return_type,
|
||||
class_name,
|
||||
fmt::join(parameter_types, ","),
|
||||
is_const ? " const " : "",
|
||||
static_cast<int>(type)
|
||||
);
|
||||
}
|
||||
|
||||
bool operator<(Func const& f) const {
|
||||
return toStr() < f.toStr();
|
||||
}
|
||||
|
||||
bool operator==(Func const& f) const {
|
||||
return (
|
||||
return_type == f.return_type &&
|
||||
is_const == f.is_const &&
|
||||
class_name == f.class_name &&
|
||||
parameter_types == f.parameter_types &&
|
||||
type == f.type
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct Ids {
|
||||
int ret = -1;
|
||||
int func = -1;
|
||||
int pure = -1;
|
||||
int meta = -1;
|
||||
int member = -1;
|
||||
};
|
||||
|
||||
class TypeBank {
|
||||
std::vector<Func> m_stuff;
|
||||
public:
|
||||
static std::string getReturn(FunctionBegin const& fn, std::string const& parent) {
|
||||
if (fn.type != FunctionType::Normal)
|
||||
return "void";
|
||||
|
||||
if (fn.ret.name == "auto") {
|
||||
std::vector<std::string> declvals;
|
||||
|
||||
for (auto& [t, n] : fn.args) {
|
||||
declvals.push_back(fmt::format("std::declval<{}>()", t.name));
|
||||
}
|
||||
|
||||
return fmt::format(
|
||||
fn.is_static ? "decltype({}::{}({}))" : "decltype(std::declval<{}>().{}({}))",
|
||||
parent,
|
||||
fn.name,
|
||||
fmt::join(declvals, ", ")
|
||||
);
|
||||
}
|
||||
|
||||
return fn.ret.name;
|
||||
}
|
||||
|
||||
static Func makeFunc(FunctionBegin const& fn, std::string const& parent) {
|
||||
Func f;
|
||||
f.return_type = TypeBank::getReturn(fn, parent);
|
||||
f.is_const = fn.is_const;
|
||||
f.class_name = parent;
|
||||
|
||||
for (auto& arg : fn.args) {
|
||||
f.parameter_types.push_back(arg.first.name);
|
||||
}
|
||||
|
||||
if (fn.is_static)
|
||||
f.type = FuncType::Static;
|
||||
else if (fn.type != FunctionType::Normal)
|
||||
f.type = FuncType::Structor;
|
||||
else
|
||||
f.type = FuncType::Member;
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
void loadFrom(Root& root) {
|
||||
for (auto& c : root.classes) {
|
||||
for (auto& f : c.fields) {
|
||||
if (codegen::getStatus(f) == BindStatus::Unbindable)
|
||||
continue;
|
||||
|
||||
m_stuff.push_back(TypeBank::makeFunc(*f.get_fn(), c.name));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(m_stuff.begin(), m_stuff.end());
|
||||
m_stuff.erase(std::unique(m_stuff.begin(), m_stuff.end()), m_stuff.end());
|
||||
}
|
||||
|
||||
std::vector<Func> const& typeList() { return m_stuff; }
|
||||
|
||||
Ids getIDs(FunctionBegin const& fn, std::string const& parent) {
|
||||
Ids out;
|
||||
Func in_f = TypeBank::makeFunc(fn, parent);
|
||||
|
||||
int i = 0;
|
||||
for (auto f : m_stuff) {
|
||||
if (out.ret == -1 && f.return_type == in_f.return_type) {
|
||||
out.ret = i;
|
||||
}
|
||||
|
||||
if (out.func == -1) {
|
||||
if (in_f.type == FuncType::Member) {
|
||||
if (f == in_f) out.func = i;
|
||||
} else if (in_f.type == FuncType::Structor) {
|
||||
if (
|
||||
f.return_type == in_f.return_type &&
|
||||
f.class_name == in_f.class_name &&
|
||||
f.is_const == in_f.is_const &&
|
||||
f.parameter_types == in_f.parameter_types
|
||||
) out.func = i;
|
||||
} else {
|
||||
if (
|
||||
f.return_type == in_f.return_type &&
|
||||
f.parameter_types == in_f.parameter_types &&
|
||||
f.type == in_f.type
|
||||
) out.func = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.meta == -1 || out.member == -1) {
|
||||
Func assume_member = f;
|
||||
assume_member.type = FuncType::Member;
|
||||
|
||||
if (in_f == assume_member) {
|
||||
out.meta = i;
|
||||
} else if (out.func != -1) {
|
||||
out.meta = out.func;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.pure == -1 && f.return_type == in_f.return_type && f.parameter_types == in_f.parameter_types) {
|
||||
out.pure = i;
|
||||
}
|
||||
|
||||
if (out.ret != -1 && out.func != -1 && out.pure != -1)
|
||||
break;
|
||||
++i;
|
||||
}
|
||||
|
||||
out.member = out.func;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int getPure(FunctionBegin const& fn, std::string const& parent) {
|
||||
Func in_f = TypeBank::makeFunc(fn, parent);
|
||||
|
||||
int i = 0;
|
||||
for (auto f : m_stuff) {
|
||||
if (f.return_type == in_f.return_type && f.parameter_types == in_f.parameter_types) {
|
||||
return i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -7,15 +7,16 @@
|
|||
#include <Geode/loader/Mod.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(index, convention, className, functionName) \
|
||||
using base##index = wrap::functionName<Base, types::pure##index>; \
|
||||
using derived##index = wrap::functionName<Derived, types::pure##index>; \
|
||||
if constexpr (derived##index::uuid != nullptr && (void*)base##index::uuid != (void*)derived##index::uuid) { \
|
||||
Mod::get()->addHook<derived##index::value, convention>( \
|
||||
#className "::" #functionName, \
|
||||
(void*)addresses::address##index() \
|
||||
); \
|
||||
} \
|
||||
#define GEODE_APPLY_MODIFY_FOR_FUNCTION(addr_index, pure_index, convention, className, functionName) \
|
||||
if constexpr ( \
|
||||
wrap::functionName<Derived, types::pure##pure_index>::uuid != nullptr && \
|
||||
(void*)wrap::functionName<Base, types::pure##pure_index>::uuid != (void*)wrap::functionName<Derived, types::pure##pure_index>::uuid \
|
||||
) { \
|
||||
Mod::get()->addHook<wrap::functionName<Derived, types::pure##pure_index>::value, convention>( \
|
||||
#className "::" #functionName, \
|
||||
(void*)addresses::address##addr_index() \
|
||||
); \
|
||||
} \
|
||||
|
||||
|
||||
namespace geode::modifier {
|
||||
|
|
Loading…
Reference in a new issue