Josh Posted July 18 Posted July 18 This code will retrieve the entire Lua API and process it, outputting some interesting data into a JSON file. What can this be used for? I am glad you asked. Soon you will learn the answer. From start to finish, it took me 45 minutes to write this code. #include "Leadwerks.h" #include <regex> using namespace Leadwerks; void Load(table& j3, table& info) { if (j3["hideFromLua"] == true) return; Print(j3["title"]); Print(j3["filename"]); table t = {}; //t["name"] = j3["title"]; t["page"] = j3["filename"]; if (j3["filename"].is_string()) { std::string s = j3["filename"]; //if (s == "Abs") DebugBreak(); auto stream = ReadFile("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/Lua/" + s + ".md"); if (stream) { //if (s == "Entity_Move") DebugBreak(); bool start = false; while (not stream->Eof()) { auto s = stream->ReadLine(); s = s.Trim(); if (s == "## Syntax") { start = true; continue; } if (start) { if (s.empty()) continue; if (s.StartsWith("-")) { s = s.Right(s.size() - 1); } s = s.Trim(); s = s.Replace("xMat4", "Mat4"); s = s.Replace("xMat3", "Mat3"); s = s.Replace("xQuat", "Quat"); s = s.Replace("xPlane", "Plane"); s = s.Replace("xVec4", "Vec4"); s = s.Replace("xVec3", "Vec3"); s = s.Replace("xVec2", "Vec2"); s = s.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); s = s.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); s = s.Replace("*", ""); int p = s.Find(" "); int p2 = s.Find("("); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); if (p > -1 and p < p2) { String rvalue = s.Left(p); s = s.Right(s.size() - p); p = rvalue.Find("("); if (p > -1) { rvalue = rvalue.Left(p); // rvalue = rvalue.Replace("[", ""); // rvalue = rvalue.Replace("]", ""); } rvalue = rvalue.Trim(); s = rvalue + " " + s.Trim(); } s = s.Trim(); t["syntax"] = s; break; } } info[std::string(j3["title"])] = t; } } if (j3["topics"].is_array()) { for (auto t : j3["topics"]) { Load(t.second, info); } } } int main(int argc, const char* argv[]) { auto j3 = LoadTable("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/toc.json"); table info; for (auto t : j3["topics"]) { if (std::string(t.second["title"]) == std::string("Programming Reference")) { for (auto child : t.second["topics"]) { Load(child.second, info); } } } SaveTable(info, GetPath(PATH_DESKTOP) + "/Lua.json"); return 0; } The output looks like this: { "ACos": { "page": "ACos", "syntax": "number ACos(number value)" }, "ASin": { "page": "ASin", "syntax": "number ASin(number value)" }, "ASyncDownloadFile": { "page": "ASyncDownloadFile", "syntax": "ASyncDownloadFileInfo AsyncDownloadFile(string url, string localpath)" }, "ATan": { "page": "ATan", "syntax": "number ATan(number value)" }, "Aabb": { "page": "Aabb" }, Quote Let's build cool stuff and have fun.
Josh Posted July 18 Author Posted July 18 Updated to fetch the command description: #include "Leadwerks.h" #include <regex> using namespace Leadwerks; void Load(table& j3, table& info) { if (j3["hideFromLua"] == true) return; Print(j3["title"]); Print(j3["filename"]); table t = {}; //t["name"] = j3["title"]; t["page"] = j3["filename"]; if (j3["filename"].is_string()) { std::string s = j3["filename"]; //if (s == "Abs") DebugBreak(); auto stream = ReadFile("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/Lua/" + s + ".md"); if (stream) { //if (s == "Entity_Move") DebugBreak(); bool start = false; String description; bool descactive = true; while (not stream->Eof()) { auto s = stream->ReadLine(); s = s.Trim(); if (descactive) { if (s.StartsWith("Base class:")) continue; if (s.StartsWith("# ")) continue; if (s.StartsWith("|") or s.StartsWith("##")) { descactive = false; } else { if (not s.empty()) description += s; } } if (s == "## Syntax") { start = true; continue; } if (start) { if (s.empty()) continue; if (s.StartsWith("-")) { s = s.Right(s.size() - 1); } s = s.Trim(); s = s.Replace("xMat4", "Mat4"); s = s.Replace("xMat3", "Mat3"); s = s.Replace("xQuat", "Quat"); s = s.Replace("xPlane", "Plane"); s = s.Replace("xVec4", "Vec4"); s = s.Replace("xVec3", "Vec3"); s = s.Replace("xVec2", "Vec2"); s = s.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); s = s.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); s = s.Replace("*", ""); int p = s.Find(" "); int p2 = s.Find("("); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); if (p > -1 and p < p2) { String rvalue = s.Left(p); s = s.Right(s.size() - p); p = rvalue.Find("("); if (p > -1) { rvalue = rvalue.Left(p); // rvalue = rvalue.Replace("[", ""); // rvalue = rvalue.Replace("]", ""); } rvalue = rvalue.Trim(); s = rvalue + " " + s.Trim(); } s = s.Trim(); t["syntax"] = s; break; } } if (not description.empty()) { int p = description.Find("."); if (p != -1) description = description.Left(p + 1); t["description"] = description; } info[std::string(j3["title"])] = t; } } if (j3["topics"].is_array()) { for (auto t : j3["topics"]) { Load(t.second, info); } } } int main(int argc, const char* argv[]) { auto j3 = LoadTable("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/toc.json"); table info; for (auto t : j3["topics"]) { if (std::string(t.second["title"]) == std::string("Programming Reference")) { for (auto child : t.second["topics"]) { Load(child.second, info); } } } SaveTable(info, GetPath(PATH_DESKTOP) + "/Lua.json"); return 0; } Quote Let's build cool stuff and have fun.
Josh Posted July 24 Author Posted July 24 This version will separate out class names, return values, function arguments, and default parameters. #include "Leadwerks.h" #include <regex> using namespace Leadwerks; void Load(table& j3, table& info) { if (j3["hideFromLua"] == true) return; Print(j3["title"]); Print(j3["filename"]); table t = {}; //t["name"] = j3["title"]; t["page"] = j3["filename"]; String s = t["page"]; auto sarr = s.Split("_"); if (sarr.size() > 1) t["class"] = sarr[0]; if (j3["filename"].is_string()) { std::string s = j3["filename"]; //if (s == "Abs") DebugBreak(); auto stream = ReadFile("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/Lua/" + s + ".md"); if (stream) { //if (s == "Entity_Move") DebugBreak(); bool start = false; String description; bool descactive = true; while (not stream->Eof()) { auto s = stream->ReadLine(); s = s.Trim(); if (descactive) { if (s.StartsWith("Base class:")) continue; if (s.StartsWith("# ")) continue; if (s.StartsWith("|") or s.StartsWith("##")) { descactive = false; } else { if (not s.empty()) description += s; } } if (s == "## Syntax") { start = true; continue; } if (start) { if (s.Find("PeekShort") > -1) { int g = 3; } if (s.StartsWith("#")) break; if (s.StartsWith("|")) break; if (s.empty()) continue; if (s.StartsWith("-")) { s = s.Right(s.size() - 1); } s = s.Trim(); s = s.Replace("xMat4", "Mat4"); s = s.Replace("xMat3", "Mat3"); s = s.Replace("xQuat", "Quat"); s = s.Replace("xPlane", "Plane"); s = s.Replace("xVec4", "Vec4"); s = s.Replace("xVec3", "Vec3"); s = s.Replace("xVec2", "Vec2"); s = s.Replace("dFloat", "number"); s = s.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); s = s.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); s = s.Replace("*", ""); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); int p = s.Find(" "); int p2 = s.Find("("); if (std::string(j3["filename"]) == "Entity_SetPosition") { int a = 3; } String rvalue; if (p > -1 and p < p2) { rvalue = s.Left(p); s = s.Right(s.size() - p); p = rvalue.Find("("); if (p > -1) { rvalue = rvalue.Left(p); // rvalue = rvalue.Replace("[", ""); // rvalue = rvalue.Replace("]", ""); } rvalue = rvalue.Trim(); s = rvalue + " " + s.Trim(); } s = s.Trim(); table syntax = {}; { int p0 = s.Find(" "); int p1 = s.Find("("); if (p1 > -1) { s = s.Right(s.size() - p1 - 1); } int p2 = s.Find(")"); if (not rvalue.empty()) syntax["return"] = rvalue; if (p1 > p0) { //syntax["return"] = s.Left(p0); } //s = s.Right(s.size() - p1 - 1); s = s.Replace(")", ""); } auto sarr = s.Split(","); if (not sarr.empty()) { for (int n = 0; n < sarr.size(); ++n) { auto ss = sarr[n].Trim().Split(""); if (ss.size() > 1) { for (int n = 2; n < ss.size(); ++n) ss[1] += ss[n]; if (not syntax["arguments"].is_object()) syntax["arguments"] = {}; table arg = {}; arg["type"] = ss[0]; String name = ss[1]; auto sarrr = name.Split("="); if (sarrr.size() > 1) { name = sarrr[0].Trim(); arg["default"] = sarrr[1].Trim(); } else { name = sarrr[0].Trim(); } arg["name"] = name; if (std::string(arg["type"]) == "extra") { int g = 3; } if (std::string(arg["name"]) == "") { arg["name"] = arg["type"]; arg["type"] = nullptr; if (std::string(arg["default"]) == "true" or std::string(arg["default"]) == "false") { arg["type"] = "boolean"; } } syntax["arguments"].push_back(arg); } } } if (not t["syntax"].is_array()) { t["syntax"] = {}; } t["syntax"].push_back(syntax); //t["syntax"] = s; //break; } } if (not description.empty()) { int p = description.Find("."); if (p != -1) description = description.Left(p + 1); t["description"] = description; } info[std::string(j3["filename"])] = t; } } if (j3["topics"].is_array()) { for (auto t : j3["topics"]) { Load(t.second, info); } } } int main(int argc, const char* argv[]) { auto j3 = LoadTable("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/toc.json"); table info; for (auto t : j3["topics"]) { if (std::string(t.second["title"]) == std::string("Programming Reference")) { for (auto child : t.second["topics"]) { Load(child.second, info); } } } SaveTable(info, GetPath(PATH_DESKTOP) + "/Commands.json"); table classtable = {}; for (auto& t : info) { if (t.second["class"].is_string()) { String classname = t.second["class"]; auto it = t.second.find("class"); t.second.erase(it); if (not classtable[classname].is_object()) { classtable[classname] = {}; classtable[classname]["methods"] = {}; } classtable[classname]["methods"].push_back(t.second); } } SaveTable(classtable, GetPath(PATH_DESKTOP) + "/Classes.json"); return 0; } Quote Let's build cool stuff and have fun.
Josh Posted July 24 Author Posted July 24 #include "Leadwerks.h" #include <regex> using namespace Leadwerks; void Load(table& j3, table& info, const String& parentname) { if (j3["hideFromLua"] == true) return; Print(j3["title"]); Print(j3["filename"]); table t = {}; //t["name"] = j3["title"]; t["page"] = j3["filename"]; String s = t["page"]; auto sarr = s.Split("_"); t["class"] = parentname; if (sarr.size() > 1) t["class"] = sarr[0]; t["type"] = "function"; if (j3["filename"].is_string()) { std::string s = j3["filename"]; if (String(t["page"]).Find("_") > -1) t["type"] = "method"; //if (s == "Abs") DebugBreak(); auto stream = ReadFile("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/Lua/" + s + ".md"); if (stream) { //if (s == "Entity_Move") DebugBreak(); bool start = false; String description; bool descactive = true; while (not stream->Eof()) { auto s = stream->ReadLine(); s = s.Trim(); if (descactive) { if (s.StartsWith("Base class:")) { //t["type"] = "method"; continue; } if (s.StartsWith("# ")) continue; if (s.StartsWith("|") or s.StartsWith("##")) { descactive = false; } else { if (not s.empty()) description += s; } } if (s == "## Syntax") { start = true; continue; } if (start) { if (s.Find("PeekShort") > -1) { int g = 3; } if (s.StartsWith("#")) break; if (s.StartsWith("|")) break; if (s.empty()) continue; if (s.StartsWith("-")) { s = s.Right(s.size() - 1); } s = s.Trim(); s = s.Replace("xMat4", "Mat4"); s = s.Replace("xMat3", "Mat3"); s = s.Replace("xQuat", "Quat"); s = s.Replace("xPlane", "Plane"); s = s.Replace("xVec4", "Vec4"); s = s.Replace("xVec3", "Vec3"); s = s.Replace("xVec2", "Vec2"); s = s.Replace("dFloat", "number"); s = s.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); s = s.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); s = s.Replace("*", ""); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); int p = s.Find(" "); int p2 = s.Find("("); if (std::string(j3["filename"]) == "Entity_SetPosition") { int a = 3; } String rvalue; if (p > -1 and p < p2) { rvalue = s.Left(p); s = s.Right(s.size() - p); p = rvalue.Find("("); if (p > -1) { rvalue = rvalue.Left(p); // rvalue = rvalue.Replace("[", ""); // rvalue = rvalue.Replace("]", ""); } rvalue = rvalue.Trim(); s = rvalue + " " + s.Trim(); if (not rvalue.empty()) { } } s = s.Trim(); table syntax = {}; { int p0 = s.Find(" "); int p1 = s.Find("("); if (p1 > -1) { s = s.Right(s.size() - p1 - 1); } int p2 = s.Find(")"); if (not rvalue.empty()) syntax["return"] = rvalue; if (p1 > p0) { //syntax["return"] = s.Left(p0); } //s = s.Right(s.size() - p1 - 1); s = s.Replace(")", ""); } auto sarr = s.Split(","); if (not sarr.empty()) { for (int n = 0; n < sarr.size(); ++n) { auto ss = sarr[n].Trim().Split(""); if (ss.size() > 1) { for (int n = 2; n < ss.size(); ++n) ss[1] += ss[n]; if (not syntax["arguments"].is_object()) syntax["arguments"] = {}; table arg = {}; arg["type"] = ss[0]; String name = ss[1]; auto sarrr = name.Split("="); if (sarrr.size() > 1) { name = sarrr[0].Trim(); arg["default"] = sarrr[1].Trim(); } else { name = sarrr[0].Trim(); } arg["name"] = name; if (std::string(arg["type"]) == "extra") { int g = 3; } if (std::string(arg["name"]) == "") { arg["name"] = arg["type"]; arg["type"] = nullptr; if (std::string(arg["default"]) == "true" or std::string(arg["default"]) == "false") { arg["type"] = "boolean"; } } syntax["arguments"].push_back(arg); } } } if (not t["syntax"].is_array()) { t["syntax"] = {}; } t["syntax"].push_back(syntax); //t["syntax"] = s; //break; } } if (not description.empty()) { int p = description.Find("."); if (p != -1) description = description.Left(p + 1); t["description"] = description; } info[std::string(j3["filename"])] = t; } } if (j3["topics"].is_array()) { for (auto t : j3["topics"]) { String name = j3["filename"]; //if (name.empty()) { name = j3["title"]; } Load(t.second, info, name); } } } int main(int argc, const char* argv[]) { auto j3 = LoadTable("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/toc.json"); table info; for (auto t : j3["topics"]) { if (std::string(t.second["title"]) == std::string("Programming Reference")) { for (auto child : t.second["topics"]) { Load(child.second, info, "Functions"); } } } SaveTable(info, GetPath(PATH_DESKTOP) + "/Commands.json"); table classtable = {}; for (auto& t : info) { if (t.second["class"].is_string()) { String classname = t.second["class"]; auto it = t.second.find("class"); t.second.erase(it); if (not classtable[classname].is_object()) classtable[classname] = {}; if (t.second["type"] == "method") { if (not classtable[classname]["methods"].is_object()) classtable[classname]["methods"] = {}; classtable[classname]["methods"].push_back(t.second); } else { if (not classtable[classname]["functions"].is_object()) classtable[classname]["functions"] = {}; classtable[classname]["functions"].push_back(t.second); } } } SaveTable(classtable, GetPath(PATH_DESKTOP) + "/Classes.json"); return 0; } Quote Let's build cool stuff and have fun.
Josh Posted July 24 Author Posted July 24 Now it writes the Lua definition files: #include "Leadwerks.h" #include <regex> using namespace Leadwerks; extern void WriteLuaDefs(table& t, const WString& path); void Load(table& j3, table& info, const String& parentname, const String& grandparentname) { if (j3["hideFromLua"] == true) return; Print(j3["title"]); Print(j3["filename"]); table t = {}; t["baseclass"] = grandparentname; //t["name"] = j3["title"]; t["page"] = j3["filename"]; String s = t["page"]; auto sarr = s.Split("_"); t["class"] = parentname; if (sarr.size() > 1) t["class"] = sarr[0]; t["type"] = "function"; if (j3["filename"].is_string()) { std::string s = j3["filename"]; if (String(t["page"]).Find("_") > -1) t["type"] = "method"; //if (s == "Abs") DebugBreak(); auto stream = ReadFile("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/Lua/" + s + ".md"); if (stream) { //if (s == "Entity_Move") DebugBreak(); bool start = false; String description; bool descactive = true; while (not stream->Eof()) { auto s = stream->ReadLine(); s = s.Trim(); if (descactive) { if (s.StartsWith("Base class:")) { s = s.Right(s.size() - 11); s = s.Trim(); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); s = s.Trim(); t["baseclass"] = s; //t["type"] = "method"; continue; } if (s.StartsWith("# ")) continue; if (s.StartsWith("|") or s.StartsWith("##")) { descactive = false; } else { if (not s.empty()) description += s; } } if (s == "## Syntax") { start = true; continue; } if (start) { if (s.Find("PeekShort") > -1) { int g = 3; } if (s.StartsWith("#")) break; if (s.StartsWith("|")) break; if (s.empty()) continue; if (s.StartsWith("-")) { s = s.Right(s.size() - 1); } s = s.Trim(); s = s.Replace("xMat4", "Mat4"); s = s.Replace("xMat3", "Mat3"); s = s.Replace("xQuat", "Quat"); s = s.Replace("xPlane", "Plane"); s = s.Replace("xVec4", "Vec4"); s = s.Replace("xVec3", "Vec3"); s = s.Replace("xVec2", "Vec2"); s = s.Replace("dFloat", "number"); s = s.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); s = s.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); s = s.Replace("*", ""); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); int p = s.Find(" "); int p2 = s.Find("("); if (std::string(j3["filename"]) == "Entity_SetPosition") { int a = 3; } String rvalue; if (p > -1 and p < p2) { rvalue = s.Left(p); s = s.Right(s.size() - p); p = rvalue.Find("("); if (p > -1) { rvalue = rvalue.Left(p); // rvalue = rvalue.Replace("[", ""); // rvalue = rvalue.Replace("]", ""); } rvalue = rvalue.Trim(); s = rvalue + " " + s.Trim(); if (not rvalue.empty()) { } } s = s.Trim(); table syntax = {}; { int p0 = s.Find(" "); int p1 = s.Find("("); if (p1 > -1) { s = s.Right(s.size() - p1 - 1); } int p2 = s.Find(")"); if (not rvalue.empty()) syntax["return"] = rvalue; if (p1 > p0) { //syntax["return"] = s.Left(p0); } //s = s.Right(s.size() - p1 - 1); s = s.Replace(")", ""); } auto sarr = s.Split(","); if (not sarr.empty()) { for (int n = 0; n < sarr.size(); ++n) { auto ss = sarr[n].Trim().Split(""); if (ss.size() > 1) { for (int n = 2; n < ss.size(); ++n) ss[1] += ss[n]; if (not syntax["arguments"].is_object()) syntax["arguments"] = {}; table arg = {}; arg["type"] = ss[0]; String name = ss[1]; auto sarrr = name.Split("="); if (sarrr.size() > 1) { name = sarrr[0].Trim(); arg["default"] = sarrr[1].Trim(); } else { name = sarrr[0].Trim(); } arg["name"] = name; if (std::string(arg["type"]) == "extra") { int g = 3; } if (std::string(arg["name"]) == "") { arg["name"] = arg["type"]; arg["type"] = nullptr; if (std::string(arg["default"]) == "true" or std::string(arg["default"]) == "false") { arg["type"] = "boolean"; } } syntax["arguments"].push_back(arg); } } } if (not t["syntax"].is_array()) { t["syntax"] = {}; } t["syntax"].push_back(syntax); //t["syntax"] = s; //break; } } if (not description.empty()) { int p = description.Find("."); if (p != -1) description = description.Left(p + 1); t["description"] = description; } info[std::string(j3["filename"])] = t; } } if (j3["topics"].is_array()) { for (auto t : j3["topics"]) { String name = j3["filename"]; //if (name.empty()) { name = j3["title"]; } Load(t.second, info, name, parentname); } } } int main(int argc, const char* argv[]) { auto j3 = LoadTable("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/toc.json"); table info; for (auto t : j3["topics"]) { if (std::string(t.second["title"]) == std::string("Programming Reference")) { for (auto child : t.second["topics"]) { Load(child.second, info, "Functions", ""); } } } SaveTable(info, GetPath(PATH_DESKTOP) + "/Commands.json"); table classtable = {}; for (auto& t : info) { if (t.second["class"].is_string()) { String classname = t.second["class"]; auto it = t.second.find("class"); t.second.erase(it); if (not classtable[classname].is_object()) classtable[classname] = {}; if (std::string(t.second["type"]) == "method") { if (not classtable[classname]["methods"].is_object()) classtable[classname]["methods"] = {}; classtable[classname]["methods"].push_back(t.second); } else { if (not classtable[classname]["functions"].is_object()) classtable[classname]["functions"] = {}; classtable[classname]["functions"].push_back(t.second); } if (t.second["baseclass"].is_string()) { std::string base = t.second["baseclass"]; classtable[classname]["baseclass"] = base; t.second["baseclass"] = nullptr; } } } SaveTable(classtable, GetPath(PATH_DESKTOP) + "/Classes.json"); CreateDir(GetPath(PATH_DESKTOP) + "/LuaDefs"); WriteLuaDefs(classtable, GetPath(PATH_DESKTOP) + "/LuaDefs"); return 0; } void WriteLuaDefs(table& t, const WString& path) { for (auto& pair : t) { String name = pair.first; auto& c = pair.second; auto stream = WriteFile(path + "/" + name + ".lua"); stream->WriteLine("---@meta"); stream->WriteString("---@class " + name, false); if (c["baseclass"].is_string()) { stream->WriteString(":" + String(c["baseclass"]), false); } stream->WriteLine(""); if (c["methods"].is_array()) { stream->WriteLine(name + " = {}\n\n----------------------------\n-- Methods\n----------------------------\n"); for (auto& p2 : c["methods"]) { auto& m = p2.second; String mname = String(m["page"]); int p = mname.Find("_"); if (p > -1) mname = mname.Right(mname.size() - p - 1); for (auto& syntaxpair : m["syntax"]) { String argstring; auto& args = syntaxpair.second["arguments"]; if (args.is_array()) { for (int n = 0; n < args.size(); ++n) { if (n > 0) argstring += ", "; argstring += String(args[n]["name"]); if (args[n]["type"].is_string()) { stream->WriteLine("---@param " + String(args[n]["name"]) + " " + String(args[n]["type"])); } } if (syntaxpair.second["return"].is_string()) { stream->WriteLine("---@return " + String(syntaxpair.second["return"]) ); } } stream->WriteString("function " + name + ":" + mname + "(", false); if (not argstring.empty()) stream->WriteString(argstring, false); stream->WriteLine(") end\n"); } } } else { stream->WriteLine(""); } if (c["functions"].is_array()) { stream->WriteLine("----------------------------\n-- Functions\n----------------------------\n"); for (auto& p2 : c["functions"]) { auto& m = p2.second; String mname = String(m["page"]); for (auto& syntaxpair : m["syntax"]) { String argstring; auto& args = syntaxpair.second["arguments"]; if (args.is_array()) { for (int n = 0; n < args.size(); ++n) { if (n > 0) argstring += ", "; argstring += String(args[n]["name"]); if (args[n]["type"].is_string()) { stream->WriteLine("---@param " + String(args[n]["name"]) + " " + String(args[n]["type"])); } } if (syntaxpair.second["return"].is_string()) { stream->WriteLine("---@return " + String(syntaxpair.second["return"])); } } stream->WriteString("function " + mname + "(", false); if (not argstring.empty()) stream->WriteString(argstring, false); stream->WriteLine(") end\n"); } //stream->WriteString("function " + String(m["page"]) + "(", false); //stream->WriteLine(") end"); } } } } Quote Let's build cool stuff and have fun.
Josh Posted July 24 Author Posted July 24 Now handles class members: #include "Leadwerks.h" #include <regex> using namespace Leadwerks; extern void WriteLuaDefs(table& t, const WString& path); std::map<String, String> classbaseclass; std::map<String, table> classparams; void Load(table& j3, table& info, const String& parentname, const String& grandparentname) { if (j3["hideFromLua"] == true) return; Print(j3["title"]); Print(j3["filename"]); bool isclasspage = false; table t = {}; if (grandparentname != "Functions") { //t["baseclass"] = grandparentname; } //t["name"] = j3["title"]; t["page"] = j3["filename"]; String name = t["page"]; if (name == "Vec3" or name == "Vec2" or name == "Vec4" or name == "Quat" or name == "Plane" or name == "Mat4" or name == "Nat3" or name == "Aabb") isclasspage = true; String s = t["page"]; auto sarr = s.Split("_"); t["class"] = parentname; if (sarr.size() > 1) t["class"] = sarr[0]; t["type"] = "function"; if (j3["filename"].is_string()) { std::string s = j3["filename"]; if (String(t["page"]).Find("_") > -1) t["type"] = "method"; //if (s == "Abs") DebugBreak(); auto stream = ReadFile("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/Lua/" + s + ".md"); if (stream) { //if (s == "Entity_Move") DebugBreak(); bool start = false; String description; bool descactive = true; while (not stream->Eof()) { auto s = stream->ReadLine(); s = s.Trim(); if (descactive) { if (s.StartsWith("Base class:")) { s = s.Right(s.size() - 11); s = s.Trim(); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); s = s.Trim(); classbaseclass[name] = s; //t["baseclass"] = s; //t["type"] = "method"; isclasspage = true; continue; } if (s.StartsWith("# ")) continue; if (s.StartsWith("|") or s.StartsWith("##")) { descactive = false; } else { if (not s.empty()) description += s; } } if (s == "| Property | Type | Description |") { start = true; continue; } if (s == "## Syntax") { start = true; continue; } if (start) { if (isclasspage) { if (s.StartsWith("| ")) { auto sarr = s.Mid(1, s.size() - 2).Split("|"); if (sarr.size() == 3) { String cname = sarr[0].Trim(); String type = sarr[1].Trim(); cname = cname.Replace("-", ""); if (cname.Find(",") > -1) { auto sarr = cname.Split(","); cname = sarr[0]; } if (type == "Method" or type == "Function" or type == "Constructor") continue; // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); //std::regex pattern2(R"(\[([^\]]+)\]\([^\)]+\\))"); // Replace matched pattern with just the captured 'word' type = std::regex_replace(type, pattern, "$1"); //type = std::regex_replace(type, pattern2, "$1"); type = type.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); type = type.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); type = type.Replace("xMat4", "Mat4"); type = type.Replace("xMat3", "Mat3"); type = type.Replace("xQuat", "Quat"); type = type.Replace("xPlane", "Plane"); type = type.Replace("xVec4", "Vec4"); type = type.Replace("xVec3", "Vec3"); type = type.Replace("xVec2", "Vec2"); type = type.Replace("dFloat", "number"); type = type.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); type = type.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); cname = std::regex_replace(cname, pattern, "$1"); //name = std::regex_replace(name, pattern2, "$1"); if (cname.empty()) continue; String desc = sarr[2].Trim(); Print(cname); Print(type); Print(""); if (not classparams[name].is_array()) classparams[name] = {}; table p = {}; p["name"] = cname; p["type"] = type; p["description"] = desc; classparams[name].push_back(p); } } continue; } if (s.Find("PeekShort") > -1) { int g = 3; } if (s.StartsWith("#")) break; if (s.StartsWith("|")) break; if (s.empty()) continue; if (s.StartsWith("-")) { s = s.Right(s.size() - 1); } s = s.Trim(); s = s.Replace("xMat4", "Mat4"); s = s.Replace("xMat3", "Mat3"); s = s.Replace("xQuat", "Quat"); s = s.Replace("xPlane", "Plane"); s = s.Replace("xVec4", "Vec4"); s = s.Replace("xVec3", "Vec3"); s = s.Replace("xVec2", "Vec2"); s = s.Replace("dFloat", "number"); s = s.Replace("[string](https://www.lua.org/manual/5.4/manual.html#6.4)", "string"); s = s.Replace("[table](https://www.lua.org/manual/5.4/manual.html#6.6)", "table"); s = s.Replace("*", ""); // Regex to match [word](word.md) pattern std::regex pattern(R"(\[([^\]]+)\]\([^\)]+\.md\))"); // Replace matched pattern with just the captured 'word' s = std::regex_replace(s, pattern, "$1"); int p = s.Find(" "); int p2 = s.Find("("); if (std::string(j3["filename"]) == "Entity_SetPosition") { int a = 3; } String rvalue; if (p > -1 and p < p2) { rvalue = s.Left(p); s = s.Right(s.size() - p); p = rvalue.Find("("); if (p > -1) { rvalue = rvalue.Left(p); // rvalue = rvalue.Replace("[", ""); // rvalue = rvalue.Replace("]", ""); } rvalue = rvalue.Trim(); s = rvalue + " " + s.Trim(); if (not rvalue.empty()) { } } s = s.Trim(); table syntax = {}; { int p0 = s.Find(" "); int p1 = s.Find("("); if (p1 > -1) { s = s.Right(s.size() - p1 - 1); } int p2 = s.Find(")"); if (not rvalue.empty()) syntax["return"] = rvalue; if (p1 > p0) { //syntax["return"] = s.Left(p0); } //s = s.Right(s.size() - p1 - 1); s = s.Replace(")", ""); } auto sarr = s.Split(","); if (not sarr.empty()) { for (int n = 0; n < sarr.size(); ++n) { auto ss = sarr[n].Trim().Split(""); if (ss.size() > 1) { for (int n = 2; n < ss.size(); ++n) ss[1] += ss[n]; if (not syntax["arguments"].is_object()) syntax["arguments"] = {}; table arg = {}; arg["type"] = ss[0]; String name = ss[1]; auto sarrr = name.Split("="); if (sarrr.size() > 1) { name = sarrr[0].Trim(); arg["default"] = sarrr[1].Trim(); } else { name = sarrr[0].Trim(); } arg["name"] = name; if (std::string(arg["type"]) == "extra") { int g = 3; } if (std::string(arg["name"]) == "") { arg["name"] = arg["type"]; arg["type"] = nullptr; if (std::string(arg["default"]) == "true" or std::string(arg["default"]) == "false") { arg["type"] = "boolean"; } } syntax["arguments"].push_back(arg); } } } if (not t["syntax"].is_array()) { t["syntax"] = {}; } t["syntax"].push_back(syntax); //t["syntax"] = s; //break; } } if (not description.empty()) { int p = description.Find("."); if (p != -1) description = description.Left(p + 1); t["description"] = description; } info[std::string(j3["filename"])] = t; } } if (j3["topics"].is_array()) { for (auto t : j3["topics"]) { String name = j3["filename"]; //if (name.empty()) { name = j3["title"]; } Load(t.second, info, name, parentname); } } } int main(int argc, const char* argv[]) { auto j3 = LoadTable("https://raw.githubusercontent.com/Leadwerks/Documentation/refs/heads/master/toc.json"); table info; for (auto t : j3["topics"]) { if (std::string(t.second["title"]) == std::string("Programming Reference")) { for (auto child : t.second["topics"]) { Load(child.second, info, "Functions", ""); } } } SaveTable(info, GetPath(PATH_DESKTOP) + "/Commands.json"); table classtable = {}; for (auto& t : info) { if (t.second["class"].is_string()) { String classname = t.second["class"]; auto it = t.second.find("class"); t.second.erase(it); if (not t.second["syntax"].is_array()) continue; if (not classtable[classname].is_object()) classtable[classname] = {}; classtable[classname]["properties"] = classparams[classname]; if (std::string(t.second["type"]) == "method") { if (not classtable[classname]["methods"].is_object()) classtable[classname]["methods"] = {}; classtable[classname]["methods"].push_back(t.second); } else { if (not classtable[classname]["functions"].is_object()) classtable[classname]["functions"] = {}; classtable[classname]["functions"].push_back(t.second); } /*if (t.second["baseclass"].is_string()) { std::string base = t.second["baseclass"]; classtable[classname]["baseclass"] = base; t.second["baseclass"] = nullptr; }*/ classtable[classname]["baseclass"] = classbaseclass[classname]; } } SaveTable(classtable, GetPath(PATH_DESKTOP) + "/Classes.json"); CreateDir(GetPath(PATH_DESKTOP) + "/LuaDefs"); WriteLuaDefs(classtable, GetPath(PATH_DESKTOP) + "/LuaDefs"); return 0; } void WriteLuaDefs(table& t, const WString& path) { for (auto& pair : t) { String name = pair.first; auto& c = pair.second; auto stream = WriteFile(path + "/" + name + ".lua"); stream->WriteLine("---@meta"); stream->WriteString("---@class " + name, false); if (c["baseclass"].is_string()) { String base = c["baseclass"]; if (not base.empty()) stream->WriteString(":" + base, false); } stream->WriteLine(""); for (auto& pair : c["properties"]) { stream->WriteLine("---@field " + String(pair.second["name"]) + " " + String(pair.second["type"])); } if (c["methods"].is_array() and not c["methods"].empty()) { stream->WriteLine(name + " = {}\n\n----------------------------\n-- Methods\n----------------------------\n"); for (auto& p2 : c["methods"]) { auto& m = p2.second; String mname = String(m["page"]); int p = mname.Find("_"); if (p > -1) mname = mname.Right(mname.size() - p - 1); for (auto& syntaxpair : m["syntax"]) { String argstring; auto& args = syntaxpair.second["arguments"]; if (args.is_array()) { for (int n = 0; n < args.size(); ++n) { if (n > 0) argstring += ", "; argstring += String(args[n]["name"]); if (args[n]["type"].is_string()) { stream->WriteLine("---@param " + String(args[n]["name"]) + " " + String(args[n]["type"])); } } } if (syntaxpair.second["return"].is_string()) { stream->WriteLine("---@return " + String(syntaxpair.second["return"])); } stream->WriteString("function " + name + ":" + mname + "(", false); if (not argstring.empty()) stream->WriteString(argstring, false); stream->WriteLine(") end\n"); } } } else { stream->WriteLine(""); } if (c["functions"].is_array() and not c["functions"].empty()) { stream->WriteLine("----------------------------\n-- Functions\n----------------------------\n"); for (auto& p2 : c["functions"]) { auto& m = p2.second; String mname = String(m["page"]); for (auto& syntaxpair : m["syntax"]) { String argstring; auto& args = syntaxpair.second["arguments"]; if (args.is_array()) { for (int n = 0; n < args.size(); ++n) { if (n > 0) argstring += ", "; argstring += String(args[n]["name"]); if (args[n]["type"].is_string()) { stream->WriteLine("---@param " + String(args[n]["name"]) + " " + String(args[n]["type"])); } } } if (syntaxpair.second["return"].is_string()) { stream->WriteLine("---@return " + String(syntaxpair.second["return"])); } stream->WriteString("function " + mname + "(", false); if (not argstring.empty()) stream->WriteString(argstring, false); stream->WriteLine(") end\n"); } //stream->WriteString("function " + String(m["page"]) + "(", false); //stream->WriteLine(") end"); } } } } Quote Let's build cool stuff and have fun.
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.