add address docs comments to codegen

This commit is contained in:
altalk23 2023-02-18 13:52:56 +03:00
parent 461a75ca29
commit e9c4649fd1
5 changed files with 117 additions and 134 deletions

View file

@ -186,15 +186,13 @@ class ButtonSprite : cocos2d::CCSprite {
) = win 0x134b0, mac 0x4f1d0;
[[docs("
/**
* Create a ButtonSprite with a top sprite and a texture.
* @param topSprite The top sprite to add on top of the sprite
* @param width Sprite width; ignored if `absolute` is false
* @param absolute Whether to use absolute width or not
* @param texture The name of the background sprite file (can't be in a spritesheet)
* @param height The height of the button, leave 0 for automatic
* @param scale Scale of top sprite
*/
Create a ButtonSprite with a top sprite and a texture.
@param topSprite The top sprite to add on top of the sprite
@param width Sprite width; ignored if `absolute` is false
@param absolute Whether to use absolute width or not
@param texture The name of the background sprite file (can't be in a spritesheet)
@param height The height of the button, leave 0 for automatic
@param scale Scale of top sprite
")]]
static ButtonSprite* create(
cocos2d::CCSprite* topSprite,
@ -208,26 +206,27 @@ class ButtonSprite : cocos2d::CCSprite {
}
[[docs("
/**
* Create a ButtonSprite with text, a font and a texture.
* @param caption The text of the ButtonSprite
* @param width Sprite width; ignored if `absolute` is false
* @param absolute Whether to use absolute width or not
* @param font The name of the BM font file to use
* @param texture The name of the background sprite file (can't be in a spritesheet)
* @param height The height of the button, leave 0 for automatic
* @param scale Scale of text
* @returns Pointer to the created ButtonSprite, or nullptr on error
*/
Create a ButtonSprite with text, a font and a texture.
@param caption The text of the ButtonSprite
@param width Sprite width; ignored if `absolute` is false
@param absolute Whether to use absolute width or not
@param font The name of the BM font file to use
@param texture The name of the background sprite file (can't be in a spritesheet)
@param height The height of the button, leave 0 for automatic
@param scale Scale of text
@returns Pointer to the created ButtonSprite, or nullptr on error
")]]
static ButtonSprite* create(const char* caption, int width, bool absolute, const char* font, const char* texture, float height, float scale) {
return create(caption, width, 0, scale, absolute, font, texture, height);
}
inline static ButtonSprite* create(char const* caption) {
static ButtonSprite* create(char const* caption) {
return ButtonSprite::create(caption, 0, 0, "goldFont.fnt", "GJ_button_01.png", .0f, 1.f);
}
inline static ButtonSprite* create(char const* caption, const char* font, const char* texture, float scale = 1.f) {
static ButtonSprite* create(char const* caption, const char* font, const char* texture) {
return ButtonSprite::create(caption, 0, 0, font, texture, .0f, 1.f);
}
static ButtonSprite* create(char const* caption, const char* font, const char* texture, float scale) {
return ButtonSprite::create(caption, 0, 0, font, texture, .0f, scale);
}
static ButtonSprite* create(char const*, int, int, float, bool) = mac 0x4fa40;
@ -1268,6 +1267,7 @@ class EditorUI : cocos2d::CCLayer, FLAlertLayerProtocol, ColorSelectDelegate, GJ
void onUngroupSticky(cocos2d::CCObject* sender) = mac 0xc1d0, win 0x87ac0;
void onGoToLayer(cocos2d::CCObject* sender) = win 0x886b0;
void onGoToBaseLayer(cocos2d::CCObject* sender) = win 0x88790;
void onToggleGuide(cocos2d::CCObject* sender) = mac 0x19da0, win 0x79160;
void editColor(cocos2d::CCObject* sender) = mac 0x19190, win 0x8d3c0;
void alignObjects(cocos2d::CCArray* objs, bool alignY) = mac 0x2cea0, win 0x8f320;
virtual void scrollWheel(float vertical, float horizontal) = win 0x921d0, mac 0x31370, ios 0x2c4884;

View file

@ -40,13 +40,18 @@ public:
char const* monostate_constructor_cutoff = R"GEN( GEODE_MONOSTATE_CONSTRUCTOR_CUTOFF({class_name}, {first_base})
)GEN";
char const* function_definition = R"GEN({docs} {static}{virtual}{return_type} {function_name}({parameters}){const};
char const* function_definition = R"GEN(
/**
{docs_addresses}{docs} */
{static}{virtual}{return_type} {function_name}({parameters}){const};
)GEN";
char const* error_definition = R"GEN(
#ifdef GEODE_WARN_INCORRECT_MEMBERS
[[deprecated("Function is not implemented - will throw at runtime!!!")]]
#endif
/**
{docs_addresses}{docs} */
{static}{return_type} {function_name}({parameters}){const}{{
throw std::runtime_error("Use of undefined function " + GEODE_PRETTY_FUNCTION);
}}
@ -56,6 +61,8 @@ public:
#ifdef GEODE_WARN_INCORRECT_MEMBERS
[[deprecated("Use of undefined virtual function - will crash at runtime!!!")]]
#endif
/**
{docs_addresses}{docs} */
{virtual}{return_type} {function_name}({parameters}){const}{{
#ifdef GEODE_NO_UNDEFINED_VIRTUALS
static_assert(false, "Undefined virtual function - implement in GeometryDash.bro");
@ -68,10 +75,13 @@ public:
#ifdef GEODE_WARN_INCORRECT_MEMBERS
[[deprecated("Member placed incorrectly - will crash at runtime!!!")]]
#endif
)GEN";
)GEN";
char const* structor_definition = R"GEN(
{function_name}({parameters});)GEN";
/**
{docs_addresses}{docs} */
{function_name}({parameters});
)GEN";
// requires: type, member_name, array
char const* member_definition = R"GEN( {type} {member_name};
@ -84,6 +94,58 @@ public:
)GEN";
}}
inline std::string nameForPlatform(Platform platform) {
switch (platform) {
case Platform::Mac: return "MacOS";
case Platform::Windows: return "Windows";
case Platform::iOS: return "iOS";
case Platform::Android: return "Android";
default: // unreachable
return "Windows";
}
}
std::string generateAddressDocs(Field const& field, FunctionBindField* fn) {
std::string ret;
for (auto platform : {Platform::Mac, Platform::Windows, Platform::iOS, Platform::Android}) {
auto status = codegen::getStatusWithPlatform(platform, field);
if (status == BindStatus::NeedsBinding) {
ret += fmt::format(" * @note[short] {}: 0x{:x}\n",
nameForPlatform(platform),
codegen::platformNumberWithPlatform(platform, fn->binds)
);
}
else if (status == BindStatus::Binded) {
ret += fmt::format(" * @note[short] {}\n",
nameForPlatform(platform)
);
}
}
return ret;
}
std::string generateDocs(std::string const& docs) {
if (docs.size() > 0) {
std::cout << docs << "\n";
}
if (docs.size() < 7) return "";
auto ret = docs.substr(1, docs.size() - 5); // i hate this but idk how to generalize
for (auto next = ret.find(" "); next != std::string::npos; next = ret.find(" ")) {
ret.replace(next, 8, " * ");
}
std::cout << ret << "\n";
return ret;
}
std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singleFolder) {
std::string output;
@ -137,6 +199,10 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
FunctionBegin* fb;
char const* used_format = format_strings::function_definition;
std::string addressDocs;
std::string docs = generateDocs(fb->docs);
if (auto i = field.get_as<InlineField>()) {
single_output += "\t" + i->inner + "\n";
continue;
@ -158,6 +224,8 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
continue;
} else if (auto fn = field.get_as<OutOfLineField>()) {
fb = &fn->beginning;
addressDocs = " * @note[short] Out of line\n";
} else if (auto fn = field.get_as<FunctionBindField>()) {
fb = &fn->beginning;
@ -170,6 +238,8 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
if (fb->type != FunctionType::Normal)
continue;
}
addressDocs = generateAddressDocs(field, fn);
}
single_output += fmt::format(used_format,
@ -181,7 +251,8 @@ std::string generateBindingHeader(Root& root, ghc::filesystem::path const& singl
fmt::arg("index", field.field_id),
fmt::arg("parameters", codegen::getParameters(*fb)),
fmt::arg("return_type", fb->ret.name),
fmt::arg("docs", fb->docs)
fmt::arg("docs_addresses", addressDocs),
fmt::arg("docs", docs)
);
}

View file

@ -34,7 +34,7 @@ int main(int argc, char** argv) try {
writeFile(writeDir / "GeneratedAddress.cpp", generateAddressHeader(root));
writeFile(writeDir / "GeneratedModify.hpp", generateModifyHeader(root, writeDir / "modify"));
// writeFile(writeDir / "GeneratedWrapper.hpp", generateWrapperHeader(root));
writeFile(writeDir / "GeneratedType.hpp", generateTypeHeader(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));

View file

@ -70,22 +70,26 @@ namespace codegen {
inline Platform platform;
inline uintptr_t platformNumber(PlatformNumber const& p) {
switch (codegen::platform) {
case Platform::Mac: return p.mac;
case Platform::Windows: return p.win;
case Platform::iOS: return p.ios;
case Platform::Android: return p.android;
inline uintptr_t platformNumberWithPlatform(Platform p, PlatformNumber const& pn) {
switch (p) {
case Platform::Mac: return pn.mac;
case Platform::Windows: return pn.win;
case Platform::iOS: return pn.ios;
case Platform::Android: return pn.android;
default: // unreachable
return p.win;
return pn.win;
}
}
inline BindStatus getStatus(Field const& field) {
inline uintptr_t platformNumber(PlatformNumber const& p) {
return platformNumberWithPlatform(codegen::platform, p);
}
inline BindStatus getStatusWithPlatform(Platform p, Field const& field) {
FunctionBegin const* fb;
if (auto fn = field.get_as<FunctionBindField>()) {
if (platformNumber(fn->binds)) return BindStatus::NeedsBinding;
if (platformNumberWithPlatform(p, fn->binds)) return BindStatus::NeedsBinding;
fb = &fn->beginning;
}
@ -96,7 +100,7 @@ namespace codegen {
// if (field.parent.rfind("GDString", 0) == 0) return BindStatus::NeedsBinding;
if (platform == Platform::Android) {
if (p == Platform::Android) {
for (auto& [type, name] : fb->args) {
if (type.name.find("gd::") != std::string::npos) return BindStatus::NeedsBinding;
}
@ -108,13 +112,17 @@ namespace codegen {
if (fb->type == FunctionType::Normal) {
if (field.parent.rfind("fmod::", 0) == 0) return BindStatus::Binded;
if (field.parent.rfind("cocos2d::", 0) == 0 && platform == Platform::Windows)
if (field.parent.rfind("cocos2d::", 0) == 0 && p == Platform::Windows)
return BindStatus::Binded;
}
return BindStatus::Unbindable;
}
inline BindStatus getStatus(Field const& field) {
return getStatusWithPlatform(codegen::platform, field);
}
inline std::string getParameters(FunctionBegin const& f) { // int p0, float p1
std::vector<std::string> parameters;

View file

@ -1,96 +0,0 @@
#include "Shared.hpp"
#include "TypeOpt.hpp"
#include <set>
std::string generateTypeHeader(Root& root) {
std::string output;
TypeBank bank;
bank.loadFrom(root);
std::map<std::string, int> used_returns;
std::map<std::string, int> used_funcs;
std::map<std::string, int> used_pures;
int i = 0;
for (auto& f : bank.typeList()) {
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;
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;
}