#include "FunctionInfo.hpp" #include #include #include std::smatch match; const std::regex usg_vld_rgx(R"(Usage: .+?\((.*?)\))"); void FunctionInfo::chk_vld() { // run all checks, so we have the full picture bool vld = true; if (prs_msg.size() > 0) vld = false; // parsing messages up until this point are hard errors if (in_cnt > -1) { // in varmap is not dynamic if (!usg.empty()) { // check against usage string if (std::regex_search(usg, match, usg_vld_rgx)) { std::string usg_params = match[1]; int comma_cnt = 0; for (char c : usg_params) comma_cnt += c == ','; if (in_cnt == 0 && !usg_params.empty() || in_cnt != comma_cnt + 1) { prs_msg.push_back(std::format("in param count ({}) does not match usage string ({})", in_cnt, !usg_params.empty() * (comma_cnt + 1))); vld = false; } } else prs_msg.push_back("usage string is malformed"); // do not consider this for validity } for (int i = 1; i <= in_cnt; i++) { // lua indexes start with 1 if (!in.contains(i)) { prs_msg.push_back("in param index not in order"); vld = false; break; } } } if (out_cnt != -1 && out_cnt != out.size()) { prs_msg.push_back(std::format("out param count ({}) does not match return value ({})", out.size(), out_cnt)); vld = false; } prs_vld = vld; } bool FunctionInfo::nil_in_varmap(bool proc_in) const { const varmap& params = proc_in ? in : out; for (auto& [key, value] : params) if (std::find(value.begin(), value.end(), "nil") != value.end()) return true; return false; } void FunctionInfo::cln_varmap(bool proc_in) { varmap& params = proc_in ? in : out; int cnt = proc_in ? in_cnt : out_cnt; if (cnt == -1) { params.clear(); // dynamic varmap does not need entries return; } for (auto& [lua_index, lua_types] : params) { std::sort(lua_types.begin(), lua_types.end()); lua_types.erase(std::unique(lua_types.begin(), lua_types.end()), lua_types.end()); } if (proc_in) in_cnt = in.size(); // input count can only be inferred by in varmap size } std::string FunctionInfo::str() const { std::string str = std::format("{:X} {}{}\n", addr, nm, prs_vld ? "" : " (invalid)"); if (!usg.empty()) str += " " + usg + "\n"; str += " in: " + str_varmap(true) + "\n"; str += " out: " + str_varmap(false); for (const std::string& err : prs_msg) str += "\n " + err; return str; } std::string FunctionInfo::str_varmap(bool proc_in) const { int cnt = proc_in ? in_cnt : out_cnt; switch (cnt) { case -1: return "dynamic"; case 0: return "0 ()"; } const varmap& params = proc_in ? in : out; if (params.size() > 0) { // cnt and params.size() might differ - lua_push* calls can be undetected std::string str = std::to_string(cnt) + " ("; for (const auto& [lua_index, lua_types] : params) { for (const auto& lua_type : lua_types) str += lua_type + "/"; str.pop_back(); // remove last slash str += ", "; } str[str.length() - 2] = ')'; // replace last comma with closing bracket str.pop_back(); // remove space after last comma return str; } return std::to_string(cnt) + " ()"; }