From 0884025b82c73e94baf920408f89fcca8594939e Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 30 Dec 2021 18:31:24 +0100 Subject: [PATCH] patterns: Added continue and break statements to arrays of structs --- .../include/hex/pattern_language/ast_node.hpp | 94 ++++++++++++++----- .../source/pattern_language/parser.cpp | 4 + 2 files changed, 77 insertions(+), 21 deletions(-) diff --git a/plugins/libimhex/include/hex/pattern_language/ast_node.hpp b/plugins/libimhex/include/hex/pattern_language/ast_node.hpp index 9a7c7952a..3e1775a0d 100644 --- a/plugins/libimhex/include/hex/pattern_language/ast_node.hpp +++ b/plugins/libimhex/include/hex/pattern_language/ast_node.hpp @@ -561,7 +561,10 @@ namespace hex::pl { for (auto &statement : other.m_body) this->m_body.push_back(statement->clone()); - this->m_postExpression = other.m_postExpression->clone(); + if (other.m_postExpression != nullptr) + this->m_postExpression = other.m_postExpression->clone(); + else + this->m_postExpression = nullptr; } [[nodiscard]] ASTNode* clone() const override { @@ -974,6 +977,13 @@ namespace hex::pl { evaluator->handleAbort(); }; + auto discardEntry = [&] { + delete entries.back(); + entries.pop_back(); + entryIndex--; + + }; + if (this->m_size != nullptr) { auto sizeNode = this->m_size->evaluate(evaluator); ON_SCOPE_EXIT { delete sizeNode; }; @@ -990,9 +1000,18 @@ namespace hex::pl { LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this); for (u64 i = 0; i < entryCount; i++) { - auto pattern = this->m_type->createPatterns(evaluator).front(); + auto patterns = this->m_type->createPatterns(evaluator); - addEntry(pattern); + if (!patterns.empty()) + addEntry(patterns.front()); + + auto ctrlFlow = evaluator->getCurrentControlFlowStatement(); + if (ctrlFlow == ControlFlowStatement::Break) + break; + else if (ctrlFlow == ControlFlowStatement::Continue) { + discardEntry(); + continue; + } } } else if (auto whileStatement = dynamic_cast(sizeNode)) { while (whileStatement->evaluateCondition(evaluator)) { @@ -1000,9 +1019,18 @@ namespace hex::pl { if (entryIndex > limit) LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this); - auto pattern = this->m_type->createPatterns(evaluator).front(); + auto patterns = this->m_type->createPatterns(evaluator); - addEntry(pattern); + if (!patterns.empty()) + addEntry(patterns.front()); + + auto ctrlFlow = evaluator->getCurrentControlFlowStatement(); + if (ctrlFlow == ControlFlowStatement::Break) + break; + else if (ctrlFlow == ControlFlowStatement::Continue) { + discardEntry(); + continue; + } } } } else { @@ -1011,26 +1039,39 @@ namespace hex::pl { if (entryIndex > limit) LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this); - auto pattern = this->m_type->createPatterns(evaluator).front(); - std::vector buffer(pattern->getSize()); + auto patterns = this->m_type->createPatterns(evaluator); - if (evaluator->dataOffset() >= evaluator->getProvider()->getActualSize() - buffer.size()) { - delete pattern; - LogConsole::abortEvaluation("reached end of file before finding end of unsized array", this); - } + if (!patterns.empty()) { + auto pattern = patterns.front(); - addEntry(pattern); + std::vector buffer(pattern->getSize()); - evaluator->getProvider()->read(evaluator->dataOffset() - pattern->getSize(), buffer.data(), buffer.size()); - bool reachedEnd = true; - for (u8 &byte : buffer) { - if (byte != 0x00) { - reachedEnd = false; - break; + if (evaluator->dataOffset() >= evaluator->getProvider()->getActualSize() - buffer.size()) { + delete pattern; + LogConsole::abortEvaluation("reached end of file before finding end of unsized array", this); } - } - if (reachedEnd) break; + addEntry(pattern); + + auto ctrlFlow = evaluator->getCurrentControlFlowStatement(); + if (ctrlFlow == ControlFlowStatement::Break) + break; + else if (ctrlFlow == ControlFlowStatement::Continue) { + discardEntry(); + continue; + } + + evaluator->getProvider()->read(evaluator->dataOffset() - pattern->getSize(), buffer.data(), buffer.size()); + bool reachedEnd = true; + for (u8 &byte : buffer) { + if (byte != 0x00) { + reachedEnd = false; + break; + } + } + + if (reachedEnd) break; + } } } @@ -2044,7 +2085,11 @@ namespace hex::pl { ASTNodeControlFlowStatement(const ASTNodeControlFlowStatement &other) : ASTNode(other) { this->m_type = other.m_type; - this->m_rvalue = other.m_rvalue->clone(); + + if (other.m_rvalue != nullptr) + this->m_rvalue = other.m_rvalue->clone(); + else + this->m_rvalue = nullptr; } [[nodiscard]] ASTNode* clone() const override { @@ -2059,6 +2104,13 @@ namespace hex::pl { return this->m_rvalue; } + [[nodiscard]] std::vector createPatterns(Evaluator *evaluator) const override { + + this->execute(evaluator); + + return { }; + } + FunctionResult execute(Evaluator *evaluator) const override { auto returnValue = this->getReturnValue(); diff --git a/plugins/libimhex/source/pattern_language/parser.cpp b/plugins/libimhex/source/pattern_language/parser.cpp index 8c7b7bbca..472fe736c 100644 --- a/plugins/libimhex/source/pattern_language/parser.cpp +++ b/plugins/libimhex/source/pattern_language/parser.cpp @@ -880,6 +880,10 @@ namespace hex::pl { return parseConditional(); else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM))) throwParseError("unexpected end of program", -2); + else if (MATCHES(sequence(KEYWORD_BREAK))) + member = new ASTNodeControlFlowStatement(ControlFlowStatement::Break, nullptr); + else if (MATCHES(sequence(KEYWORD_CONTINUE))) + member = new ASTNodeControlFlowStatement(ControlFlowStatement::Continue, nullptr); else throwParseError("invalid struct member", 0);