AngelscriptLanguageServer/server/src/src/ASTypeDefParser/Parser.cpp

220 lines
7.8 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 (std::string(" \r\n\t").find(data.at(index)) != std::string::npos){
index++;
continue;
}
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;
}
}