From c053d54d1027223a473182e1480a17d93965fd58 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 25 Aug 2021 17:54:47 +0200 Subject: [PATCH] patterns: Add multi-variable declarations --- .../libimhex/include/hex/lang/ast_node.hpp | 26 +++++++++++++++++++ plugins/libimhex/source/lang/evaluator.cpp | 16 ++++++++++++ plugins/libimhex/source/lang/parser.cpp | 17 +++++++++++- 3 files changed, 58 insertions(+), 1 deletion(-) diff --git a/plugins/libimhex/include/hex/lang/ast_node.hpp b/plugins/libimhex/include/hex/lang/ast_node.hpp index 49f3da09f..5b36bd184 100644 --- a/plugins/libimhex/include/hex/lang/ast_node.hpp +++ b/plugins/libimhex/include/hex/lang/ast_node.hpp @@ -285,6 +285,32 @@ namespace hex::lang { ASTNode *m_placementOffset; }; + class ASTNodeMultiVariableDecl : public ASTNode { + public: + explicit ASTNodeMultiVariableDecl(std::vector variables) : m_variables(std::move(variables)) { } + + ASTNodeMultiVariableDecl(const ASTNodeMultiVariableDecl &other) : ASTNode(other) { + for (auto &variable : other.m_variables) + this->m_variables.push_back(variable->clone()); + } + + ~ASTNodeMultiVariableDecl() override { + for (auto &variable : this->m_variables) + delete variable; + } + + [[nodiscard]] ASTNode* clone() const override { + return new ASTNodeMultiVariableDecl(*this); + } + + [[nodiscard]] std::vector getVariables() { + return this->m_variables; + } + + private: + std::vector m_variables; + }; + class ASTNodeStruct : public ASTNode, public Attributable { public: ASTNodeStruct() : ASTNode() { } diff --git a/plugins/libimhex/source/lang/evaluator.cpp b/plugins/libimhex/source/lang/evaluator.cpp index fe3a45519..5b9b3cf0f 100644 --- a/plugins/libimhex/source/lang/evaluator.cpp +++ b/plugins/libimhex/source/lang/evaluator.cpp @@ -521,6 +521,14 @@ namespace hex::lang { } else if (auto varDeclNode = dynamic_cast(statement); varDeclNode != nullptr) { auto pattern = this->evaluateVariable(varDeclNode); this->createLocalVariable(varDeclNode->getName(), pattern); + } else if (auto multiVarDeclNode = dynamic_cast(statement); multiVarDeclNode != nullptr) { + for (auto &delc : multiVarDeclNode->getVariables()) { + if (auto varDecl = dynamic_cast(delc); varDecl != nullptr) { + auto pattern = this->evaluateVariable(varDecl); + this->createLocalVariable(varDecl->getName(), pattern); + } else + this->getConsole().abortEvaluation("invalid multi-variable declaration"); + } } else if (auto assignmentNode = dynamic_cast(statement); assignmentNode != nullptr) { if (auto numericExpressionNode = dynamic_cast(assignmentNode->getRValue()); numericExpressionNode != nullptr) { auto value = this->evaluateMathematicalExpression(numericExpressionNode); @@ -677,6 +685,14 @@ namespace hex::lang { if (auto memberVariableNode = dynamic_cast(node); memberVariableNode != nullptr) currMembers.push_back(this->evaluateVariable(memberVariableNode)); + else if (auto memberMultiVariableNode = dynamic_cast(node); memberMultiVariableNode != nullptr) { + for (auto decl : memberMultiVariableNode->getVariables()) { + if (auto variableDecl = dynamic_cast(decl); variableDecl != nullptr) + currMembers.push_back(this->evaluateVariable(variableDecl)); + else + this->getConsole().abortEvaluation("invalid multi-variable declaration"); + } + } else if (auto memberArrayNode = dynamic_cast(node); memberArrayNode != nullptr) currMembers.push_back(this->evaluateArray(memberArrayNode)); else if (auto memberPointerNode = dynamic_cast(node); memberPointerNode != nullptr) diff --git a/plugins/libimhex/source/lang/parser.cpp b/plugins/libimhex/source/lang/parser.cpp index 112fdafbf..95fa1abb4 100644 --- a/plugins/libimhex/source/lang/parser.cpp +++ b/plugins/libimhex/source/lang/parser.cpp @@ -634,7 +634,22 @@ namespace hex::lang { ASTNode* Parser::parseMemberVariable(ASTNodeTypeDecl *type) { if (type == nullptr) throwParseError("invalid type used in variable declaration", -1); - return new ASTNodeVariableDecl(getValue(-1), type); + if (peek(SEPARATOR_COMMA)) { + + std::vector variables; + auto variableCleanup = SCOPE_GUARD { for (auto var : variables) delete var; }; + + do { + variables.push_back(new ASTNodeVariableDecl(getValue(-1), type->clone())); + } while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER))); + + delete type; + + variableCleanup.release(); + + return new ASTNodeMultiVariableDecl(variables); + } else + return new ASTNodeVariableDecl(getValue(-1), type); } // (parseType) Identifier[(parseMathematicalExpression)]