216 lines
7.7 KiB
C++
216 lines
7.7 KiB
C++
|
#include "Parser.hpp"
|
||
|
#include <iostream>
|
||
|
#include <regex>
|
||
|
#include <unordered_set>
|
||
|
#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<char>& 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<std::string> definitions;
|
||
|
std::vector<std::tuple<int, std::string>> 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<std::tuple<std::string, int>> 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;
|
||
|
}
|
||
|
}
|