Added print & warnAssert functions and a colored console
This commit is contained in:
parent
e54dbcf574
commit
7a8e923b41
@ -16,12 +16,12 @@ namespace hex::lang {
|
||||
|
||||
class Evaluator {
|
||||
public:
|
||||
Evaluator(prv::Provider* &provider, std::endian defaultDataEndian);
|
||||
|
||||
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
|
||||
|
||||
const std::pair<u32, std::string>& getError() { return this->m_error; }
|
||||
|
||||
enum ConsoleLogLevel {
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
|
||||
struct Function {
|
||||
constexpr static u32 UnlimitedParameters = 0xFFFF'FFFF;
|
||||
@ -33,6 +33,11 @@ namespace hex::lang {
|
||||
std::function<ASTNodeIntegerLiteral*(std::vector<ASTNode*>)> func;
|
||||
};
|
||||
|
||||
Evaluator(prv::Provider* &provider, std::endian defaultDataEndian);
|
||||
|
||||
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
|
||||
const auto& getConsoleLog() { return this->m_consoleLog; }
|
||||
|
||||
private:
|
||||
std::map<std::string, ASTNode*> m_types;
|
||||
prv::Provider* &m_provider;
|
||||
@ -43,12 +48,24 @@ namespace hex::lang {
|
||||
std::vector<std::vector<PatternData*>*> m_currMembers;
|
||||
std::map<std::string, Function> m_functions;
|
||||
|
||||
std::pair<u32, std::string> m_error;
|
||||
std::vector<std::pair<ConsoleLogLevel, std::string>> m_consoleLog;
|
||||
|
||||
using EvaluateError = std::pair<u32, std::string>;
|
||||
using EvaluateError = std::string;
|
||||
|
||||
[[noreturn]] static void throwEvaluateError(std::string_view error, u32 lineNumber) {
|
||||
throw EvaluateError(lineNumber, "Evaluator: " + std::string(error));
|
||||
void emmitDebugInfo(std::string_view message) {
|
||||
this->m_consoleLog.emplace_back(ConsoleLogLevel::Debug, "[-] " + std::string(message));
|
||||
}
|
||||
|
||||
void emmitInfo(std::string_view message) {
|
||||
this->m_consoleLog.emplace_back(ConsoleLogLevel::Info, "[i] " + std::string(message));
|
||||
}
|
||||
|
||||
void emmitWaring(std::string_view message) {
|
||||
this->m_consoleLog.emplace_back(ConsoleLogLevel::Warning, "[*] " + std::string(message));
|
||||
}
|
||||
|
||||
[[noreturn]] static void throwEvaluateError(std::string_view message) {
|
||||
throw EvaluateError("[!] " + std::string(message));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::endian getCurrentEndian() const {
|
||||
@ -57,7 +74,7 @@ namespace hex::lang {
|
||||
|
||||
void addFunction(std::string_view name, u32 parameterCount, std::function<ASTNodeIntegerLiteral*(std::vector<ASTNode*>)> func) {
|
||||
if (this->m_functions.contains(name.data()))
|
||||
throwEvaluateError(hex::format("redefinition of function '%s'", name.data()), 1);
|
||||
throwEvaluateError(hex::format("redefinition of function '%s'", name.data()));
|
||||
|
||||
this->m_functions[name.data()] = { parameterCount, func };
|
||||
}
|
||||
@ -87,7 +104,7 @@ namespace hex::lang {
|
||||
if (auto evaluatedParam = dynamic_cast<T*>(param); evaluatedParam != nullptr)
|
||||
return evaluatedParam;
|
||||
else
|
||||
throwEvaluateError("function got wrong type of parameter", 1);
|
||||
throwEvaluateError("function got wrong type of parameter");
|
||||
}
|
||||
|
||||
|
||||
@ -99,6 +116,8 @@ namespace hex::lang {
|
||||
BUILTIN_FUNCTION(readSigned);
|
||||
|
||||
BUILTIN_FUNCTION(assert);
|
||||
BUILTIN_FUNCTION(warnAssert);
|
||||
BUILTIN_FUNCTION(print);
|
||||
|
||||
#undef BUILTIN_FUNCTION
|
||||
};
|
||||
|
@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "lang/ast_node.hpp"
|
||||
|
||||
#include "views/view.hpp"
|
||||
#include "lang/pattern_data.hpp"
|
||||
#include "lang/evaluator.hpp"
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
|
||||
@ -29,7 +28,7 @@ namespace hex {
|
||||
std::filesystem::path m_possiblePatternFile;
|
||||
|
||||
TextEditor m_textEditor;
|
||||
std::vector<std::string> m_console;
|
||||
std::vector<std::pair<lang::Evaluator::ConsoleLogLevel, std::string>> m_console;
|
||||
imgui_addons::ImGuiFileBrowser m_fileBrowser;
|
||||
|
||||
void loadPatternFile(std::string path);
|
||||
|
@ -14,7 +14,7 @@ namespace hex::lang {
|
||||
if (value <= 0xFF)
|
||||
return value;
|
||||
else
|
||||
throwEvaluateError("sequence bytes need to fit into 1 byte", 1);
|
||||
throwEvaluateError("sequence bytes need to fit into 1 byte");
|
||||
}, asType<ASTNodeIntegerLiteral>(params[i])->getValue()));
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ namespace hex::lang {
|
||||
}
|
||||
}
|
||||
|
||||
throwEvaluateError("failed to find sequence", 1);
|
||||
throwEvaluateError("failed to find sequence");
|
||||
}
|
||||
|
||||
BUILTIN_FUNCTION(readUnsigned) {
|
||||
@ -41,11 +41,11 @@ namespace hex::lang {
|
||||
auto size = asType<ASTNodeIntegerLiteral>(params[1])->getValue();
|
||||
|
||||
if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize()))
|
||||
throwEvaluateError("address out of range", 1);
|
||||
throwEvaluateError("address out of range");
|
||||
|
||||
return std::visit([this](auto &&address, auto &&size) {
|
||||
if (size <= 0 || size > 16)
|
||||
throwEvaluateError("invalid read size", 1);
|
||||
throwEvaluateError("invalid read size");
|
||||
|
||||
u8 value[(u8)size];
|
||||
this->m_provider->read(address, value, size);
|
||||
@ -56,7 +56,7 @@ namespace hex::lang {
|
||||
case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast<u32*>(value), 4, this->getCurrentEndian()) });
|
||||
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast<u64*>(value), 8, this->getCurrentEndian()) });
|
||||
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast<u128*>(value), 16, this->getCurrentEndian()) });
|
||||
default: throwEvaluateError("invalid read size", 1);
|
||||
default: throwEvaluateError("invalid read size");
|
||||
}
|
||||
}, address, size);
|
||||
}
|
||||
@ -66,11 +66,11 @@ namespace hex::lang {
|
||||
auto size = asType<ASTNodeIntegerLiteral>(params[1])->getValue();
|
||||
|
||||
if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize()))
|
||||
throwEvaluateError("address out of range", 1);
|
||||
throwEvaluateError("address out of range");
|
||||
|
||||
return std::visit([this](auto &&address, auto &&size) {
|
||||
if (size <= 0 || size > 16)
|
||||
throwEvaluateError("invalid read size", 1);
|
||||
throwEvaluateError("invalid read size");
|
||||
|
||||
u8 value[(u8)size];
|
||||
this->m_provider->read(address, value, size);
|
||||
@ -81,17 +81,59 @@ namespace hex::lang {
|
||||
case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, hex::changeEndianess(*reinterpret_cast<s32*>(value), 4, this->getCurrentEndian()) });
|
||||
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast<s64*>(value), 8, this->getCurrentEndian()) });
|
||||
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast<s128*>(value), 16, this->getCurrentEndian()) });
|
||||
default: throwEvaluateError("invalid read size", 1);
|
||||
default: throwEvaluateError("invalid read size");
|
||||
}
|
||||
}, address, size);
|
||||
}
|
||||
|
||||
BUILTIN_FUNCTION(assert) {
|
||||
auto condition = asType<ASTNodeIntegerLiteral>(params[0])->getValue();
|
||||
auto error = asType<ASTNodeStringLiteral>(params[1])->getString();
|
||||
auto message = asType<ASTNodeStringLiteral>(params[1])->getString();
|
||||
|
||||
if (LITERAL_COMPARE(condition, condition == 0))
|
||||
throwEvaluateError(hex::format("assertion failed: '%s'", error.data()), 1);
|
||||
throwEvaluateError(hex::format("assert failed \"%s\"", message.data()));
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BUILTIN_FUNCTION(warnAssert) {
|
||||
auto condition = asType<ASTNodeIntegerLiteral>(params[0])->getValue();
|
||||
auto message = asType<ASTNodeStringLiteral>(params[1])->getString();
|
||||
|
||||
if (LITERAL_COMPARE(condition, condition == 0))
|
||||
this->emmitWaring(hex::format("assert failed \"%s\"", message.data()));
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BUILTIN_FUNCTION(print) {
|
||||
|
||||
std::string message;
|
||||
for (auto& param : params) {
|
||||
if (auto integerLiteral = dynamic_cast<ASTNodeIntegerLiteral*>(param); integerLiteral != nullptr) {
|
||||
switch (integerLiteral->getType()) {
|
||||
case Token::ValueType::Character: message += std::get<s8>(integerLiteral->getValue()); break;
|
||||
case Token::ValueType::Unsigned8Bit: message += std::to_string(std::get<u8>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Signed8Bit: message += std::to_string(std::get<s8>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Unsigned16Bit: message += std::to_string(std::get<u16>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Signed16Bit: message += std::to_string(std::get<s16>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Unsigned32Bit: message += std::to_string(std::get<u32>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Signed32Bit: message += std::to_string(std::get<s32>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Unsigned64Bit: message += std::to_string(std::get<u64>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Signed64Bit: message += std::to_string(std::get<s64>(integerLiteral->getValue())); break;
|
||||
//case Token::ValueType::Unsigned128Bit: message += std::to_string(std::get<u128>(integerLiteral->getValue())); break;
|
||||
//case Token::ValueType::Signed128Bit: message += std::to_string(std::get<s128>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Float: message += std::to_string(std::get<float>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Double: message += std::to_string(std::get<double>(integerLiteral->getValue())); break;
|
||||
case Token::ValueType::Boolean: message += std::get<u8>(integerLiteral->getValue()) ? "true" : "false"; break;
|
||||
case Token::ValueType::CustomType: message += "< Custom Type >"; break;
|
||||
}
|
||||
}
|
||||
else if (auto stringLiteral = dynamic_cast<ASTNodeStringLiteral*>(param); stringLiteral != nullptr)
|
||||
message += stringLiteral->getString();
|
||||
}
|
||||
|
||||
this->emmitInfo(message);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -28,6 +28,14 @@ namespace hex::lang {
|
||||
this->addFunction("assert", 2, [this](auto params) {
|
||||
return this->builtin_assert(params);
|
||||
});
|
||||
|
||||
this->addFunction("warnAssert", 2, [this](auto params) {
|
||||
return this->builtin_warnAssert(params);
|
||||
});
|
||||
|
||||
this->addFunction("print", Function::MoreParametersThan | 0, [this](auto params) {
|
||||
return this->builtin_print(params);
|
||||
});
|
||||
}
|
||||
|
||||
ASTNodeIntegerLiteral* Evaluator::evaluateScopeResolution(ASTNodeScopeResolution *node) {
|
||||
@ -46,12 +54,12 @@ namespace hex::lang {
|
||||
}
|
||||
}
|
||||
|
||||
throwEvaluateError("failed to find identifier", node->getLineNumber());
|
||||
throwEvaluateError("failed to find identifier");
|
||||
}
|
||||
|
||||
ASTNodeIntegerLiteral* Evaluator::evaluateRValue(ASTNodeRValue *node) {
|
||||
if (this->m_currMembers.empty() && this->m_globalMembers.empty())
|
||||
throwEvaluateError("no variables available", node->getLineNumber());
|
||||
throwEvaluateError("no variables available");
|
||||
|
||||
std::vector<PatternData*> currMembers;
|
||||
|
||||
@ -74,7 +82,7 @@ namespace hex::lang {
|
||||
continue;
|
||||
}
|
||||
else if (currPattern != nullptr)
|
||||
throwEvaluateError("tried to access member of a non-struct/union type", node->getLineNumber());
|
||||
throwEvaluateError("tried to access member of a non-struct/union type");
|
||||
|
||||
auto candidate = std::find_if(currMembers.begin(), currMembers.end(), [&](auto member) {
|
||||
return member->getVariableName() == identifier;
|
||||
@ -83,7 +91,7 @@ namespace hex::lang {
|
||||
if (candidate != currMembers.end())
|
||||
currPattern = *candidate;
|
||||
else
|
||||
throwEvaluateError(hex::format("could not find identifier '%s'", identifier.c_str()), node->getLineNumber());
|
||||
throwEvaluateError(hex::format("could not find identifier '%s'", identifier.c_str()));
|
||||
}
|
||||
|
||||
if (auto pointerPattern = dynamic_cast<PatternDataPointer*>(currPattern); pointerPattern != nullptr)
|
||||
@ -99,7 +107,7 @@ namespace hex::lang {
|
||||
case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast<u32*>(value), 4, this->getCurrentEndian()) });
|
||||
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast<u64*>(value), 8, this->getCurrentEndian()) });
|
||||
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast<u128*>(value), 16, this->getCurrentEndian()) });
|
||||
default: throwEvaluateError("invalid rvalue size", node->getLineNumber());
|
||||
default: throwEvaluateError("invalid rvalue size");
|
||||
}
|
||||
} else if (auto signedPattern = dynamic_cast<PatternDataSigned*>(currPattern); signedPattern != nullptr) {
|
||||
u8 value[unsignedPattern->getSize()];
|
||||
@ -111,7 +119,7 @@ namespace hex::lang {
|
||||
case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, hex::changeEndianess(*reinterpret_cast<s32*>(value), 4, this->getCurrentEndian()) });
|
||||
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast<s64*>(value), 8, this->getCurrentEndian()) });
|
||||
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast<s128*>(value), 16, this->getCurrentEndian()) });
|
||||
default: throwEvaluateError("invalid rvalue size", node->getLineNumber());
|
||||
default: throwEvaluateError("invalid rvalue size");
|
||||
}
|
||||
} else if (auto enumPattern = dynamic_cast<PatternDataEnum*>(currPattern); enumPattern != nullptr) {
|
||||
u8 value[enumPattern->getSize()];
|
||||
@ -123,10 +131,10 @@ namespace hex::lang {
|
||||
case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast<u32*>(value), 4, this->getCurrentEndian()) });
|
||||
case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast<u64*>(value), 8, this->getCurrentEndian()) });
|
||||
case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast<u128*>(value), 16, this->getCurrentEndian()) });
|
||||
default: throwEvaluateError("invalid rvalue size", node->getLineNumber());
|
||||
default: throwEvaluateError("invalid rvalue size");
|
||||
}
|
||||
} else
|
||||
throwEvaluateError("tried to use non-integer value in numeric expression", node->getLineNumber());
|
||||
throwEvaluateError("tried to use non-integer value in numeric expression");
|
||||
}
|
||||
|
||||
ASTNodeIntegerLiteral* Evaluator::evaluateFunctionCall(ASTNodeFunctionCall *node) {
|
||||
@ -144,7 +152,7 @@ namespace hex::lang {
|
||||
}
|
||||
|
||||
if (!this->m_functions.contains(node->getFunctionName().data()))
|
||||
throwEvaluateError(hex::format("no function named '%s' found", node->getFunctionName().data()), node->getLineNumber());
|
||||
throwEvaluateError(hex::format("no function named '%s' found", node->getFunctionName().data()));
|
||||
|
||||
auto &function = this->m_functions[node->getFunctionName().data()];
|
||||
|
||||
@ -153,12 +161,12 @@ namespace hex::lang {
|
||||
}
|
||||
else if (function.parameterCount & Function::LessParametersThan) {
|
||||
if (evaluatedParams.size() >= (function.parameterCount & ~Function::LessParametersThan))
|
||||
throwEvaluateError(hex::format("too many parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~Function::LessParametersThan), node->getLineNumber());
|
||||
throwEvaluateError(hex::format("too many parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~Function::LessParametersThan));
|
||||
} else if (function.parameterCount & Function::MoreParametersThan) {
|
||||
if (evaluatedParams.size() <= (function.parameterCount & ~Function::MoreParametersThan))
|
||||
throwEvaluateError(hex::format("too few parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~Function::MoreParametersThan), node->getLineNumber());
|
||||
throwEvaluateError(hex::format("too few parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~Function::MoreParametersThan));
|
||||
} else if (function.parameterCount != evaluatedParams.size()) {
|
||||
throwEvaluateError(hex::format("invalid number of parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount), node->getLineNumber());
|
||||
throwEvaluateError(hex::format("invalid number of parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount));
|
||||
}
|
||||
|
||||
return function.func(evaluatedParams);
|
||||
@ -266,12 +274,12 @@ namespace hex::lang {
|
||||
case Token::Operator::BoolNot:
|
||||
return new ASTNodeIntegerLiteral({ newType, !rightValue });
|
||||
default:
|
||||
throwEvaluateError("invalid operator used in mathematical expression", left->getLineNumber());
|
||||
throwEvaluateError("invalid operator used in mathematical expression");
|
||||
}
|
||||
|
||||
}, left->getValue(), right->getValue());
|
||||
} catch (std::runtime_error &e) {
|
||||
throwEvaluateError("bitwise operations on floating point numbers are forbidden", left->getLineNumber());
|
||||
throwEvaluateError("bitwise operations on floating point numbers are forbidden");
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,12 +298,12 @@ namespace hex::lang {
|
||||
auto returnValue = evaluateFunctionCall(exprFunctionCall);
|
||||
|
||||
if (returnValue == nullptr)
|
||||
throwEvaluateError("function returning void used in expression", node->getLineNumber());
|
||||
throwEvaluateError("function returning void used in expression");
|
||||
else
|
||||
return returnValue;
|
||||
}
|
||||
else
|
||||
throwEvaluateError("invalid operand", node->getLineNumber());
|
||||
throwEvaluateError("invalid operand");
|
||||
}
|
||||
|
||||
ASTNodeIntegerLiteral* Evaluator::evaluateTernaryExpression(ASTNodeTernaryExpression *node) {
|
||||
@ -310,7 +318,7 @@ namespace hex::lang {
|
||||
return this->evaluateOperand(node->getThirdOperand());
|
||||
}
|
||||
default:
|
||||
throwEvaluateError("invalid operator used in ternary expression", node->getLineNumber());
|
||||
throwEvaluateError("invalid operator used in ternary expression");
|
||||
}
|
||||
}
|
||||
|
||||
@ -338,7 +346,7 @@ namespace hex::lang {
|
||||
else if (Token::isFloatingPoint(type))
|
||||
pattern = new PatternDataFloat(this->m_currOffset, typeSize);
|
||||
else
|
||||
throwEvaluateError("invalid builtin type", node->getLineNumber());
|
||||
throwEvaluateError("invalid builtin type");
|
||||
|
||||
this->m_currOffset += typeSize;
|
||||
|
||||
@ -376,7 +384,7 @@ namespace hex::lang {
|
||||
return patterns;
|
||||
}
|
||||
else
|
||||
throwEvaluateError("invalid struct member", node->getLineNumber());
|
||||
throwEvaluateError("invalid struct member");
|
||||
}
|
||||
|
||||
PatternData* Evaluator::evaluateStruct(ASTNodeStruct *node) {
|
||||
@ -418,7 +426,7 @@ namespace hex::lang {
|
||||
for (auto &[name, value] : node->getEntries()) {
|
||||
auto expression = dynamic_cast<ASTNodeNumericExpression*>(value);
|
||||
if (expression == nullptr)
|
||||
throwEvaluateError("invalid expression in enum value", value->getLineNumber());
|
||||
throwEvaluateError("invalid expression in enum value");
|
||||
|
||||
auto valueNode = evaluateMathematicalExpression(expression);
|
||||
SCOPE_EXIT( delete valueNode; );
|
||||
@ -430,7 +438,7 @@ namespace hex::lang {
|
||||
if (auto underlyingType = dynamic_cast<const ASTNodeBuiltinType*>(node->getUnderlyingType()); underlyingType != nullptr)
|
||||
size = Token::getTypeSize(underlyingType->getType());
|
||||
else
|
||||
throwEvaluateError("invalid enum underlying type", node->getLineNumber());
|
||||
throwEvaluateError("invalid enum underlying type");
|
||||
|
||||
return new PatternDataEnum(startOffset, size, entryPatterns);
|
||||
}
|
||||
@ -443,19 +451,19 @@ namespace hex::lang {
|
||||
for (auto &[name, value] : node->getEntries()) {
|
||||
auto expression = dynamic_cast<ASTNodeNumericExpression*>(value);
|
||||
if (expression == nullptr)
|
||||
throwEvaluateError("invalid expression in bitfield field size", value->getLineNumber());
|
||||
throwEvaluateError("invalid expression in bitfield field size");
|
||||
|
||||
auto valueNode = evaluateMathematicalExpression(expression);
|
||||
SCOPE_EXIT( delete valueNode; );
|
||||
|
||||
auto fieldBits = std::visit([node, type = valueNode->getType()] (auto &&value) {
|
||||
if (Token::isFloatingPoint(type))
|
||||
throwEvaluateError("bitfield entry size must be an integer value", node->getLineNumber());
|
||||
throwEvaluateError("bitfield entry size must be an integer value");
|
||||
return static_cast<s128>(value);
|
||||
}, valueNode->getValue());
|
||||
|
||||
if (fieldBits > 64 || fieldBits <= 0)
|
||||
throwEvaluateError("bitfield entry must occupy between 1 and 64 bits", value->getLineNumber());
|
||||
throwEvaluateError("bitfield entry must occupy between 1 and 64 bits");
|
||||
|
||||
bits += fieldBits;
|
||||
|
||||
@ -485,7 +493,7 @@ namespace hex::lang {
|
||||
else if (auto bitfieldNode = dynamic_cast<ASTNodeBitfield*>(type); bitfieldNode != nullptr)
|
||||
pattern = this->evaluateBitfield(bitfieldNode);
|
||||
else
|
||||
throwEvaluateError("type could not be evaluated", node->getLineNumber());
|
||||
throwEvaluateError("type could not be evaluated");
|
||||
|
||||
if (!node->getName().empty())
|
||||
pattern->setTypeName(node->getName().data());
|
||||
@ -505,12 +513,12 @@ namespace hex::lang {
|
||||
|
||||
this->m_currOffset = std::visit([node, type = valueNode->getType()] (auto &&value) {
|
||||
if (Token::isFloatingPoint(type))
|
||||
throwEvaluateError("placement offset must be an integer value", node->getLineNumber());
|
||||
throwEvaluateError("placement offset must be an integer value");
|
||||
return static_cast<u64>(value);
|
||||
}, valueNode->getValue());
|
||||
}
|
||||
if (this->m_currOffset >= this->m_provider->getActualSize())
|
||||
throwEvaluateError("variable placed out of range", node->getLineNumber());
|
||||
throwEvaluateError("variable placed out of range");
|
||||
|
||||
PatternData *pattern;
|
||||
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr)
|
||||
@ -518,7 +526,7 @@ namespace hex::lang {
|
||||
else if (auto builtinTypeDecl = dynamic_cast<ASTNodeBuiltinType*>(node->getType()); builtinTypeDecl != nullptr)
|
||||
pattern = this->evaluateBuiltinType(builtinTypeDecl);
|
||||
else
|
||||
throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!", 1);
|
||||
throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!");
|
||||
|
||||
pattern->setVariableName(node->getName().data());
|
||||
|
||||
@ -533,7 +541,7 @@ namespace hex::lang {
|
||||
|
||||
this->m_currOffset = std::visit([node, type = valueNode->getType()] (auto &&value) {
|
||||
if (Token::isFloatingPoint(type))
|
||||
throwEvaluateError("placement offset must be an integer value", node->getLineNumber());
|
||||
throwEvaluateError("placement offset must be an integer value");
|
||||
return static_cast<u64>(value);
|
||||
}, valueNode->getValue());
|
||||
}
|
||||
@ -547,13 +555,13 @@ namespace hex::lang {
|
||||
if (auto sizeNumericExpression = dynamic_cast<ASTNodeNumericExpression*>(node->getSize()); sizeNumericExpression != nullptr)
|
||||
valueNode = evaluateMathematicalExpression(sizeNumericExpression);
|
||||
else
|
||||
throwEvaluateError("array size not a numeric expression", node->getLineNumber());
|
||||
throwEvaluateError("array size not a numeric expression");
|
||||
|
||||
SCOPE_EXIT( delete valueNode; );
|
||||
|
||||
arraySize = std::visit([node, type = valueNode->getType()] (auto &&value) {
|
||||
if (Token::isFloatingPoint(type))
|
||||
throwEvaluateError("array size must be an integer value", node->getLineNumber());
|
||||
throwEvaluateError("array size must be an integer value");
|
||||
return static_cast<u64>(value);
|
||||
}, valueNode->getValue());
|
||||
|
||||
@ -586,7 +594,7 @@ namespace hex::lang {
|
||||
entry = this->evaluateBuiltinType(builtinTypeDecl);
|
||||
}
|
||||
else
|
||||
throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!", 1);
|
||||
throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!");
|
||||
|
||||
entry->setVariableName(hex::format("[%llu]", (u64)i));
|
||||
entry->setEndian(this->getCurrentEndian());
|
||||
@ -598,7 +606,7 @@ namespace hex::lang {
|
||||
entries.push_back(entry);
|
||||
|
||||
if (this->m_currOffset >= this->m_provider->getActualSize())
|
||||
throwEvaluateError("array exceeds size of file", node->getLineNumber());
|
||||
throwEvaluateError("array exceeds size of file");
|
||||
}
|
||||
|
||||
PatternData *pattern;
|
||||
@ -609,7 +617,7 @@ namespace hex::lang {
|
||||
pattern = new PatternDataString(startOffset, (this->m_currOffset - startOffset), color.value_or(0));
|
||||
else {
|
||||
if (node->getSize() == nullptr)
|
||||
throwEvaluateError("no bounds provided for array", node->getLineNumber());
|
||||
throwEvaluateError("no bounds provided for array");
|
||||
pattern = new PatternDataArray(startOffset, (this->m_currOffset - startOffset), entries, color.value_or(0));
|
||||
}
|
||||
|
||||
@ -626,7 +634,7 @@ namespace hex::lang {
|
||||
|
||||
pointerOffset = std::visit([node, type = valueNode->getType()] (auto &&value) {
|
||||
if (Token::isFloatingPoint(type))
|
||||
throwEvaluateError("pointer offset must be an integer value", node->getLineNumber());
|
||||
throwEvaluateError("pointer offset must be an integer value");
|
||||
return static_cast<s128>(value);
|
||||
}, valueNode->getValue());
|
||||
this->m_currOffset = pointerOffset;
|
||||
@ -638,12 +646,12 @@ namespace hex::lang {
|
||||
|
||||
auto underlyingType = dynamic_cast<ASTNodeTypeDecl*>(node->getSizeType());
|
||||
if (underlyingType == nullptr)
|
||||
throwEvaluateError("underlying type is not ASTNodeTypeDecl. This is a bug", node->getLineNumber());
|
||||
throwEvaluateError("underlying type is not ASTNodeTypeDecl. This is a bug");
|
||||
|
||||
if (auto builtinTypeNode = dynamic_cast<ASTNodeBuiltinType*>(underlyingType->getType()); builtinTypeNode != nullptr) {
|
||||
sizeType = evaluateBuiltinType(builtinTypeNode);
|
||||
} else
|
||||
throwEvaluateError("pointer size is not a builtin type", node->getLineNumber());
|
||||
throwEvaluateError("pointer size is not a builtin type");
|
||||
|
||||
size_t pointerSize = sizeType->getSize();
|
||||
|
||||
@ -655,7 +663,7 @@ namespace hex::lang {
|
||||
|
||||
|
||||
if (this->m_currOffset > this->m_provider->getActualSize())
|
||||
throwEvaluateError("pointer points past the end of the data", 1);
|
||||
throwEvaluateError("pointer points past the end of the data");
|
||||
|
||||
PatternData *pointedAt;
|
||||
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr)
|
||||
@ -663,7 +671,7 @@ namespace hex::lang {
|
||||
else if (auto builtinTypeDecl = dynamic_cast<ASTNodeBuiltinType*>(node->getType()); builtinTypeDecl != nullptr)
|
||||
pointedAt = this->evaluateBuiltinType(builtinTypeDecl);
|
||||
else
|
||||
throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!", 1);
|
||||
throwEvaluateError("ASTNodeVariableDecl had an invalid type. This is a bug!");
|
||||
|
||||
this->m_currOffset = pointerOffset + pointerSize;
|
||||
|
||||
@ -697,7 +705,7 @@ namespace hex::lang {
|
||||
this->m_endianStack.pop_back();
|
||||
}
|
||||
} catch (EvaluateError &e) {
|
||||
this->m_error = e;
|
||||
this->m_consoleLog.emplace_back(ConsoleLogLevel::Error, e);
|
||||
this->m_endianStack.clear();
|
||||
|
||||
return { };
|
||||
|
@ -28,6 +28,7 @@ namespace hex {
|
||||
{ "s8", 1 }, { "s16", 2 }, { "s32", 4 }, { "s64", 8 }, { "s128", 16 },
|
||||
{ "float", 4 }, { "double", 8 }, { "char", 1 }, { "bool", 1 }, { "padding", 1 }
|
||||
};
|
||||
|
||||
for (const auto &[name, size] : builtInTypes) {
|
||||
TextEditor::Identifier id;
|
||||
id.mDeclaration = std::to_string(size);
|
||||
@ -52,6 +53,8 @@ namespace hex {
|
||||
paletteIndex = TextEditor::PaletteIndex::Number;
|
||||
else if (TokenizeCStyleCharacterLiteral(inBegin, inEnd, outBegin, outEnd))
|
||||
paletteIndex = TextEditor::PaletteIndex::CharLiteral;
|
||||
else if (TokenizeCStyleString(inBegin, inEnd, outBegin, outEnd))
|
||||
paletteIndex = TextEditor::PaletteIndex::String;
|
||||
|
||||
return paletteIndex != TextEditor::PaletteIndex::Max;
|
||||
};
|
||||
@ -191,15 +194,33 @@ namespace hex {
|
||||
|
||||
auto consoleSize = ImGui::GetContentRegionAvail();
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.0, 0.0, 0.0, 1.0));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0, 1.0, 1.0, 1.0));
|
||||
|
||||
if (ImGui::BeginChild("##console", consoleSize, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
for (auto &line : this->m_console)
|
||||
ImGui::TextUnformatted(line.c_str());
|
||||
for (auto &[level, message] : this->m_console) {
|
||||
switch (level) {
|
||||
case lang::Evaluator::ConsoleLogLevel::Debug:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImColor(0x1F, 0xA9, 0x49, 0xFF).Value);
|
||||
break;
|
||||
case lang::Evaluator::ConsoleLogLevel::Info:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImColor(0x00, 0x70, 0xB4, 0xFF).Value);
|
||||
break;
|
||||
case lang::Evaluator::ConsoleLogLevel::Warning:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImColor(0xFF, 0xC8, 0x01, 0xFF).Value);
|
||||
break;
|
||||
case lang::Evaluator::ConsoleLogLevel::Error:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImColor(0xAE, 0x0C, 0x00, 0xFF).Value);
|
||||
break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted(message.c_str());
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopStyleColor(1);
|
||||
|
||||
if (this->m_textEditor.IsTextChanged()) {
|
||||
this->parsePattern(this->m_textEditor.GetText().data());
|
||||
@ -320,11 +341,11 @@ namespace hex {
|
||||
|
||||
auto provider = *SharedData::get().currentProvider;
|
||||
hex::lang::Evaluator evaluator(provider, defaultDataEndianess);
|
||||
|
||||
auto patternData = evaluator.evaluate(ast.value());
|
||||
if (!patternData.has_value()) {
|
||||
this->m_console.push_back(evaluator.getError().second);
|
||||
this->m_console = evaluator.getConsoleLog();
|
||||
if (!patternData.has_value())
|
||||
return;
|
||||
}
|
||||
|
||||
this->m_patternData = patternData.value();
|
||||
this->postEvent(Events::PatternChanged);
|
||||
|
Loading…
Reference in New Issue
Block a user