| 110 | } |
| 111 | |
| 112 | Utils::CPP::Struct Utils::CPP::parseDataStruct(const std::string &sourceCode, const std::string &structName) |
| 113 | { |
| 114 | // remove line and multi-line comments |
| 115 | auto code = std::regex_replace(sourceCode, std::regex(R"(//[^\n]*)"), ""); |
| 116 | code = std::regex_replace(code, std::regex(R"(/\*[\s\S]*?\*/)"), ""); |
| 117 | |
| 118 | std::vector<Struct> structs{}; |
| 119 | |
| 120 | // match all structs to get the body of it |
| 121 | std::regex structRegex(R"(P64_DATA\(([\s\S]*?)\);)"); |
| 122 | |
| 123 | std::smatch structMatch; |
| 124 | auto structBegin = code.cbegin(); |
| 125 | |
| 126 | while (std::regex_search(structBegin, code.cend(), structMatch, structRegex)) |
| 127 | { |
| 128 | Struct s{.name = "Data"}; |
| 129 | if (s.name != structName)continue; |
| 130 | |
| 131 | std::string body = structMatch[1]; |
| 132 | |
| 133 | // Regex for attributes + field lines |
| 134 | std::regex fieldRegex( |
| 135 | R"((\[\[\s*([^\]]+)\s*\]\]\s*)?([\w:<>]+)\s+(\w+)(\[[0-9]+\])?(?:\s*\=(.*))?\s*;)" |
| 136 | ); |
| 137 | |
| 138 | std::smatch fieldMatch; |
| 139 | auto fieldBegin = body.cbegin(); |
| 140 | |
| 141 | while (std::regex_search(fieldBegin, body.cend(), fieldMatch, fieldRegex)) |
| 142 | { |
| 143 | Field field{ |
| 144 | .type = fromString(fieldMatch[3]), |
| 145 | .dataSize = getTypeSize(fromString(fieldMatch[3])), |
| 146 | .name = fieldMatch[4], |
| 147 | .attr = parseAttributes(fieldMatch[2]), |
| 148 | .defaultValue = fieldMatch[6], |
| 149 | }; |
| 150 | |
| 151 | // Pre-parse the bitmask attribute for unsigned int fields, so the editor doesn't re-parse each frame. |
| 152 | if (field.type == DataType::u8 || field.type == DataType::u16 || field.type == DataType::u32) { |
| 153 | auto bitmaskAttr = field.attr.find("P64::Bitmask"); |
| 154 | if (bitmaskAttr != field.attr.end()) { |
| 155 | field.bitmask = parseBitmask(bitmaskAttr->second); |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | if(field.type == DataType::string) { |
| 160 | try |
| 161 | { |
| 162 | auto strSize = fieldMatch[5].str(); // -> [42] |
| 163 | field.dataSize = std::stoul(strSize.substr(1, strSize.size() - 2)); // parse without brackets |
| 164 | } catch(...) { |
| 165 | Logger::log( |
| 166 | "Failed to parse size for string field: " + field.name + ", defaulting to 4 bytes.", |
| 167 | Logger::LEVEL_ERROR |
| 168 | ); |
| 169 | field.dataSize = 4; |
nothing calls this directly
no test coverage detected