From ff566aa51f5b773e7bcbf404b57d1aa72a52b924 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 21 Jan 2021 17:49:30 +0100 Subject: [PATCH] Added attributes syntax to pattern language This comes with two experimental attributes for variables called `name` and `color` --- .../libimhex/include/hex/lang/ast_node.hpp | 121 ++++++++++++------ .../libimhex/include/hex/lang/evaluator.hpp | 5 +- plugins/libimhex/include/hex/lang/parser.hpp | 1 + plugins/libimhex/source/lang/evaluator.cpp | 55 +++++++- plugins/libimhex/source/lang/parser.cpp | 29 +++++ 5 files changed, 165 insertions(+), 46 deletions(-) diff --git a/plugins/libimhex/include/hex/lang/ast_node.hpp b/plugins/libimhex/include/hex/lang/ast_node.hpp index 256bd246f..3a3356187 100644 --- a/plugins/libimhex/include/hex/lang/ast_node.hpp +++ b/plugins/libimhex/include/hex/lang/ast_node.hpp @@ -9,6 +9,26 @@ namespace hex::lang { + class ASTNodeAttribute; + + class Attributable { + protected: + Attributable() = default; + Attributable(const Attributable&) = default; + public: + + void addAttribute(ASTNodeAttribute *attribute) { + this->m_attributes.push_back(attribute); + } + + [[nodiscard]] const auto& getAttributes() const { + return this->m_attributes; + } + + private: + std::vector m_attributes; + }; + class ASTNode { public: constexpr ASTNode() = default; @@ -16,9 +36,9 @@ namespace hex::lang { constexpr ASTNode(const ASTNode &) = default; [[nodiscard]] constexpr u32 getLineNumber() const { return this->m_lineNumber; } - constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; } + [[maybe_unused]] constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; } - virtual ASTNode* clone() const = 0; + [[nodiscard]] virtual ASTNode* clone() const = 0; private: u32 m_lineNumber = 1; @@ -26,11 +46,11 @@ namespace hex::lang { class ASTNodeIntegerLiteral : public ASTNode { public: - ASTNodeIntegerLiteral(Token::IntegerLiteral literal) : ASTNode(), m_literal(literal) { } + explicit ASTNodeIntegerLiteral(Token::IntegerLiteral literal) : ASTNode(), m_literal(std::move(literal)) { } ASTNodeIntegerLiteral(const ASTNodeIntegerLiteral&) = default; - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeIntegerLiteral(*this); } @@ -62,7 +82,7 @@ namespace hex::lang { this->m_right = other.m_right->clone(); } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeNumericExpression(*this); } @@ -93,7 +113,7 @@ namespace hex::lang { this->m_third = other.m_third->clone(); } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeTernaryExpression(*this); } @@ -114,7 +134,7 @@ namespace hex::lang { [[nodiscard]] constexpr const auto& getType() const { return this->m_type; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeBuiltinType(*this); } @@ -122,12 +142,12 @@ namespace hex::lang { const Token::ValueType m_type; }; - class ASTNodeTypeDecl : public ASTNode { + class ASTNodeTypeDecl : public ASTNode, public Attributable { public: ASTNodeTypeDecl(std::string_view name, ASTNode *type, std::optional endian = { }) : ASTNode(), m_name(name), m_type(type), m_endian(endian) { } - ASTNodeTypeDecl(const ASTNodeTypeDecl& other) : ASTNode(other) { + ASTNodeTypeDecl(const ASTNodeTypeDecl& other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; this->m_type = other.m_type->clone(); this->m_endian = other.m_endian; @@ -137,7 +157,7 @@ namespace hex::lang { delete this->m_type; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeTypeDecl(*this); } @@ -151,12 +171,12 @@ namespace hex::lang { std::optional m_endian; }; - class ASTNodeVariableDecl : public ASTNode { + class ASTNodeVariableDecl : public ASTNode, public Attributable { 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) { + ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; this->m_type = other.m_type->clone(); @@ -170,7 +190,7 @@ namespace hex::lang { delete this->m_type; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeVariableDecl(*this); } @@ -184,12 +204,12 @@ namespace hex::lang { ASTNode *m_placementOffset; }; - class ASTNodeArrayVariableDecl : public ASTNode { + class ASTNodeArrayVariableDecl : public ASTNode, public Attributable { 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) { + ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; this->m_type = other.m_type->clone(); if (other.m_size != nullptr) @@ -208,7 +228,7 @@ namespace hex::lang { delete this->m_size; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeArrayVariableDecl(*this); } @@ -224,12 +244,12 @@ namespace hex::lang { ASTNode *m_placementOffset; }; - class ASTNodePointerVariableDecl : public ASTNode { + class ASTNodePointerVariableDecl : public ASTNode, public Attributable { 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) { + ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other), Attributable(other) { this->m_name = other.m_name; this->m_type = other.m_type->clone(); this->m_sizeType = other.m_sizeType->clone(); @@ -244,7 +264,7 @@ namespace hex::lang { delete this->m_type; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodePointerVariableDecl(*this); } @@ -260,11 +280,11 @@ namespace hex::lang { ASTNode *m_placementOffset; }; - class ASTNodeStruct : public ASTNode { + class ASTNodeStruct : public ASTNode, public Attributable { public: ASTNodeStruct() : ASTNode() { } - ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other) { + ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other), Attributable(other) { for (const auto &otherMember : other.getMembers()) this->m_members.push_back(otherMember->clone()); } @@ -274,7 +294,7 @@ namespace hex::lang { delete member; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeStruct(*this); } @@ -285,11 +305,11 @@ namespace hex::lang { std::vector m_members; }; - class ASTNodeUnion : public ASTNode { + class ASTNodeUnion : public ASTNode, public Attributable { public: ASTNodeUnion() : ASTNode() { } - ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other) { + ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other), Attributable(other) { for (const auto &otherMember : other.getMembers()) this->m_members.push_back(otherMember->clone()); } @@ -299,7 +319,7 @@ namespace hex::lang { delete member; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeUnion(*this); } @@ -310,11 +330,11 @@ namespace hex::lang { std::vector m_members; }; - class ASTNodeEnum : public ASTNode { + class ASTNodeEnum : public ASTNode, public Attributable { public: explicit ASTNodeEnum(ASTNode *underlyingType) : ASTNode(), m_underlyingType(underlyingType) { } - ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other) { + ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other), Attributable(other) { for (const auto &[name, entry] : other.getEntries()) this->m_entries.insert({ name, entry->clone() }); this->m_underlyingType = other.m_underlyingType->clone(); @@ -326,7 +346,7 @@ namespace hex::lang { delete this->m_underlyingType; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeEnum(*this); } @@ -340,11 +360,11 @@ namespace hex::lang { ASTNode *m_underlyingType; }; - class ASTNodeBitfield : public ASTNode { + class ASTNodeBitfield : public ASTNode, public Attributable { public: ASTNodeBitfield() : ASTNode() { } - ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other) { + ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other), Attributable(other) { for (const auto &[name, entry] : other.getEntries()) this->m_entries.emplace_back(name, entry->clone()); } @@ -354,7 +374,7 @@ namespace hex::lang { delete expr; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeBitfield(*this); } @@ -371,7 +391,7 @@ namespace hex::lang { ASTNodeRValue(const ASTNodeRValue&) = default; - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeRValue(*this); } @@ -389,7 +409,7 @@ namespace hex::lang { ASTNodeScopeResolution(const ASTNodeScopeResolution&) = default; - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeScopeResolution(*this); } @@ -424,7 +444,7 @@ namespace hex::lang { this->m_falseBody.push_back(statement->clone()); } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeConditionalStatement(*this); } @@ -462,7 +482,7 @@ namespace hex::lang { this->m_params.push_back(param->clone()); } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeFunctionCall(*this); } @@ -483,13 +503,13 @@ namespace hex::lang { public: explicit ASTNodeStringLiteral(std::string_view string) : ASTNode(), m_string(string) { } - ~ASTNodeStringLiteral() override { } + ~ASTNodeStringLiteral() override = default; ASTNodeStringLiteral(const ASTNodeStringLiteral &other) : ASTNode(other) { this->m_string = other.m_string; } - ASTNode* clone() const override { + [[nodiscard]] ASTNode* clone() const override { return new ASTNodeStringLiteral(*this); } @@ -501,5 +521,32 @@ namespace hex::lang { std::string m_string; }; + class ASTNodeAttribute : public ASTNode { + public: + explicit ASTNodeAttribute(std::string_view attribute, std::string_view value = { }) + : ASTNode(), m_attribute(attribute), m_value(value) { } + + ~ASTNodeAttribute() override = default; + + ASTNodeAttribute(const ASTNodeAttribute &other) : ASTNode(other) { + this->m_attribute = other.m_attribute; + this->m_value = other.m_value; + } + + [[nodiscard]] ASTNode* clone() const override { + return new ASTNodeAttribute(*this); + } + + [[nodiscard]] std::string_view getAttribute() const { + return this->m_attribute; + } + + [[nodiscard]] std::string_view getValue() const { + return this->m_value; + } + + private: + std::string m_attribute, m_value; + }; } \ No newline at end of file diff --git a/plugins/libimhex/include/hex/lang/evaluator.hpp b/plugins/libimhex/include/hex/lang/evaluator.hpp index 9336ba0ef..f8f2cb486 100644 --- a/plugins/libimhex/include/hex/lang/evaluator.hpp +++ b/plugins/libimhex/include/hex/lang/evaluator.hpp @@ -37,7 +37,7 @@ namespace hex::lang { } } - [[noreturn]] static void abortEvaluation(std::string_view message) { + [[noreturn]] void abortEvaluation(std::string_view message) { throw EvaluateError(message); } @@ -51,7 +51,7 @@ namespace hex::lang { std::optional> evaluate(const std::vector& ast); - auto& getConsole() { return this->m_console; } + LogConsole& getConsole() { return this->m_console; } private: std::map m_types; @@ -76,6 +76,7 @@ namespace hex::lang { ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node); PatternData* patternFromName(const std::vector &name); + PatternData* evaluateAttributes(ASTNode *currNode, PatternData *currPattern); PatternData* evaluateBuiltinType(ASTNodeBuiltinType *node); void evaluateMember(ASTNode *node, std::vector &currMembers, bool increaseOffset); PatternData* evaluateStruct(ASTNodeStruct *node); diff --git a/plugins/libimhex/include/hex/lang/parser.hpp b/plugins/libimhex/include/hex/lang/parser.hpp index a9bb56367..ecf9979b4 100644 --- a/plugins/libimhex/include/hex/lang/parser.hpp +++ b/plugins/libimhex/include/hex/lang/parser.hpp @@ -71,6 +71,7 @@ namespace hex::lang { ASTNode* parseTernaryConditional(); ASTNode* parseMathematicalExpression(); + void parseAttribute(Attributable *currNode); ASTNode* parseConditional(); ASTNode* parseType(s32 startIndex); ASTNode* parseUsingDeclaration(); diff --git a/plugins/libimhex/source/lang/evaluator.cpp b/plugins/libimhex/source/lang/evaluator.cpp index fbc73234e..bf4a550e6 100644 --- a/plugins/libimhex/source/lang/evaluator.cpp +++ b/plugins/libimhex/source/lang/evaluator.cpp @@ -331,6 +331,47 @@ namespace hex::lang { return evaluateOperator(leftInteger, rightInteger, node->getOperator()); } + PatternData* Evaluator::evaluateAttributes(ASTNode *currNode, PatternData *currPattern) { + auto attributableNode = dynamic_cast(currNode); + if (attributableNode == nullptr) + this->getConsole().abortEvaluation("attributes applied to invalid expression"); + + auto handleVariableAttributes = [this, &currPattern](auto attribute, auto value) { + + if (attribute == "color") + currPattern->setColor(strtoul(value.data(), nullptr, 0)); + else if (attribute == "name") + currPattern->setVariableName(value.data()); + else + this->getConsole().abortEvaluation("unknown or invalid attribute"); + + }; + + auto &attributes = attributableNode->getAttributes(); + + if (auto variableDeclNode = dynamic_cast(currNode); variableDeclNode != nullptr) { + for (auto &attribute : attributes) + handleVariableAttributes(attribute->getAttribute(), attribute->getValue()); + } else if (auto arrayDeclNode = dynamic_cast(currNode); arrayDeclNode != nullptr) { + for (auto &attribute : attributes) + handleVariableAttributes(attribute->getAttribute(), attribute->getValue()); + } else if (auto pointerDeclNode = dynamic_cast(currNode); pointerDeclNode != nullptr) { + for (auto &attribute : attributes) + handleVariableAttributes(attribute->getAttribute(), attribute->getValue()); + } else if (auto structNode = dynamic_cast(currNode); structNode != nullptr) { + this->getConsole().abortEvaluation("unknown or invalid attribute"); + } else if (auto unionNode = dynamic_cast(currNode); unionNode != nullptr) { + this->getConsole().abortEvaluation("unknown or invalid attribute"); + } else if (auto enumNode = dynamic_cast(currNode); enumNode != nullptr) { + this->getConsole().abortEvaluation("unknown or invalid attribute"); + } else if (auto bitfieldNode = dynamic_cast(currNode); bitfieldNode != nullptr) { + this->getConsole().abortEvaluation("unknown or invalid attribute"); + } else + this->getConsole().abortEvaluation("attributes applied to invalid expression"); + + return currPattern; + } + PatternData* Evaluator::evaluateBuiltinType(ASTNodeBuiltinType *node) { auto &type = node->getType(); auto typeSize = Token::getTypeSize(type); @@ -400,7 +441,7 @@ namespace hex::lang { this->evaluateMember(member, memberPatterns, true); } - return new PatternDataStruct(startOffset, this->m_currOffset - startOffset, memberPatterns); + return this->evaluateAttributes(node, new PatternDataStruct(startOffset, this->m_currOffset - startOffset, memberPatterns)); } PatternData* Evaluator::evaluateUnion(ASTNodeUnion *node) { @@ -421,7 +462,7 @@ namespace hex::lang { this->m_currOffset += size; - return new PatternDataUnion(startOffset, size, memberPatterns); + return this->evaluateAttributes(node, new PatternDataUnion(startOffset, size, memberPatterns)); } PatternData* Evaluator::evaluateEnum(ASTNodeEnum *node) { @@ -451,7 +492,7 @@ namespace hex::lang { this->m_currOffset += size; - return new PatternDataEnum(startOffset, size, entryPatterns);; + return this->evaluateAttributes(node, new PatternDataEnum(startOffset, size, entryPatterns)); } PatternData* Evaluator::evaluateBitfield(ASTNodeBitfield *node) { @@ -484,7 +525,7 @@ namespace hex::lang { size_t size = (bits + 7) / 8; this->m_currOffset += size; - return new PatternDataBitfield(startOffset, size, entryPatterns); + return this->evaluateAttributes(node, new PatternDataBitfield(startOffset, size, entryPatterns)); } PatternData* Evaluator::evaluateType(ASTNodeTypeDecl *node) { @@ -544,7 +585,7 @@ namespace hex::lang { pattern->setVariableName(node->getName().data()); - return pattern; + return this->evaluateAttributes(node, pattern); } PatternData* Evaluator::evaluateArray(ASTNodeArrayVariableDecl *node) { @@ -637,7 +678,7 @@ namespace hex::lang { pattern->setVariableName(node->getName().data()); - return pattern; + return this->evaluateAttributes(node, pattern); } PatternData* Evaluator::evaluatePointer(ASTNodePointerVariableDecl *node) { @@ -694,7 +735,7 @@ namespace hex::lang { pattern->setVariableName(node->getName().data()); pattern->setEndian(this->getCurrentEndian()); - return pattern; + return this->evaluateAttributes(node, pattern); } std::optional> Evaluator::evaluate(const std::vector &ast) { diff --git a/plugins/libimhex/source/lang/parser.cpp b/plugins/libimhex/source/lang/parser.cpp index e32154d6b..b0d8b528e 100644 --- a/plugins/libimhex/source/lang/parser.cpp +++ b/plugins/libimhex/source/lang/parser.cpp @@ -262,6 +262,29 @@ namespace hex::lang { return this->parseTernaryConditional(); } + // [[ ]] + void Parser::parseAttribute(Attributable *currNode) { + if (currNode == nullptr) + throwParseError("tried to apply attribute to invalid statement"); + + do { + if (!MATCHES(sequence(IDENTIFIER))) + throwParseError("expected attribute expression"); + + auto attribute = this->getValue(-1); + + if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN, STRING, SEPARATOR_ROUNDBRACKETCLOSE))) { + auto value = this->getValue(-2); + currNode->addAttribute(new ASTNodeAttribute(attribute, value)); + } + else + currNode->addAttribute(new ASTNodeAttribute(attribute)); + + } while (MATCHES(sequence(SEPARATOR_COMMA))); + + if (!MATCHES(sequence(SEPARATOR_SQUAREBRACKETCLOSE, SEPARATOR_SQUAREBRACKETCLOSE))) + throwParseError("unfinished attribute. Expected ']]'"); + } /* Control flow */ @@ -410,6 +433,9 @@ namespace hex::lang { else throwParseError("invalid struct member", 0); + if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN))) + parseAttribute(dynamic_cast(member)); + if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) throwParseError("missing ';' at end of expression", -1); @@ -605,6 +631,9 @@ namespace hex::lang { statement = parseFunctionCall(); else throwParseError("invalid sequence", 0); + if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN, SEPARATOR_SQUAREBRACKETOPEN))) + parseAttribute(dynamic_cast(statement)); + if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) throwParseError("missing ';' at end of expression", -1);