patterns: Limit max number of patterns

Can be overriden with the pattern_limit pragma
Further improves situation with #313
This commit is contained in:
WerWolv 2021-10-02 15:22:38 +02:00
parent aef959854f
commit 12a8cadcfe
7 changed files with 204 additions and 75 deletions

View File

@ -310,21 +310,21 @@ namespace hex::pl {
PatternData *pattern;
if (Token::isUnsigned(this->m_type))
pattern = new PatternDataUnsigned(offset, size);
pattern = new PatternDataUnsigned(offset, size, evaluator);
else if (Token::isSigned(this->m_type))
pattern = new PatternDataSigned(offset, size);
pattern = new PatternDataSigned(offset, size, evaluator);
else if (Token::isFloatingPoint(this->m_type))
pattern = new PatternDataFloat(offset, size);
pattern = new PatternDataFloat(offset, size, evaluator);
else if (this->m_type == Token::ValueType::Boolean)
pattern = new PatternDataBoolean(offset);
pattern = new PatternDataBoolean(offset, evaluator);
else if (this->m_type == Token::ValueType::Character)
pattern = new PatternDataCharacter(offset);
pattern = new PatternDataCharacter(offset, evaluator);
else if (this->m_type == Token::ValueType::Character16)
pattern = new PatternDataCharacter16(offset);
pattern = new PatternDataCharacter16(offset, evaluator);
else if (this->m_type == Token::ValueType::Padding)
pattern = new PatternDataPadding(offset, 1);
pattern = new PatternDataPadding(offset, 1, evaluator);
else if (this->m_type == Token::ValueType::String)
pattern = new PatternDataString(offset, 1);
pattern = new PatternDataString(offset, 1, evaluator);
else if (this->m_type == Token::ValueType::Auto)
return { nullptr };
else
@ -589,7 +589,6 @@ namespace hex::pl {
if (function.parameterCount != 1)
LogConsole::abortEvaluation("formatter function needs exactly one parameter", node);
pattern->setEvaluator(evaluator);
pattern->setFormatterFunction(function);
} else if (name == "transform" && requiresValue()) {
auto functions = evaluator->getCustomFunctions();
@ -600,7 +599,6 @@ namespace hex::pl {
if (function.parameterCount != 1)
LogConsole::abortEvaluation("transform function needs exactly one parameter", node);
pattern->setEvaluator(evaluator);
pattern->setTransformFunction(function);
} else if (name == "pointer_base" && requiresValue()) {
auto functions = evaluator->getCustomFunctions();
@ -816,13 +814,13 @@ namespace hex::pl {
PatternData *outputPattern;
if (dynamic_cast<PatternDataPadding*>(templatePattern)) {
outputPattern = new PatternDataPadding(startOffset, 0);
outputPattern = new PatternDataPadding(startOffset, 0, evaluator);
} else if (dynamic_cast<PatternDataCharacter*>(templatePattern)) {
outputPattern = new PatternDataString(startOffset, 0);
outputPattern = new PatternDataString(startOffset, 0, evaluator);
} else if (dynamic_cast<PatternDataCharacter16*>(templatePattern)) {
outputPattern = new PatternDataString16(startOffset, 0);
outputPattern = new PatternDataString16(startOffset, 0, evaluator);
} else {
auto arrayPattern = new PatternDataStaticArray(startOffset, 0);
auto arrayPattern = new PatternDataStaticArray(startOffset, 0, evaluator);
arrayPattern->setEntries(templatePattern->clone(), entryCount);
outputPattern = arrayPattern;
}
@ -839,10 +837,15 @@ namespace hex::pl {
}
PatternData* createDynamicArray(Evaluator *evaluator) const {
auto arrayPattern = new PatternDataDynamicArray(evaluator->dataOffset(), 0);
auto arrayPattern = new PatternDataDynamicArray(evaluator->dataOffset(), 0, evaluator);
arrayPattern->setVariableName(this->m_name);
std::vector<PatternData *> entries;
auto arrayCleanup = SCOPE_GUARD {
for (auto entry : entries)
delete entry;
};
size_t size = 0;
u64 entryCount = 0;
@ -934,6 +937,8 @@ namespace hex::pl {
arrayPattern->setEntries(entries);
arrayPattern->setSize(size);
arrayCleanup.release();
return arrayPattern;
}
};
@ -986,7 +991,7 @@ namespace hex::pl {
auto sizePattern = this->m_sizeType->createPatterns(evaluator).front();
ON_SCOPE_EXIT { delete sizePattern; };
auto pattern = new PatternDataPointer(offset, sizePattern->getSize());
auto pattern = new PatternDataPointer(offset, sizePattern->getSize(), evaluator);
pattern->setVariableName(this->m_name);
offset = evaluator->dataOffset();
@ -1085,10 +1090,15 @@ namespace hex::pl {
}
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
auto pattern = new PatternDataStruct(evaluator->dataOffset(), 0);
auto pattern = new PatternDataStruct(evaluator->dataOffset(), 0, evaluator);
u64 startOffset = evaluator->dataOffset();
std::vector<PatternData*> memberPatterns;
auto structCleanup = SCOPE_GUARD {
delete pattern;
for (auto member : memberPatterns)
delete member;
};
evaluator->pushScope(pattern, memberPatterns);
@ -1116,6 +1126,8 @@ namespace hex::pl {
pattern->setMembers(memberPatterns);
pattern->setSize(evaluator->dataOffset() - startOffset);
structCleanup.release();
return { pattern };
}
@ -1149,12 +1161,18 @@ namespace hex::pl {
}
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
auto pattern = new PatternDataUnion(evaluator->dataOffset(), 0);
auto pattern = new PatternDataUnion(evaluator->dataOffset(), 0, evaluator);
size_t size = 0;
std::vector<PatternData*> memberPatterns;
u64 startOffset = evaluator->dataOffset();
auto unionCleanup = SCOPE_GUARD {
delete pattern;
for (auto member : memberPatterns)
delete member;
};
evaluator->pushScope(pattern, memberPatterns);
for (auto member : this->m_members) {
for (auto &memberPattern : member->createPatterns(evaluator)) {
@ -1169,6 +1187,8 @@ namespace hex::pl {
pattern->setMembers(memberPatterns);
pattern->setSize(size);
unionCleanup.release();
return { pattern };
}
@ -1200,7 +1220,9 @@ namespace hex::pl {
}
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
auto pattern = new PatternDataEnum(evaluator->dataOffset(), 0);
auto pattern = new PatternDataEnum(evaluator->dataOffset(), 0, evaluator);
auto enumCleanup = SCOPE_GUARD { delete pattern; };
std::vector<std::pair<Token::Literal, std::string>> enumEntries;
for (const auto &[name, value] : this->m_entries) {
@ -1217,6 +1239,8 @@ namespace hex::pl {
pattern->setSize(underlying->getSize());
pattern->setEndian(underlying->getEndian());
enumCleanup.release();
return { pattern };
}
@ -1252,10 +1276,17 @@ namespace hex::pl {
void addEntry(const std::string &name, ASTNode* size) { this->m_entries.emplace_back(name, size); }
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
auto pattern = new PatternDataBitfield(evaluator->dataOffset(), 0);
auto pattern = new PatternDataBitfield(evaluator->dataOffset(), 0, evaluator);
size_t bitOffset = 0;
std::vector<PatternData*> fields;
auto bitfieldCleanup = SCOPE_GUARD {
delete pattern;
for (auto field : fields)
delete field;
};
evaluator->pushScope(pattern, fields);
for (auto [name, bitSizeNode] : this->m_entries) {
auto literal = bitSizeNode->evaluate(evaluator);
@ -1267,7 +1298,7 @@ namespace hex::pl {
[](auto &&offset) -> u8 { return static_cast<u8>(offset); }
}, dynamic_cast<ASTNodeLiteral*>(literal)->getValue());
auto field = new PatternDataBitfieldField(evaluator->dataOffset(), bitOffset, bitSize);
auto field = new PatternDataBitfieldField(evaluator->dataOffset(), bitOffset, bitSize, evaluator);
field->setVariableName(name);
bitOffset += bitSize;
@ -1280,6 +1311,8 @@ namespace hex::pl {
evaluator->dataOffset() += pattern->getSize();
bitfieldCleanup.release();
return { pattern };
}
@ -1915,7 +1948,12 @@ namespace hex::pl {
std::vector<PatternData*> variables;
ctx->pushScope(nullptr, variables);
ON_SCOPE_EXIT { ctx->popScope(); };
ON_SCOPE_EXIT {
for (auto variable : variables)
delete variable;
ctx->popScope();
};
u32 paramIndex = 0;
for (const auto &[name, type] : this->m_params) {

View File

@ -15,6 +15,7 @@ namespace hex::prv { class Provider; }
namespace hex::pl {
class PatternData;
class PatternCreationLimiter;
class ASTNode;
class Evaluator {
@ -87,6 +88,20 @@ namespace hex::pl {
return this->m_arrayLimit;
}
void setPatternLimit(u32 limit) {
this->m_patternLimit = limit;
}
[[nodiscard]]
u32 getPatternLimit() {
return this->m_patternLimit;
}
[[nodiscard]]
u32 getPatternCount() {
return this->m_currPatternCount;
}
u64& dataOffset() { return this->m_currOffset; }
bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguageFunctions::Callback &function) {
@ -106,9 +121,13 @@ namespace hex::pl {
}
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt);
void setVariable(const std::string &name, const Token::Literal& value);
private:
void patternCreated();
void patternDestroyed();
private:
u64 m_currOffset;
prv::Provider *m_provider = nullptr;
@ -117,11 +136,16 @@ namespace hex::pl {
std::endian m_defaultEndian = std::endian::native;
u32 m_evalDepth;
u32 m_arrayLimit;
u32 m_patternLimit;
u32 m_currPatternCount;
std::vector<Scope> m_scopes;
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_customFunctions;
std::vector<ASTNode*> m_customFunctionDefinitions;
std::vector<Token::Literal> m_stack;
friend class PatternCreationLimiter;
};
}

View File

@ -6,6 +6,8 @@
#include <hex/providers/provider.hpp>
#include <hex/pattern_language/token.hpp>
#include <hex/pattern_language/evaluator.hpp>
#include <hex/views/view.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
@ -51,10 +53,29 @@ namespace hex::pl {
bool m_inlined = false;
};
class PatternData {
class PatternCreationLimiter {
public:
PatternData(u64 offset, size_t size, u32 color = 0)
: m_offset(offset), m_size(size), m_color(color), m_parent(nullptr) {
explicit PatternCreationLimiter(Evaluator *evaluator) : m_evaluator(evaluator) {
this->m_evaluator->patternCreated();
}
PatternCreationLimiter(const PatternCreationLimiter &other) {
this->m_evaluator = other.m_evaluator;
this->m_evaluator->patternCreated();
}
~PatternCreationLimiter() {
this->m_evaluator->patternDestroyed();
}
private:
Evaluator *m_evaluator;
};
class PatternData : public PatternCreationLimiter {
public:
PatternData(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternCreationLimiter(evaluator), m_offset(offset), m_size(size), m_color(color), m_parent(nullptr), m_evaluator(evaluator) {
constexpr u32 Palette[] = { 0x70b4771f, 0x700e7fff, 0x702ca02c, 0x702827d6, 0x70bd6794, 0x704b568c, 0x70c277e3, 0x707f7f7f, 0x7022bdbc, 0x70cfbe17 };
if (color != 0)
@ -100,7 +121,6 @@ namespace hex::pl {
void setDisplayName(const std::string &name) { this->m_displayName = name; }
[[nodiscard]] Evaluator* getEvaluator() const { return this->m_evaluator; }
void setEvaluator(Evaluator *evaluator) { this->m_evaluator = evaluator; }
[[nodiscard]] const auto& getTransformFunction() const { return this->m_transformFunction; }
void setTransformFunction(const ContentRegistry::PatternLanguageFunctions::Function &function) { this->m_transformFunction = function; }
@ -295,7 +315,7 @@ namespace hex::pl {
class PatternDataPadding : public PatternData {
public:
PatternDataPadding(u64 offset, size_t size) : PatternData(offset, size, 0xFF000000) { }
PatternDataPadding(u64 offset, size_t size, Evaluator *evaluator) : PatternData(offset, size, evaluator, 0xFF000000) { }
PatternData* clone() override {
return new PatternDataPadding(*this);
@ -313,8 +333,8 @@ namespace hex::pl {
class PatternDataPointer : public PatternData {
public:
PatternDataPointer(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color), m_pointedAt(nullptr) {
PatternDataPointer(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color), m_pointedAt(nullptr) {
}
PatternDataPointer(const PatternDataPointer &other) : PatternData(other) {
@ -415,8 +435,8 @@ namespace hex::pl {
class PatternDataUnsigned : public PatternData {
public:
PatternDataUnsigned(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternDataUnsigned(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) { }
PatternData* clone() override {
return new PatternDataUnsigned(*this);
@ -446,8 +466,8 @@ namespace hex::pl {
class PatternDataSigned : public PatternData {
public:
PatternDataSigned(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternDataSigned(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) { }
PatternData* clone() override {
return new PatternDataSigned(*this);
@ -478,8 +498,8 @@ namespace hex::pl {
class PatternDataFloat : public PatternData {
public:
PatternDataFloat(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternDataFloat(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) { }
PatternData* clone() override {
return new PatternDataFloat(*this);
@ -514,8 +534,8 @@ namespace hex::pl {
class PatternDataBoolean : public PatternData {
public:
explicit PatternDataBoolean(u64 offset, u32 color = 0)
: PatternData(offset, 1, color) { }
explicit PatternDataBoolean(u64 offset, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, 1, evaluator, color) { }
PatternData* clone() override {
return new PatternDataBoolean(*this);
@ -542,8 +562,8 @@ namespace hex::pl {
class PatternDataCharacter : public PatternData {
public:
explicit PatternDataCharacter(u64 offset, u32 color = 0)
: PatternData(offset, 1, color) { }
explicit PatternDataCharacter(u64 offset, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, 1, evaluator, color) { }
PatternData* clone() override {
return new PatternDataCharacter(*this);
@ -565,8 +585,8 @@ namespace hex::pl {
class PatternDataCharacter16 : public PatternData {
public:
explicit PatternDataCharacter16(u64 offset, u32 color = 0)
: PatternData(offset, 2, color) { }
explicit PatternDataCharacter16(u64 offset, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, 2, evaluator, color) { }
PatternData* clone() override {
return new PatternDataCharacter16(*this);
@ -590,8 +610,8 @@ namespace hex::pl {
class PatternDataString : public PatternData {
public:
PatternDataString(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternDataString(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) { }
PatternData* clone() override {
return new PatternDataString(*this);
@ -613,8 +633,8 @@ namespace hex::pl {
class PatternDataString16 : public PatternData {
public:
PatternDataString16(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) { }
PatternDataString16(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) { }
PatternData* clone() override {
return new PatternDataString16(*this);
@ -641,8 +661,8 @@ namespace hex::pl {
class PatternDataDynamicArray : public PatternData, public Inlinable {
public:
PatternDataDynamicArray(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) {
PatternDataDynamicArray(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) {
}
PatternDataDynamicArray(const PatternDataDynamicArray &other) : PatternData(other) {
@ -773,8 +793,8 @@ namespace hex::pl {
class PatternDataStaticArray : public PatternData, public Inlinable {
public:
PatternDataStaticArray(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) {
PatternDataStaticArray(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) {
}
PatternDataStaticArray(const PatternDataStaticArray &other) : PatternData(other) {
@ -910,7 +930,8 @@ namespace hex::pl {
class PatternDataStruct : public PatternData, public Inlinable {
public:
PatternDataStruct(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color){
PatternDataStruct(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color){
}
PatternDataStruct(const PatternDataStruct &other) : PatternData(other) {
@ -1045,7 +1066,8 @@ namespace hex::pl {
class PatternDataUnion : public PatternData, public Inlinable {
public:
PatternDataUnion(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) {
PatternDataUnion(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) {
}
@ -1181,7 +1203,8 @@ namespace hex::pl {
class PatternDataEnum : public PatternData {
public:
PatternDataEnum(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) {
PatternDataEnum(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) {
}
@ -1274,8 +1297,8 @@ namespace hex::pl {
class PatternDataBitfieldField : public PatternData {
public:
PatternDataBitfieldField(u64 offset, u8 bitOffset, u8 bitSize, u32 color = 0)
: m_bitOffset(bitOffset), m_bitSize(bitSize), PatternData(offset, 0, color) {
PatternDataBitfieldField(u64 offset, u8 bitOffset, u8 bitSize, Evaluator *evaluator, u32 color = 0)
: m_bitOffset(bitOffset), m_bitSize(bitSize), PatternData(offset, 0, evaluator, color) {
}
@ -1343,7 +1366,8 @@ namespace hex::pl {
class PatternDataBitfield : public PatternData, public Inlinable {
public:
PatternDataBitfield(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) {
PatternDataBitfield(u64 offset, size_t size, Evaluator *evaluator, u32 color = 0)
: PatternData(offset, size, evaluator, color) {
}

View File

@ -34,6 +34,9 @@ namespace hex::pl {
const std::vector<std::pair<LogConsole::Level, std::string>>& getConsoleLog();
const std::optional<std::pair<u32, std::string>>& getError();
u32 getCreatedPatternCount();
u32 getMaximumPatternCount();
private:
Preprocessor *m_preprocessor;
Lexer *m_lexer;
@ -45,8 +48,6 @@ namespace hex::pl {
prv::Provider *m_provider = nullptr;
std::endian m_defaultEndian = std::endian::native;
u32 m_evalDepth;
u32 m_arrayLimit;
std::optional<std::pair<u32, std::string>> m_currError;
};

View File

@ -21,19 +21,21 @@ namespace hex::pl {
LogConsole::abortEvaluation("cannot determine type of auto variable", type);
if (std::get_if<u128>(&*value) != nullptr)
pattern = new PatternDataUnsigned(0, sizeof(u128));
pattern = new PatternDataUnsigned(0, sizeof(u128), this);
else if (std::get_if<s128>(&*value) != nullptr)
pattern = new PatternDataSigned(0, sizeof(s128));
pattern = new PatternDataSigned(0, sizeof(s128), this);
else if (std::get_if<double>(&*value) != nullptr)
pattern = new PatternDataFloat(0, sizeof(double));
pattern = new PatternDataFloat(0, sizeof(double), this);
else if (std::get_if<bool>(&*value) != nullptr)
pattern = new PatternDataBoolean(0);
pattern = new PatternDataBoolean(0, this);
else if (std::get_if<char>(&*value) != nullptr)
pattern = new PatternDataCharacter(0);
pattern = new PatternDataCharacter(0, this);
else if (std::get_if<PatternData*>(&*value) != nullptr)
pattern = std::get<PatternData*>(*value)->clone();
else if (std::get_if<std::string>(&*value) != nullptr)
pattern = new PatternDataString(0, 1);
pattern = new PatternDataString(0, 1, this);
else
__builtin_unreachable();
}
pattern->setVariableName(name);
@ -106,6 +108,7 @@ namespace hex::pl {
this->m_scopes.clear();
this->dataOffset() = 0x00;
this->m_currPatternCount = 0;
for (auto &func : this->m_customFunctionDefinitions)
delete func;
@ -139,10 +142,22 @@ namespace hex::pl {
delete pattern;
patterns.clear();
this->m_currPatternCount = 0;
return std::nullopt;
}
return patterns;
}
void Evaluator::patternCreated() {
if (this->m_currPatternCount > this->m_patternLimit)
LogConsole::abortEvaluation(hex::format("exceeded maximum number of patterns: {}", this->m_patternLimit));
this->m_currPatternCount++;
}
void Evaluator::patternDestroyed() {
this->m_currPatternCount--;
}
}

View File

@ -43,21 +43,31 @@ namespace hex::pl {
if (limit <= 0)
return false;
this->m_evalDepth = limit;
this->m_evaluator->setEvaluationDepth(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("array_limit", [this](std::string value) {
this->m_preprocessor->addPragmaHandler("array_limit", [this](const std::string &value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_arrayLimit = limit;
this->m_evaluator->setArrayLimit(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("base_address", [](std::string value) {
this->m_preprocessor->addPragmaHandler("pattern_limit", [this](const std::string &value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_evaluator->setPatternLimit(limit);
return true;
});
this->m_preprocessor->addPragmaHandler("base_address", [](const std::string &value) {
auto baseAddress = strtoull(value.c_str(), nullptr, 0);
ImHexApi::Provider::get()->setBaseAddress(baseAddress);
@ -79,8 +89,10 @@ namespace hex::pl {
this->m_currError.reset();
this->m_evaluator->getConsole().clear();
this->m_evaluator->setProvider(provider);
this->m_evalDepth = 32;
this->m_arrayLimit = 0x1000;
this->m_evaluator->setDefaultEndian(std::endian::native);
this->m_evaluator->setEvaluationDepth(32);
this->m_evaluator->setArrayLimit(0x1000);
this->m_evaluator->setPatternLimit(0x2000);
for (auto &node : this->m_currAST)
delete node;
@ -92,10 +104,6 @@ namespace hex::pl {
return { };
}
this->m_evaluator->setDefaultEndian(this->m_defaultEndian);
this->m_evaluator->setEvaluationDepth(this->m_evalDepth);
this->m_evaluator->setArrayLimit(this->m_arrayLimit);
auto tokens = this->m_lexer->lex(preprocessedCode.value());
if (!tokens.has_value()) {
this->m_currError = this->m_lexer->getError();
@ -134,4 +142,12 @@ namespace hex::pl {
return this->m_currError;
}
u32 PatternLanguage::getCreatedPatternCount() {
return this->m_evaluator->getPatternCount();
}
u32 PatternLanguage::getMaximumPatternCount() {
return this->m_evaluator->getPatternLimit();
}
}

View File

@ -259,12 +259,23 @@ namespace hex {
ImGui::SameLine();
if (this->m_evaluatorRunning)
ImGui::TextSpinner("hex.view.pattern.evaluating"_lang);
else
else {
if (ImGui::Checkbox("hex.view.pattern.auto"_lang, &this->m_runAutomatically)) {
if (this->m_runAutomatically)
this->m_hasUnevaluatedChanges = true;
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
ImGui::TextUnformatted(hex::format("{} / {}",
this->m_patternLanguageRuntime->getCreatedPatternCount(),
this->m_patternLanguageRuntime->getMaximumPatternCount()
).c_str()
);
}
if (this->m_textEditor.IsTextChanged()) {
ProjectFile::markDirty();