From 78ef07cf0ff196915ff1f29ca9c6c4652729cffe Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sat, 2 Jan 2021 20:27:11 +0100 Subject: [PATCH] Pattern Language rewrite (#111) * Initial parser rewrite effort Lexer and Token cleanup, Parser started over * Greatly improved parser syntax * Reimplemented using declarations and variable placement parsing * Added back unions and structs * Added enums as well as mathematical expressions (+, -, *, /, <<, >>, &, |, ^) * Code style improvement * Implemented arrays and fixed memory issues * Fixed more memory issues in parser, reimplemented validator, evaluator and patterns * Fixed builtin types, arrays and reimplemented strings * Improved error messages * Made character a distinct type, used for chars and strings * Implemented padding, fixed arrays * Added bitfields * Added rvalue parsing, no evaluating yet * Added .idea folder to gitignore * Fixed build on MacOS * Added custom implementation of integral concept if not available * Rebased onto master * Fixed array variable decl crash * Added rvalues and dot syntax * Lower case all pattern language error messages * Fixed typo in variable name * Fixed bug where preprocessor would not ignore commented out directives * Reimplemented pointers * Fixed rebase issues --- .gitignore | 2 +- .idea/imhex.iml | 2 + .idea/modules.xml | 8 + include/lang/ast_node.hpp | 389 ++++++-- include/lang/evaluator.hpp | 38 +- include/lang/lexer.hpp | 6 + include/lang/parser.hpp | 158 +++- include/lang/pattern_data.hpp | 322 ++++--- include/lang/preprocessor.hpp | 8 +- include/lang/token.hpp | 237 +++-- include/lang/validator.hpp | 8 + include/views/view_pattern.hpp | 1 + plugins/libimhex/include/helpers/utils.hpp | 41 +- plugins/libimhex/include/hex.hpp | 48 + source/lang/evaluator.cpp | 729 +++++++-------- source/lang/lexer.cpp | 319 +++---- source/lang/parser.cpp | 997 ++++++++------------- source/lang/preprocessor.cpp | 305 ++++--- source/lang/validator.cpp | 242 ++--- source/main.cpp | 1 + source/views/view_pattern.cpp | 24 +- 21 files changed, 2204 insertions(+), 1681 deletions(-) create mode 100644 .idea/imhex.iml create mode 100644 .idea/modules.xml diff --git a/.gitignore b/.gitignore index 6e0c73491..71b1c9799 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .vscode/ - +.idea/ cmake-build-debug/ diff --git a/.idea/imhex.iml b/.idea/imhex.iml new file mode 100644 index 000000000..f08604bb6 --- /dev/null +++ b/.idea/imhex.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..f3b44c0fe --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/include/lang/ast_node.hpp b/include/lang/ast_node.hpp index 3840ff188..24538d1ce 100644 --- a/include/lang/ast_node.hpp +++ b/include/lang/ast_node.hpp @@ -4,130 +4,351 @@ #include #include -#include +#include #include namespace hex::lang { class ASTNode { public: - enum class Type { - VariableDecl, - TypeDecl, - Struct, - Union, - Enum, - Bitfield, - Scope, - }; + constexpr ASTNode() = default; + constexpr virtual ~ASTNode() = default; + constexpr ASTNode(const ASTNode &) = default; - explicit ASTNode(Type type, u32 lineNumber) : m_type(type), m_lineNumber(lineNumber) {} - virtual ~ASTNode() = default; + [[nodiscard]] constexpr u32 getLineNumber() const { return this->m_lineNumber; } + constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; } - Type getType() { return this->m_type; } - u32 getLineNumber() { return this->m_lineNumber; } + virtual ASTNode* clone() = 0; private: - Type m_type; - u32 m_lineNumber; + u32 m_lineNumber = 1; }; - class ASTNodeVariableDecl : public ASTNode { + class ASTNodeIntegerLiteral : public ASTNode { public: - explicit ASTNodeVariableDecl(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "", std::optional offset = { }, size_t arraySize = 1, std::optional arraySizeVariable = { }, std::optional pointerSize = { }, std::optional endianess = { }) - : ASTNode(Type::VariableDecl, lineNumber), m_type(type), m_name(name), m_customTypeName(customTypeName), m_offset(offset), m_arraySize(arraySize), m_arraySizeVariable(arraySizeVariable), m_pointerSize(pointerSize), m_endianess(endianess) { } + ASTNodeIntegerLiteral(std::variant value, Token::ValueType type) + : ASTNode(), m_value(value), m_type(type) { - const Token::TypeToken::Type& getVariableType() const { return this->m_type; } - const std::string& getCustomVariableTypeName() const { return this->m_customTypeName; } - const std::string& getVariableName() const { return this->m_name; }; - std::optional getOffset() const { return this->m_offset; } - size_t getArraySize() const { return this->m_arraySize; } - std::optional getArraySizeVariable() const { return this->m_arraySizeVariable; } - std::optional getPointerSize() const { return this->m_pointerSize; } - std::optional getEndianess() const { return this->m_endianess; } + } + ASTNodeIntegerLiteral(const ASTNodeIntegerLiteral&) = default; + + ASTNode* clone() override { + return new ASTNodeIntegerLiteral(*this); + } + + [[nodiscard]] const auto& getValue() const { + return this->m_value; + } + + [[nodiscard]] Token::ValueType getType() const { + return this->m_type; + } private: - Token::TypeToken::Type m_type; - std::string m_name, m_customTypeName; - std::optional m_offset; - size_t m_arraySize; - std::optional m_arraySizeVariable; - std::optional m_pointerSize; - std::optional m_endianess = { }; + std::variant m_value; + Token::ValueType m_type; }; - class ASTNodeScope : public ASTNode { + class ASTNodeNumericExpression : public ASTNode { public: - explicit ASTNodeScope(u32 lineNumber, std::vector nodes) : ASTNode(Type::Scope, lineNumber), m_nodes(nodes) { } + ASTNodeNumericExpression(ASTNode *left, ASTNode *right, Token::Operator op) + : ASTNode(), m_left(left), m_right(right), m_operator(op) { } + + ~ASTNodeNumericExpression() override { + delete this->m_left; + delete this->m_right; + } + + ASTNodeNumericExpression(const ASTNodeNumericExpression &other) : ASTNode(other) { + this->m_operator = other.m_operator; + this->m_left = other.m_left->clone(); + this->m_right = other.m_right->clone(); + } + + ASTNode* clone() override { + return new ASTNodeNumericExpression(*this); + } + + ASTNode *getLeftOperand() { return this->m_left; } + ASTNode *getRightOperand() { return this->m_right; } + Token::Operator getOperator() { return this->m_operator; } - std::vector &getNodes() { return this->m_nodes; } private: - std::vector m_nodes; + ASTNode *m_left, *m_right; + Token::Operator m_operator; }; - class ASTNodeStruct : public ASTNode { + class ASTNodeBuiltinType : public ASTNode { public: - explicit ASTNodeStruct(u32 lineNumber, std::string name, std::vector nodes) - : ASTNode(Type::Struct, lineNumber), m_name(name), m_nodes(nodes) { } + constexpr explicit ASTNodeBuiltinType(Token::ValueType type) + : ASTNode(), m_type(type) { } + + [[nodiscard]] constexpr const auto& getType() const { return this->m_type; } + + ASTNode* clone() override { + return new ASTNodeBuiltinType(*this); + } - const std::string& getName() const { return this->m_name; } - std::vector &getNodes() { return this->m_nodes; } private: - std::string m_name; - std::vector m_nodes; - }; - - class ASTNodeUnion : public ASTNode { - public: - explicit ASTNodeUnion(u32 lineNumber, std::string name, std::vector nodes) - : ASTNode(Type::Union, lineNumber), m_name(name), m_nodes(nodes) { } - - const std::string& getName() const { return this->m_name; } - std::vector &getNodes() { return this->m_nodes; } - private: - std::string m_name; - std::vector m_nodes; - }; - - class ASTNodeBitField : public ASTNode { - public: - explicit ASTNodeBitField(u32 lineNumber, std::string name, std::vector> fields) - : ASTNode(Type::Bitfield, lineNumber), m_name(name), m_fields(fields) { } - - const std::string& getName() const { return this->m_name; } - std::vector> &getFields() { return this->m_fields; } - private: - std::string m_name; - std::vector> m_fields; + const Token::ValueType m_type; }; class ASTNodeTypeDecl : public ASTNode { public: - explicit ASTNodeTypeDecl(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name, const std::string& customTypeName = "") - : ASTNode(Type::TypeDecl, lineNumber), m_type(type), m_name(name), m_customTypeName(customTypeName) { } + ASTNodeTypeDecl(std::string_view name, ASTNode *type, std::optional endian = { }) + : ASTNode(), m_name(name), m_type(type), m_endian(endian) { } - const std::string& getTypeName() const { return this->m_name; }; + ASTNodeTypeDecl(const ASTNodeTypeDecl& other) : ASTNode(other) { + this->m_name = other.m_name; + this->m_type = other.m_type->clone(); + this->m_endian = other.m_endian; + } + + ~ASTNodeTypeDecl() override { + delete this->m_type; + } + + ASTNode* clone() override { + return new ASTNodeTypeDecl(*this); + } + + [[nodiscard]] std::string_view getName() const { return this->m_name; } + [[nodiscard]] ASTNode* getType() { return this->m_type; } + [[nodiscard]] std::optional getEndian() const { return this->m_endian; } - const Token::TypeToken::Type& getAssignedType() const { return this->m_type; } - const std::string& getAssignedCustomTypeName() const { return this->m_customTypeName; } private: - Token::TypeToken::Type m_type; - std::string m_name, m_customTypeName; + std::string m_name; + ASTNode *m_type; + std::optional m_endian; + }; + + class ASTNodeVariableDecl : public ASTNode { + public: + ASTNodeVariableDecl(std::string_view name, ASTNode *type, ASTNode *placementOffset = nullptr) + : ASTNode(), m_name(name), m_type(type), m_placementOffset(placementOffset) { } + + ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other) { + this->m_name = other.m_name; + this->m_type = other.m_type->clone(); + + if (other.m_placementOffset != nullptr) + this->m_placementOffset = other.m_placementOffset->clone(); + else + this->m_placementOffset = nullptr; + } + + ~ASTNodeVariableDecl() override { + delete this->m_type; + } + + ASTNode* clone() override { + return new ASTNodeVariableDecl(*this); + } + + [[nodiscard]] std::string_view getName() const { return this->m_name; } + [[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; } + [[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; } + + private: + std::string m_name; + ASTNode *m_type; + ASTNode *m_placementOffset; + }; + + class ASTNodeArrayVariableDecl : public ASTNode { + public: + ASTNodeArrayVariableDecl(std::string_view name, ASTNode *type, ASTNode *size, ASTNode *placementOffset = nullptr) + : ASTNode(), m_name(name), m_type(type), m_size(size), m_placementOffset(placementOffset) { } + + ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other) { + this->m_name = other.m_name; + this->m_type = other.m_type->clone(); + this->m_size = other.m_size->clone(); + + if (other.m_placementOffset != nullptr) + this->m_placementOffset = other.m_placementOffset->clone(); + else + this->m_placementOffset = nullptr; + } + + ~ASTNodeArrayVariableDecl() override { + delete this->m_type; + delete this->m_size; + } + + ASTNode* clone() override { + return new ASTNodeArrayVariableDecl(*this); + } + + [[nodiscard]] std::string_view getName() const { return this->m_name; } + [[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; } + [[nodiscard]] constexpr ASTNode* getSize() const { return this->m_size; } + [[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; } + + private: + std::string m_name; + ASTNode *m_type; + ASTNode *m_size; + ASTNode *m_placementOffset; + }; + + class ASTNodePointerVariableDecl : public ASTNode { + public: + ASTNodePointerVariableDecl(std::string_view name, ASTNode *type, ASTNode *sizeType, ASTNode *placementOffset = nullptr) + : ASTNode(), m_name(name), m_type(type), m_sizeType(sizeType), m_placementOffset(placementOffset) { } + + ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other) { + this->m_name = other.m_name; + this->m_type = other.m_type->clone(); + this->m_sizeType = other.m_sizeType->clone(); + + if (other.m_placementOffset != nullptr) + this->m_placementOffset = other.m_placementOffset->clone(); + else + this->m_placementOffset = nullptr; + } + + ~ASTNodePointerVariableDecl() override { + delete this->m_type; + } + + ASTNode* clone() override { + return new ASTNodePointerVariableDecl(*this); + } + + [[nodiscard]] std::string_view getName() const { return this->m_name; } + [[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; } + [[nodiscard]] constexpr ASTNode* getSizeType() const { return this->m_sizeType; } + [[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; } + + private: + std::string m_name; + ASTNode *m_type; + ASTNode *m_sizeType; + ASTNode *m_placementOffset; + }; + + class ASTNodeStruct : public ASTNode { + public: + ASTNodeStruct() : ASTNode() { } + + ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other) { + for (const auto &otherMember : other.getMembers()) + this->m_members.push_back(otherMember->clone()); + } + + ~ASTNodeStruct() override { + for (auto &member : this->m_members) + delete member; + } + + ASTNode* clone() override { + return new ASTNodeStruct(*this); + } + + [[nodiscard]] const std::vector& getMembers() const { return this->m_members; } + void addMember(ASTNode *node) { this->m_members.push_back(node); } + + private: + std::vector m_members; + }; + + class ASTNodeUnion : public ASTNode { + public: + ASTNodeUnion() : ASTNode() { } + + ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other) { + for (const auto &otherMember : other.getMembers()) + this->m_members.push_back(otherMember->clone()); + } + + ~ASTNodeUnion() override { + for (auto &member : this->m_members) + delete member; + } + + ASTNode* clone() override { + return new ASTNodeUnion(*this); + } + + [[nodiscard]] const std::vector& getMembers() const { return this->m_members; } + void addMember(ASTNode *node) { this->m_members.push_back(node); } + + private: + std::vector m_members; }; class ASTNodeEnum : public ASTNode { public: - explicit ASTNodeEnum(u32 lineNumber, const Token::TypeToken::Type &type, const std::string &name) - : ASTNode(Type::Enum, lineNumber), m_type(type), m_name(name) { } + explicit ASTNodeEnum(ASTNode *underlyingType) : ASTNode(), m_underlyingType(underlyingType) { } - const std::string& getName() const { return this->m_name; }; + ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other) { + for (const auto &[name, entry] : other.getEntries()) + this->m_entries.emplace_back(name, entry->clone()); + this->m_underlyingType = other.m_underlyingType->clone(); + } + + ~ASTNodeEnum() override { + for (auto &[name, expr] : this->m_entries) + delete expr; + delete this->m_underlyingType; + } + + ASTNode* clone() override { + return new ASTNodeEnum(*this); + } + + [[nodiscard]] const std::vector>& getEntries() const { return this->m_entries; } + void addEntry(const std::string &name, ASTNode* expression) { this->m_entries.emplace_back(name, expression); } + + [[nodiscard]] const ASTNode *getUnderlyingType() const { return this->m_underlyingType; } - const Token::TypeToken::Type& getUnderlyingType() const { return this->m_type; } - std::vector>& getValues() { return this->m_values; } private: - Token::TypeToken::Type m_type; - std::string m_name; - std::vector> m_values; + std::vector> m_entries; + ASTNode *m_underlyingType; + }; + + class ASTNodeBitfield : public ASTNode { + public: + ASTNodeBitfield() : ASTNode() { } + + ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other) { + for (const auto &[name, entry] : other.getEntries()) + this->m_entries.emplace_back(name, entry->clone()); + } + + ~ASTNodeBitfield() override { + for (auto &[name, expr] : this->m_entries) + delete expr; + } + + ASTNode* clone() override { + return new ASTNodeBitfield(*this); + } + + [[nodiscard]] const std::vector>& getEntries() const { return this->m_entries; } + void addEntry(const std::string &name, ASTNode* size) { this->m_entries.emplace_back(name, size); } + + private: + std::vector> m_entries; + }; + + class ASTNodeRValue : public ASTNode { + public: + explicit ASTNodeRValue(std::vector path) : ASTNode(), m_path(std::move(path)) { } + + ASTNodeRValue(const ASTNodeRValue&) = default; + + ASTNode* clone() override { + return new ASTNodeRValue(*this); + } + + const std::vector& getPath() { + return this->m_path; + } + + private: + std::vector m_path; }; } \ No newline at end of file diff --git a/include/lang/evaluator.hpp b/include/lang/evaluator.hpp index 16bac1cfa..cd513ac0f 100644 --- a/include/lang/evaluator.hpp +++ b/include/lang/evaluator.hpp @@ -15,7 +15,7 @@ namespace hex::lang { class Evaluator { public: - Evaluator(prv::Provider* &provider, std::endian defaultDataEndianess); + Evaluator(prv::Provider* &provider, std::endian defaultDataEndian); std::optional> evaluate(const std::vector& ast); @@ -24,18 +24,36 @@ namespace hex::lang { private: std::unordered_map m_types; prv::Provider* &m_provider; - std::endian m_defaultDataEndianess; + std::endian m_defaultDataEndian; + u64 m_currOffset = 0; + std::optional m_currEndian; + std::vector *m_currMembers = nullptr; std::pair m_error; - std::pair createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); - std::pair createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); - std::pair createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); - std::pair createBitfieldPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); - std::pair createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); - std::pair createStringPattern(ASTNodeVariableDecl *varDeclNode, u64 offset); - std::pair createCustomTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset); - std::pair createBuiltInTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset); + using EvaluateError = std::pair; + + [[noreturn]] static void throwEvaluateError(std::string_view error, u32 lineNumber) { + throw EvaluateError(lineNumber, "Evaluator: " + std::string(error)); + } + + [[nodiscard]] std::endian getCurrentEndian() const { + return this->m_currEndian.value_or(this->m_defaultDataEndian); + } + + ASTNodeIntegerLiteral* evaluateRValue(ASTNodeRValue *node); + ASTNodeIntegerLiteral* evaluateOperator(ASTNodeIntegerLiteral *left, ASTNodeIntegerLiteral *right, Token::Operator op); + ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node); + + PatternData* evaluateBuiltinType(ASTNodeBuiltinType *node); + PatternData* evaluateStruct(ASTNodeStruct *node); + PatternData* evaluateUnion(ASTNodeUnion *node); + PatternData* evaluateEnum(ASTNodeEnum *node); + PatternData* evaluateBitfield(ASTNodeBitfield *node); + PatternData* evaluateType(ASTNodeTypeDecl *node); + PatternData* evaluateVariable(ASTNodeVariableDecl *node); + PatternData* evaluateArray(ASTNodeArrayVariableDecl *node); + PatternData* evaluatePointer(ASTNodePointerVariableDecl *node); }; diff --git a/include/lang/lexer.hpp b/include/lang/lexer.hpp index cef75995b..2cf01a440 100644 --- a/include/lang/lexer.hpp +++ b/include/lang/lexer.hpp @@ -20,6 +20,12 @@ namespace hex::lang { private: std::pair m_error; + + using LexerError = std::pair; + + [[noreturn]] void throwLexerError(std::string_view error, u32 lineNumber) const { + throw LexerError(lineNumber, "Lexer: " + std::string(error)); + } }; } \ No newline at end of file diff --git a/include/lang/parser.hpp b/include/lang/parser.hpp index f24596631..63b5d9177 100644 --- a/include/lang/parser.hpp +++ b/include/lang/parser.hpp @@ -1,16 +1,23 @@ #pragma once #include + #include "token.hpp" #include "ast_node.hpp" +#include "helpers/utils.hpp" + +#include +#include +#include #include namespace hex::lang { class Parser { public: - Parser(); + Parser() = default; + ~Parser() = default; using TokenIter = std::vector::const_iterator; @@ -19,31 +26,138 @@ namespace hex::lang { const std::pair& getError() { return this->m_error; } private: - std::pair m_error; + using ParseError = std::pair; + ParseError m_error; + TokenIter m_curr; + TokenIter m_originalPosition; - ASTNode* parseBuiltinVariableDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseCustomTypeVariableDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseBuiltinPointerVariableDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseCustomTypePointerVariableDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseBuiltinArrayDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseCustomTypeArrayDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseBuiltinVariableArrayDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseCustomTypeVariableArrayDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parsePaddingDecl(TokenIter &curr); - ASTNode* parseFreeBuiltinVariableDecl(TokenIter &curr, bool hasEndianDef); - ASTNode* parseFreeCustomTypeVariableDecl(TokenIter &curr, bool hasEndianDef); + std::unordered_map m_types; + std::vector m_matchedOptionals; - ASTNode* parseStruct(TokenIter &curr); - ASTNode* parseUnion(TokenIter &curr); - ASTNode* parseEnum(TokenIter &curr); - ASTNode *parseBitField(TokenIter &curr); - ASTNode *parseScope(TokenIter &curr); - std::optional parseUsingDeclaration(TokenIter &curr); - std::optional> parseStatement(TokenIter &curr); + u32 getLineNumber(s32 index) const { + return this->m_curr[index].lineNumber; + } + + template + const T& getValue(s32 index) const { + auto value = std::get_if(&this->m_curr[index].value); + + if (value == nullptr) + throwParseError("failed to decode token. Invalid type.", getLineNumber(index)); + + return *value; + } + + Token::Type getType(s32 index) const { + return this->m_curr[index].type; + } + + ASTNode* parseRValue(std::vector &path); + ASTNode* parseFactor(); + ASTNode* parseMultiplicativeExpression(); + ASTNode* parseAdditiveExpression(); + ASTNode* parseShiftExpression(); + ASTNode* parseBinaryAndExpression(); + ASTNode* parseBinaryXorExpression(); + ASTNode* parseBinaryOrExpression(); + ASTNode* parseMathematicalExpression(); + + ASTNode* parseType(s32 startIndex); + ASTNode* parseUsingDeclaration(); + ASTNode* parsePadding(); + ASTNode* parseMemberVariable(); + ASTNode* parseMemberArrayVariable(); + ASTNode* parseMemberPointerVariable(); + ASTNode* parseStruct(); + ASTNode* parseUnion(); + ASTNode* parseEnum(); + ASTNode* parseBitfield(); + ASTNode* parseVariablePlacement(); + ASTNode* parseArrayVariablePlacement(); + ASTNode* parsePointerVariablePlacement(); + ASTNode* parseStatement(); + + std::vector parseTillToken(Token::Type endTokenType, const auto value) { + std::vector program; + ScopeExit guard([&]{ for (auto &node : program) delete node; }); + + while (this->m_curr->type != endTokenType || (*this->m_curr) != value) { + program.push_back(parseStatement()); + } + + this->m_curr++; + + guard.release(); + + return program; + } + + [[noreturn]] void throwParseError(std::string_view error, s32 token = -1) const { + throw ParseError(this->m_curr[token].lineNumber, "Parser: " + std::string(error)); + } + + /* Token consuming */ + + bool begin() { + this->m_originalPosition = this->m_curr; + this->m_matchedOptionals.clear(); + + return true; + } + + bool sequence() { + return true; + } + + bool sequence(Token::Type type, auto value, auto ... args) { + if (!peek(type, value)) { + this->m_curr = this->m_originalPosition; + return false; + } + + this->m_curr++; + + if (!sequence(args...)) { + this->m_curr = this->m_originalPosition; + return false; + } + + return true; + } + + bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) { + if (!peek(type1, value1)) { + if (!peek(type2, value2)) { + this->m_curr = this->m_originalPosition; + return false; + } + } + + this->m_curr++; + + return true; + } + + bool optional(Token::Type type, auto value) { + if (peek(type, value)) { + this->m_matchedOptionals.push_back(this->m_curr); + this->m_curr++; + } + + return true; + } + + bool peek(Token::Type type, auto value, s32 index = 0) { + return this->m_curr[index].type == type && this->m_curr[index] == value; + } + + bool peekOptional(Token::Type type, auto value, u32 index = 0) { + if (index >= this->m_matchedOptionals.size()) + return false; + return peek(type, value, std::distance(this->m_curr, this->m_matchedOptionals[index])); + } - std::vector parseTillToken(TokenIter &curr, Token::Type endTokenType); - bool tryConsume(TokenIter &curr, std::initializer_list tokenTypes); }; } \ No newline at end of file diff --git a/include/lang/pattern_data.hpp b/include/lang/pattern_data.hpp index 9f6e63e74..b674b8908 100644 --- a/include/lang/pattern_data.hpp +++ b/include/lang/pattern_data.hpp @@ -1,7 +1,6 @@ #pragma once #include -#include #include "imgui.h" #include "imgui_memory_editor.h" @@ -9,7 +8,9 @@ #include "providers/provider.hpp" #include "helpers/utils.hpp" +#include #include +#include namespace hex::lang { @@ -33,11 +34,9 @@ namespace hex::lang { class PatternData { public: - enum class Type { Padding, Unsigned, Signed, Float, Character, String, Struct, Union, Array, Enum }; - - PatternData(Type type, u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0) - : m_type(type), m_offset(offset), m_size(size), m_name(name), m_endianess(endianess), m_color(color) { - constexpr u32 Palette[] = { 0x50b4771f, 0x500e7fff, 0x502ca02c, 0x502827d6, 0x50bd6794, 0x504b568c, 0x50c277e3, 0x507f7f7f, 0x5022bdbc, 0x50cfbe17 }; + PatternData(u64 offset, size_t size, u32 color = 0) + : m_offset(offset), m_size(size), m_color(color) { + constexpr u32 Palette[] = { 0x70b4771f, 0x700e7fff, 0x702ca02c, 0x702827d6, 0x70bd6794, 0x704b568c, 0x70c277e3, 0x707f7f7f, 0x7022bdbc, 0x70cfbe17 }; if (color != 0) return; @@ -49,21 +48,25 @@ namespace hex::lang { } virtual ~PatternData() = default; - [[nodiscard]] Type getPatternType() const { return this->m_type; } + virtual PatternData* clone() = 0; + [[nodiscard]] u64 getOffset() const { return this->m_offset; } [[nodiscard]] size_t getSize() const { return this->m_size; } - [[nodiscard]] const std::string& getName() const { return this->m_name; } - void setName(std::string name) { this->m_name = name; } + [[nodiscard]] const std::string& getVariableName() const { return this->m_variableName; } + void setVariableName(std::string name) { this->m_variableName = std::move(name); } + + [[nodiscard]] const std::string& getTypeName() const { return this->m_typeName; } + void setTypeName(std::string name) { this->m_typeName = std::move(name); } [[nodiscard]] u32 getColor() const { return this->m_color; } void setColor(u32 color) { this->m_color = color; } - [[nodiscard]] std::endian getEndianess() const { return this->m_endianess; } - void setEndianess(std::endian endianess) { this->m_endianess = endianess; } + [[nodiscard]] std::endian getEndian() const { return this->m_endian; } + void setEndian(std::endian endian) { this->m_endian = endian; } virtual void createEntry(prv::Provider* &provider) = 0; - virtual std::string getTypeName() = 0; + [[nodiscard]] virtual std::string getFormattedName() const = 0; virtual std::optional highlightBytes(size_t offset) { if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize())) @@ -77,9 +80,9 @@ namespace hex::lang { static bool sortPatternDataTable(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider, lang::PatternData* left, lang::PatternData* right) { if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) { if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) - return left->getName() > right->getName(); + return left->getVariableName() > right->getVariableName(); else - return left->getName() < right->getName(); + return left->getVariableName() < right->getVariableName(); } else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) { if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) @@ -100,9 +103,9 @@ namespace hex::lang { provider->read(left->getOffset(), leftBuffer.data(), left->getSize()); provider->read(right->getOffset(), rightBuffer.data(), right->getSize()); - if (left->m_endianess != std::endian::native) + if (left->m_endian != std::endian::native) std::reverse(leftBuffer.begin(), leftBuffer.end()); - if (right->m_endianess != std::endian::native) + if (right->m_endian != std::endian::native) std::reverse(rightBuffer.begin(), rightBuffer.end()); if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending) @@ -129,38 +132,38 @@ namespace hex::lang { static void resetPalette() { PatternData::s_paletteOffset = 0; } protected: - void createDefaultEntry(std::string value) { + void createDefaultEntry(std::string_view value) const { ImGui::TableNextRow(); - ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap); + ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap); ImGui::TableNextColumn(); if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { Region selectRegion = { this->getOffset(), this->getSize() }; View::postEvent(Events::SelectionChangeRequest, &selectRegion); } ImGui::SameLine(); - ImGui::Text("%s", this->getName().c_str()); + ImGui::Text("%s", this->getVariableName().c_str()); ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14)); + ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1); ImGui::TableNextColumn(); - ImGui::Text("0x%04lx", this->getSize()); + ImGui::Text("0x%04llx", this->getSize()); ImGui::TableNextColumn(); - ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getTypeName().c_str()); + ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getFormattedName().c_str()); ImGui::TableNextColumn(); - ImGui::Text("%s", value.c_str()); + ImGui::Text("%s", value.data()); } protected: - std::endian m_endianess = std::endian::native; + std::endian m_endian = std::endian::native; private: - Type m_type; u64 m_offset; size_t m_size; u32 m_color; - std::string m_name; + std::string m_variableName; + std::string m_typeName; static inline u8 s_paletteOffset = 0; @@ -168,41 +171,49 @@ namespace hex::lang { class PatternDataPadding : public PatternData { public: - PatternDataPadding(u64 offset, size_t size) : PatternData(Type::Padding, offset, size, "", { }, 0x00FFFFFF) { } + PatternDataPadding(u64 offset, size_t size) : PatternData(offset, size, 0x00FFFFFF) { } + + PatternData* clone() override { + return new PatternDataPadding(*this); + } void createEntry(prv::Provider* &provider) override { } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { return ""; } }; class PatternDataPointer : public PatternData { public: - PatternDataPointer(u64 offset, size_t size, const std::string &name, PatternData *pointedAt, std::endian endianess, u32 color = 0) - : PatternData(Type::Unsigned, offset, size, name, endianess, color), m_pointedAt(pointedAt) { - this->m_pointedAt->setName("*" + this->m_pointedAt->getName()); + PatternDataPointer(u64 offset, size_t size, PatternData *pointedAt, u32 color = 0) + : PatternData(offset, size, color), m_pointedAt(pointedAt) { + this->m_pointedAt->setVariableName("*" + this->m_pointedAt->getVariableName()); + } + + PatternData* clone() override { + return new PatternDataPointer(*this); } void createEntry(prv::Provider* &provider) override { u64 data = 0; provider->read(this->getOffset(), &data, this->getSize()); - data = hex::changeEndianess(data, this->getSize(), this->m_endianess); + data = hex::changeEndianess(data, this->getSize(), this->getEndian()); ImGui::TableNextRow(); ImGui::TableNextColumn(); - bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); + bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14)); + ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1); ImGui::TableNextColumn(); - ImGui::Text("0x%04lx", this->getSize()); + ImGui::Text("0x%04llx", this->getSize()); ImGui::TableNextColumn(); - ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getTypeName().c_str()); + ImGui::TextColored(ImColor(0xFF9BC64D), "%s*", this->m_pointedAt->getFormattedName().c_str()); ImGui::TableNextColumn(); - ImGui::Text("*(0x%0*llx)", this->getSize() * 2, data); + ImGui::Text("*(0x%llx)", data); if (open) { this->m_pointedAt->createEntry(provider); @@ -211,7 +222,7 @@ namespace hex::lang { } } - virtual std::optional highlightBytes(size_t offset) { + std::optional highlightBytes(size_t offset) override { if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize())) return this->getColor(); else if (auto color = this->m_pointedAt->highlightBytes(offset); color.has_value()) @@ -220,7 +231,7 @@ namespace hex::lang { return { }; } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { return "Pointer"; } @@ -230,18 +241,22 @@ namespace hex::lang { class PatternDataUnsigned : public PatternData { public: - PatternDataUnsigned(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0) - : PatternData(Type::Unsigned, offset, size, name, endianess, color) { } + PatternDataUnsigned(u64 offset, size_t size, u32 color = 0) + : PatternData(offset, size, color) { } + + PatternData* clone() override { + return new PatternDataUnsigned(*this); + } void createEntry(prv::Provider* &provider) override { u64 data = 0; provider->read(this->getOffset(), &data, this->getSize()); - data = hex::changeEndianess(data, this->getSize(), this->m_endianess); + data = hex::changeEndianess(data, this->getSize(), this->getEndian()); this->createDefaultEntry(hex::format("%lu (0x%0*lx)", data, this->getSize() * 2, data)); } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { switch (this->getSize()) { case 1: return "u8"; case 2: return "u16"; @@ -255,20 +270,24 @@ namespace hex::lang { class PatternDataSigned : public PatternData { public: - PatternDataSigned(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0) - : PatternData(Type::Signed, offset, size, name, endianess, color) { } + PatternDataSigned(u64 offset, size_t size, u32 color = 0) + : PatternData(offset, size, color) { } + + PatternData* clone() override { + return new PatternDataSigned(*this); + } void createEntry(prv::Provider* &provider) override { u64 data = 0; provider->read(this->getOffset(), &data, this->getSize()); - data = hex::changeEndianess(data, this->getSize(), this->m_endianess); + data = hex::changeEndianess(data, this->getSize(), this->getEndian()); - s64 signedData = signedData = hex::signExtend(data, this->getSize(), 64); + s64 signedData = hex::signExtend(data, this->getSize(), 64); this->createDefaultEntry(hex::format("%ld (0x%0*lx)", signedData, this->getSize() * 2, data)); } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { switch (this->getSize()) { case 1: return "s8"; case 2: return "s16"; @@ -282,21 +301,25 @@ namespace hex::lang { class PatternDataFloat : public PatternData { public: - PatternDataFloat(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0) - : PatternData(Type::Float, offset, size, name, endianess, color) { } + PatternDataFloat(u64 offset, size_t size, u32 color = 0) + : PatternData(offset, size, color) { } + + PatternData* clone() override { + return new PatternDataFloat(*this); + } void createEntry(prv::Provider* &provider) override { double formatData = 0; if (this->getSize() == 4) { float data = 0; provider->read(this->getOffset(), &data, 4); - data = hex::changeEndianess(data, 4, this->m_endianess); + data = hex::changeEndianess(data, 4, this->getEndian()); formatData = data; } else if (this->getSize() == 8) { double data = 0; provider->read(this->getOffset(), &data, 8); - data = hex::changeEndianess(data, 8, this->m_endianess); + data = hex::changeEndianess(data, 8, this->getEndian()); formatData = data; } @@ -304,7 +327,7 @@ namespace hex::lang { this->createDefaultEntry(hex::format("%f (0x%0*lx)", formatData, this->getSize() * 2, formatData)); } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { switch (this->getSize()) { case 4: return "float"; case 8: return "double"; @@ -315,8 +338,12 @@ namespace hex::lang { class PatternDataCharacter : public PatternData { public: - PatternDataCharacter(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0) - : PatternData(Type::Character, offset, size, name, endianess, color) { } + explicit PatternDataCharacter(u64 offset, u32 color = 0) + : PatternData(offset, 1, color) { } + + PatternData* clone() override { + return new PatternDataCharacter(*this); + } void createEntry(prv::Provider* &provider) override { char character; @@ -325,15 +352,19 @@ namespace hex::lang { this->createDefaultEntry(hex::format("'%c'", character)); } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { return "Character"; } }; class PatternDataString : public PatternData { public: - PatternDataString(u64 offset, size_t size, const std::string &name, std::endian endianess, u32 color = 0) - : PatternData(Type::String, offset, size, name, endianess, color) { } + PatternDataString(u64 offset, size_t size, u32 color = 0) + : PatternData(offset, size, color) { } + + PatternData* clone() override { + return new PatternDataString(*this); + } void createEntry(prv::Provider* &provider) override { std::vector buffer(this->getSize() + 1, 0x00); @@ -343,15 +374,24 @@ namespace hex::lang { this->createDefaultEntry(hex::format("\"%s\"", makeDisplayable(buffer.data(), this->getSize()).c_str())); } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { return "String"; } }; class PatternDataArray : public PatternData { public: - PatternDataArray(u64 offset, size_t size, const std::string &name, std::endian endianess, const std::vector & entries, u32 color = 0) - : PatternData(Type::Array, offset, size, name, endianess, color), m_entries(entries) { } + PatternDataArray(u64 offset, size_t size, std::vector entries, u32 color = 0) + : PatternData(offset, size, color), m_entries(std::move(entries)) { } + + PatternDataArray(const PatternDataArray &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) { + for (const auto &entry : other.m_entries) + this->m_entries.push_back(entry->clone()); + } + + PatternData* clone() override { + return new PatternDataArray(*this); + } void createEntry(prv::Provider* &provider) override { if (this->m_entries.empty()) @@ -359,13 +399,13 @@ namespace hex::lang { ImGui::TableNextRow(); ImGui::TableNextColumn(); - bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); + bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14)); + ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1); ImGui::TableNextColumn(); - ImGui::Text("0x%04lx", this->getSize()); + ImGui::Text("0x%04llx", this->getSize()); ImGui::TableNextColumn(); ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_entries[0]->getTypeName().c_str()); ImGui::SameLine(0, 0); @@ -396,7 +436,7 @@ namespace hex::lang { return { }; } - std::string getTypeName() override { + [[nodiscard]] std::string getFormattedName() const override { return this->m_entries[0]->getTypeName() + "[" + std::to_string(this->m_entries.size()) + "]"; } @@ -406,20 +446,29 @@ namespace hex::lang { class PatternDataStruct : public PatternData { public: - PatternDataStruct(u64 offset, size_t size, const std::string &name, std::endian endianess, const std::string &structName, const std::vector & members, u32 color = 0) - : PatternData(Type::Struct, offset, size, name, endianess, color), m_structName(structName), m_members(members), m_sortedMembers(members) { } + PatternDataStruct(u64 offset, size_t size, const std::vector & members, u32 color = 0) + : PatternData(offset, size, color), m_members(members), m_sortedMembers(members) { } + + PatternDataStruct(const PatternDataStruct &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) { + for (const auto &member : other.m_members) + this->m_members.push_back(member->clone()); + } + + PatternData* clone() override { + return new PatternDataStruct(*this); + } void createEntry(prv::Provider* &provider) override { ImGui::TableNextRow(); ImGui::TableNextColumn(); - bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); + bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); ImGui::TableNextColumn(); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1); ImGui::TableNextColumn(); - ImGui::Text("0x%04lx", this->getSize()); + ImGui::Text("0x%04llx", this->getSize()); ImGui::TableNextColumn(); - ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->m_structName.c_str()); + ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->getTypeName().c_str()); ImGui::TableNextColumn(); ImGui::Text("%s", "{ ... }"); @@ -452,32 +501,44 @@ namespace hex::lang { member->sort(sortSpecs, provider); } - std::string getTypeName() override { - return "struct " + this->m_structName; + [[nodiscard]] std::string getFormattedName() const override { + return "struct " + PatternData::getTypeName(); + } + + const auto& getMembers() const { + return this->m_members; } private: - std::string m_structName; std::vector m_members; std::vector m_sortedMembers; }; class PatternDataUnion : public PatternData { public: - PatternDataUnion(u64 offset, size_t size, const std::string &name, const std::string &unionName, const std::vector & members, std::endian endianess, u32 color = 0) - : PatternData(Type::Union, offset, size, name, endianess, color), m_unionName(unionName), m_members(members), m_sortedMembers(members) { } + PatternDataUnion(u64 offset, size_t size, const std::vector & members, u32 color = 0) + : PatternData(offset, size, color), m_members(members), m_sortedMembers(members) { } + + PatternDataUnion(const PatternDataUnion &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) { + for (const auto &member : other.m_members) + this->m_members.push_back(member->clone()); + } + + PatternData* clone() override { + return new PatternDataUnion(*this); + } void createEntry(prv::Provider* &provider) override { ImGui::TableNextRow(); ImGui::TableNextColumn(); - bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); + bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); ImGui::TableNextColumn(); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1); ImGui::TableNextColumn(); - ImGui::Text("0x%04lx", this->getSize()); + ImGui::Text("0x%04llx", this->getSize()); ImGui::TableNextColumn(); - ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", this->m_unionName.c_str()); + ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str()); ImGui::TableNextColumn(); ImGui::Text("%s", "{ ... }"); @@ -511,27 +572,34 @@ namespace hex::lang { member->sort(sortSpecs, provider); } - std::string getTypeName() override { - return "union " + this->m_unionName; + [[nodiscard]] std::string getFormattedName() const override { + return "union " + PatternData::getTypeName();; + } + + const auto& getMembers() const { + return this->m_members; } private: - std::string m_unionName; std::vector m_members; std::vector m_sortedMembers; }; class PatternDataEnum : public PatternData { public: - PatternDataEnum(u64 offset, size_t size, const std::string &name, const std::string &enumName, std::vector> enumValues, std::endian endianess, u32 color = 0) - : PatternData(Type::Enum, offset, size, name, endianess, color), m_enumName(enumName), m_enumValues(enumValues) { } + PatternDataEnum(u64 offset, size_t size, std::vector> enumValues, u32 color = 0) + : PatternData(offset, size, color), m_enumValues(std::move(enumValues)) { } + + PatternData* clone() override { + return new PatternDataEnum(*this); + } void createEntry(prv::Provider* &provider) override { u64 value = 0; provider->read(this->getOffset(), &value, this->getSize()); - value = hex::changeEndianess(value, this->getSize(), this->m_endianess); + value = hex::changeEndianess(value, this->getSize(), this->getEndian()); - std::string valueString = this->m_enumName + "::"; + std::string valueString = PatternData::getTypeName() + "::"; bool foundValue = false; for (auto &[entryValue, entryName] : this->m_enumValues) { @@ -546,69 +614,84 @@ namespace hex::lang { valueString += "???"; ImGui::TableNextRow(); - ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth); ImGui::TableNextColumn(); if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { Region selectRegion = { this->getOffset(), this->getSize() }; View::postEvent(Events::SelectionChangeRequest, &selectRegion); } ImGui::SameLine(); - ImGui::Text("%s", this->getName().c_str()); + ImGui::Text("%s", this->getVariableName().c_str()); ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14)); + ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1); ImGui::TableNextColumn(); - ImGui::Text("0x%04lx", this->getSize()); + ImGui::Text("0x%04llx", this->getSize()); ImGui::TableNextColumn(); - ImGui::TextColored(ImColor(0xFFD69C56), "enum"); ImGui::SameLine(); ImGui::Text("%s", this->m_enumName.c_str()); + ImGui::TextColored(ImColor(0xFFD69C56), "enum"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str()); ImGui::TableNextColumn(); ImGui::Text("%s", hex::format("%s (0x%0*lx)", valueString.c_str(), this->getSize() * 2, value).c_str()); } - std::string getTypeName() override { - return "enum " + this->m_enumName; + [[nodiscard]] std::string getFormattedName() const override { + return "enum " + PatternData::getTypeName(); + } + + const auto& getEnumValues() const { + return this->m_enumValues; } private: - std::string m_enumName; std::vector> m_enumValues; }; class PatternDataBitfield : public PatternData { public: - PatternDataBitfield(u64 offset, size_t size, const std::string &name, const std::string &bitfieldName, std::vector> fields, std::endian endianess, u32 color = 0) - : PatternData(Type::Enum, offset, size, name, endianess, color), m_bitfieldName(bitfieldName), m_fields(fields) { } + PatternDataBitfield(u64 offset, size_t size, std::vector> fields, u32 color = 0) + : PatternData(offset, size, color), m_fields(std::move(fields)) { } + + PatternData* clone() override { + return new PatternDataBitfield(*this); + } void createEntry(prv::Provider* &provider) override { - u64 value = 0; - provider->read(this->getOffset(), &value, this->getSize()); - value = hex::changeEndianess(value, this->getSize(), this->m_endianess); + std::vector value(this->getSize(), 0); + provider->read(this->getOffset(), &value[0], value.size()); + + if (this->m_endian == std::endian::big) + std::reverse(value.begin(), value.end()); ImGui::TableNextRow(); ImGui::TableNextColumn(); - bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); + bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); ImGui::TableNextColumn(); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset(), this->getOffset() + this->getSize() - 1); ImGui::TableNextColumn(); - ImGui::Text("0x%04lx", this->getSize()); + ImGui::Text("0x%04llx", this->getSize()); ImGui::TableNextColumn(); - ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", this->m_bitfieldName.c_str()); + ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str()); ImGui::TableNextColumn(); - ImGui::Text("{ %llx }", value); + + std::string valueString = "{ "; + for (u64 i = 0; i < value.size(); i++) + valueString += hex::format("%02x ", value[i]); + valueString += "}"; + + ImGui::TextUnformatted(valueString.c_str()); if (open) { u16 bitOffset = 0; for (auto &[entryName, entrySize] : this->m_fields) { ImGui::TableNextRow(); - ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth); + ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth); ImGui::TableNextColumn(); ImGui::Text("%s", entryName.c_str()); ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14)); + ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); ImGui::TableNextColumn(); - ImGui::Text("0x%08lx : 0x%08lx", this->getOffset() + (bitOffset >> 3), this->getOffset() + ((bitOffset + entrySize) >> 3) - 1); + ImGui::Text("0x%08llx : 0x%08llx", this->getOffset() + (bitOffset >> 3), this->getOffset() + ((bitOffset + entrySize) >> 3)); ImGui::TableNextColumn(); if (entrySize == 1) ImGui::Text("%llu bit", entrySize); @@ -617,7 +700,11 @@ namespace hex::lang { ImGui::TableNextColumn(); ImGui::Text("%s", entryName.c_str()); ImGui::TableNextColumn(); - ImGui::Text("%llx", hex::extract((bitOffset + entrySize) - 1, bitOffset, value)); + { + u128 fieldValue = 0; + std::memcpy(&fieldValue, value.data() + (bitOffset / 8), (entrySize / 8) + 1); + ImGui::Text("%llx", hex::extract((bitOffset + entrySize) - 1 - ((bitOffset / 8) * 8), bitOffset - ((bitOffset / 8) * 8), fieldValue)); + } bitOffset += entrySize; } @@ -626,12 +713,15 @@ namespace hex::lang { } - std::string getTypeName() override { - return "bitfield " + this->m_bitfieldName; + [[nodiscard]] std::string getFormattedName() const override { + return "bitfield " + PatternData::getTypeName(); + } + + const auto& getFields() const { + return this->m_fields; } private: - std::string m_bitfieldName; std::vector> m_fields; }; diff --git a/include/lang/preprocessor.hpp b/include/lang/preprocessor.hpp index e137517f5..6982ddcd1 100644 --- a/include/lang/preprocessor.hpp +++ b/include/lang/preprocessor.hpp @@ -18,12 +18,18 @@ namespace hex::lang { std::optional preprocess(const std::string& code, bool initialRun = true); - void addPragmaHandler(std::string pragmaType, std::function function); + void addPragmaHandler(const std::string &pragmaType, const std::function &function); void addDefaultPragmaHandlers(); const std::pair& getError() { return this->m_error; } private: + using PreprocessorError = std::pair; + + [[noreturn]] void throwPreprocessorError(std::string_view error, u32 lineNumber) const { + throw PreprocessorError(lineNumber, "Preprocessor: " + std::string(error)); + } + std::unordered_map> m_pragmaHandlers; std::set> m_defines; diff --git a/include/lang/token.hpp b/include/lang/token.hpp index e0a27af5c..8ccff6b64 100644 --- a/include/lang/token.hpp +++ b/include/lang/token.hpp @@ -2,86 +2,209 @@ #include +#include "helpers/utils.hpp" + #include +#include namespace hex::lang { - struct Token { + class Token { + public: enum class Type : u64 { Keyword, - Type, + ValueType, Operator, Integer, Identifier, + Separator + }; + + enum class Keyword { + Struct, + Union, + Using, + Enum, + Bitfield, + LittleEndian, + BigEndian, + }; + + enum class Operator { + AtDeclaration, + Assignment, + Inherit, + Plus, + Minus, + Star, + Slash, + ShiftLeft, + ShiftRight, + BitOr, + BitAnd, + BitXor + }; + + enum class ValueType { + Unsigned8Bit = 0x10, + Signed8Bit = 0x11, + Unsigned16Bit = 0x20, + Signed16Bit = 0x21, + Unsigned32Bit = 0x40, + Signed32Bit = 0x41, + Unsigned64Bit = 0x80, + Signed64Bit = 0x81, + Unsigned128Bit = 0x100, + Signed128Bit = 0x101, + Character = 0x13, + Float = 0x42, + Double = 0x82, + CustomType = 0x00, + Padding = 0x1F, + + Unsigned = 0xFF00, + Signed = 0xFF01, + FloatingPoint = 0xFF02, + Integer = 0xFF03, + Any = 0xFFFF + }; + + enum class Separator { + RoundBracketOpen, + RoundBracketClose, + CurlyBracketOpen, + CurlyBracketClose, + SquareBracketOpen, + SquareBracketClose, + Comma, + Dot, EndOfExpression, - ScopeOpen, - ScopeClose, - ArrayOpen, - ArrayClose, - Separator, EndOfProgram - } type; + }; - struct KeywordToken { - enum class Keyword { - Struct, - Union, - Using, - Enum, - Bitfield, - LittleEndian, - BigEndian - } keyword; - } keywordToken; - struct IdentifierToken { - std::string identifier; - } identifierToken; - struct OperatorToken { - enum class Operator { - AtDeclaration, - Assignment, - Inherit, - Star - } op; - } operatorToken; - struct IntegerToken { - s128 integer; - } integerToken; - struct TypeToken { - enum class Type { - Unsigned8Bit = 0x10, - Signed8Bit = 0x11, - Unsigned16Bit = 0x20, - Signed16Bit = 0x21, - Unsigned32Bit = 0x40, - Signed32Bit = 0x41, - Unsigned64Bit = 0x80, - Signed64Bit = 0x81, - Unsigned128Bit = 0x100, - Signed128Bit = 0x101, - Float = 0x42, - Double = 0x82, - CustomType = 0x00, - Padding = 0x1F - } type; - } typeToken; + using ValueTypes = std::variant; - u32 lineNumber; + Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) { - [[nodiscard]] constexpr static inline bool isUnsigned(const TypeToken::Type type) { + } + + [[nodiscard]] constexpr static inline bool isUnsigned(const ValueType type) { return (static_cast(type) & 0x0F) == 0x00; } - [[nodiscard]] constexpr static inline bool isSigned(const TypeToken::Type type) { + [[nodiscard]] constexpr static inline bool isSigned(const ValueType type) { return (static_cast(type) & 0x0F) == 0x01; } - [[nodiscard]] constexpr static inline bool isFloatingPoint(const TypeToken::Type type) { + [[nodiscard]] constexpr static inline bool isFloatingPoint(const ValueType type) { return (static_cast(type) & 0x0F) == 0x02; } - [[nodiscard]] constexpr static inline u32 getTypeSize(const TypeToken::Type type) { + [[nodiscard]] constexpr static inline u32 getTypeSize(const ValueType type) { return static_cast(type) >> 4; } + + [[nodiscard]] constexpr static auto getTypeName(const lang::Token::ValueType type) { + switch (type) { + case ValueType::Signed8Bit: return "s8"; + case ValueType::Signed16Bit: return "s16"; + case ValueType::Signed32Bit: return "s32"; + case ValueType::Signed64Bit: return "s64"; + case ValueType::Signed128Bit: return "s128"; + case ValueType::Unsigned8Bit: return "u8"; + case ValueType::Unsigned16Bit: return "u16"; + case ValueType::Unsigned32Bit: return "u32"; + case ValueType::Unsigned64Bit: return "u64"; + case ValueType::Unsigned128Bit: return "u128"; + case ValueType::Float: return "float"; + case ValueType::Double: return "double"; + case ValueType::Character: return "char"; + default: return "< ??? >"; + } + } + + bool operator==(const ValueTypes &other) const { + if (this->type == Type::Integer || this->type == Type::Identifier) + return true; + else if (this->type == Type::ValueType) { + auto otherValueType = std::get_if(&other); + auto valueType = std::get_if(&this->value); + + if (otherValueType == nullptr) return false; + if (valueType == nullptr) return false; + + if (*otherValueType == *valueType) + return true; + else if (*otherValueType == ValueType::Any) + return *valueType != ValueType::CustomType && *valueType != ValueType::Padding; + else if (*otherValueType == ValueType::Unsigned) + return isUnsigned(*valueType); + else if (*otherValueType == ValueType::Signed) + return isSigned(*valueType); + else if (*otherValueType == ValueType::FloatingPoint) + return isFloatingPoint(*valueType); + else if (*otherValueType == ValueType::Integer) + return isUnsigned(*valueType) || isSigned(*valueType); + } + else + return other == this->value; + + return false; + } + + bool operator!=(const ValueTypes &other) const { + return !operator==(other); + } + + Type type; + ValueTypes value; + u32 lineNumber; + }; -} \ No newline at end of file + +} + +#define COMPONENT(type, value) hex::lang::Token::Type::type, hex::lang::Token::type::value + +#define KEYWORD_STRUCT COMPONENT(Keyword, Struct) +#define KEYWORD_UNION COMPONENT(Keyword, Union) +#define KEYWORD_USING COMPONENT(Keyword, Using) +#define KEYWORD_ENUM COMPONENT(Keyword, Enum) +#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield) +#define KEYWORD_LE COMPONENT(Keyword, LittleEndian) +#define KEYWORD_BE COMPONENT(Keyword, BigEndian) + +#define INTEGER hex::lang::Token::Type::Integer, 0xFFFF'FFFF'FFFF'FFFF +#define IDENTIFIER hex::lang::Token::Type::Identifier, "" + +#define OPERATOR_AT COMPONENT(Operator, AtDeclaration) +#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment) +#define OPERATOR_INHERIT COMPONENT(Operator, Inherit) +#define OPERATOR_PLUS COMPONENT(Operator, Plus) +#define OPERATOR_MINUS COMPONENT(Operator, Minus) +#define OPERATOR_STAR COMPONENT(Operator, Star) +#define OPERATOR_SLASH COMPONENT(Operator, Slash) +#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft) +#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight) +#define OPERATOR_BITOR COMPONENT(Operator, BitOr) +#define OPERATOR_BITAND COMPONENT(Operator, BitAnd) +#define OPERATOR_BITXOR COMPONENT(Operator, BitXor) + +#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType) +#define VALUETYPE_PADDING COMPONENT(ValueType, Padding) +#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned) +#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed) +#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint) +#define VALUETYPE_INTEGER COMPONENT(ValueType, Integer) +#define VALUETYPE_ANY COMPONENT(ValueType, Any) + +#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen) +#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose) +#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen) +#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose) +#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen) +#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose) +#define SEPARATOR_COMMA COMPONENT(Separator, Comma) +#define SEPARATOR_DOT COMPONENT(Separator, Dot) +#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression) +#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram) \ No newline at end of file diff --git a/include/lang/validator.hpp b/include/lang/validator.hpp index a0548b7ce..069e6eda9 100644 --- a/include/lang/validator.hpp +++ b/include/lang/validator.hpp @@ -15,11 +15,19 @@ namespace hex::lang { Validator(); bool validate(const std::vector& ast); + void printAST(const std::vector& ast); const std::pair& getError() { return this->m_error; } private: std::pair m_error; + + using ValidatorError = std::pair; + + [[noreturn]] void throwValidateError(std::string_view error, u32 lineNumber) const { + throw ValidatorError(lineNumber, error); + } + }; } \ No newline at end of file diff --git a/include/views/view_pattern.hpp b/include/views/view_pattern.hpp index 24964de05..a96dd7a80 100644 --- a/include/views/view_pattern.hpp +++ b/include/views/view_pattern.hpp @@ -9,6 +9,7 @@ #include #include +#include #include "ImGuiFileBrowser.h" #include "TextEditor.h" diff --git a/plugins/libimhex/include/helpers/utils.hpp b/plugins/libimhex/include/helpers/utils.hpp index d37b18611..cecc53881 100644 --- a/plugins/libimhex/include/helpers/utils.hpp +++ b/plugins/libimhex/include/helpers/utils.hpp @@ -28,21 +28,44 @@ // Make sure we break when derived_from is implemented in libc++. Then we can fix a compatibility version above #include #endif -// libcxx 12 still doesn't have derived_from implemented, as a result we need to define it ourself using clang built-ins. +// libcxx 12 still doesn't have many default concepts implemented, as a result we need to define it ourself using clang built-ins. // [concept.derived] (patch from https://reviews.llvm.org/D74292) namespace hex { template - concept derived_from = - __is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*); +concept derived_from = + __is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*); +} + +// [concepts.arithmetic] +namespace hex { +template +concept integral = __is_integral(_Tp); + +template +concept signed_integral = integral<_Tp> && __is_signed(_Tp); + +template +concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>; + +template +concept floating_point = __is_floating_point(_Tp); } #else // Assume supported #include namespace hex { using std::derived_from; + + using std::integral; + using std::signed_integral; + using std::unsigned_integral; + using std::floating_point; } #endif +#define TOKEN_CONCAT_IMPL(x, y) x ## y +#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y) + namespace hex { template @@ -58,14 +81,15 @@ namespace hex { return std::string(buffer.data(), buffer.data() + size); } - [[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const u64 &value) { - u64 mask = (std::numeric_limits::max() >> (63 - (from - to))) << to; + [[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) { + std::remove_cvref_t mask = (std::numeric_limits>::max() >> (((sizeof(value) * 8) - 1) - (from - to))) << to; return (value & mask) >> to; } - [[nodiscard]] constexpr inline u64 signExtend(u64 value, u8 currWidth, u8 targetWidth) { - u64 mask = 1LLU << (currWidth - 1); - return (((value ^ mask) - mask) << (64 - targetWidth)) >> (64 - targetWidth); + template + [[nodiscard]] constexpr inline T signExtend(T value, u8 currWidth, u8 targetWidth) { + T mask = 1LLU << (currWidth - 1); + return (((value ^ mask) - mask) << ((sizeof(T) * 8) - targetWidth)) >> ((sizeof(T) * 8) - targetWidth); } std::string toByteString(u64 bytes); @@ -123,6 +147,7 @@ namespace hex { std::vector readFile(std::string_view path); + #define SCOPE_EXIT(func) ScopeExit TOKEN_CONCAT(scopeGuard, __COUNTER__)([&] { func }) class ScopeExit { public: ScopeExit(std::function func) : m_func(func) {} diff --git a/plugins/libimhex/include/hex.hpp b/plugins/libimhex/include/hex.hpp index 824fede55..c527edbde 100644 --- a/plugins/libimhex/include/hex.hpp +++ b/plugins/libimhex/include/hex.hpp @@ -23,4 +23,52 @@ extern char **mainArgv; #define MAGIC_PATH_SEPARATOR ";" #else #define MAGIC_PATH_SEPARATOR ":" +#endif + +template<> +struct std::is_integral : public std::true_type { }; +template<> +struct std::is_integral : public std::true_type { }; +template<> +struct std::is_signed : public std::true_type { }; + +#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 12000 +#if __has_include() +// Make sure we break when derived_from is implemented in libc++. Then we can fix a compatibility version above +#include +#endif +// libcxx 12 still doesn't have many default concepts implemented, as a result we need to define it ourself using clang built-ins. +// [concept.derived] (patch from https://reviews.llvm.org/D74292) +namespace hex { +template +concept derived_from = + __is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*); +} + +// [concepts.arithmetic] (patch from https://reviews.llvm.org/D88131) +namespace hex { +template +concept integral = __is_integral(_Tp); + +template +concept signed_integral = integral<_Tp> && __is_signed(_Tp); + +template +concept unsigned_integral = integral<_Tp> && !signed_integral<_Tp>; + +template +concept floating_point = __is_floating_point(_Tp); +} +#else +// Assume supported +#include + +namespace hex { + using std::derived_from; + + using std::integral; + using std::signed_integral; + using std::unsigned_integral; + using std::floating_point; +} #endif \ No newline at end of file diff --git a/source/lang/evaluator.cpp b/source/lang/evaluator.cpp index aeac9a380..6f31ddfd7 100644 --- a/source/lang/evaluator.cpp +++ b/source/lang/evaluator.cpp @@ -3,428 +3,435 @@ #include "lang/token.hpp" #include -#include +#include +#include + +#include namespace hex::lang { - Evaluator::Evaluator(prv::Provider* &provider, std::endian defaultDataEndianess) : m_provider(provider), m_defaultDataEndianess(defaultDataEndianess) { - + Evaluator::Evaluator(prv::Provider* &provider, std::endian defaultDataEndian) + : m_provider(provider), m_defaultDataEndian(defaultDataEndian) { } - std::pair Evaluator::createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - std::vector members; + ASTNodeIntegerLiteral* Evaluator::evaluateRValue(ASTNodeRValue *node) { - auto structNode = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); + const std::vector* currMembers = this->m_currMembers; - if (structNode == nullptr) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; - } + PatternData *currPattern = nullptr; + for (const auto &identifier : node->getPath()) { + if (auto structPattern = dynamic_cast(currPattern); structPattern != nullptr) + currMembers = &structPattern->getMembers(); + else if (auto unionPattern = dynamic_cast(currPattern); unionPattern != nullptr) + currMembers = &unionPattern->getMembers(); + else if (currPattern != nullptr) + throwEvaluateError("tried to access member of a non-struct/union type", node->getLineNumber()); - size_t structSize = 0; - for (const auto &node : structNode->getNodes()) { - const auto &member = static_cast(node); + auto candidate = std::find_if(currMembers->begin(), currMembers->end(), [&](auto member) { + return member->getVariableName() == identifier; + }); - u64 memberOffset = 0; - - if (member->getPointerSize().has_value()) { - this->m_provider->read(offset + structSize, &memberOffset, member->getPointerSize().value()); - - memberOffset = hex::changeEndianess(memberOffset, member->getPointerSize().value(), member->getEndianess().value_or(varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess))); - } + if (candidate != currMembers->end()) + currPattern = *candidate; else - memberOffset = offset + structSize; - - const auto typeDeclNode = static_cast(this->m_types[member->getCustomVariableTypeName()]); - - PatternData *pattern = nullptr; - size_t memberSize = 0; - - if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) { - std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset); - } else if (member->getVariableType() == Token::TypeToken::Type::CustomType - && typeDeclNode != nullptr && typeDeclNode->getAssignedType() == Token::TypeToken::Type::Signed8Bit - && member->getArraySize() > 1) { - - std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset); - } - else if (member->getArraySize() > 1 || member->getVariableType() == Token::TypeToken::Type::Padding) { - std::tie(pattern, memberSize) = this->createArrayPattern(member, memberOffset); - } - else if (member->getArraySizeVariable().has_value()) { - std::optional arraySize; - - - for (auto &prevMember : members) { - if (prevMember->getPatternType() == PatternData::Type::Unsigned && prevMember->getName() == member->getArraySizeVariable()) { - u64 value = 0; - this->m_provider->read(prevMember->getOffset(), &value, prevMember->getSize()); - - value = hex::changeEndianess(value, prevMember->getSize(), prevMember->getEndianess()); - - arraySize = value; - } - } - - if (!arraySize.has_value()) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a previous member of '%s'", member->getArraySizeVariable().value().c_str(), varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; - } - - if (arraySize.value() == 0) - continue; - - ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getLineNumber(), member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value()); - - std::tie(pattern, memberSize) = this->createArrayPattern(processedMember, memberOffset); - } - else if (member->getVariableType() != Token::TypeToken::Type::CustomType) { - std::tie(pattern, memberSize) = this->createBuiltInTypePattern(member, memberOffset); - } - else { - std::tie(pattern, memberSize) = this->createCustomTypePattern(member, memberOffset); - } - - if (pattern == nullptr) - return { nullptr, 0 }; - - pattern->setEndianess(member->getEndianess().value_or(varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess))); - - if (member->getPointerSize().has_value()) { - members.push_back(new PatternDataPointer(offset + structSize, member->getPointerSize().value(), member->getVariableName(), pattern, member->getEndianess().value_or(varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)))); - structSize += member->getPointerSize().value(); - } - else { - members.push_back(pattern); - structSize += memberSize; - } + throwEvaluateError(hex::format("could not find identifier '%s'", identifier.c_str()), node->getLineNumber()); } - return { new PatternDataStruct(offset, structSize, varDeclNode->getVariableName(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess), structNode->getName(), members, 0x00FFFFFF), structSize }; + if (auto unsignedPattern = dynamic_cast(currPattern); unsignedPattern != nullptr) { + s128 value = 0; + this->m_provider->read(unsignedPattern->getOffset(), &value, unsignedPattern->getSize()); + return new ASTNodeIntegerLiteral(value, Token::ValueType::Signed128Bit); + } else if (auto signedPattern = dynamic_cast(currPattern); signedPattern != nullptr) { + s128 value = 0; + this->m_provider->read(signedPattern->getOffset(), &value, signedPattern->getSize()); + return new ASTNodeIntegerLiteral(signExtend(value, signedPattern->getSize() * 8, 128), Token::ValueType::Signed128Bit); + } else + throwEvaluateError("tried to use non-integer value in numeric expression", node->getLineNumber()); } - std::pair Evaluator::createUnionPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - std::vector members; + ASTNodeIntegerLiteral* Evaluator::evaluateOperator(ASTNodeIntegerLiteral *left, ASTNodeIntegerLiteral *right, Token::Operator op) { + return std::visit([&](auto &&leftValue, auto &&rightValue) -> ASTNodeIntegerLiteral* { - auto unionNode = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); + auto newType = [&] { + #define CHECK_TYPE(type) if (left->getType() == (type) || right->getType() == (type)) return (type) + #define DEFAULT_TYPE(type) return (type) - if (unionNode == nullptr) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; - } + CHECK_TYPE(Token::ValueType::Double); + CHECK_TYPE(Token::ValueType::Float); + CHECK_TYPE(Token::ValueType::Unsigned128Bit); + CHECK_TYPE(Token::ValueType::Signed128Bit); + CHECK_TYPE(Token::ValueType::Unsigned64Bit); + CHECK_TYPE(Token::ValueType::Signed64Bit); + CHECK_TYPE(Token::ValueType::Unsigned32Bit); + CHECK_TYPE(Token::ValueType::Signed32Bit); + CHECK_TYPE(Token::ValueType::Unsigned16Bit); + CHECK_TYPE(Token::ValueType::Signed16Bit); + CHECK_TYPE(Token::ValueType::Unsigned8Bit); + CHECK_TYPE(Token::ValueType::Signed8Bit); + CHECK_TYPE(Token::ValueType::Character); + DEFAULT_TYPE(Token::ValueType::Signed32Bit); - size_t unionSize = 0; - for (const auto &node : unionNode->getNodes()) { - const auto &member = static_cast(node); + #undef CHECK_TYPE + #undef DEFAULT_TYPE + }(); - u64 memberOffset = 0; + switch (op) { + case Token::Operator::Plus: + return new ASTNodeIntegerLiteral(leftValue + rightValue, newType); + case Token::Operator::Minus: + return new ASTNodeIntegerLiteral(leftValue - rightValue, newType); + case Token::Operator::Star: + return new ASTNodeIntegerLiteral(leftValue * rightValue, newType); + case Token::Operator::Slash: + return new ASTNodeIntegerLiteral(leftValue / rightValue, newType); + case Token::Operator::ShiftLeft: + return new ASTNodeIntegerLiteral(leftValue << rightValue, newType); + case Token::Operator::ShiftRight: + return new ASTNodeIntegerLiteral(leftValue >> rightValue, newType); + case Token::Operator::BitAnd: + return new ASTNodeIntegerLiteral(leftValue & rightValue, newType); + case Token::Operator::BitXor: + return new ASTNodeIntegerLiteral(leftValue ^ rightValue, newType); + case Token::Operator::BitOr: + return new ASTNodeIntegerLiteral(leftValue | rightValue, newType); + default: throwEvaluateError("invalid operator used in mathematical expression", left->getLineNumber()); - if (member->getPointerSize().has_value()) { - this->m_provider->read(offset + unionSize, &memberOffset, member->getPointerSize().value()); - - memberOffset = hex::changeEndianess(memberOffset, member->getPointerSize().value(), member->getEndianess().value_or(this->m_defaultDataEndianess)); } + + }, left->getValue(), right->getValue()); + } + + ASTNodeIntegerLiteral* Evaluator::evaluateMathematicalExpression(ASTNodeNumericExpression *node) { + ASTNodeIntegerLiteral *leftInteger, *rightInteger; + + if (auto leftExprLiteral = dynamic_cast(node->getLeftOperand()); leftExprLiteral != nullptr) + leftInteger = leftExprLiteral; + else if (auto leftExprExpression = dynamic_cast(node->getLeftOperand()); leftExprExpression != nullptr) + leftInteger = evaluateMathematicalExpression(leftExprExpression); + else if (auto leftExprRvalue = dynamic_cast(node->getLeftOperand()); leftExprRvalue != nullptr) + leftInteger = evaluateRValue(leftExprRvalue); + else + throwEvaluateError("invalid expression. Expected integer literal", node->getLineNumber()); + + if (auto rightExprLiteral = dynamic_cast(node->getRightOperand()); rightExprLiteral != nullptr) + rightInteger = rightExprLiteral; + else if (auto rightExprExpression = dynamic_cast(node->getRightOperand()); rightExprExpression != nullptr) + rightInteger = evaluateMathematicalExpression(rightExprExpression); + else if (auto rightExprRvalue = dynamic_cast(node->getRightOperand()); rightExprRvalue != nullptr) + rightInteger = evaluateRValue(rightExprRvalue); + else + throwEvaluateError("invalid expression. Expected integer literal", node->getLineNumber()); + + return evaluateOperator(leftInteger, rightInteger, node->getOperator()); + } + + PatternData* Evaluator::evaluateBuiltinType(ASTNodeBuiltinType *node) { + auto &type = node->getType(); + auto typeSize = Token::getTypeSize(type); + + PatternData *pattern; + + if (type == Token::ValueType::Character) + pattern = new PatternDataCharacter(this->m_currOffset); + else if (Token::isUnsigned(type)) + pattern = new PatternDataUnsigned(this->m_currOffset, typeSize); + else if (Token::isSigned(type)) + pattern = new PatternDataSigned(this->m_currOffset, typeSize); + else if (Token::isFloatingPoint(type)) + pattern = new PatternDataFloat(this->m_currOffset, typeSize); + else + throwEvaluateError("invalid builtin type", node->getLineNumber()); + + this->m_currOffset += typeSize; + + pattern->setTypeName(Token::getTypeName(type)); + + return pattern; + } + + PatternData* Evaluator::evaluateStruct(ASTNodeStruct *node) { + std::vector memberPatterns; + + ScopeExit currMemberReset([this] { this->m_currMembers = nullptr; }); + if (this->m_currMembers == nullptr) + this->m_currMembers = &memberPatterns; + else + currMemberReset.release(); + + auto startOffset = this->m_currOffset; + for (auto &member : node->getMembers()) { + if (auto memberVariableNode = dynamic_cast(member); memberVariableNode != nullptr) + memberPatterns.emplace_back(this->evaluateVariable(memberVariableNode)); + else if (auto memberArrayNode = dynamic_cast(member); memberArrayNode != nullptr) + memberPatterns.emplace_back(this->evaluateArray(memberArrayNode)); + else if (auto memberPointerNode = dynamic_cast(member); memberPointerNode != nullptr) + memberPatterns.emplace_back(this->evaluatePointer(memberPointerNode)); else - memberOffset = offset; + throwEvaluateError("invalid struct member", member->getLineNumber()); - const auto typeDeclNode = static_cast(this->m_types[member->getCustomVariableTypeName()]); + this->m_currEndian.reset(); + } - PatternData *pattern = nullptr; - size_t memberSize = 0; + return new PatternDataStruct(startOffset, this->m_currOffset - startOffset, memberPatterns); + } - if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) { - std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset); + PatternData* Evaluator::evaluateUnion(ASTNodeUnion *node) { + std::vector memberPatterns; - } else if (member->getVariableType() == Token::TypeToken::Type::CustomType - && typeDeclNode != nullptr && typeDeclNode->getAssignedType() == Token::TypeToken::Type::Signed8Bit - && member->getArraySize() > 1) { + ScopeExit currMemberReset([this] { this->m_currMembers = nullptr; }); + if (this->m_currMembers == nullptr) + this->m_currMembers = &memberPatterns; + else + currMemberReset.release(); - std::tie(pattern, memberSize) = this->createStringPattern(member, memberOffset); + auto startOffset = this->m_currOffset; + for (auto &member : node->getMembers()) { + if (auto memberVariableNode = dynamic_cast(member); memberVariableNode != nullptr) + memberPatterns.emplace_back(this->evaluateVariable(memberVariableNode)); + else if (auto memberArrayNode = dynamic_cast(member); memberArrayNode != nullptr) + memberPatterns.emplace_back(this->evaluateArray(memberArrayNode)); + else if (auto memberPointerNode = dynamic_cast(member); memberPointerNode != nullptr) + memberPatterns.emplace_back(this->evaluatePointer(memberPointerNode)); + else + throwEvaluateError("invalid union member", member->getLineNumber()); - } - else if (member->getArraySize() > 1 || member->getVariableType() == Token::TypeToken::Type::Padding) { - std::tie(pattern, memberSize) = this->createArrayPattern(member, memberOffset); + this->m_currOffset = startOffset; + this->m_currEndian.reset(); + } - } - else if (member->getArraySizeVariable().has_value()) { - std::optional arraySize; + return new PatternDataUnion(startOffset, this->m_currOffset - startOffset, memberPatterns); + } + PatternData* Evaluator::evaluateEnum(ASTNodeEnum *node) { + std::vector> entryPatterns; - for (auto &prevMember : members) { - if (prevMember->getPatternType() == PatternData::Type::Unsigned && prevMember->getName() == member->getArraySizeVariable()) { - u64 value = 0; - this->m_provider->read(prevMember->getOffset(), &value, prevMember->getSize()); + auto startOffset = this->m_currOffset; + for (auto &[name, value] : node->getEntries()) { + auto expression = dynamic_cast(value); + if (expression == nullptr) + throwEvaluateError("invalid expression in enum value", value->getLineNumber()); - value = hex::changeEndianess(value, prevMember->getSize(), prevMember->getEndianess()); + auto valueNode = evaluateMathematicalExpression(expression); + SCOPE_EXIT( delete valueNode; ); - arraySize = value; - } + entryPatterns.emplace_back( std::get(valueNode->getValue()), name ); + } + + size_t size; + if (auto underlyingType = dynamic_cast(node->getUnderlyingType()); underlyingType != nullptr) + size = Token::getTypeSize(underlyingType->getType()); + else + throwEvaluateError("invalid enum underlying type", node->getLineNumber()); + + return new PatternDataEnum(startOffset, size, entryPatterns); + } + + PatternData* Evaluator::evaluateBitfield(ASTNodeBitfield *node) { + std::vector> entryPatterns; + + auto startOffset = this->m_currOffset; + size_t bits = 0; + for (auto &[name, value] : node->getEntries()) { + auto expression = dynamic_cast(value); + if (expression == nullptr) + throwEvaluateError("invalid expression in bitfield field size", value->getLineNumber()); + + auto valueNode = evaluateMathematicalExpression(expression); + SCOPE_EXIT( delete valueNode; ); + + auto fieldBits = std::get(valueNode->getValue()); + if (fieldBits > 64) + throwEvaluateError("bitfield entry must at most occupy 64 bits", value->getLineNumber()); + + bits += fieldBits; + + entryPatterns.emplace_back(name, fieldBits); + } + + return new PatternDataBitfield(startOffset, (bits / 8) + 1, entryPatterns); + } + + PatternData* Evaluator::evaluateType(ASTNodeTypeDecl *node) { + auto type = node->getType(); + + if (!this->m_currEndian.has_value()) + this->m_currEndian = node->getEndian(); + + PatternData *pattern; + + if (auto builtinTypeNode = dynamic_cast(type); builtinTypeNode != nullptr) + return this->evaluateBuiltinType(builtinTypeNode); + else if (auto typeDeclNode = dynamic_cast(type); typeDeclNode != nullptr) + pattern = this->evaluateType(typeDeclNode); + else if (auto structNode = dynamic_cast(type); structNode != nullptr) + pattern = this->evaluateStruct(structNode); + else if (auto unionNode = dynamic_cast(type); unionNode != nullptr) + pattern = this->evaluateUnion(unionNode); + else if (auto enumNode = dynamic_cast(type); enumNode != nullptr) + pattern = this->evaluateEnum(enumNode); + else if (auto bitfieldNode = dynamic_cast(type); bitfieldNode != nullptr) + pattern = this->evaluateBitfield(bitfieldNode); + else + throwEvaluateError("type could not be evaluated", node->getLineNumber()); + + if (!node->getName().empty()) + pattern->setTypeName(node->getName().data()); + + return pattern; + } + + PatternData* Evaluator::evaluateVariable(ASTNodeVariableDecl *node) { + + if (auto offset = dynamic_cast(node->getPlacementOffset()); offset != nullptr) { + auto valueNode = evaluateMathematicalExpression(offset); + SCOPE_EXIT( delete valueNode; ); + + this->m_currOffset = std::get(valueNode->getValue()); + } + if (this->m_currOffset >= this->m_provider->getActualSize()) + throwEvaluateError("array exceeds size of file", node->getLineNumber()); + + PatternData *pattern; + if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) + pattern = this->evaluateType(typeDecl); + else if (auto builtinTypeDecl = dynamic_cast(node->getType()); builtinTypeDecl != nullptr) + pattern = this->evaluateBuiltinType(builtinTypeDecl); + else + throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!", 1); + + pattern->setVariableName(node->getName().data()); + pattern->setEndian(this->getCurrentEndian()); + this->m_currEndian.reset(); + + return pattern; + } + + PatternData* Evaluator::evaluateArray(ASTNodeArrayVariableDecl *node) { + + if (auto offset = dynamic_cast(node->getPlacementOffset()); offset != nullptr) { + auto valueNode = evaluateMathematicalExpression(offset); + SCOPE_EXIT( delete valueNode; ); + + this->m_currOffset = std::get(valueNode->getValue()); + } + + auto startOffset = this->m_currOffset; + + auto sizeNode = dynamic_cast(node->getSize()); + if (sizeNode == nullptr) + throwEvaluateError("array size not a numeric expression", node->getLineNumber()); + + auto valueNode = evaluateMathematicalExpression(sizeNode); + SCOPE_EXIT( delete valueNode; ); + + auto arraySize = std::get(valueNode->getValue()); + + if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) { + if (auto builtinType = dynamic_cast(typeDecl->getType()); builtinType != nullptr) { + if (builtinType->getType() == Token::ValueType::Padding) { + this->m_currOffset += arraySize; + return new PatternDataPadding(startOffset, arraySize); } - - if (!arraySize.has_value()) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a previous member of '%s'", member->getArraySizeVariable().value().c_str(), varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; - } - - if (arraySize.value() == 0) - continue; - - ASTNodeVariableDecl *processedMember = new ASTNodeVariableDecl(member->getLineNumber(), member->getVariableType(), member->getVariableName(), member->getCustomVariableTypeName(), member->getOffset(), arraySize.value()); - - std::tie(pattern, memberSize) = this->createArrayPattern(processedMember, memberOffset); - } - else if (member->getVariableType() != Token::TypeToken::Type::CustomType) { - std::tie(pattern, memberSize) = this->createBuiltInTypePattern(member, memberOffset); - } - else { - std::tie(pattern, memberSize) = this->createCustomTypePattern(member, memberOffset); - } - - if (pattern == nullptr) - return { nullptr, 0 }; - - pattern->setEndianess(member->getEndianess().value_or(varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess))); - - if (member->getPointerSize().has_value()) { - members.push_back(new PatternDataPointer(offset, member->getPointerSize().value(), member->getVariableName(), pattern, member->getEndianess().value_or(this->m_defaultDataEndianess))); - unionSize = std::max(size_t(member->getPointerSize().value()), unionSize); - } - else { - members.push_back(pattern); - unionSize = std::max(memberSize, unionSize); } } - return { new PatternDataUnion(offset, unionSize, varDeclNode->getVariableName(), unionNode->getName(), members, varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess), 0x00FFFFFF), unionSize }; - } - - std::pair Evaluator::createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - auto *enumType = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - - if (enumType == nullptr) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; - } - - size_t size = Token::getTypeSize(enumType->getUnderlyingType()); - - return { new PatternDataEnum(offset, size, varDeclNode->getVariableName(), enumType->getName(), enumType->getValues(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), size }; - } - - std::pair Evaluator::createBitfieldPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - - auto *bitfieldType = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - - if (bitfieldType == nullptr) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; - } - - size_t size = 0; - for (auto &[fieldName, fieldSize] : bitfieldType->getFields()) - size += fieldSize; - - size = bit_ceil(size) / 8; - - return { new PatternDataBitfield(offset, size, varDeclNode->getVariableName(), bitfieldType->getName(), bitfieldType->getFields(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), size }; - } - - std::pair Evaluator::createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { std::vector entries; - - size_t arrayOffset = 0; - std::optional arrayColor; - for (u32 i = 0; i < varDeclNode->getArraySize(); i++) { - ASTNodeVariableDecl *nonArrayVarDeclNode = new ASTNodeVariableDecl(varDeclNode->getLineNumber(), varDeclNode->getVariableType(), "[" + std::to_string(i) + "]", varDeclNode->getCustomVariableTypeName(), varDeclNode->getOffset(), 1); - - - if (varDeclNode->getVariableType() == Token::TypeToken::Type::Padding) { - return { new PatternDataPadding(offset, varDeclNode->getArraySize()), varDeclNode->getArraySize() }; - } else if (varDeclNode->getVariableType() != Token::TypeToken::Type::CustomType) { - const auto& [pattern, size] = this->createBuiltInTypePattern(nonArrayVarDeclNode, offset + arrayOffset); - - if (pattern == nullptr) { - delete nonArrayVarDeclNode; - return { nullptr, 0 }; - } - - pattern->setEndianess(varDeclNode->getEndianess().value_or(varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess))); - - if (!arrayColor.has_value()) - arrayColor = pattern->getColor(); - - pattern->setColor(arrayColor.value()); - - entries.push_back(pattern); - arrayOffset += size; - } else { - const auto &[pattern, size] = this->createCustomTypePattern(nonArrayVarDeclNode, offset + arrayOffset); - - if (pattern == nullptr) { - delete nonArrayVarDeclNode; - return { nullptr, 0 }; - } - - pattern->setEndianess(varDeclNode->getEndianess().value_or(varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess))); - - if (!arrayColor.has_value()) - arrayColor = pattern->getColor(); - - pattern->setColor(arrayColor.value()); - - entries.push_back(pattern); - arrayOffset += size; + std::optional color; + for (s128 i = 0; i < arraySize; i++) { + PatternData *entry; + if (auto typeDecl = dynamic_cast(node->getType()); typeDecl != nullptr) + entry = this->evaluateType(typeDecl); + else if (auto builtinTypeDecl = dynamic_cast(node->getType()); builtinTypeDecl != nullptr) { + entry = this->evaluateBuiltinType(builtinTypeDecl); } + else + throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!", 1); - delete nonArrayVarDeclNode; + entry->setVariableName(hex::format("[%llu]", (u64)i)); + entry->setEndian(this->getCurrentEndian()); + + if (!color.has_value()) + color = entry->getColor(); + entry->setColor(color.value_or(0)); + + entries.push_back(entry); + + if (this->m_currOffset >= this->m_provider->getActualSize()) + throwEvaluateError("array exceeds size of file", node->getLineNumber()); } - return { new PatternDataArray(offset, arrayOffset, varDeclNode->getVariableName(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess), entries, arrayColor.value_or(0xFF000000)), arrayOffset }; + this->m_currEndian.reset(); + + if (entries.empty()) + throwEvaluateError("array size must be greater than zero", node->getLineNumber()); + + + PatternData *pattern; + if (dynamic_cast(entries[0])) + pattern = new PatternDataString(startOffset, (this->m_currOffset - startOffset), color.value_or(0)); + else + pattern = new PatternDataArray(startOffset, (this->m_currOffset - startOffset), entries, color.value_or(0)); + + pattern->setVariableName(node->getName().data()); + + return pattern; } - std::pair Evaluator::createStringPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - size_t arraySize = varDeclNode->getArraySize(); + PatternData* Evaluator::evaluatePointer(ASTNodePointerVariableDecl *node) { + s128 pointerOffset; + if (auto offset = dynamic_cast(node->getPlacementOffset()); offset != nullptr) { + auto valueNode = evaluateMathematicalExpression(offset); + SCOPE_EXIT( delete valueNode; ); - return { new PatternDataString(offset, arraySize, varDeclNode->getVariableName(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), arraySize }; - } - - std::pair Evaluator::createCustomTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - auto &currType = this->m_types[varDeclNode->getCustomVariableTypeName()]; - - if (currType == nullptr) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; + pointerOffset = std::get(valueNode->getValue()); + this->m_currOffset = pointerOffset; + } else { + pointerOffset = this->m_currOffset; } - switch (currType->getType()) { - case ASTNode::Type::Struct: - return this->createStructPattern(varDeclNode, offset); - case ASTNode::Type::Union: - return this->createUnionPattern(varDeclNode, offset); - case ASTNode::Type::Enum: - return this->createEnumPattern(varDeclNode, offset); - case ASTNode::Type::Bitfield: - return this->createBitfieldPattern(varDeclNode, offset); - case ASTNode::Type::TypeDecl: - return this->createBuiltInTypePattern(varDeclNode, offset); - } + PatternData *sizeType; + if (auto builtinTypeNode = dynamic_cast(node->getSizeType()); builtinTypeNode != nullptr) { + sizeType = evaluateBuiltinType(builtinTypeNode); + } else + throwEvaluateError("Pointer size is not a builtin type", node->getLineNumber()); - return { nullptr, 0 }; - } + size_t pointerSize = sizeType->getSize(); + delete sizeType; - std::pair Evaluator::createBuiltInTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset) { - auto type = varDeclNode->getVariableType(); - if (type == Token::TypeToken::Type::CustomType) { - const auto &currType = static_cast(this->m_types[varDeclNode->getCustomVariableTypeName()]); - if (currType == nullptr) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("'%s' does not name a type", varDeclNode->getCustomVariableTypeName().c_str()) }; - return { nullptr, 0 }; - } + u128 pointedAtOffset = 0; + this->m_provider->read(pointerOffset, &pointedAtOffset, pointerSize); - type = currType->getAssignedType(); - } + this->m_currOffset = pointedAtOffset; + auto pointedAt = evaluateType(dynamic_cast(node->getType())); + this->m_currOffset = pointerOffset + pointerSize; - size_t typeSize = Token::getTypeSize(type); - size_t arraySize = varDeclNode->getArraySize(); - - if (Token::isSigned(type)) { - if (typeSize == 1 && arraySize == 1) - return { new PatternDataCharacter(offset, typeSize, varDeclNode->getVariableName(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), 1 }; - else if (arraySize > 1) - return createArrayPattern(varDeclNode, offset); - else - return { new PatternDataSigned(offset, typeSize, varDeclNode->getVariableName(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), typeSize * arraySize }; - } else if (Token::isUnsigned(varDeclNode->getVariableType())) { - if (arraySize > 1) - return createArrayPattern(varDeclNode, offset); - else - return { new PatternDataUnsigned(offset, typeSize, varDeclNode->getVariableName(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), typeSize * arraySize }; - } else if (Token::isFloatingPoint(varDeclNode->getVariableType())) { - if (arraySize > 1) - return createArrayPattern(varDeclNode, offset); - else - return { new PatternDataFloat(offset, typeSize, varDeclNode->getVariableName(), varDeclNode->getEndianess().value_or(this->m_defaultDataEndianess)), typeSize * arraySize }; - } - - return { nullptr, 0 }; + return new PatternDataPointer(pointerOffset, pointerSize, pointedAt); } std::optional> Evaluator::evaluate(const std::vector &ast) { - // Evaluate types - for (const auto &node : ast) { + std::vector patterns; - switch(node->getType()) { - case ASTNode::Type::Struct: - { - auto *structNode = static_cast(node); - this->m_types.emplace(structNode->getName(), structNode); - } - break; - case ASTNode::Type::Union: - { - auto *unionNode = static_cast(node); - this->m_types.emplace(unionNode->getName(), unionNode); - } - break; - case ASTNode::Type::Enum: - { - auto *enumNode = static_cast(node); - this->m_types.emplace(enumNode->getName(), enumNode); - } - break; - case ASTNode::Type::Bitfield: - { - auto *bitfieldNode = static_cast(node); - this->m_types.emplace(bitfieldNode->getName(), bitfieldNode); - } - break; - case ASTNode::Type::TypeDecl: - { - auto *typeDeclNode = static_cast(node); + try { + for (const auto& node : ast) { + this->m_currEndian.reset(); - if (typeDeclNode->getAssignedType() == Token::TypeToken::Type::CustomType) - this->m_types.emplace(typeDeclNode->getTypeName(), this->m_types[typeDeclNode->getAssignedCustomTypeName()]); - else - this->m_types.emplace(typeDeclNode->getTypeName(), typeDeclNode); + if (auto variableDeclNode = dynamic_cast(node); variableDeclNode != nullptr) { + patterns.push_back(this->evaluateVariable(variableDeclNode)); + } else if (auto arrayDeclNode = dynamic_cast(node); arrayDeclNode != nullptr) { + patterns.push_back(this->evaluateArray(arrayDeclNode)); + } else if (auto pointerDeclNode = dynamic_cast(node); pointerDeclNode != nullptr) { + patterns.push_back(this->evaluatePointer(pointerDeclNode)); } - break; - case ASTNode::Type::VariableDecl: break; - case ASTNode::Type::Scope: break; + } + } catch (EvaluateError &e) { + this->m_error = e; + return { }; } - // Evaluate variable declarations - std::vector variables; - for (const auto &node : ast) { - if (node->getType() != ASTNode::Type::VariableDecl) - continue; - - auto *varDeclNode = static_cast(node); - - if (varDeclNode->getVariableType() == Token::TypeToken::Type::Signed8Bit && varDeclNode->getArraySize() > 1) { - const auto &[pattern, _] = createStringPattern(varDeclNode, varDeclNode->getOffset().value()); - variables.push_back(pattern); - } - else if (varDeclNode->getArraySize() > 1) { - const auto &[pattern, _] = this->createArrayPattern(varDeclNode, varDeclNode->getOffset().value()); - variables.push_back(pattern); - - } else if (varDeclNode->getVariableType() != Token::TypeToken::Type::CustomType) { - const auto &[pattern, _] = this->createBuiltInTypePattern(varDeclNode, varDeclNode->getOffset().value()); - variables.push_back(pattern); - } else { - const auto &[pattern, _] = this->createCustomTypePattern(varDeclNode, varDeclNode->getOffset().value()); - variables.push_back(pattern); - } - } - - for (const auto &var : variables) - if (var == nullptr) - return { }; - - return variables; + return patterns; } } \ No newline at end of file diff --git a/source/lang/lexer.cpp b/source/lang/lexer.cpp index 9cf2a2d92..c05b3a3bb 100644 --- a/source/lang/lexer.cpp +++ b/source/lang/lexer.cpp @@ -6,6 +6,9 @@ namespace hex::lang { +#define TOKEN(type, value) Token::Type::type, Token::type::value, lineNumber +#define VALUE_TOKEN(type, value) Token::Type::type, value, lineNumber + Lexer::Lexer() { } std::string matchTillInvalid(const char* characters, std::function predicate) { @@ -72,186 +75,192 @@ namespace hex::lang { u32 lineNumber = 1; - while (offset < code.length()) { + try { - // Handle comments - if (code[offset] == '/') { - offset++; + while (offset < code.length()) { + const char& c = code[offset]; - if (offset < code.length() && code[offset] == '/') { - offset++; - while (offset < code.length()) { - if (code[offset] == '\n' || code[offset] == '\r') - break; - offset++; - } - } else if (offset < code.length() && code[offset] == '*') { - offset++; - while (offset < (code.length() - 1)) { - if (code[offset] == '\n') lineNumber++; - - if (code[offset] == '*' && code[offset + 1] == '/') - break; - offset++; - } + if (c == 0x00) + break; + if (std::isblank(c) || std::isspace(c)) { + if (code[offset] == '\n') lineNumber++; + offset += 1; + } else if (c == ';') { + tokens.emplace_back(TOKEN(Separator, EndOfExpression)); + offset += 1; + } else if (c == '(') { + tokens.emplace_back(TOKEN(Separator, RoundBracketOpen)); + offset += 1; + } else if (c == ')') { + tokens.emplace_back(TOKEN(Separator, RoundBracketClose)); + offset += 1; + } else if (c == '{') { + tokens.emplace_back(TOKEN(Separator, CurlyBracketOpen)); + offset += 1; + } else if (c == '}') { + tokens.emplace_back(TOKEN(Separator, CurlyBracketClose)); + offset += 1; + } else if (c == '[') { + tokens.emplace_back(TOKEN(Separator, SquareBracketOpen)); + offset += 1; + } else if (c == ']') { + tokens.emplace_back(TOKEN(Separator, SquareBracketClose)); + offset += 1; + } else if (c == ',') { + tokens.emplace_back(TOKEN(Separator, Comma)); + offset += 1; + } else if (c == '.') { + tokens.emplace_back(TOKEN(Separator, Dot)); + offset += 1; + } else if (c == '@') { + tokens.emplace_back(TOKEN(Operator, AtDeclaration)); + offset += 1; + } else if (c == '=') { + tokens.emplace_back(TOKEN(Operator, Assignment)); + offset += 1; + } else if (c == ':') { + tokens.emplace_back(TOKEN(Operator, Inherit)); + offset += 1; + } else if (c == '+') { + tokens.emplace_back(TOKEN(Operator, Plus)); + offset += 1; + } else if (c == '-') { + tokens.emplace_back(TOKEN(Operator, Minus)); + offset += 1; + } else if (c == '*') { + tokens.emplace_back(TOKEN(Operator, Star)); + offset += 1; + } else if (c == '/') { + tokens.emplace_back(TOKEN(Operator, Slash)); + offset += 1; + } else if (offset + 1 <= code.length() && code[offset] == '<' && code[offset + 1] == '<') { + tokens.emplace_back(TOKEN(Operator, ShiftLeft)); offset += 2; - } else offset--; - } - - const char& c = code[offset]; - - if (c == 0x00) - break; - - if (std::isblank(c) || std::isspace(c)) { - if (code[offset] == '\n') lineNumber++; - offset += 1; - } else if (c == ';') { - tokens.push_back({ .type = Token::Type::EndOfExpression, .lineNumber = lineNumber }); - offset += 1; - } else if (c == '{') { - tokens.push_back({ .type = Token::Type::ScopeOpen, .lineNumber = lineNumber }); - offset += 1; - } else if (c == '}') { - tokens.push_back({ .type = Token::Type::ScopeClose, .lineNumber = lineNumber }); - offset += 1; - } else if (c == '[') { - tokens.push_back({ .type = Token::Type::ArrayOpen, .lineNumber = lineNumber }); - offset += 1; - } else if (c == ']') { - tokens.push_back({.type = Token::Type::ArrayClose, .lineNumber = lineNumber }); - offset += 1; - } else if (c == ',') { - tokens.push_back({ .type = Token::Type::Separator, .lineNumber = lineNumber }); - offset += 1; - } else if (c == '@') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::AtDeclaration }, .lineNumber = lineNumber }); - offset += 1; - } else if (c == '=') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Assignment }, .lineNumber = lineNumber }); - offset += 1; - } else if (c == ':') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Inherit }, .lineNumber = lineNumber }); - offset += 1; - } else if (c == '*') { - tokens.push_back({ .type = Token::Type::Operator, .operatorToken = { .op = Token::OperatorToken::Operator::Star }, .lineNumber = lineNumber }); - offset += 1; - } else if (c == '\'') { - offset += 1; - - if (offset >= code.length()) { - this->m_error = { lineNumber, "Invalid character literal" }; - return { }; - } - - char character = code[offset]; - - if (character == '\\') { + } else if (offset + 1 <= code.length() && code[offset] == '>' && code[offset + 1] == '>') { + tokens.emplace_back(TOKEN(Operator, ShiftRight)); + offset += 2; + } else if (c == '|') { + tokens.emplace_back(TOKEN(Operator, BitOr)); + offset += 1; + } else if (c == '&') { + tokens.emplace_back(TOKEN(Operator, BitAnd)); + offset += 1; + } else if (c == '^') { + tokens.emplace_back(TOKEN(Operator, BitXor)); + offset += 1; + } else if (c == '\'') { offset += 1; - if (offset >= code.length()) { - this->m_error = { lineNumber, "Invalid character literal" }; - return { }; + if (offset >= code.length()) + throwLexerError("invalid character literal", lineNumber); + + char character = code[offset]; + + if (character == '\\') { + offset += 1; + + if (offset >= code.length()) + throwLexerError("invalid character literal", lineNumber); + + if (code[offset] != '\\' && code[offset] != '\'') + throwLexerError("invalid escape sequence", lineNumber); + + + character = code[offset]; + } else { + if (code[offset] == '\\' || code[offset] == '\'' || character == '\n' || character == '\r') + throwLexerError("invalid character literal", lineNumber); + } - if (code[offset] != '\\' && code[offset] != '\'') { - this->m_error = { lineNumber, "Invalid escape sequence" }; - return { }; - } + offset += 1; - character = code[offset]; - } else { - if (code[offset] == '\\' || code[offset] == '\'' || character == '\n' || character == '\r') { - this->m_error = { lineNumber, "Invalid character literal" }; - return { }; - } - } + if (offset >= code.length() || code[offset] != '\'') + throwLexerError("missing terminating ' after character literal", lineNumber); - offset += 1; + tokens.emplace_back(VALUE_TOKEN(Integer, character)); + offset += 1; - if (offset >= code.length() || code[offset] != '\'') { - this->m_error = { lineNumber, "Missing terminating ' after character literal" }; - return { }; - } + } else if (std::isalpha(c)) { + std::string identifier = matchTillInvalid(&code[offset], [](char c) -> bool { return std::isalnum(c) || c == '_'; }); - tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = character }, .lineNumber = lineNumber }); - offset += 1; + // Check for reserved keywords - } else if (std::isalpha(c)) { - std::string identifier = matchTillInvalid(&code[offset], [](char c) -> bool { return std::isalnum(c) || c == '_'; }); + if (identifier == "struct") + tokens.emplace_back(TOKEN(Keyword, Struct)); + else if (identifier == "union") + tokens.emplace_back(TOKEN(Keyword, Union)); + else if (identifier == "using") + tokens.emplace_back(TOKEN(Keyword, Using)); + else if (identifier == "enum") + tokens.emplace_back(TOKEN(Keyword, Enum)); + else if (identifier == "bitfield") + tokens.emplace_back(TOKEN(Keyword, Bitfield)); + else if (identifier == "be") + tokens.emplace_back(TOKEN(Keyword, BigEndian)); + else if (identifier == "le") + tokens.emplace_back(TOKEN(Keyword, LittleEndian)); - // Check for reserved keywords + // Check for built-in types + else if (identifier == "u8") + tokens.emplace_back(TOKEN(ValueType, Unsigned8Bit)); + else if (identifier == "s8") + tokens.emplace_back(TOKEN(ValueType, Signed8Bit)); + else if (identifier == "u16") + tokens.emplace_back(TOKEN(ValueType, Unsigned16Bit)); + else if (identifier == "s16") + tokens.emplace_back(TOKEN(ValueType, Signed16Bit)); + else if (identifier == "u32") + tokens.emplace_back(TOKEN(ValueType, Unsigned32Bit)); + else if (identifier == "s32") + tokens.emplace_back(TOKEN(ValueType, Signed32Bit)); + else if (identifier == "u64") + tokens.emplace_back(TOKEN(ValueType, Unsigned64Bit)); + else if (identifier == "s64") + tokens.emplace_back(TOKEN(ValueType, Signed64Bit)); + else if (identifier == "u128") + tokens.emplace_back(TOKEN(ValueType, Unsigned128Bit)); + else if (identifier == "s128") + tokens.emplace_back(TOKEN(ValueType, Signed128Bit)); + else if (identifier == "float") + tokens.emplace_back(TOKEN(ValueType, Float)); + else if (identifier == "double") + tokens.emplace_back(TOKEN(ValueType, Double)); + else if (identifier == "char") + tokens.emplace_back(TOKEN(ValueType, Character)); + else if (identifier == "padding") + tokens.emplace_back(TOKEN(ValueType, Padding)); - if (identifier == "struct") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Struct }, .lineNumber = lineNumber }); - else if (identifier == "union") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Union }, .lineNumber = lineNumber }); - else if (identifier == "using") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Using }, .lineNumber = lineNumber }); - else if (identifier == "enum") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Enum }, .lineNumber = lineNumber }); - else if (identifier == "bitfield") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::Bitfield }, .lineNumber = lineNumber }); - else if (identifier == "be") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::BigEndian }, .lineNumber = lineNumber }); - else if (identifier == "le") - tokens.push_back({ .type = Token::Type::Keyword, .keywordToken = { .keyword = Token::KeywordToken::Keyword::LittleEndian }, .lineNumber = lineNumber }); + // If it's not a keyword and a builtin type, it has to be an identifier - // Check for built-in types - else if (identifier == "u8") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned8Bit }, .lineNumber = lineNumber }); - else if (identifier == "s8") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed8Bit }, .lineNumber = lineNumber }); - else if (identifier == "u16") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned16Bit }, .lineNumber = lineNumber }); - else if (identifier == "s16") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed16Bit }, .lineNumber = lineNumber }); - else if (identifier == "u32") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned32Bit }, .lineNumber = lineNumber }); - else if (identifier == "s32") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed32Bit }, .lineNumber = lineNumber }); - else if (identifier == "u64") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned64Bit }, .lineNumber = lineNumber }); - else if (identifier == "s64") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed64Bit }, .lineNumber = lineNumber }); - else if (identifier == "u128") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Unsigned128Bit }, .lineNumber = lineNumber }); - else if (identifier == "s128") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Signed128Bit }, .lineNumber = lineNumber }); - else if (identifier == "float") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Float }, .lineNumber = lineNumber }); - else if (identifier == "double") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Double }, .lineNumber = lineNumber }); - else if (identifier == "padding") - tokens.push_back({ .type = Token::Type::Type, .typeToken = { .type = Token::TypeToken::Type::Padding }, .lineNumber = lineNumber }); + else + tokens.emplace_back(VALUE_TOKEN(Identifier, identifier)); - // If it's not a keyword and a builtin type, it has to be an identifier + offset += identifier.length(); + } else if (std::isdigit(c)) { + char *end = nullptr; + std::strtoull(&code[offset], &end, 0); - else - tokens.push_back({.type = Token::Type::Identifier, .identifierToken = { .identifier = identifier }, .lineNumber = lineNumber }); + auto integer = parseInt(std::string_view(&code[offset], end - &code[offset])); - offset += identifier.length(); - } else if (std::isdigit(c)) { - char *end = nullptr; - std::strtoull(&code[offset], &end, 0); + if (!integer.has_value()) + throwLexerError("invalid integer literal", lineNumber); - auto integer = parseInt(std::string_view(&code[offset], end - &code[offset])); - if (!integer.has_value()) { - this->m_error = { lineNumber, "Invalid integer literal" }; - return { }; - } + tokens.emplace_back(VALUE_TOKEN(Integer, integer.value())); + offset += (end - &code[offset]); + } else + throwLexerError("unknown token", lineNumber); - tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = integer.value() }, .lineNumber = lineNumber }); - offset += (end - &code[offset]); - } else { - this->m_error = { lineNumber, "Unknown token" }; - return { }; } + + tokens.emplace_back(TOKEN(Separator, EndOfProgram)); + } catch (LexerError &e) { + this->m_error = e; + return { }; } - tokens.push_back({ .type = Token::Type::EndOfProgram, .lineNumber = lineNumber }); return tokens; } diff --git a/source/lang/parser.cpp b/source/lang/parser.cpp index bec534a42..22309628d 100644 --- a/source/lang/parser.cpp +++ b/source/lang/parser.cpp @@ -1,664 +1,453 @@ #include "lang/parser.hpp" -#include "helpers/utils.hpp" -#include "lang/token.hpp" - #include +#include +#define MATCHES(x) (begin() && x) + +// Definition syntax: +// [A] : Either A or no token +// [A|B] : Either A, B or no token +// : Either A or B +// : One or more of A +// A B C : Sequence of tokens A then B then C +// (parseXXXX) : Parsing handled by other function namespace hex::lang { - Parser::Parser() { + /* Mathematical expressions */ + // + ASTNode* Parser::parseRValue(std::vector &path) { + if (peek(IDENTIFIER, -1)) + path.push_back(getValue(-1)); + + if (MATCHES(sequence(SEPARATOR_DOT))) { + if (MATCHES(sequence(IDENTIFIER))) + return this->parseRValue(path); + else + throwParseError("expected member name", -1); + } else + return new ASTNodeRValue(path); } - bool Parser::tryConsume(TokenIter &curr, std::initializer_list tokenTypes) { - std::vector::const_iterator originalPosition = curr; - - for (const auto& type : tokenTypes) { - if (curr->type != type) { - curr = originalPosition; - return false; - } - curr++; - } - - return true; - } - - - ASTNode* Parser::parseBuiltinVariableDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; - - if (curr[-4].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-4].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; - } - - return new ASTNodeVariableDecl(curr[-4].lineNumber, curr[-3].typeToken.type, curr[-2].identifierToken.identifier, "", {}, 1, {}, {}, endianess); + // + ASTNode* Parser::parseFactor() { + if (MATCHES(sequence(INTEGER))) + return new ASTNodeNumericExpression(new ASTNodeIntegerLiteral(getValue(-1), Token::ValueType::Signed128Bit), new ASTNodeIntegerLiteral(0, Token::ValueType::Signed128Bit), Token::Operator::Plus); + else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN))) { + auto node = this->parseMathematicalExpression(); + if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) + throwParseError("expected closing parenthesis"); + return node; + } else if (MATCHES(sequence(IDENTIFIER))) { + std::vector path; + return this->parseRValue(path); } else - return new ASTNodeVariableDecl(curr[-3].lineNumber, curr[-3].typeToken.type, curr[-2].identifierToken.identifier); + throwParseError("expected integer or parenthesis"); } - ASTNode* Parser::parseCustomTypeVariableDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; + // (parseFactor) <*|/> (parseFactor) + ASTNode* Parser::parseMultiplicativeExpression() { + auto node = this->parseFactor(); - if (curr[-4].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-4].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else return nullptr; - - return new ASTNodeVariableDecl(curr[-4].lineNumber, Token::TypeToken::Type::CustomType, curr[-2].identifierToken.identifier, curr[-3].identifierToken.identifier, {}, 1, {}, {}, endianess); + while (MATCHES(variant(OPERATOR_STAR, OPERATOR_SLASH))) { + if (peek(OPERATOR_STAR, -1)) + node = new ASTNodeNumericExpression(node, this->parseFactor(), Token::Operator::Star); + else + node = new ASTNodeNumericExpression(node, this->parseFactor(), Token::Operator::Slash); } + + return node; + } + + // (parseMultiplicativeExpression) <+|-> (parseMultiplicativeExpression) + ASTNode* Parser::parseAdditiveExpression() { + auto node = this->parseMultiplicativeExpression(); + + while (MATCHES(variant(OPERATOR_PLUS, OPERATOR_MINUS))) { + if (peek(OPERATOR_PLUS, -1)) + node = new ASTNodeNumericExpression(node, this->parseMultiplicativeExpression(), Token::Operator::Plus); + else + node = new ASTNodeNumericExpression(node, this->parseMultiplicativeExpression(), Token::Operator::Minus); + } + + return node; + } + + // (parseAdditiveExpression) <>>|<<> (parseAdditiveExpression) + ASTNode* Parser::parseShiftExpression() { + auto node = this->parseAdditiveExpression(); + + while (MATCHES(variant(OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT))) { + if (peek(OPERATOR_SHIFTLEFT, -1)) + node = new ASTNodeNumericExpression(node, this->parseAdditiveExpression(), Token::Operator::ShiftLeft); + else + node = new ASTNodeNumericExpression(node, this->parseAdditiveExpression(), Token::Operator::ShiftRight); + } + + return node; + } + + // (parseShiftExpression) & (parseShiftExpression) + ASTNode* Parser::parseBinaryAndExpression() { + auto node = this->parseShiftExpression(); + + while (MATCHES(sequence(OPERATOR_BITAND))) { + node = new ASTNodeNumericExpression(node, this->parseShiftExpression(), Token::Operator::BitAnd); + } + + return node; + } + + // (parseBinaryAndExpression) ^ (parseBinaryAndExpression) + ASTNode* Parser::parseBinaryXorExpression() { + auto node = this->parseBinaryAndExpression(); + + while (MATCHES(sequence(OPERATOR_BITXOR))) { + node = new ASTNodeNumericExpression(node, this->parseBinaryAndExpression(), Token::Operator::BitXor); + } + + return node; + } + + // (parseBinaryXorExpression) | (parseBinaryXorExpression) + ASTNode* Parser::parseBinaryOrExpression() { + auto node = this->parseBinaryXorExpression(); + + while (MATCHES(sequence(OPERATOR_BITOR))) { + node = new ASTNodeNumericExpression(node, this->parseBinaryXorExpression(), Token::Operator::BitOr); + } + + return node; + } + + // (parseBinaryOrExpression) + ASTNode* Parser::parseMathematicalExpression() { + return this->parseBinaryOrExpression(); + } + + /* Type declarations */ + + // [be|le] + ASTNode* Parser::parseType(s32 startIndex) { + std::optional endian; + + if (peekOptional(KEYWORD_LE, 0)) + endian = std::endian::little; + else if (peekOptional(KEYWORD_BE, 0)) + endian = std::endian::big; + + if (getType(startIndex) == Token::Type::Identifier) { // Custom type + if (!this->m_types.contains(getValue(startIndex))) + throwParseError("failed to parse type"); + + return new ASTNodeTypeDecl({ }, this->m_types[getValue(startIndex)]->clone(), endian); + } + else { // Builtin type + return new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(getValue(startIndex)), endian); + } + } + + // using Identifier = (parseType) + ASTNode* Parser::parseUsingDeclaration() { + auto *temporaryType = dynamic_cast(parseType(-1)); + if (temporaryType == nullptr) throwParseError("invalid type used in variable declaration", -1); + SCOPE_EXIT( delete temporaryType; ); + + if (peekOptional(KEYWORD_BE) || peekOptional(KEYWORD_LE)) + return new ASTNodeTypeDecl(getValue(-4), temporaryType->getType()->clone(), temporaryType->getEndian()); else - return new ASTNodeVariableDecl(curr[-3].lineNumber, Token::TypeToken::Type::CustomType, curr[-2].identifierToken.identifier, curr[-3].identifierToken.identifier); + return new ASTNodeTypeDecl(getValue(-3), temporaryType->getType()->clone(), temporaryType->getEndian()); } - ASTNode* Parser::parseBuiltinPointerVariableDecl(TokenIter &curr, bool hasEndianDef) { - auto pointerType = curr[-2].typeToken.type; + // padding[(parseMathematicalExpression)] + ASTNode* Parser::parsePadding() { + auto size = parseMathematicalExpression(); - if (!Token::isUnsigned(pointerType)) { - this->m_error = { curr->lineNumber, "Pointer size needs to be a unsigned type" }; - return nullptr; + if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) { + delete size; + throwParseError("expected closing ']' at end of array declaration", -1); } - if (curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star) { - this->m_error = { curr->lineNumber, "Expected '*' for pointer definition" }; - return nullptr; + return new ASTNodeArrayVariableDecl({ }, new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(Token::ValueType::Padding)), size);; + } + + // (parseType) Identifier + ASTNode* Parser::parseMemberVariable() { + auto temporaryType = dynamic_cast(parseType(-2)); + if (temporaryType == nullptr) throwParseError("invalid type used in variable declaration", -1); + SCOPE_EXIT( delete temporaryType; ); + + return new ASTNodeVariableDecl(getValue(-1), temporaryType->getType()->clone()); + } + + // (parseType) Identifier[(parseMathematicalExpression)] + ASTNode* Parser::parseMemberArrayVariable() { + auto temporaryType = dynamic_cast(parseType(-3)); + if (temporaryType == nullptr) throwParseError("invalid type used in variable declaration", -1); + SCOPE_EXIT( delete temporaryType; ); + + auto name = getValue(-2); + auto size = parseMathematicalExpression(); + + if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) + throwParseError("expected closing ']' at end of array declaration", -1); + + return new ASTNodeArrayVariableDecl(name, temporaryType->getType()->clone(), size); + } + + // (parseType) *Identifier : (parseType) + ASTNode* Parser::parseMemberPointerVariable() { + auto name = getValue(-2); + + auto temporaryPointerType = dynamic_cast(parseType(-4)); + if (temporaryPointerType == nullptr) throwParseError("invalid type used in variable declaration", -1); + SCOPE_EXIT( delete temporaryPointerType; ); + + if (!MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && sequence(VALUETYPE_UNSIGNED))) + throwParseError("expected unsigned builtin type as size", -1); + + auto temporarySizeType = dynamic_cast(parseType(-1)); + if (temporarySizeType == nullptr) throwParseError("invalid type used for pointer size", -1); + SCOPE_EXIT( delete temporarySizeType; ); + + return new ASTNodePointerVariableDecl(name, temporaryPointerType->getType()->clone(), temporarySizeType->getType()->clone()); + } + + // struct Identifier { <(parseMember)...> } + ASTNode* Parser::parseStruct() { + const auto structNode = new ASTNodeStruct(); + const auto &typeName = getValue(-2); + ScopeExit structGuard([&]{ delete structNode; }); + + while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { + if (MATCHES(sequence(VALUETYPE_PADDING, SEPARATOR_SQUAREBRACKETOPEN))) + structNode->addMember(parsePadding()); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) + structNode->addMember(parseMemberArrayVariable()); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER))) + structNode->addMember(parseMemberVariable()); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) + structNode->addMember(parseMemberPointerVariable()); + else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) + throwParseError("unexpected end of program", -2); + else + throwParseError("invalid struct member", 0); + + if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) + throwParseError("missing ';' at end of expression", -1); } - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { - this->m_error = { curr->lineNumber, "Expected ':' after member name" }; - return nullptr; + structGuard.release(); + + return new ASTNodeTypeDecl(typeName, structNode); + } + + // union Identifier { <(parseMember)...> } + ASTNode* Parser::parseUnion() { + const auto unionNode = new ASTNodeUnion(); + const auto &typeName = getValue(-2); + ScopeExit unionGuard([&]{ delete unionNode; }); + + while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { + if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) + unionNode->addMember(parseMemberArrayVariable()); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER))) + unionNode->addMember(parseMemberVariable()); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) + unionNode->addMember(parseMemberPointerVariable()); + else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) + throwParseError("unexpected end of program", -2); + else + throwParseError("invalid union member", 0); + + if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) + throwParseError("missing ';' at end of expression", -1); } + unionGuard.release(); - if (hasEndianDef) { - std::endian endianess; + return new ASTNodeTypeDecl(typeName, unionNode); + } - if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else return nullptr; - - return new ASTNodeVariableDecl(curr[-7].lineNumber, curr[-6].typeToken.type, curr[-4].identifierToken.identifier, "", { }, 1, { }, Token::getTypeSize(pointerType), endianess); - } + // enum Identifier : (parseType) { <...> } + ASTNode* Parser::parseEnum() { + std::string typeName; + if (peekOptional(KEYWORD_BE) || peekOptional(KEYWORD_LE)) + typeName = getValue(-5); else - return new ASTNodeVariableDecl(curr[-6].lineNumber, curr[-6].typeToken.type, curr[-4].identifierToken.identifier, "", { }, 1, { }, Token::getTypeSize(pointerType)); - } + typeName = getValue(-4); - ASTNode* Parser::parseCustomTypePointerVariableDecl(TokenIter &curr, bool hasEndianDef) { - auto pointerType = curr[-2].typeToken.type; + auto temporaryTypeDecl = dynamic_cast(parseType(-2)); + if (temporaryTypeDecl == nullptr) throwParseError("failed to parse type", -2); + auto underlyingType = dynamic_cast(temporaryTypeDecl->getType()); + if (underlyingType == nullptr) throwParseError("underlying type is not a built-in type", -2); - if (!Token::isUnsigned(pointerType)) { - this->m_error = { curr->lineNumber, "Pointer size needs to be a unsigned type" }; - return nullptr; - } + const auto enumNode = new ASTNodeEnum(underlyingType); + ScopeExit enumGuard([&]{ delete enumNode; }); - if (curr[-5].operatorToken.op != Token::OperatorToken::Operator::Star) { - this->m_error = { curr->lineNumber, "Expected '*' for pointer definition" }; - return nullptr; - } - - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { - this->m_error = { curr->lineNumber, "Expected ':' after member name" }; - return nullptr; - } - - if (hasEndianDef) { - std::endian endianess; - - if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; + while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { + if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) { + auto name = getValue(-2); + enumNode->addEntry(name, parseMathematicalExpression()); } - - return new ASTNodeVariableDecl(curr[-7].lineNumber,Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 1, { }, Token::getTypeSize(pointerType), endianess); - } - else - return new ASTNodeVariableDecl(curr[-6].lineNumber, Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 1, { }, Token::getTypeSize(pointerType)); - } - - ASTNode* Parser::parseBuiltinArrayDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; - - if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; - } - - return new ASTNodeVariableDecl(curr[-7].lineNumber, curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, curr[-3].integerToken.integer, { }, { }, endianess); - } - else - return new ASTNodeVariableDecl(curr[-6].lineNumber, curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, curr[-3].integerToken.integer); - } - - ASTNode* Parser::parseCustomTypeArrayDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; - - if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; - } - - return new ASTNodeVariableDecl(curr[-7].lineNumber, Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, curr[-3].integerToken.integer, { }, { }, endianess); - } - else - return new ASTNodeVariableDecl(curr[-6].lineNumber, Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, curr[-3].integerToken.integer); - } - - ASTNode* Parser::parseBuiltinVariableArrayDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; - - if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; - } - - return new ASTNodeVariableDecl(curr[-7].lineNumber, curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, 0, curr[-3].identifierToken.identifier, { }, endianess); - } - else - return new ASTNodeVariableDecl(curr[-6].lineNumber, curr[-6].typeToken.type, curr[-5].identifierToken.identifier, "", { }, 0, curr[-3].identifierToken.identifier); - } - - ASTNode* Parser::parseCustomTypeVariableArrayDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; - - if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-7].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; - } - - return new ASTNodeVariableDecl(curr[-7].lineNumber, Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 0, curr[-3].identifierToken.identifier, { }, endianess); - } - else - return new ASTNodeVariableDecl(curr[-6].lineNumber, Token::TypeToken::Type::CustomType, curr[-5].identifierToken.identifier, curr[-6].identifierToken.identifier, { }, 0, curr[-3].identifierToken.identifier); - } - - ASTNode* Parser::parsePaddingDecl(TokenIter &curr) { - return new ASTNodeVariableDecl(curr[-5].lineNumber, curr[-5].typeToken.type, "", "", { }, curr[-3].integerToken.integer); - } - - ASTNode* Parser::parseFreeBuiltinVariableDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; - - if (curr[-6].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-6].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; - } - - return new ASTNodeVariableDecl(curr[-6].lineNumber, curr[-5].typeToken.type, curr[-4].identifierToken.identifier, "", curr[-2].integerToken.integer, 1, { }, { }, endianess); - } - else - return new ASTNodeVariableDecl(curr[-5].lineNumber, curr[-5].typeToken.type, curr[-4].identifierToken.identifier, "", curr[-2].integerToken.integer); - } - - ASTNode* Parser::parseFreeCustomTypeVariableDecl(TokenIter &curr, bool hasEndianDef) { - if (hasEndianDef) { - std::endian endianess; - - if (curr[-6].keywordToken.keyword == Token::KeywordToken::Keyword::LittleEndian) - endianess = std::endian::little; - else if (curr[-6].keywordToken.keyword == Token::KeywordToken::Keyword::BigEndian) - endianess = std::endian::big; - else { - this->m_error = { curr->lineNumber, "Expected be or le identifier" }; - return nullptr; - } - - return new ASTNodeVariableDecl(curr[-6].lineNumber, Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-5].identifierToken.identifier, curr[-2].integerToken.integer, 1, { }, { }, endianess); - } - else - return new ASTNodeVariableDecl(curr[-5].lineNumber, Token::TypeToken::Type::CustomType, curr[-4].identifierToken.identifier, curr[-5].identifierToken.identifier, curr[-2].integerToken.integer); - } - - ASTNode* Parser::parseStruct(TokenIter &curr) { - const std::string &structName = curr[-2].identifierToken.identifier; - std::vector nodes; - - u32 startLineNumber = curr[-3].lineNumber; - - while (!tryConsume(curr, {Token::Type::ScopeClose})) { - if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinArrayDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeArrayDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Identifier, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinVariableArrayDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Identifier, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeVariableArrayDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Type, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) { - if (curr[-5].typeToken.type != Token::TypeToken::Type::Padding) { - for(auto &node : nodes) delete node; - - this->m_error = { curr[-5].lineNumber, "No member name provided" }; - return nullptr; - } - nodes.push_back(parsePaddingDecl(curr)); - } else if (tryConsume(curr, {Token::Type::Type, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinPointerVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypePointerVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Type, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinVariableDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Identifier, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeVariableDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinArrayDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeArrayDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Identifier, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinVariableArrayDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Identifier, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeVariableArrayDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Type, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinPointerVariableDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypePointerVariableDecl(curr, true)); - else { - for(auto &node : nodes) delete node; - this->m_error = { curr[-1].lineNumber, "Invalid sequence, expected member declaration" }; - return nullptr; - } - } - - if (!tryConsume(curr, {Token::Type::EndOfExpression})) { - this->m_error = { curr[-1].lineNumber, "Expected ';' after struct definition" }; - for(auto &node : nodes) delete node; - return nullptr; - } - - return new ASTNodeStruct(startLineNumber, structName, nodes); - } - - ASTNode* Parser::parseUnion(TokenIter &curr) { - const std::string &unionName = curr[-2].identifierToken.identifier; - std::vector nodes; - - u32 startLineNumber = curr[-3].lineNumber; - - while (!tryConsume(curr, {Token::Type::ScopeClose})) { - if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinArrayDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeArrayDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Type, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinPointerVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypePointerVariableDecl(curr, false)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Type, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinVariableDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Identifier, Token::Type::Identifier, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeVariableDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Type, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinArrayDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Identifier, Token::Type::Identifier, Token::Type::ArrayOpen, Token::Type::Integer, Token::Type::ArrayClose, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypeArrayDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Type, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseBuiltinPointerVariableDecl(curr, true)); - else if (tryConsume(curr, {Token::Type::Keyword, Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) - nodes.push_back(parseCustomTypePointerVariableDecl(curr, true)); - else { - for(auto &node : nodes) delete node; - this->m_error = { curr[-1].lineNumber, "Invalid sequence, expected member declaration" }; - return nullptr; - } - } - - if (!tryConsume(curr, {Token::Type::EndOfExpression})) { - for(auto &node : nodes) delete node; - this->m_error = { curr[-1].lineNumber, "Expected ';' after union definition" }; - return nullptr; - } - - return new ASTNodeUnion(startLineNumber, unionName, nodes); - } - - ASTNode* Parser::parseEnum(TokenIter &curr) { - const std::string &enumName = curr[-4].identifierToken.identifier; - const Token::TypeToken::Type underlyingType = curr[-2].typeToken.type; - - u32 startLineNumber = curr[-5].lineNumber; - - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { - this->m_error = { curr[-3].lineNumber, "Expected ':' after enum name" }; - return nullptr; - } - - if (!Token::isUnsigned(underlyingType)) { - this->m_error = { curr[-3].lineNumber, "Underlying type needs to be an unsigned type" }; - return nullptr; - } - - auto enumNode = new ASTNodeEnum(startLineNumber, underlyingType, enumName); - - while (!tryConsume(curr, {Token::Type::ScopeClose})) { - if (tryConsume(curr, { Token::Type::Identifier, Token::Type::Separator }) || tryConsume(curr, { Token::Type::Identifier, Token::Type::ScopeClose })) { - u64 value; - if (enumNode->getValues().empty()) - value = 0; + else if (MATCHES(sequence(IDENTIFIER))) { + ASTNode *valueExpr; + auto name = getValue(-1); + if (enumNode->getEntries().empty()) + valueExpr = new ASTNodeIntegerLiteral(0, underlyingType->getType()); else - value = enumNode->getValues().back().first + 1; + valueExpr = new ASTNodeNumericExpression(enumNode->getEntries().back().second, new ASTNodeIntegerLiteral(1, Token::ValueType::Signed128Bit), Token::Operator::Plus); - enumNode->getValues().emplace_back(value, curr[-2].identifierToken.identifier); + enumNode->addEntry(name, valueExpr); + } + else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) + throwParseError("unexpected end of program", -2); + else + throwParseError("invalid union member", 0); - if (curr[-1].type == Token::Type::ScopeClose) + if (!MATCHES(sequence(SEPARATOR_COMMA))) { + if (MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) break; - } - else if (tryConsume(curr, { Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::Separator})) { - enumNode->getValues().emplace_back(curr[-2].integerToken.integer, curr[-4].identifierToken.identifier); - } - else if (tryConsume(curr, { Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::ScopeClose})) { - enumNode->getValues().emplace_back(curr[-2].integerToken.integer, curr[-4].identifierToken.identifier); - break; - } - else { - delete enumNode; - this->m_error = { curr->lineNumber, "Expected constant identifier" }; - return nullptr; + else + throwParseError("missing ',' between enum entries", 0); } } - if (!tryConsume(curr, {Token::Type::EndOfExpression})) { - delete enumNode; - this->m_error = { curr[-1].lineNumber, "Expected ';' after enum definition" }; - return nullptr; - } + enumGuard.release(); - return enumNode; + return new ASTNodeTypeDecl(typeName, enumNode); } - ASTNode* Parser::parseBitField(TokenIter &curr) { - const std::string &bitfieldName = curr[-2].identifierToken.identifier; - std::vector> fields; + // bitfield Identifier { } + ASTNode* Parser::parseBitfield() { + std::string typeName = getValue(-2); - u32 startLineNumber = curr[-3].lineNumber; + const auto bitfieldNode = new ASTNodeBitfield(); + ScopeExit enumGuard([&]{ delete bitfieldNode; }); - while (!tryConsume(curr, {Token::Type::ScopeClose})) { - if (tryConsume(curr, {Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::Inherit) { - this->m_error = { curr[-3].lineNumber, "Expected ':' after member name" }; - return nullptr; - } - - fields.emplace_back(curr[-4].identifierToken.identifier, curr[-2].integerToken.integer); + while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) { + if (MATCHES(sequence(IDENTIFIER, OPERATOR_INHERIT))) { + auto name = getValue(-2); + bitfieldNode->addEntry(name, parseMathematicalExpression()); } - else { - this->m_error = { curr[-1].lineNumber, "Invalid sequence, expected member declaration" }; - return nullptr; + else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) + throwParseError("unexpected end of program", -2); + else + throwParseError("invalid bitfield member", 0); + + if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) { + throwParseError("missing ';' at end of expression", -1); } } - if (!tryConsume(curr, {Token::Type::EndOfExpression})) { - this->m_error = { curr[-1].lineNumber, "Expected ';' after bitfield definition" }; - return nullptr; - } + enumGuard.release(); - return new ASTNodeBitField(startLineNumber, bitfieldName, fields); + return new ASTNodeTypeDecl(typeName, bitfieldNode); } - ASTNode* Parser::parseScope(TokenIter &curr) { - return new ASTNodeScope(curr[-1].lineNumber, parseTillToken(curr, Token::Type::ScopeClose)); + // (parseType) Identifier @ Integer + ASTNode* Parser::parseVariablePlacement() { + auto temporaryType = dynamic_cast(parseType(-3)); + if (temporaryType == nullptr) throwParseError("invalid type used in variable declaration", -1); + SCOPE_EXIT( delete temporaryType; ); + + return new ASTNodeVariableDecl(getValue(-2), temporaryType->getType()->clone(), parseMathematicalExpression()); } - std::optional Parser::parseUsingDeclaration(TokenIter &curr) { - auto keyword = curr[-5].keywordToken; - auto name = curr[-4].identifierToken; - auto op = curr[-3].operatorToken; + // (parseType) Identifier[(parseMathematicalExpression)] @ Integer + ASTNode* Parser::parseArrayVariablePlacement() { + auto temporaryType = dynamic_cast(parseType(-3)); + if (temporaryType == nullptr) throwParseError("invalid type used in variable declaration", -1); + SCOPE_EXIT( delete temporaryType; ); - if (keyword.keyword != Token::KeywordToken::Keyword::Using) { - this->m_error = { curr[-5].lineNumber, "Invalid keyword. Expected 'using'" }; - return { }; + auto name = getValue(-2); + auto size = parseMathematicalExpression(); + + if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE))) + throwParseError("expected closing ']' at end of array declaration", -1); + + if (!MATCHES(sequence(OPERATOR_AT))) + throwParseError("expected placement instruction", -1); + + return new ASTNodeArrayVariableDecl(name, temporaryType->getType()->clone(), size, parseMathematicalExpression()); + } + + // (parseType) *Identifier : (parseType) @ Integer + ASTNode* Parser::parsePointerVariablePlacement() { + auto name = getValue(-2); + + auto temporaryPointerType = dynamic_cast(parseType(-4)); + if (temporaryPointerType == nullptr) throwParseError("invalid type used in variable declaration", -1); + SCOPE_EXIT( delete temporaryPointerType; ); + + if (!MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && sequence(VALUETYPE_UNSIGNED))) + throwParseError("expected unsigned builtin type as size", -1); + + auto temporaryPointerSizeType = dynamic_cast(parseType(-1)); + if (temporaryPointerSizeType == nullptr) throwParseError("invalid size type used in pointer declaration", -1); + SCOPE_EXIT( delete temporaryPointerSizeType; ); + + if (!MATCHES(sequence(OPERATOR_AT))) + throwParseError("expected placement instruction", -1); + + return new ASTNodePointerVariableDecl(name, temporaryPointerType->getType()->clone(), temporaryPointerSizeType->getType()->clone(), parseMathematicalExpression()); + } + + + + /* Program */ + + // <(parseUsingDeclaration)|(parseVariablePlacement)|(parseStruct)> + ASTNode* Parser::parseStatement() { + ASTNode *statement; + + if (MATCHES(sequence(KEYWORD_USING, IDENTIFIER, OPERATOR_ASSIGNMENT) && (optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY))) + statement = dynamic_cast(parseUsingDeclaration()); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN))) + statement = parseArrayVariablePlacement(); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, OPERATOR_AT))) + statement = parseVariablePlacement(); + else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(OPERATOR_STAR, IDENTIFIER, OPERATOR_INHERIT))) + statement = parsePointerVariablePlacement(); + else if (MATCHES(sequence(KEYWORD_STRUCT, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) + statement = parseStruct(); + else if (MATCHES(sequence(KEYWORD_UNION, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) + statement = parseUnion(); + else if (MATCHES(sequence(KEYWORD_ENUM, IDENTIFIER, OPERATOR_INHERIT) && (optional(KEYWORD_BE), optional(KEYWORD_LE)) && sequence(VALUETYPE_UNSIGNED, SEPARATOR_CURLYBRACKETOPEN))) + statement = parseEnum(); + else if (MATCHES(sequence(KEYWORD_BITFIELD, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN))) + statement = parseBitfield(); + else throwParseError("invalid sequence", 0); + + if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) + throwParseError("missing ';' at end of expression", -1); + + if (auto typeDecl = dynamic_cast(statement); typeDecl != nullptr) + this->m_types.insert({ typeDecl->getName().data(), typeDecl }); + + return statement; + } + + // <(parseStatement)...> EndOfProgram + std::optional> Parser::parse(const std::vector &tokens) { + this->m_curr = tokens.begin(); + + this->m_types.clear(); + + try { + auto program = parseTillToken(SEPARATOR_ENDOFPROGRAM); + + if (program.empty() || this->m_curr != tokens.end()) + throwParseError("program is empty!", -1); + + return program; + } catch (ParseError &e) { + this->m_error = e; } - if (op.op != Token::OperatorToken::Operator::Assignment) { - this->m_error = { curr[-3].lineNumber, "Invalid operator. Expected '='" }; - return { }; - } - - if (curr[-2].type == Token::Type::Type) { - auto type = curr[-2].typeToken; - - return new ASTNodeTypeDecl(curr[-2].lineNumber, type.type, name.identifier); - } else if (curr[-2].type == Token::Type::Identifier) { - auto customType = curr[-2].identifierToken; - - return new ASTNodeTypeDecl(curr[-2].lineNumber, Token::TypeToken::Type::CustomType, name.identifier, customType.identifier); - } - - this->m_error = { curr[-2].lineNumber, hex::format("'%s' does not name a type") }; return { }; } - std::optional> Parser::parseStatement(TokenIter &curr) { - std::vector program; - - // Struct - if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Identifier, Token::Type::ScopeOpen })) { - if (curr[-3].keywordToken.keyword == Token::KeywordToken::Keyword::Struct) { - auto structAst = parseStruct(curr); - - if (structAst == nullptr) { - for(auto &node : program) delete node; - return { }; - } - - program.push_back(structAst); - } else if (curr[-3].keywordToken.keyword == Token::KeywordToken::Keyword::Union) { - auto unionAst = parseUnion(curr); - - if (unionAst == nullptr) { - for(auto &node : program) delete node; - return { }; - } - - program.push_back(unionAst); - } else if (curr[-3].keywordToken.keyword == Token::KeywordToken::Keyword::Bitfield) { - auto bitfieldAst = parseBitField(curr); - - if (bitfieldAst == nullptr) { - for(auto &node : program) delete node; - return { }; - } - - program.push_back(bitfieldAst); - } - - return program; - - } // Enum - else if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::ScopeOpen })) { - if (curr[-5].keywordToken.keyword == Token::KeywordToken::Keyword::Enum) { - auto enumAst = parseEnum(curr); - - if (enumAst == nullptr) { - for(auto &node : program) delete node; - return { }; - } - - program.push_back(enumAst); - } - - return program; - // Scope - } else if (tryConsume(curr, { Token::Type::ScopeOpen })) { - program.push_back(parseScope(curr)); - - return program; - - // Using declaration with built-in type - } else if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Identifier, Token::Type::Operator, Token::Type::Type, Token::Type::EndOfExpression})) { - auto usingDecl = parseUsingDeclaration(curr); - - if (!usingDecl.has_value()) { - for(auto &node : program) delete node; - return { }; - } - - program.push_back(usingDecl.value()); - - return program; - - // Using declaration with custom type - } else if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Identifier, Token::Type::Operator, Token::Type::Identifier, Token::Type::EndOfExpression})) { - auto usingDecl = parseUsingDeclaration(curr); - - if (!usingDecl.has_value()) { - for(auto &node : program) delete node; - return { }; - } - - program.push_back(usingDecl.value()); - - return program; - // Variable placement declaration with built-in type - } else if (tryConsume(curr, { Token::Type::Type, Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::AtDeclaration) { - this->m_error = { curr[-3].lineNumber, "Expected '@' after variable placement declaration" }; - for(auto &node : program) delete node; - return { }; - } - - auto variableDecl = parseFreeBuiltinVariableDecl(curr, false); - - program.push_back(variableDecl); - - return program; - - // Variable placement declaration with custom type - } else if (tryConsume(curr, { Token::Type::Identifier, Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::AtDeclaration) { - this->m_error = { curr[-3].lineNumber, "Expected '@' after variable placement declaration" }; - for(auto &node : program) delete node; - return { }; - } - - auto variableDecl = parseFreeCustomTypeVariableDecl(curr, false); - - program.push_back(variableDecl); - - return program; - - // Variable placement declaration with built-in type and big/little endian setting - } else if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Type, Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::AtDeclaration) { - this->m_error = { curr[-3].lineNumber, "Expected '@' after variable placement declaration" }; - for(auto &node : program) delete node; - return { }; - } - - if (curr[-6].keywordToken.keyword != Token::KeywordToken::Keyword::LittleEndian && curr[-6].keywordToken.keyword != Token::KeywordToken::Keyword::BigEndian) { - this->m_error = { curr[-3].lineNumber, "Expected endianess identifier" }; - for(auto &node : program) delete node; - return { }; - } - - auto variableDecl = parseFreeBuiltinVariableDecl(curr, true); - - program.push_back(variableDecl); - - return program; - - // Variable placement declaration with custom type and big/little endian setting - } else if (tryConsume(curr, { Token::Type::Keyword, Token::Type::Identifier, Token::Type::Identifier, Token::Type::Operator, Token::Type::Integer, Token::Type::EndOfExpression})) { - if (curr[-3].operatorToken.op != Token::OperatorToken::Operator::AtDeclaration) { - this->m_error = { curr[-3].lineNumber, "Expected '@' after variable placement declaration" }; - for(auto &node : program) delete node; - return { }; - } - - if (curr[-6].keywordToken.keyword != Token::KeywordToken::Keyword::LittleEndian && curr[-6].keywordToken.keyword != Token::KeywordToken::Keyword::BigEndian) { - this->m_error = { curr[-6].lineNumber, "Expected endianess identifier" }; - for(auto &node : program) delete node; - return { }; - } - - auto variableDecl = parseFreeCustomTypeVariableDecl(curr, true); - - program.push_back(variableDecl); - - return program; - } - else { - for(auto &node : program) delete node; - this->m_error = { curr->lineNumber, "Invalid sequence" }; - return { }; - } - } - - std::vector Parser::parseTillToken(TokenIter &curr, Token::Type endTokenType) { - std::vector program; - - while (curr->type != endTokenType) { - auto newTokens = parseStatement(curr); - - if (!newTokens.has_value()) { - for (auto &node : program) delete node; - return { }; - } - - program.insert(program.end(), newTokens->begin(), newTokens->end()); - } - - curr++; - - return program; - } - - std::optional> Parser::parse(const std::vector &tokens) { - auto currentToken = tokens.begin(); - - auto program = parseTillToken(currentToken, Token::Type::EndOfProgram); - - if (program.empty() || currentToken != tokens.end()) - return { }; - - return program; - } - } \ No newline at end of file diff --git a/source/lang/preprocessor.cpp b/source/lang/preprocessor.cpp index d3e8d0b60..e57f9b76c 100644 --- a/source/lang/preprocessor.cpp +++ b/source/lang/preprocessor.cpp @@ -18,165 +18,188 @@ namespace hex::lang { std::string output; output.reserve(code.length()); - while (offset < code.length()) { - if (code[offset] == '#') { + try { + while (offset < code.length()) { + if (code[offset] == '#') { + offset += 1; + + if (code.substr(offset, 7) == "include") { + offset += 7; + + while (std::isblank(code[offset]) || std::isspace(code[offset])) + offset += 1; + + if (code[offset] != '<' && code[offset] != '"') + throwPreprocessorError("expected '<' or '\"' before file name", lineNumber); + + char endChar = code[offset]; + if (endChar == '<') endChar = '>'; + + offset += 1; + + std::string includeFile; + while (code[offset] != endChar) { + includeFile += code[offset]; + offset += 1; + + if (offset >= code.length()) + throwPreprocessorError(hex::format("missing terminating '%c' character", endChar), lineNumber); + } + offset += 1; + + if (includeFile[0] != '/') + includeFile = "include/" + includeFile; + + FILE *file = fopen(includeFile.c_str(), "r"); + if (file == nullptr) + throwPreprocessorError(hex::format("%s: No such file or directory", includeFile.c_str()), lineNumber); + + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + char *buffer = new char[size + 1]; + rewind(file); + + fread(buffer, size, 1, file); + buffer[size] = 0x00; + + auto preprocessedInclude = this->preprocess(buffer, false); + if (!preprocessedInclude.has_value()) + throw this->m_error; + + output += preprocessedInclude.value(); + + delete[] buffer; + + fclose(file); + } else if (code.substr(offset, 6) == "define") { + offset += 6; + + while (std::isblank(code[offset])) { + offset += 1; + } + + std::string defineName; + while (!std::isblank(code[offset])) { + defineName += code[offset]; + + if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r') + throwPreprocessorError("no value given in #define directive", lineNumber); + offset += 1; + } + + while (std::isblank(code[offset])) { + offset += 1; + if (offset >= code.length()) + throwPreprocessorError("no value given in #define directive", lineNumber); + } + + std::string replaceValue; + while (code[offset] != '\n' && code[offset] != '\r') { + if (offset >= code.length()) + throwPreprocessorError("missing new line after #define directive", lineNumber); + + replaceValue += code[offset]; + offset += 1; + } + + if (replaceValue.empty()) + throwPreprocessorError("no value given in #define directive", lineNumber); + + this->m_defines.emplace(defineName, replaceValue); + } else if (code.substr(offset, 6) == "pragma") { + offset += 6; + + while (std::isblank(code[offset])) + offset += 1; + + std::string pragmaKey; + while (!std::isblank(code[offset])) { + pragmaKey += code[offset]; + + if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r') + throwPreprocessorError("no instruction given in #pragma directive", lineNumber); + + offset += 1; + } + + while (std::isblank(code[offset])) + offset += 1; + + std::string pragmaValue; + while (code[offset] != '\n' && code[offset] != '\r') { + if (offset >= code.length()) + throwPreprocessorError("missing new line after #pragma directive", lineNumber); + + pragmaValue += code[offset]; + offset += 1; + } + + if (pragmaValue.empty()) + throwPreprocessorError("missing value in #pragma directive", lineNumber); + + this->m_pragmas.emplace(pragmaKey, pragmaValue); + } else + throwPreprocessorError("unknown preprocessor directive", lineNumber); + } else if (code.substr(offset, 2) == "//") { + while (code[offset] != '\n' && offset < code.length()) + offset += 1; + } else if (code.substr(offset, 2) == "/*") { + while (code.substr(offset, 2) != "*/" && offset < code.length()) { + if (code[offset] == '\n') + lineNumber++; + + offset += 1; + } + + offset += 2; + if (offset >= code.length()) + throwPreprocessorError("unterminated comment", lineNumber); + } + + if (code[offset] == '\n') + lineNumber++; + + output += code[offset]; offset += 1; - - if (code.substr(offset, 7) == "include") { - offset += 7; - - while (std::isblank(code[offset]) || std::isspace(code[offset])) - offset += 1; - - if (code[offset] != '<' && code[offset] != '"') - return { }; - - char endChar = code[offset]; - if (endChar == '<') endChar = '>'; - - offset += 1; - - std::string includeFile; - while (code[offset] != endChar) { - includeFile += code[offset]; - offset += 1; - - if (offset >= code.length()) - return { }; - } - offset += 1; - - if (includeFile[0] != '/') - includeFile = "include/" + includeFile; - - FILE *file = fopen(includeFile.c_str(), "r"); - if (file == nullptr) - return { }; - - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - char *buffer = new char[size + 1]; - rewind(file); - - fread(buffer, size, 1, file); - buffer[size] = 0x00; - - auto preprocessedInclude = this->preprocess(buffer, false); - if (!preprocessedInclude.has_value()) - return { }; - - output += preprocessedInclude.value(); - - delete[] buffer; - - fclose(file); - } else if (code.substr(offset, 6) == "define") { - offset += 6; - - while (std::isblank(code[offset])) - offset += 1; - - std::string defineName; - while (!std::isblank(code[offset])) { - defineName += code[offset]; - - if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r') - return { }; - offset += 1; - } - - while (std::isblank(code[offset])) - offset += 1; - - std::string replaceValue; - while (code[offset] != '\n' && code[offset] != '\r') { - if (offset >= code.length()) - return { }; - - replaceValue += code[offset]; - offset += 1; - } - - if (replaceValue.empty()) - return { }; - - this->m_defines.emplace(defineName, replaceValue); - } else if (code.substr(offset, 6) == "pragma") { - offset += 6; - - while (std::isblank(code[offset])) - offset += 1; - - std::string pragmaKey; - while (!std::isblank(code[offset])) { - pragmaKey += code[offset]; - - if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r') - return { }; - - offset += 1; - } - - while (std::isblank(code[offset])) - offset += 1; - - std::string pragmaValue; - while (code[offset] != '\n' && code[offset] != '\r') { - if (offset >= code.length()) - return { }; - - pragmaValue += code[offset]; - offset += 1; - } - - if (pragmaValue.empty()) - return { }; - - this->m_pragmas.emplace(pragmaKey, pragmaValue); - } else - return { }; } - if (code[offset] == '\n') - lineNumber++; + if (initialRun) { + // Apply defines + for (const auto &[define, value] : this->m_defines) { + s32 index = 0; + while((index = output.find(define, index)) != std::string::npos) { + output.replace(index, define.length(), value); + index += value.length(); + } + } - output += code[offset]; - offset += 1; - } - - if (initialRun) { - // Apply defines - for (const auto &[define, value] : this->m_defines) { - s32 index = 0; - while((index = output.find(define, index)) != std::string::npos) { - output.replace(index, define.length(), value); - index += value.length(); + // Handle pragmas + for (const auto &[type, value] : this->m_pragmas) { + if (this->m_pragmaHandlers.contains(type)) { + if (!this->m_pragmaHandlers[type](value)) + throwPreprocessorError(hex::format("invalid value provided to '%s' #pragma directive", type.c_str()), lineNumber); + } else + throwPreprocessorError(hex::format("no #pragma handler registered for type %s", type.c_str()), lineNumber); } } - - // Handle pragmas - for (const auto &[type, value] : this->m_pragmas) { - if (this->m_pragmaHandlers.contains(type)) { - if (!this->m_pragmaHandlers[type](value)) - return { }; - } else - return { }; - } + } catch (PreprocessorError &e) { + this->m_error = e; + return { }; } return output; } - void Preprocessor::addPragmaHandler(std::string pragmaType, std::function function) { + void Preprocessor::addPragmaHandler(const std::string &pragmaType, const std::function &function) { if (!this->m_pragmaHandlers.contains(pragmaType)) this->m_pragmaHandlers.emplace(pragmaType, function); } void Preprocessor::addDefaultPragmaHandlers() { - this->addPragmaHandler("MIME", [](std::string value) { + this->addPragmaHandler("MIME", [](const std::string &value) { return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r'); }); - this->addPragmaHandler("endian", [](std::string value) { + this->addPragmaHandler("endian", [](const std::string &value) { return value == "big" || value == "little" || value == "native"; }); } diff --git a/source/lang/validator.cpp b/source/lang/validator.cpp index f316275fd..f5c5eb506 100644 --- a/source/lang/validator.cpp +++ b/source/lang/validator.cpp @@ -12,116 +12,152 @@ namespace hex::lang { } bool Validator::validate(const std::vector& ast) { + std::unordered_set identifiers; - std::unordered_set typeNames; + try { - for (const auto &node : ast) { - if (node == nullptr) { - this->m_error = { 1, "Empty AST" }; - return false; + for (const auto &node : ast) { + if (node == nullptr) + throwValidateError("nullptr in AST. This is a bug!", 1); + + if (auto variableDeclNode = dynamic_cast(node); variableDeclNode != nullptr) { + if (!identifiers.insert(variableDeclNode->getName().data()).second) + throwValidateError(hex::format("redefinition of identifier '%s'", variableDeclNode->getName().data()), variableDeclNode->getLineNumber()); + + this->validate({ variableDeclNode->getType() }); + } else if (auto typeDeclNode = dynamic_cast(node); typeDeclNode != nullptr) { + if (!identifiers.insert(typeDeclNode->getName().data()).second) + throwValidateError(hex::format("redefinition of identifier '%s'", typeDeclNode->getName().data()), typeDeclNode->getLineNumber()); + + this->validate({ typeDeclNode->getType() }); + } else if (auto structNode = dynamic_cast(node); structNode != nullptr) { + this->validate(structNode->getMembers()); + } else if (auto unionNode = dynamic_cast(node); unionNode != nullptr) { + this->validate(unionNode->getMembers()); + } else if (auto enumNode = dynamic_cast(node); enumNode != nullptr) { + std::unordered_set enumIdentifiers; + for (auto &[name, value] : enumNode->getEntries()) { + if (!enumIdentifiers.insert(name).second) + throwValidateError(hex::format("redefinition of enum constant '%s'", name.c_str()), value->getLineNumber()); + } + } } - switch (node->getType()) { - case ASTNode::Type::VariableDecl: - { - // Check for duplicate variable names - auto varDeclNode = static_cast(node); - if (!typeNames.insert(varDeclNode->getVariableName()).second) { - this->m_error = { varDeclNode->getLineNumber(), hex::format("Redefinition of variable '%s'", varDeclNode->getVariableName().c_str()) }; - return false; - } - - if (varDeclNode->getArraySize() == 0 && !varDeclNode->getArraySizeVariable().has_value() || - varDeclNode->getArraySize() != 0 && varDeclNode->getArraySizeVariable().has_value()) { - - this->m_error = { varDeclNode->getLineNumber(), "Invalid array size" }; - return false; - } - } - break; - case ASTNode::Type::TypeDecl: - { - // Check for duplicate type names - auto typeDeclNode = static_cast(node); - if (!typeNames.insert(typeDeclNode->getTypeName()).second) { - this->m_error = { typeDeclNode->getLineNumber(), hex::format("Redefinition of type '%s'", typeDeclNode->getTypeName().c_str()) }; - return false; - } - - if (typeDeclNode->getAssignedType() == Token::TypeToken::Type::CustomType && !typeNames.contains(typeDeclNode->getAssignedCustomTypeName())) { - this->m_error = { typeDeclNode->getLineNumber(), "Type declaration without a name" }; - return false; - } - } - break; - case ASTNode::Type::Struct: - { - // Check for duplicate type name - auto structNode = static_cast(node); - if (!typeNames.insert(structNode->getName()).second) { - this->m_error = { structNode->getLineNumber(), hex::format("Redeclaration of type '%s'", structNode->getName().c_str()) }; - return false; - } - - // Check for duplicate member names - std::unordered_set memberNames; - for (const auto &member : structNode->getNodes()) - if (!memberNames.insert(static_cast(member)->getVariableName()).second) { - this->m_error = { member->getLineNumber(), hex::format("Redeclaration of member '%s'", static_cast(member)->getVariableName().c_str()) }; - return false; - } - } - break; - case ASTNode::Type::Enum: - { - // Check for duplicate type name - auto enumNode = static_cast(node); - if (!typeNames.insert(enumNode->getName()).second) { - this->m_error = { enumNode->getLineNumber(), hex::format("Redeclaration of type '%s'", enumNode->getName().c_str()) }; - return false; - } - - // Check for duplicate constant names - std::unordered_set constantNames; - for (const auto &[value, name] : enumNode->getValues()) - if (!constantNames.insert(name).second) { - this->m_error = { enumNode->getLineNumber(), hex::format("Redeclaration of enum constant '%s'", name.c_str()) }; - return false; - } - } - break; - case ASTNode::Type::Bitfield: - { - // Check for duplicate type name - auto bitfieldNode = static_cast(node); - if (!typeNames.insert(bitfieldNode->getName()).second) { - this->m_error = { bitfieldNode->getLineNumber(), hex::format("Redeclaration of type '%s'", bitfieldNode->getName().c_str()) }; - return false; - } - - size_t bitfieldSize = 0; - - // Check for duplicate constant names - std::unordered_set flagNames; - for (const auto &[name, size] : bitfieldNode->getFields()) { - if (!flagNames.insert(name).second) { - this->m_error = { bitfieldNode->getLineNumber(), hex::format("Redeclaration of member '%s'", name.c_str()) }; - return false; - } - - bitfieldSize += size; - } - - if (bitfieldSize > 64) { - this->m_error = { bitfieldNode->getLineNumber(), "Bitfield exceeds maximum size of 64 bits" }; - return false; - } - } - break; - } + } catch (ValidatorError &e) { + this->m_error = e; + return false; } return true; } + void Validator::printAST(const std::vector& ast){ + #if DEBUG + #define INDENT_VALUE indent, ' ' + static s32 indent = -2; + + indent += 2; + for (const auto &node : ast) { + if (auto variableDeclNode = dynamic_cast(node); variableDeclNode != nullptr) { + if (auto offset = dynamic_cast(variableDeclNode->getPlacementOffset()); offset != nullptr) { + printf("%*c ASTNodeVariableDecl (%s) @\n", INDENT_VALUE, variableDeclNode->getName().data()); + printAST({ offset }); + } + else + printf("%*c ASTNodeVariableDecl (%s)\n", INDENT_VALUE, variableDeclNode->getName().data()); + printAST({ variableDeclNode->getType() }); + } else if (auto pointerDeclNode = dynamic_cast(node); pointerDeclNode != nullptr) { + if (auto offset = dynamic_cast(pointerDeclNode->getPlacementOffset()); offset != nullptr) { + printf("%*c ASTNodePointerVariableDecl (*%s) @\n", INDENT_VALUE, pointerDeclNode->getName().data()); + printAST({ offset }); + } + else + printf("%*c ASTNodePointerVariableDecl (*%s)\n", INDENT_VALUE, pointerDeclNode->getName().data()); + printAST({ pointerDeclNode->getType() }); + printAST({ pointerDeclNode->getSizeType() }); + } else if (auto arrayDeclNode = dynamic_cast(node); arrayDeclNode != nullptr) { + auto sizeExpr = dynamic_cast(arrayDeclNode->getSize()); + if (sizeExpr == nullptr) { + printf("%*c Invalid size!\n", INDENT_VALUE); + continue; + } + + if (auto offset = dynamic_cast(arrayDeclNode->getPlacementOffset()); offset != nullptr) { + printf("%*c ASTNodeArrayVariableDecl (%s[]) @\n", INDENT_VALUE, arrayDeclNode->getName().data()); + printAST({ sizeExpr }); + printAST({ offset }); + } + else { + printf("%*c ASTNodeArrayVariableDecl (%s[])\n", INDENT_VALUE, arrayDeclNode->getName().data()); + printAST({ sizeExpr }); + } + + printAST({ arrayDeclNode->getType() }); + printAST({ arrayDeclNode->getSize() }); + } else if (auto typeDeclNode = dynamic_cast(node); typeDeclNode != nullptr) { + printf("%*c ASTNodeTypeDecl (%s %s)\n", INDENT_VALUE, typeDeclNode->getEndian().value_or(std::endian::native) == std::endian::little ? "le" : "be", typeDeclNode->getName().empty() ? "" : typeDeclNode->getName().data()); + printAST({ typeDeclNode->getType() }); + } else if (auto builtinTypeNode = dynamic_cast(node); builtinTypeNode != nullptr) { + std::string typeName = Token::getTypeName(builtinTypeNode->getType()); + printf("%*c ASTNodeTypeDecl (%s)\n", INDENT_VALUE, typeName.c_str()); + } else if (auto integerLiteralNode = dynamic_cast(node); integerLiteralNode != nullptr) { + printf("%*c ASTNodeIntegerLiteral %lld\n", INDENT_VALUE, (s64)std::get(integerLiteralNode->getValue())); + } else if (auto numericExpressionNode = dynamic_cast(node); numericExpressionNode != nullptr) { + std::string op; + switch (numericExpressionNode->getOperator()) { + case Token::Operator::Plus: op = "+"; break; + case Token::Operator::Minus: op = "-"; break; + case Token::Operator::Star: op = "*"; break; + case Token::Operator::Slash: op = "/"; break; + + case Token::Operator::ShiftLeft: op = ">>"; break; + case Token::Operator::ShiftRight: op = "<<"; break; + + case Token::Operator::BitAnd: op = "&"; break; + case Token::Operator::BitOr: op = "|"; break; + case Token::Operator::BitXor: op = "^"; break; + default: op = "???"; + } + printf("%*c ASTNodeNumericExpression %s\n", INDENT_VALUE, op.c_str()); + printf("%*c Left:\n", INDENT_VALUE); + printAST({ numericExpressionNode->getLeftOperand() }); + printf("%*c Right:\n", INDENT_VALUE); + printAST({ numericExpressionNode->getRightOperand() }); + } else if (auto structNode = dynamic_cast(node); structNode != nullptr) { + printf("%*c ASTNodeStruct\n", INDENT_VALUE); + printAST(structNode->getMembers()); + } else if (auto unionNode = dynamic_cast(node); unionNode != nullptr) { + printf("%*c ASTNodeUnion\n", INDENT_VALUE); + printAST(unionNode->getMembers()); + } else if (auto enumNode = dynamic_cast(node); enumNode != nullptr) { + printf("%*c ASTNodeEnum\n", INDENT_VALUE); + + for (const auto &[name, entry] : enumNode->getEntries()) { + printf("%*c ::%s\n", INDENT_VALUE, name.c_str()); + printAST({ entry }); + } + } else if (auto bitfieldNode = dynamic_cast(node); bitfieldNode != nullptr) { + printf("%*c ASTNodeBitfield\n", INDENT_VALUE); + + for (const auto &[name, entry] : bitfieldNode->getEntries()) { + printf("%*c %s : \n", INDENT_VALUE, name.c_str()); + printAST({ entry }); + } + } else if (auto rvalueNode = dynamic_cast(node); rvalueNode != nullptr) { + printf("%*c ASTNodeRValue\n", INDENT_VALUE); + + printf("%*c ", INDENT_VALUE); + for (const auto &path : rvalueNode->getPath()) + printf("%s.", path.c_str()); + printf("\n"); + } else { + printf("%*c Invalid AST node!\n", INDENT_VALUE); + } + } + indent -= 2; + + #undef INDENT_VALUE + #endif + } + } \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index bd1371cda..af0fdd2c9 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,3 +1,4 @@ +#include "helpers/utils.hpp" #include "window.hpp" #include "lang/pattern_data.hpp" diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index ed05601be..68605e544 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -26,7 +26,7 @@ namespace hex { static std::pair builtInTypes[] = { { "u8", 1 }, { "u16", 2 }, { "u32", 4 }, { "u64", 8 }, { "u128", 16 }, { "s8", 1 }, { "s16", 2 }, { "s32", 4 }, { "s64", 8 }, { "s128", 16 }, - { "float", 4 }, { "double", 8 }, { "padding", 1 } + { "float", 4 }, { "double", 8 }, { "char", 1 }, { "padding", 1 } }; for (const auto &[name, size] : builtInTypes) { TextEditor::Identifier id; @@ -251,17 +251,6 @@ namespace hex { lang::PatternData::resetPalette(); } - template T> - static std::vector findNodes(const lang::ASTNode::Type type, const std::vector &nodes) { - std::vector result; - - for (const auto & node : nodes) - if (node->getType() == type) - result.push_back(static_cast(node)); - - return result; - } - void ViewPattern::parsePattern(char *buffer) { this->clearPatternData(); this->m_textEditor.SetErrorMarkers({ }); @@ -285,14 +274,14 @@ namespace hex { }); preprocessor.addDefaultPragmaHandlers(); - auto preprocesedCode = preprocessor.preprocess(buffer); - if (!preprocesedCode.has_value()) { + auto preprocessedCode = preprocessor.preprocess(buffer); + if (!preprocessedCode.has_value()) { this->m_textEditor.SetErrorMarkers({ preprocessor.getError() }); return; } hex::lang::Lexer lexer; - auto tokens = lexer.lex(preprocesedCode.value()); + auto tokens = lexer.lex(preprocessedCode.value()); if (!tokens.has_value()) { this->m_textEditor.SetErrorMarkers({ lexer.getError() }); return; @@ -302,11 +291,10 @@ namespace hex { auto ast = parser.parse(tokens.value()); if (!ast.has_value()) { this->m_textEditor.SetErrorMarkers({ parser.getError() }); - printf("%d %s\n", parser.getError().first, parser.getError().second.c_str()); return; } - hex::ScopeExit deleteAst([&ast]{ for(auto &node : ast.value()) delete node; }); + SCOPE_EXIT( for(auto &node : ast.value()) delete node; ); hex::lang::Validator validator; auto validatorResult = validator.validate(ast.value()); @@ -322,8 +310,8 @@ namespace hex { this->m_textEditor.SetErrorMarkers({ evaluator.getError() }); return; } - this->m_patternData = patternData.value(); + this->m_patternData = patternData.value(); this->postEvent(Events::PatternChanged); }