#include "Parser.hpp" #include #include #include #include "TypeDefResult.hpp" #include "angelscript.h" namespace ASTypeDefParser { std::string trim(const std::string& str) { size_t first = str.find_first_not_of(" \r\n\t"); if (std::string::npos == first) { return str; } size_t last = str.find_last_not_of(" \r\n\t"); return str.substr(first, (last - first + 1)); } static std::string ReadUpTo(const std::string& data, size_t& index, const std::unordered_set& chars, char& lastChar) { std::stringstream s; while (index < data.size()) { lastChar = data.at(index); if (lastChar == ' ' || lastChar == '\t' || lastChar == '\n' || lastChar == '\r') { index++; continue; } else { break; } } while (index < data.size()) { lastChar = data.at(index); if (chars.contains(lastChar)) { break; } s << lastChar; index++; } return s.str(); } #define Assert(expression) \ if (!(expression)) { \ throw std::logic_error("Failed assertion: " #expression); \ } std::regex templateTypeCleaner("class "); std::regex propertyCleaner(R"((.*?)\s*(\w+)\s*\{\s*(get)?\s*(const)?;*\s*(set)?\s*(const)?;*\s*\})"); static void ParseType(const std::string& type, TypeDefResult& result, const std::string& data, size_t& index) { char end; auto def = trim(ReadUpTo(data, index, {'{', ';'}, end)); long flags; if (type == "type"){ flags = asOBJ_REF | asOBJ_NOCOUNT; } else if (type == "valuetype"){ flags = asOBJ_VALUE; } std::string className = def; if (def.find('<') != std::string::npos) { flags |= asOBJ_TEMPLATE; className = std::regex_replace(className, templateTypeCleaner, ""); } std::vector definitions; std::vector> behaviours; if (end == '{') { index++; while (index <= data.size()) { if (data.at(index) == '}') { break; } auto innerDef = trim(ReadUpTo(data, index, {';'}, end)); index++; if (innerDef.empty()) { continue; } if (innerDef == "}") { break; } if (innerDef.find("behave") == 0){ char c; size_t pos = 0; ReadUpTo(innerDef, pos, {'b'}, c); ReadUpTo(innerDef, pos, {' '}, c); pos++; auto behaviour = ReadUpTo(innerDef, pos, {' '}, c); auto i = std::stoi(behaviour); auto d = ReadUpTo(innerDef, pos, {';'}, c); behaviours.emplace_back(i, d); } // Ugly hack for properties. else if (innerDef.find('{') != std::string::npos) { index--; innerDef += ReadUpTo(data, index, {'}'}, end) + end; index++; std::smatch m; if (std::regex_search(innerDef, m, propertyCleaner)) { auto ret = m[1].str(); auto name = m[2].str(); if (m.size() > 3) { if (m[3].str() == "get") { bool isConst = m.size() > 4 && m[4].str() == "const"; auto decl = ret + " get_" + name + "() "; if (isConst) { decl += "const "; } decl += "property"; definitions.push_back(decl); } } if (m.size() > 5) { if (m[5].str() == "set") { bool isConst = m.size() > 6 && m[6].str() == "const"; auto decl = "void set_" + name + "(" + ret + " value) "; if (isConst) { decl += "const "; } decl += "property"; definitions.push_back(decl); } } } } else { definitions.push_back(innerDef); } } } index++; result.StoreType(type, def, className, flags, definitions, behaviours); } static void ParseEnum(TypeDefResult& result, const std::string& data, size_t& index) { char end; auto def = trim(ReadUpTo(data, index, {'{'}, end)); index++; std::vector> values; auto block = ReadUpTo(data, index, {'}'}, end); size_t innerIndex = 0; int enumValue = 0; while (true) { if (innerIndex >= block.size()) { break; } auto statement = trim(ReadUpTo(block, innerIndex, {',', '}'}, end)); innerIndex++; if (statement.empty()) { continue; } size_t i = 0; char statementEnd; auto first = trim(ReadUpTo(statement, i, {'='}, statementEnd)); if (statementEnd == '=') { i++; auto val = trim(ReadUpTo(statement, i, {}, statementEnd)); auto num = std::stoi(val); enumValue = num; values.emplace_back(first, enumValue); } else { values.emplace_back(first, enumValue); } enumValue++; if (end == '}') { break; } } result.StoreEnum(def, values); } static void ParseFunc(TypeDefResult& result, const std::string& data, size_t& index) { char end; auto statement = ReadUpTo(data, index, {';'}, end); result.StoreFunc(statement); } TypeDefResult Parser::ParseAndRegister(TypeDefResult& result, const std::string& data) { size_t index = 0; while (true) { if (index >= data.size()) { break; } auto c = data[index]; if (c >= 'a' && c <= 'z') { std::stringstream identifier; while (c >= 'a' && c <= 'z') { identifier << c; index++; if (index >= data.size()) { break; } c = data[index]; } auto str = identifier.str(); if (str == "type" || str == "valuetype") { index++; ParseType(str, result, data, index); } else if (str == "enum") { index++; ParseEnum(result, data, index); } else if (str == "func") { index++; ParseFunc(result, data, index); } } index++; } return result; } }