#pragma once #include #include #include #include #include #include #include #include #include #include namespace analysis { struct class_attribute_info; /** * @brief 工具 */ class utils { public: /** * @brief 字符串 */ class string { public: /** * @brief 替换 * @param value * @param old_str * @param new_str * @return */ static std::string replace(std::string const& value, std::string const& old_str, std::string const& new_str) { std::string result = value; for (std::string::size_type pos(0); pos != std::string::npos; pos += new_str.length()) { pos = result.find(old_str, pos); if (pos != std::string::npos) result.replace(pos, old_str.length(), new_str); else break; } return result; } /** * @brief 分割字符串 * @param value * @return */ static std::vector split(std::string const& value) { std::string c = ","; std::vector result; if (value.empty()) { return result; } std::string strs = value + c; size_t pos = strs.find(c); while (pos != strs.npos) { std::string temp = strs.substr(0, pos); result.push_back(temp); strs = strs.substr(pos + c.size(), strs.size()); pos = strs.find(c); } return result; } /** * @brief * @param values * @return */ static std::string join(std::vector values, std::string c = ",") { std::string result; while (!values.empty()) { if (result.empty()) { result = values[0]; values.erase(values.begin()); } else { result += c + values[0]; values.erase(values.begin()); } } return result; } /** * @brief 删除首尾空格 * @param value * @return */ static std::string trim(std::string const& value) { std::string result = value; while (!result.empty()) { if (result[0] == ' ' || result[0] == '\t' || result[0] == '\r' || result[0] == '\n') result.erase(result.begin()); else break; } while (!result.empty()) { if (result[result.size() - 1] == ' ' || result[result.size() - 1] == '\t' || result[result.size() - 1] == '\r' || result[result.size() - 1] == '\n') result.pop_back(); else break; } return result; } /** * @brief 大括号 * @param code * @param index * @return */ static bool ergodic(std::string& code, std::size_t& index) { index++; for (; index < code.size(); ++index) { if (code[index] == '}' || code[index] == ')') { return true; } else if (code[index] == '{') { ergodic(code, index); } else if (code[index] == '(') { ergodic(code, index); } else if (code[index] == '"') { quotation_mark(code, index); } } return false; } /** * @brief 引号 * @param code * @param index * @return */ static bool quotation_mark(std::string& code, std::size_t& index) { index++; for (; index < code.size(); ++index) { if (code[index] == '"') { return true; } } return false; } /** * @brief * @return */ static unsigned int random_char() { std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<> dis(0, 255); return dis(gen); } /** * @brief * @param len * @return */ static std::string generate_hex(const unsigned int len) { std::stringstream ss; for (unsigned int i = 0; i < len; i++) { const auto rc = random_char(); std::stringstream hexstream; hexstream << std::hex << rc; auto hex = hexstream.str(); ss << (hex.length() < 2 ? '0' + hex : hex); } return ss.str(); } /** * @brief 当前时间 * @return */ static std::string current_time() { std::time_t timestamp = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); std::tm now_time; #ifdef WINDOWS_BUILD localtime_s(&now_time, ×tamp); #elif LINUX_BUILD localtime_r(×tamp, &now_time); #endif std::stringstream ss; ss << std::put_time(&now_time, "%Y-%m-%d %H:%M:%S"); return ss.str(); } }; /** * @brief 正则表达式 */ class regex { public: /** * @brief 特性 * @return */ static std::regex& attribute() { static std::regex value("\\[\\[[ \t]{0,30}(ActionType|Method|Authen|Route|ContentType|FileMapping|Json|NoJson|Sql|NoSql|SqlKey|Excel|NoExcel|NoArchive|NoReflect|SqlTable|TemplateType|FromQuery|FromBody|FromHeader|FromUrl|Version|Namespace|Wsdl)[ \t]{0,30}\\([ \t]{0,30}([\\s\\S]*?)[ \t]{0,30}\\)\\]\\]"); return value; } /** * @brief 属性 * @return */ static std::regex& property() { static std::regex value("(\\[\\[[\\s\\S]*?\\]\\]|)[ \r\n\t]{0,100}(int|bool|double|float|std::int64_t|v3::datetime|std::string|std::vector<[a-zA-Z_0-9]{1,100}>|[a-zA-Z_0-9]{1,100})[ \t]{1,30}([a-zA-Z_0-9]{1,100})[^;]*;"); return value; } /** * @brief 方法 * @return */ static std::regex& method() { static std::regex value("(\\[\\[[\\s\\S]*?\\]\\]|)[ \r\n\t]{0,100}(WebResponse|SoapResponse)[ \r\n\t]{1,30}([a-zA-Z_0-9]{1,100})[ \r\n\t]{0,30}\\(([a-zA-Z0-9\",\\[\\], \r\n\t:<>_\\(\\)]{0,500})\\)"); return value; } /** * @brief 类 * @return */ static std::regex& class_() { static std::regex value("(template[ \r\n\t]{0,30}<[\\s\\S]{1,100}>|)[ \r\n\t]{1,30}(struct|class)[ \r\n\t]{1,30}(\\[\\[[\\s\\S]*?\\]\\]|)[ \r\n\t]{0,30}([a-zA-Z_0-9]{1,200})"); return value; } /** * @brief 模板 * @return */ static std::regex& template_() { static std::regex value("template[ \r\n\t]{0,30}<([\\s\\S]{1,100})>"); return value; } /** * @brief 参数 * @return */ static std::regex& parameter() { static std::regex value("(\\[\\[[ \t]{0,30}(FromQuery|FromBody|FromHeader|FromUrl)[ \t]{0,30}\\([ \t]{0,30}([\\s\\S]*?)[ \t]{0,30}\\)\\]\\]|)[ \r\n\t]{0,100}([a-zA-Z_0-9:<>]{1,100})[ \t\r\n]{1,100}([a-zA-Z_0-9]{1,100})"); return value; } }; /** * @brief 特性 */ class attribute { public: //查找 static std::vector find(std::vector const& src, std::string const& attribute); }; }; struct class_attribute_info { class_attribute_info() {} class_attribute_info(std::string code) : content(code) { deserialize(code); } std::string content; std::string attribute; bool bool_value = false; std::string string_value; std::vector vector_string_value; std::vector vector_bool_value; private: /** * @brief * @param code */ void deserialize(std::string code) { std::smatch smatch; if (std::regex_search(code, smatch, utils::regex::attribute())) { if (smatch.size() == 3) { std::vector item; attribute = smatch[1]; get_value(smatch[2]); } } } /** * @brief 获取值 * @param code */ void get_value(std::string code) { if (code.empty()) return; auto params = utils::string::split(code); for (auto it : params) { it = utils::string::trim(it); if (attribute == "TemplateType") { if (it == "false" || it == "true") { vector_bool_value.push_back(it == "true"); } else if (it.find('"') != std::string::npos) { vector_string_value.push_back(it.substr(1, it.size() - 2)); } } else { if (it == "false" || it == "true") { bool_value = it == "true"; } else if (it.find('"') != std::string::npos) { string_value = it.substr(1, it.size() - 2); } } } } }; std::vector utils::attribute::find(std::vector const& src, std::string const& attribute) { std::vector result; for (auto it : src) { if (it.attribute == attribute) { result.push_back(it); } } return result; } struct class_property_info { class_property_info() {} class_property_info(std::string code) : content(code) { deserialize(code); } std::string content; std::string type; std::string name; std::vector attributes; std::string generate_code() { auto Json = utils::attribute::find(attributes, "Json"); auto Sql = utils::attribute::find(attributes, "Sql"); auto Excel = utils::attribute::find(attributes, "Excel"); auto NoJson = utils::attribute::find(attributes, "NoJson"); auto NoSql = utils::attribute::find(attributes, "NoSql"); auto NoExcel = utils::attribute::find(attributes, "NoExcel"); auto SqlKey = utils::attribute::find(attributes, "SqlKey"); auto NoArchive = utils::attribute::find(attributes, "NoArchive"); return fmt::format("property(\"{}\",&{{0}}::{})(rttr::metadata(\"Json\",\"{}\"),rttr::metadata(\"Sql\",\"{}\"),rttr::metadata(\"Excel\",R\"({})\"),rttr::metadata(\"NoJson\",{}),rttr::metadata(\"NoSql\",{}),rttr::metadata(\"NoExcel\",{}),rttr::metadata(\"SqlKey\",{}),rttr::metadata(\"NoArchive\",{}),rttr::metadata(\"Offset\",robotics::v3::utils::pointer_cast(&{{0}}::{})))", name, name, Json.empty() ? name : Json[0].string_value, Sql.empty() ? name : Sql[0].string_value, Excel.empty() ? name : Excel[0].string_value, NoJson.empty() ? "false" : (NoJson[0].bool_value ? "true" : "false"), NoSql.empty() ? "false" : (NoSql[0].bool_value ? "true" : "false"), NoExcel.empty() ? "false" : (NoExcel[0].bool_value ? "true" : "false"), SqlKey.empty() ? "false" : (SqlKey[0].bool_value ? "true" : "false"), NoArchive.empty() ? "false" : (NoArchive[0].bool_value ? "true" : "false"), name); } private: /** * @brief 反序列化 * @param code */ void deserialize(std::string code) { std::smatch smatch; if (std::regex_search(code, smatch, utils::regex::property())) { if (smatch.size() == 4) { type = smatch[2]; name = smatch[3]; for (auto& it : get_attributes(smatch[1])) { attributes.push_back(class_attribute_info(it)); } } } } /** * @brief 获取特性列表 * @param code * @return */ std::vector get_attributes(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::attribute())) { if (smatch.size() == 3) { result.push_back(smatch[0]); } code = smatch.suffix(); } return result; } }; struct class_parameter_info { class_parameter_info() {} class_parameter_info(std::string code) : content(code) { deserialize(code); } std::string content; std::string type; std::string name; std::vector attributes; std::string generate_cntlr_code(std::string const& method_type) { static std::map type_map = { {"int", "robotics::v3::mvc::argument_type::Int"}, {"std::int64_t", "robotics::v3::mvc::argument_type::Int64"}, {"float", "robotics::v3::mvc::argument_type::Float"}, {"double", "robotics::v3::mvc::argument_type::Double"}, {"long", "robotics::v3::mvc::argument_type::Long"}, {"bool", "robotics::v3::mvc::argument_type::Bool_"}, {"std::string", "robotics::v3::mvc::argument_type::String"}, {"robotics::v3::datetime", "robotics::v3::mvc::argument_type::DateTime"}, {"v3::datetime", "robotics::v3::mvc::argument_type::DateTime"}, {"datetime", "robotics::v3::mvc::argument_type::DateTime"}, {"std::vector", "robotics::v3::mvc::argument_type::Binary"}, {"std::vector", "robotics::v3::mvc::argument_type::VecInt"}, {"std::vector", "robotics::v3::mvc::argument_type::VecInt64"}, {"std::vector", "robotics::v3::mvc::argument_type::VecFloat"}, {"std::vector", "robotics::v3::mvc::argument_type::VecDouble"}, {"std::vector", "robotics::v3::mvc::argument_type::VecLong"}, {"std::vector", "robotics::v3::mvc::argument_type::VecBool"}, {"std::vector", "robotics::v3::mvc::argument_type::VecString"}, {"std::vector", "robotics::v3::mvc::argument_type::VecDateTime"}, {"std::vector", "robotics::v3::mvc::argument_type::VecDateTime"}, {"std::vector", "robotics::v3::mvc::argument_type::VecDateTime"}, {"VecJson", "robotics::v3::mvc::argument_type::VecJson"}, {"Json", "robotics::v3::mvc::argument_type::Json"}, {"Multipart", "robotics::v3::mvc::argument_type::Multipart"} }; auto FromQuery = utils::attribute::find(attributes, "FromQuery"); auto FromBody = utils::attribute::find(attributes, "FromBody"); auto FromHeader = utils::attribute::find(attributes, "FromHeader"); auto FromUrl = utils::attribute::find(attributes, "FromUrl"); std::stringstream ss; ss << "\t\t{" << std::endl; ss << "\t\t\tstd::shared_ptr argument(new robotics::v3::mvc::action_argument());" << std::endl; if (type_map.contains(type)) { ss << "\t\t\targument->argument_type_ = " << type_map[type] << ";" << std::endl; if (method_type == "POST") { if (!FromQuery.empty()) { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::QUERY;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", FromQuery[0].string_value.empty() ? name : FromQuery[0].string_value) << std::endl; } else if (!FromBody.empty()) { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::BODY;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", FromBody[0].string_value) << std::endl; } else if (!FromHeader.empty()) { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::HEADER;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", FromHeader[0].string_value.empty() ? name : FromHeader[0].string_value) << std::endl; } else { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::BODY;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", name) << std::endl; } } else { if (!FromQuery.empty()) { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::QUERY;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", FromQuery[0].string_value.empty() ? name : FromQuery[0].string_value) << std::endl; } else if (!FromUrl.empty()) { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::URL;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", FromUrl[0].string_value.empty() ? name : FromUrl[0].string_value) << std::endl; } else if (!FromHeader.empty()) { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::HEADER;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", FromHeader[0].string_value.empty() ? name : FromHeader[0].string_value) << std::endl; } else { ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::QUERY;" << std::endl; ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", name) << std::endl; } } } else if (type == "robotics::v3::mvc::multipart_value" || type == "v3::mvc::multipart_value" || type == "mvc::multipart_value") { ss << "\t\t\targument->argument_type_ = " << type_map["Multipart"] << ";" << std::endl; ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::BODY;" << std::endl; ss << "\t\t\targument->parameter_name_ = \"\";" << std::endl; } else if (type.size() > 12 && type.substr(0, 11) == "std::vector") { ss << "\t\t\targument->argument_type_ = " << type_map["VecJson"] << ";" << std::endl; ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::BODY;" << std::endl; ss << "\t\t\targument->parameter_name_ = \"\";" << std::endl; } else { ss << "\t\t\targument->argument_type_ = " << type_map["Json"] << ";" << std::endl; ss << "\t\t\targument->from_storage_type_ = robotics::v3::mvc::from_storage_type::BODY;" << std::endl; ss << "\t\t\targument->parameter_name_ = \"\";" << std::endl; } ss << "\t\t\taction->arguments.push_back(argument);" << std::endl; ss << "\t\t}" << std::endl; return ss.str(); } std::string generate_soap_code() { static std::map type_map = { {"int","robotics::v3::soap_argument_type::Int"}, {"std::int64_t","robotics::v3::soap_argument_type::Int64"}, {"float","robotics::v3::soap_argument_type::Float"}, {"double","robotics::v3::soap_argument_type::Double"}, {"long","robotics::v3::soap_argument_type::Long"}, {"bool","robotics::v3::soap_argument_type::Bool_"}, {"std::string","robotics::v3::soap_argument_type::String"}, {"robotics::v3::datetime","robotics::v3::soap_argument_type::DateTime"}, {"v3::datetime","robotics::v3::soap_argument_type::DateTime"}, {"datetime","robotics::v3::soap_argument_type::DateTime"} }; std::stringstream ss; ss << "\t\t{" << std::endl; ss << "\t\t\tstd::shared_ptr argument(new robotics::v3::soap_action_argument());" << std::endl; if (type_map.contains(type)) { ss << fmt::format("\t\t\targument->argument_type_ = {};", type_map[type]) << std::endl; } ss << fmt::format("\t\t\targument->parameter_name_ = \"{}\";", name) << std::endl; ss << "\t\t\taction->arguments.push_back(argument);" << std::endl; ss << "\t\t}" << std::endl; return ss.str(); } private: /** * @brief 反序列化 * @param code */ void deserialize(std::string code) { std::smatch smatch; if (std::regex_search(code, smatch, utils::regex::parameter())) { if (smatch.size() == 6) { type = smatch[4]; name = smatch[5]; for (auto& it : get_attributes(smatch[1])) { attributes.push_back(class_attribute_info(it)); } } } } /** * @brief 获取特性列表 * @param code * @return */ std::vector get_attributes(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::attribute())) { if (smatch.size() == 3) { result.push_back(smatch[0]); } code = smatch.suffix(); } return result; } }; struct class_method_info { class_method_info() {} class_method_info(std::string code) : content(code) { deserialize(code); } std::string content; std::string result; std::string name; std::string signature; std::vector parameters; std::vector attributes; std::string generate_code() { if (parameters.empty()) { return fmt::format("method(\"{}\",&{{}}::{})", name, name); } else { std::vector param_names; std::vector param_types; for (auto& it : parameters) { param_names.push_back(fmt::format("\"{}\"", it.name)); param_types.push_back(fmt::format("{}{{{{}}}}", it.type)); } return fmt::format("method(\"{}\",&{{}}::{})(rttr::default_arguments({}),rttr::parameter_names({}))", name, name, utils::string::join(param_types, ","), utils::string::join(param_names, ",")); } } std::string generate_cntlr_code() { std::stringstream ss; auto ActionType = utils::attribute::find(attributes, "ActionType"); auto Method = utils::attribute::find(attributes, "Method"); auto Authen = utils::attribute::find(attributes, "Authen"); auto Route = utils::attribute::find(attributes, "Route"); auto ContentType = utils::attribute::find(attributes, "ContentType"); auto FileMapping = utils::attribute::find(attributes, "FileMapping"); ss << "\t{" << std::endl; ss << "\t\tstd::shared_ptr action(new robotics::v3::mvc::controller_action());" << std::endl; for (auto& it : parameters) { if (!Method.empty()) { ss << it.generate_cntlr_code(Method[0].string_value == "POST" ? "POST" : "GET"); } else { ss << it.generate_cntlr_code("GET"); } } ss << fmt::format("\t\taction->action_name = \"{}\";", name) << std::endl; ss << "\t\taction->parent = controller;" << std::endl; if (!Authen.empty()) { ss << fmt::format("\t\taction->authen = {};", Authen[0].bool_value ? "true" : "false") << std::endl; ss << fmt::format("\t\taction->authen_jump = \"{}\";", Authen[0].string_value) << std::endl; } else { ss << "\t\taction->authen = true;" << std::endl; ss << "\t\taction->authen_jump = \"\";" << std::endl; } if (!ContentType.empty()) { ss << fmt::format("\t\taction->content_type = \"{}\";", ContentType[0].string_value.empty() ? "application/x-www-form-urlencoded" : ContentType[0].string_value) << std::endl; } else { ss << "\t\taction->content_type = \"application/x-www-form-urlencoded\";" << std::endl; } if (!ActionType.empty()) { ss << fmt::format("\t\taction->action_type = \"{}\";", ActionType[0].string_value) << std::endl; } else { ss << "\t\taction->action_type = \"\";" << std::endl; } if (!FileMapping.empty()) { ss << fmt::format("\t\taction->file_mapping = \"{}\";", FileMapping[0].string_value) << std::endl; } else { ss << "\t\taction->file_mapping = \"\";" << std::endl; } if (!Method.empty()) { if (Method[0].string_value == "POST") { ss << "\t\taction->method = robotics::v3::mvc::http_method::POST;" << std::endl; } else { ss << "\t\taction->method = robotics::v3::mvc::http_method::GET;" << std::endl; } } else { ss << "\t\taction->method = robotics::v3::mvc::http_method::GET;" << std::endl; } if (!Route.empty()) { ss << fmt::format("\t\tcontroller->actions[\"{}\"] = action;", Route[0].string_value.empty() ? name : Route[0].string_value) << std::endl; } else { ss << fmt::format("\t\tcontroller->actions[\"{}\"] = action;", name) << std::endl; } ss << "\t}" << std::endl; return ss.str(); } std::string generate_soap_code() { auto Method = utils::attribute::find(attributes, "Method"); std::stringstream ss; ss << "\t{" << std::endl; ss << "\t\tstd::shared_ptr action(new robotics::v3::soap_controller_action());" << std::endl; for (auto& it : parameters) { ss << it.generate_soap_code(); } ss << fmt::format("\t\taction->action_name = \"{}\";", name) << std::endl; if (!Method.empty()) { ss << fmt::format("\t\tcontroller->actions[\"{}\"] = action;", Method[0].string_value.empty() ? name : Method[0].string_value) << std::endl; } else { ss << fmt::format("\t\tcontroller->actions[\"{}\"] = action;", name) << std::endl; } ss << "\t}" << std::endl; return ss.str(); } private: /** * @brief 反序列化 * @param code */ void deserialize(std::string code) { std::smatch smatch; if (std::regex_search(code, smatch, utils::regex::method())) { if (smatch.size() == 5) { std::vector params; result = smatch[2]; name = smatch[3]; for (auto& it : get_parameters(smatch[4])) { parameters.push_back(class_parameter_info(it)); params.push_back(parameters[parameters.size() - 1].type); } for (auto& it : get_attributes(smatch[1])) { attributes.push_back(class_attribute_info(it)); } signature = result + "(" + utils::string::join(params) + ")"; } } } /** * @brief 获取特性列表 * @param code * @return */ std::vector get_attributes(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::attribute())) { if (smatch.size() == 3) { result.push_back(smatch[0]); } code = smatch.suffix(); } return result; } /** * @brief 获取参数列表 * @param code * @return */ std::vector get_parameters(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::parameter())) { if (smatch.size() == 6) { result.push_back(smatch[0]); } code = smatch.suffix(); } return result; } }; struct class_view_info { class_view_info() {} class_view_info(std::string code, int type) : content(code), class_type(type) { deserialize(code); } int class_type = 0; std::string content; std::string type; std::string name; bool is_tmpl = false; std::vector tmpl_params; std::vector attributes; std::vector propertys; std::vector cntlr_methods; std::vector soap_methods; std::pair generate_code() { std::stringstream ss; std::string funcname = fmt::format("func_{}()", utils::string::generate_hex(16)); ss << "static void " << funcname << " {" << std::endl; if (class_type == 0) { auto SqlTable = utils::attribute::find(attributes, "SqlTable"); auto NoReflect = utils::attribute::find(attributes, "NoReflect"); auto TemplateType = utils::attribute::find(attributes, "TemplateType"); if (NoReflect.empty() || (!NoReflect.empty() && !NoReflect[0].bool_value)) { if (!is_tmpl) { std::vector item; item.push_back(fmt::format("\trttr::registration::class_<{} {}>(\"{}\").constructor<>()(rttr::detail::as_object{{}})", type, name, SqlTable.empty() ? name : SqlTable[0].string_value)); for (auto it : propertys) { item.push_back(fmt::vformat(it.generate_code(), fmt::make_format_args(name))); } if (item.size() > 1) { ss << utils::string::join(item, ".\n\t\t") << ";" << std::endl; } } else { std::vector class_propertys; for (auto it : propertys) { class_propertys.push_back(it.generate_code()); } for (auto it : TemplateType) { std::vector item; std::string tablename = name + "<" + utils::string::join(it.vector_string_value, ",") + ">"; item.push_back(fmt::format("\trttr::registration::class_<{} {}>(\"{}\").constructor<>()(rttr::detail::as_object{{}})", type, tablename, tablename)); for (auto it1 : class_propertys) { item.push_back(fmt::vformat(it1, fmt::make_format_args(tablename))); } if (item.size() > 1) { ss << utils::string::join(item, ".\n\t\t") << ";" << std::endl; } } } } } else if (class_type == 1) { auto NoReflect = utils::attribute::find(attributes, "NoReflect"); if (NoReflect.empty() || (!NoReflect.empty() && !NoReflect[0].bool_value)) { std::vector item; item.push_back(fmt::format("\trttr::registration::class_<{} {}>(\"{}\").constructor<>()()", type, name, name)); for (auto it : cntlr_methods) { item.push_back(fmt::vformat(it.generate_code(), fmt::make_format_args(name))); } if (item.size() > 1) { ss << utils::string::join(item, ".\n\t\t") << ";" << std::endl; } } ss << "\tstd::shared_ptr controller(new robotics::v3::mvc::controller());" << std::endl; for (auto& it : cntlr_methods) { ss << it.generate_cntlr_code(); } ss << fmt::format("\tcontroller->controller_name = \"{}\";", name) << std::endl; ss << "\trobotics::v3::mvc::ico_controller::attach(controller);" << std::endl; } else if (class_type == 2) { auto NoReflect = utils::attribute::find(attributes, "NoReflect"); auto Route = utils::attribute::find(attributes, "Route"); auto Version = utils::attribute::find(attributes, "Version"); auto Namespace = utils::attribute::find(attributes, "Namespace"); auto Wsdl = utils::attribute::find(attributes, "Wsdl"); if (NoReflect.empty() || (!NoReflect.empty() && !NoReflect[0].bool_value)) { std::vector item; item.push_back(fmt::format("\trttr::registration::class_<{} {}>(\"{}\").constructor<>()()", type, name, name)); for (auto it : soap_methods) { item.push_back(fmt::vformat(it.generate_code(), fmt::make_format_args(name))); } if (item.size() > 1) { ss << utils::string::join(item, ".\n\t\t") << ";" << std::endl; } ss << "\tstd::shared_ptr controller(new robotics::v3::soap_controller());" << std::endl; for (auto& it : soap_methods) { ss << it.generate_soap_code(); } ss << fmt::format("\tcontroller->controller_name = \"{}\";", name) << std::endl; if (!Wsdl.empty()) { ss << fmt::format("\tcontroller->wsdl = \"{}\";", Wsdl[0].string_value) << std::endl; } else { ss << "\tstatic_assert(false, \"wsdl path error\");" << std::endl; } if (!Route.empty()) { ss << fmt::format("\tcontroller->route = \"{}\";", Route[0].string_value) << std::endl; } else { ss << "\tstatic_assert(false, \"route path error\");" << std::endl; } if (!Namespace.empty()) { ss << fmt::format("\tcontroller->namespace_name = \"{}\";", Namespace[0].string_value) << std::endl; } else { ss << "\tstatic_assert(false, \"namespace path error\");" << std::endl; } if (!Version.empty()) { ss << fmt::format("\tcontroller->version = {};", Version[0].string_value == "1.1" ? "robotics::v3::soap_version::VER1_1" : "robotics::v3::soap_version::VER1_2") << std::endl; } else { ss << "\tcontroller->version = robotics::v3::soap_version::VER1_1;" << std::endl; } ss << "\trobotics::v3::soap_ioc_controller::attach(controller);" << std::endl; } } ss << "}" << std::endl; return std::pair(funcname, ss.str()); } private: /** * @brief * @param code */ void deserialize(std::string code) { std::smatch smatch; if (std::regex_search(code, smatch, utils::regex::class_())) { if (smatch.size() == 5) { std::string tmp_code = smatch.suffix(); std::size_t index = tmp_code.find('{'); if (index != std::string::npos && utils::string::ergodic(tmp_code, index)) { tmpl_params = get_tmpl_params(smatch[1]); type = smatch[2]; name = smatch[4]; is_tmpl = !smatch[1].str().empty(); for (auto& it : get_attributes(smatch[3])) { attributes.push_back(class_attribute_info(it)); } if (class_type == 0) { for (auto& it : get_propertys(tmp_code.substr(0, index + 1))) { propertys.push_back(class_property_info(it)); } } else if (class_type == 1) { for (auto& it : get_methods(tmp_code.substr(0, index + 1))) { cntlr_methods.push_back(class_method_info(it)); } } else if (class_type == 2) { for (auto& it : get_methods(tmp_code.substr(0, index + 1))) { soap_methods.push_back(class_method_info(it)); } } code = smatch.suffix().str().substr(index + 1); } else { code = smatch.suffix(); } } else { code = smatch.suffix(); } } } /** * @brief 获取特性列表 * @param code * @return */ std::vector get_attributes(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::attribute())) { if (smatch.size() == 3) { result.push_back(smatch[0]); } code = smatch.suffix(); } return result; } /** * @brief 获取模板参数名称 * @param code * @return */ std::vector get_tmpl_params(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::template_())) { if (smatch.size() == 2) { auto params = utils::string::split(smatch[1]); for (auto it : params) { it = utils::string::replace(it, "typename", ""); result.push_back(utils::string::trim(it)); } } code = smatch.suffix(); } return result; } /** * @brief 获取属性列表 * @param code * @return */ std::vector get_propertys(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::property())) { if (smatch.size() == 4) { result.push_back(smatch[0]); } code = smatch.suffix(); } return result; } /** * @brief * @param code * @return */ std::vector get_methods(std::string code) { std::vector result; std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::method())) { if (smatch.size() == 5) { result.push_back(smatch[0]); } code = smatch.suffix(); } return result; } }; struct class_code_info { class_code_info() {} class_code_info(std::string code, int _type, std::string path, std::string relative_path) : content(code), type(_type), root_directory(path), relative_directory(relative_path) { deserialize(code); } //0实体类,1web控制器,2saop控制器 int type = 0; std::string root_directory; std::string content; std::string relative_directory; std::vector views; std::pair, std::string> generate_code() { std::vector funclist; std::stringstream ss; for (auto& it : views) { auto view_code = it.generate_code(); funclist.push_back(view_code.first); ss << view_code.second; } return std::pair(funclist, ss.str()); } private: /** * @brief * @param code */ void deserialize(std::string code) { delete_excess(code); std::smatch smatch; while (std::regex_search(code, smatch, utils::regex::class_())) { if (smatch.size() == 5) { std::string src = smatch[0]; std::string tmp_code = smatch.suffix(); std::size_t index = tmp_code.find('{'); if (index != std::string::npos && utils::string::ergodic(tmp_code, index)) { src += tmp_code.substr(0, index + 1); views.push_back(class_view_info(src, type)); code = smatch.suffix().str().substr(index + 1); } else { code = smatch.suffix(); } } else { code = smatch.suffix(); } } } /** * @brief 删除注释 * @param code */ void delete_excess(std::string& code) { static std::vector> notes = { {"/*","*/"}, {"//","\n"}, {"#include","\n"}, {"#pragma", "\n"}, {"#ifndef", "\n"}, {"#define", "\n"}, {"#if", "\n"}, {"#endif", "\n"} }; for (auto& note : notes) { std::size_t begin = 0; std::size_t end = 0; while ((begin = code.find(note.first, begin)) != std::string::npos && (end = code.find(note.second, begin)) != std::string::npos) { if (begin > 0 && code[begin - 1] == ':') { begin += note.second.size(); continue; } code.erase(begin, end - begin + note.second.size()); code.insert(code.begin() + begin, ' '); begin++; } } } }; class code_analysis { public: static std::string generate_code(std::string const& path) { std::stringstream ss; std::vector funclist; //解析代码 auto values = code_analysis(path).get_class_code(); //生成时间 ss << "//生成时间:" << utils::string::current_time() << std::endl; ss << "#pragma once" << std::endl; ss << "#include " << std::endl; ss << "#include " << std::endl; //头文件 for (auto& it : values) { ss << "#include \"" << it.relative_directory << "\"" << std::endl; } ss << std::endl; for (auto& it : values) { auto view_code = it.generate_code(); funclist.insert(funclist.end(), view_code.first.begin(), view_code.first.end()); ss << view_code.second; } ss << "RTTR_REGISTRATION {" << std::endl; ss << "\t" << utils::string::join(funclist, ";\n\t") << ";" << std::endl; ss << "}" << std::endl; return ss.str(); } static std::vector get_class_code(std::string const& path) { return code_analysis(path).get_class_code(); } private: code_analysis(std::string const& path) : path_(path) { path_ = utils::string::replace(path_, "\\", "/"); if (path_[path_.size() - 1] != '/') { path_ += '/'; } } std::vector get_class_code() { std::vector result; auto values = get_models(); result.insert(result.end(), values.begin(), values.end()); values = get_controllers(); result.insert(result.end(), values.begin(), values.end()); values = get_webservices(); result.insert(result.end(), values.begin(), values.end()); return result; } std::vector get_models() { std::vector result; for (auto& it : get_files(path_ + "models", { ".h" })) { result.push_back(class_code_info(get_code(path_ + it), 0, path_, it)); } return result; } std::vector get_controllers() { std::vector result; for (auto& it : get_files(path_ + "controllers", { ".hpp" })) { result.push_back(class_code_info(get_code(path_ + it), 1, path_, it)); result[result.size() - 1].root_directory = path_; result[result.size() - 1].relative_directory = it; result[result.size() - 1].type = 1; } return result; } std::vector get_webservices() { std::vector result; for (auto& it : get_files(path_ + "webservices", { ".hpp" })) { result.push_back(class_code_info(get_code(path_ + it), 2, path_, it)); result[result.size() - 1].root_directory = path_; result[result.size() - 1].relative_directory = it; result[result.size() - 1].type = 2; } return result; } std::string get_code(std::string const& path) { std::ifstream file(path, std::ios::out); if (file.is_open()) { return std::string((std::istreambuf_iterator(file)), std::istreambuf_iterator()); } return ""; } std::vector get_files(std::string const& path, std::vector const& extension) { std::vector result; if (!std::filesystem::is_directory(path)) { return result; } for (auto& itr : std::filesystem::directory_iterator(path)) { if (std::filesystem::is_directory(itr.status())) { auto values = get_files(itr.path().string(), extension); result.insert(result.end(), values.begin(), values.end()); } else { if (std::find(extension.begin(), extension.end(), itr.path().extension()) != extension.end()) { std::string tmp = itr.path().string(); tmp = utils::string::replace(tmp, "\\", "/"); tmp = utils::string::replace(tmp, path_, ""); result.push_back(tmp); } } } return result; } private: std::string path_; }; }