// Copyright (c) 2023 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "PrefabRegistry.hpp" using namespace Dawn; struct PrefabComponentParserRuleset PrefabRegistry::getRuleset(std::string type) { std::vector pathsToScan; pathsToScan.push_back(this->sources); auto it = pathsToScan.begin(); while(it != pathsToScan.end()) { auto str = *it; pathsToScan.erase(it); Directory dir = Directory(str); auto children = dir.readDirectory(); auto itChildren = children.begin(); while(itChildren != children.end()) { if(itChildren->second == DIRECTORY_CHILD_TYPE_DIRECTORY) { pathsToScan.push_back(str + "/" + itChildren->first); ++itChildren; continue; } if(itChildren->first != type+".hpp") { ++itChildren; continue; } // Load ruleset std::string data; File file(str + "/" + itChildren->first); if(!file.readString(&data)) { std::cout << "Failed to read ruleset file!" << std::endl; return { .name = "" }; } // Begin scanning contentsr // std::string include = this->sources; auto toRemove = File::normalizeSlashes(this->sources + FILE_PATH_SEP); auto includePath = file.filename.substr(toRemove.size(), file.filename.size() - toRemove.size()); // Now locate the first subdir since we don't want to include the root path (e.g. dawn, dawnrose, etc) auto firstSlash = includePath.find(FILE_PATH_SEP); if(firstSlash != std::string::npos) { includePath = includePath.substr(firstSlash + 1, includePath.size() - firstSlash - 1); } struct PrefabComponentParserRuleset ruleset; // Replace all file seps with slashes size_t pos = 0; while ((pos = includePath.find(FILE_PATH_SEP, pos)) != std::string::npos) { includePath.replace(pos, 1, "/"); pos += 1; } ruleset.include = includePath; ruleset.name = type; // Find each instance of "@optional" when it's used within a comment // e.g. // @optional or /* @optional */ in the string data. std::regex regex("^\\s*(?:\\/\\/|\\/\\*){1}\\s*\\@optional\\s*(?:\\*\\/)?\\s*$", std::regex_constants::ECMAScript); std::sregex_iterator it(data.begin(), data.end(), regex); std::sregex_iterator end; while(it != end) { // Find the next ";" auto endPos = data.find(";", it->position() + it->length()); if(endPos == std::string::npos) { std::cout << "Failed to find end of line for optional attribute!" << std::endl; return { .name = "" }; } // Go backwards see if there's an equals sign after the match but before endPos auto equalsPos = data.rfind("=", endPos); // If there's an equals sign, we search backwards from there, // otherwise we search backwards from the ; auto varStart = it->position() + it->length() + 1; size_t lastSearchPos = ( (equalsPos == std::string::npos || equalsPos <= varStart) ? endPos : equalsPos ); // Now we have our string auto varLength = lastSearchPos - varStart; auto variableString = data.substr(varStart, varLength); // Now (should) be able to extract the type; std::regex regex2("^\\s*(?:[\\S]+<)?([\\w*:_\\s]+)(?:[\\S]+)? (\\**[\\w]+)\\s*$", std::regex_constants::ECMAScript); std::smatch match; if(!std::regex_search(variableString, match, regex2)) { std::cout << "Failed to extract type and name from variable string! " << variableString << std::endl; return { .name = "" }; } // Now we have our type and name auto type = match[1].str(); auto name = match[2].str(); ruleset.optional[name] = type; ++it; } return ruleset; ++itChildren; } it = pathsToScan.begin(); }; return { .name = "" }; }