patterns: Rewrite evaluation engine (#306)

* patterns: Rewrite most of the evaluator to mainly use polymorphism instead of just RTTI

* patterns: Fixed a couple of AST memory leaks

* patterns: Parse string operations correctly

* patterns: Various fixes and cleanup

* patterns: Implement primitive function definitions

Function parameters now need to provide their type in the definition

* patterns: Added function variable definition and assignment

* patterns: Added remaining function statements

* patterns: Added unsized and while-sized arrays

* patterns: Added multi variable declarations to functions

* patterns: Added std::format built-in function

* patterns: Allow passing custom types to functions

* patterns: Added attributes and new "format" attribute

* patterns: Use libfmt for std::print instead of custom version

* patterns: Remove unnecessary string compare function

* pattern: Fix preprocessor directives

* patterns: Fix unit tests

* patterns: Added cast expression

* patterns: Handle endianess in function parameters

* patterns: Added casting to different endian

* patterns: Added 'str' type for functions
This commit is contained in:
WerWolv
2021-09-21 21:29:18 +02:00
committed by GitHub
parent ed9e463550
commit c051f5d3e7
25 changed files with 2000 additions and 1903 deletions

View File

@@ -6,8 +6,12 @@
#include <string>
#include <variant>
#include <hex/helpers/utils.hpp>
namespace hex::pl {
class PatternData;
class Token {
public:
enum class Type : u64 {
@@ -31,6 +35,7 @@ namespace hex::pl {
If,
Else,
Parent,
This,
While,
Function,
Return,
@@ -85,6 +90,7 @@ namespace hex::pl {
Boolean = 0x14,
Float = 0x42,
Double = 0x82,
String = 0x15,
CustomType = 0x00,
Padding = 0x1F,
@@ -108,8 +114,21 @@ namespace hex::pl {
EndOfProgram
};
using IntegerLiteral = std::variant<char, bool, u8, s8, u16, s16, u32, s32, u64, s64, u128, s128, float, double>;
using ValueTypes = std::variant<Keyword, std::string, Operator, IntegerLiteral, ValueType, Separator>;
struct Identifier {
explicit Identifier(std::string identifier) : m_identifier(std::move(identifier)) { }
[[nodiscard]]
const std::string &get() const { return this->m_identifier; }
auto operator<=>(const Identifier&) const = default;
bool operator==(const Identifier&) const = default;
private:
std::string m_identifier;
};
using Literal = std::variant<char, bool, u128, s128, double, std::string, PatternData*>;
using ValueTypes = std::variant<Keyword, Identifier, Operator, Literal, ValueType, Separator>;
Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) {
@@ -131,6 +150,58 @@ namespace hex::pl {
return static_cast<u32>(type) >> 4;
}
static u128 literalToUnsigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> u128 { throw std::string("expected integral type, got string"); },
[](PatternData*) -> u128 { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> u128 { return value; }
},
literal);
}
static s128 literalToSigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> s128 { throw std::string("expected integral type, got string"); },
[](PatternData*) -> s128 { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> s128 { return value; }
},
literal);
}
static double literalToFloatingPoint(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> double { throw std::string("expected integral type, got string"); },
[](PatternData*) -> double { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> double { return value; }
},
literal);
}
static bool literalToBoolean(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> bool { throw std::string("expected integral type, got string"); },
[](PatternData*) -> bool { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> bool { return value != 0; }
},
literal);
}
static std::string literalToString(const pl::Token::Literal &literal, bool cast) {
if (!cast && std::get_if<std::string>(&literal) == nullptr)
throw std::string("expected string type, got integral");
return std::visit(overloaded {
[](std::string value) -> std::string { return value; },
[](u128 value) -> std::string { return std::to_string(u64(value)); },
[](s128 value) -> std::string { return std::to_string(s64(value)); },
[](bool value) -> std::string { return value ? "true" : "false"; },
[](char value) -> std::string { return std::string() + value; },
[](PatternData*) -> std::string { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> std::string { return std::to_string(value); }
},
literal);
}
[[nodiscard]] constexpr static auto getTypeName(const pl::Token::ValueType type) {
switch (type) {
case ValueType::Signed8Bit: return "s8";
@@ -147,6 +218,7 @@ namespace hex::pl {
case ValueType::Double: return "double";
case ValueType::Character: return "char";
case ValueType::Character16: return "char16";
case ValueType::Padding: return "padding";
default: return "< ??? >";
}
}
@@ -204,14 +276,15 @@ namespace hex::pl {
#define KEYWORD_IF COMPONENT(Keyword, If)
#define KEYWORD_ELSE COMPONENT(Keyword, Else)
#define KEYWORD_PARENT COMPONENT(Keyword, Parent)
#define KEYWORD_THIS COMPONENT(Keyword, This)
#define KEYWORD_WHILE COMPONENT(Keyword, While)
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::IntegerLiteral(u64(0))
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""
#define STRING hex::pl::Token::Type::String, ""
#define STRING hex::pl::Token::Type::String, hex::pl::Token::Literal("")
#define OPERATOR_AT COMPONENT(Operator, AtDeclaration)
#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment)