diff --git a/CMakeLists.txt b/CMakeLists.txt index fdb883823..2db3877fb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,13 +153,6 @@ add_executable(imhex ${application_type} source/helpers/loader_script_handler.cpp source/helpers/plugin_handler.cpp - source/lang/preprocessor.cpp - source/lang/lexer.cpp - source/lang/parser.cpp - source/lang/validator.cpp - source/lang/evaluator.cpp - source/lang/builtin_functions.cpp - source/providers/file_provider.cpp source/views/view_hexeditor.cpp diff --git a/plugins/libimhex/CMakeLists.txt b/plugins/libimhex/CMakeLists.txt index 2fd1308d2..a95725cac 100644 --- a/plugins/libimhex/CMakeLists.txt +++ b/plugins/libimhex/CMakeLists.txt @@ -16,6 +16,13 @@ add_library(libimhex STATIC source/helpers/utils.cpp source/helpers/content_registry.cpp + source/lang/preprocessor.cpp + source/lang/lexer.cpp + source/lang/parser.cpp + source/lang/validator.cpp + source/lang/evaluator.cpp + source/lang/builtin_functions.cpp + source/providers/provider.cpp source/views/view.cpp diff --git a/plugins/libimhex/include/helpers/content_registry.hpp b/plugins/libimhex/include/helpers/content_registry.hpp index e78824b9a..8068e25bd 100644 --- a/plugins/libimhex/include/helpers/content_registry.hpp +++ b/plugins/libimhex/include/helpers/content_registry.hpp @@ -12,6 +12,8 @@ namespace hex { + namespace lang { class ASTNode; } + class ContentRegistry { public: ContentRegistry() = delete; @@ -58,6 +60,23 @@ namespace hex { static void add(Type type, std::string_view command, std::string_view description, const std::function &callback); static std::vector getEntries(); }; + + struct PatternLanguageFunctions { + PatternLanguageFunctions() = delete; + + constexpr static u32 UnlimitedParameters = 0xFFFF'FFFF; + constexpr static u32 MoreParametersThan = 0x8000'0000; + constexpr static u32 LessParametersThan = 0x4000'0000; + constexpr static u32 NoParameters = 0x0000'0000; + + struct Function { + u32 parameterCount; + std::function)> func; + }; + + static void add(std::string_view name, u32 parameterCount, const std::function)> &func); + static std::map getEntries(); + }; }; } \ No newline at end of file diff --git a/plugins/libimhex/include/helpers/shared_data.hpp b/plugins/libimhex/include/helpers/shared_data.hpp index a59e0cd4a..eacd785dd 100644 --- a/plugins/libimhex/include/helpers/shared_data.hpp +++ b/plugins/libimhex/include/helpers/shared_data.hpp @@ -59,6 +59,7 @@ namespace hex { static std::map customEventsStorage; static u32 customEventsLastIdStorage = u32(Events::Events_BuiltinEnd) + 1; static std::vector commandPaletteCommandsStorage; + static std::map patternLanguageFunctionsStorage; this->imguiContext = ImGui::GetCurrentContext(); this->eventHandlers = &eventHandlersStorage; @@ -72,6 +73,7 @@ namespace hex { this->customEvents = &customEventsStorage; this->customEventsLastId = &customEventsLastIdStorage; this->commandPaletteCommands = &commandPaletteCommandsStorage; + this->patternLanguageFunctions = &patternLanguageFunctionsStorage; } void initializeData(const SharedData &other) { @@ -87,6 +89,7 @@ namespace hex { this->customEvents = other.customEvents; this->customEventsLastId = other.customEventsLastId; this->commandPaletteCommands = other.commandPaletteCommands; + this->patternLanguageFunctions = other.patternLanguageFunctions; } public: @@ -99,6 +102,7 @@ namespace hex { std::map *customEvents; u32 *customEventsLastId; std::vector *commandPaletteCommands; + std::map *patternLanguageFunctions; ImVec2 *windowPos; ImVec2 *windowSize; diff --git a/include/lang/ast_node.hpp b/plugins/libimhex/include/lang/ast_node.hpp similarity index 100% rename from include/lang/ast_node.hpp rename to plugins/libimhex/include/lang/ast_node.hpp diff --git a/include/lang/evaluator.hpp b/plugins/libimhex/include/lang/evaluator.hpp similarity index 79% rename from include/lang/evaluator.hpp rename to plugins/libimhex/include/lang/evaluator.hpp index c5727b666..86f30a475 100644 --- a/include/lang/evaluator.hpp +++ b/plugins/libimhex/include/lang/evaluator.hpp @@ -23,16 +23,6 @@ namespace hex::lang { Error }; - struct Function { - constexpr static u32 UnlimitedParameters = 0xFFFF'FFFF; - constexpr static u32 MoreParametersThan = 0x8000'0000; - constexpr static u32 LessParametersThan = 0x4000'0000; - constexpr static u32 NoParameters = 0x0000'0000; - - u32 parameterCount; - std::function)> func; - }; - Evaluator(prv::Provider* &provider, std::endian defaultDataEndian); std::optional> evaluate(const std::vector& ast); @@ -46,7 +36,6 @@ namespace hex::lang { std::vector m_endianStack; std::vector m_globalMembers; std::vector*> m_currMembers; - std::map m_functions; std::vector> m_consoleLog; @@ -72,16 +61,9 @@ namespace hex::lang { return this->m_endianStack.back(); } - void addFunction(std::string_view name, u32 parameterCount, std::function)> func) { - if (this->m_functions.contains(name.data())) - throwEvaluateError(hex::format("redefinition of function '%s'", name.data())); - - this->m_functions[name.data()] = { parameterCount, func }; - } - ASTNodeIntegerLiteral* evaluateScopeResolution(ASTNodeScopeResolution *node); ASTNodeIntegerLiteral* evaluateRValue(ASTNodeRValue *node); - ASTNodeIntegerLiteral* evaluateFunctionCall(ASTNodeFunctionCall *node); + ASTNode* evaluateFunctionCall(ASTNodeFunctionCall *node); ASTNodeIntegerLiteral* evaluateOperator(ASTNodeIntegerLiteral *left, ASTNodeIntegerLiteral *right, Token::Operator op); ASTNodeIntegerLiteral* evaluateOperand(ASTNode *node); ASTNodeIntegerLiteral* evaluateTernaryExpression(ASTNodeTernaryExpression *node); @@ -98,7 +80,6 @@ namespace hex::lang { PatternData* evaluateArray(ASTNodeArrayVariableDecl *node); PatternData* evaluatePointer(ASTNodePointerVariableDecl *node); - template T* asType(ASTNode *param) { if (auto evaluatedParam = dynamic_cast(param); evaluatedParam != nullptr) @@ -107,7 +88,7 @@ namespace hex::lang { throwEvaluateError("function got wrong type of parameter"); } - + void registerBuiltinFunctions(); #define BUILTIN_FUNCTION(name) ASTNodeIntegerLiteral* TOKEN_CONCAT(builtin_, name)(std::vector params) diff --git a/include/lang/lexer.hpp b/plugins/libimhex/include/lang/lexer.hpp similarity index 100% rename from include/lang/lexer.hpp rename to plugins/libimhex/include/lang/lexer.hpp diff --git a/include/lang/parser.hpp b/plugins/libimhex/include/lang/parser.hpp similarity index 100% rename from include/lang/parser.hpp rename to plugins/libimhex/include/lang/parser.hpp diff --git a/include/lang/pattern_data.hpp b/plugins/libimhex/include/lang/pattern_data.hpp similarity index 99% rename from include/lang/pattern_data.hpp rename to plugins/libimhex/include/lang/pattern_data.hpp index 7719cd723..7c66e7e61 100644 --- a/include/lang/pattern_data.hpp +++ b/plugins/libimhex/include/lang/pattern_data.hpp @@ -2,12 +2,12 @@ #include -#include "imgui.h" -#include "imgui_memory_editor.h" +#include #include "providers/provider.hpp" #include "helpers/utils.hpp" #include "lang/token.hpp" +#include "views/view.hpp" #include #include diff --git a/include/lang/preprocessor.hpp b/plugins/libimhex/include/lang/preprocessor.hpp similarity index 100% rename from include/lang/preprocessor.hpp rename to plugins/libimhex/include/lang/preprocessor.hpp diff --git a/include/lang/token.hpp b/plugins/libimhex/include/lang/token.hpp similarity index 100% rename from include/lang/token.hpp rename to plugins/libimhex/include/lang/token.hpp diff --git a/include/lang/validator.hpp b/plugins/libimhex/include/lang/validator.hpp similarity index 100% rename from include/lang/validator.hpp rename to plugins/libimhex/include/lang/validator.hpp diff --git a/plugins/libimhex/source/helpers/content_registry.cpp b/plugins/libimhex/source/helpers/content_registry.cpp index 6b0d57d08..334f71627 100644 --- a/plugins/libimhex/source/helpers/content_registry.cpp +++ b/plugins/libimhex/source/helpers/content_registry.cpp @@ -73,4 +73,15 @@ namespace hex { return *SharedData::get().commandPaletteCommands; } + + /* Pattern Language Functions */ + + void ContentRegistry::PatternLanguageFunctions::add(std::string_view name, u32 parameterCount, const std::function)> &func) { + (*SharedData::get().patternLanguageFunctions)[name.data()] = Function{ parameterCount, func }; + } + + std::map ContentRegistry::PatternLanguageFunctions::getEntries() { + return *SharedData::get().patternLanguageFunctions; + } + } \ No newline at end of file diff --git a/plugins/libimhex/source/lang/builtin_functions.cpp b/plugins/libimhex/source/lang/builtin_functions.cpp new file mode 100644 index 000000000..6f7db7003 --- /dev/null +++ b/plugins/libimhex/source/lang/builtin_functions.cpp @@ -0,0 +1,143 @@ +#include "lang/evaluator.hpp" +#include "helpers/content_registry.hpp" + +namespace hex::lang { + + #define LITERAL_COMPARE(literal, cond) std::visit([&, this](auto &&literal) { return (cond) != 0; }, literal) + + void Evaluator::registerBuiltinFunctions() { + /* findSequence */ + ContentRegistry::PatternLanguageFunctions::add("findSequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [this](auto params) { + auto& occurrenceIndex = asType(params[0])->getValue(); + std::vector sequence; + for (u32 i = 1; i < params.size(); i++) { + sequence.push_back(std::visit([](auto &&value) -> u8 { + if (value <= 0xFF) + return value; + else + throwEvaluateError("sequence bytes need to fit into 1 byte"); + }, asType(params[i])->getValue())); + } + + std::vector bytes(sequence.size(), 0x00); + u32 occurrences = 0; + for (u64 offset = 0; offset < this->m_provider->getSize() - sequence.size(); offset++) { + this->m_provider->read(offset, bytes.data(), bytes.size()); + + if (bytes == sequence) { + if (LITERAL_COMPARE(occurrenceIndex, occurrences < occurrenceIndex)) { + occurrences++; + continue; + } + + return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, offset }); + } + } + + throwEvaluateError("failed to find sequence"); + }); + + /* assert */ + ContentRegistry::PatternLanguageFunctions::add("readUnsigned", 2, [this](auto params) { + auto address = asType(params[0])->getValue(); + auto size = asType(params[1])->getValue(); + + if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize())) + throwEvaluateError("address out of range"); + + return std::visit([this](auto &&address, auto &&size) { + if (size <= 0 || size > 16) + throwEvaluateError("invalid read size"); + + u8 value[(u8)size]; + this->m_provider->read(address, value, size); + + switch ((u8)size) { + case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned8Bit, hex::changeEndianess(*reinterpret_cast(value), 1, this->getCurrentEndian()) }); + case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned16Bit, hex::changeEndianess(*reinterpret_cast(value), 2, this->getCurrentEndian()) }); + case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, this->getCurrentEndian()) }); + case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, this->getCurrentEndian()) }); + case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, this->getCurrentEndian()) }); + default: throwEvaluateError("invalid read size"); + } + }, address, size); + }); + + ContentRegistry::PatternLanguageFunctions::add("readSigned", 2, [this](auto params) { + auto address = asType(params[0])->getValue(); + auto size = asType(params[1])->getValue(); + + if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize())) + throwEvaluateError("address out of range"); + + return std::visit([this](auto &&address, auto &&size) { + if (size <= 0 || size > 16) + throwEvaluateError("invalid read size"); + + u8 value[(u8)size]; + this->m_provider->read(address, value, size); + + switch ((u8)size) { + case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed8Bit, hex::changeEndianess(*reinterpret_cast(value), 1, this->getCurrentEndian()) }); + case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed16Bit, hex::changeEndianess(*reinterpret_cast(value), 2, this->getCurrentEndian()) }); + case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, this->getCurrentEndian()) }); + case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, this->getCurrentEndian()) }); + case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, this->getCurrentEndian()) }); + default: throwEvaluateError("invalid read size"); + } + }, address, size); + }); + + ContentRegistry::PatternLanguageFunctions::add("assert", 2, [this](auto params) { + auto condition = asType(params[0])->getValue(); + auto message = asType(params[1])->getString(); + + if (LITERAL_COMPARE(condition, condition == 0)) + throwEvaluateError(hex::format("assert failed \"%s\"", message.data())); + + return nullptr; + }); + + ContentRegistry::PatternLanguageFunctions::add("warnAssert", 2, [this](auto params) { + auto condition = asType(params[0])->getValue(); + auto message = asType(params[1])->getString(); + + if (LITERAL_COMPARE(condition, condition == 0)) + this->emmitWaring(hex::format("assert failed \"%s\"", message.data())); + + return nullptr; + }); + + ContentRegistry::PatternLanguageFunctions::add("print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [this](auto params) { + std::string message; + for (auto& param : params) { + if (auto integerLiteral = dynamic_cast(param); integerLiteral != nullptr) { + switch (integerLiteral->getType()) { + case Token::ValueType::Character: message += std::get(integerLiteral->getValue()); break; + case Token::ValueType::Unsigned8Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Signed8Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Unsigned16Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Signed16Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Unsigned32Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Signed32Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Unsigned64Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Signed64Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Unsigned128Bit: message += "A lot"; break; // TODO: Implement u128 to_string + case Token::ValueType::Signed128Bit: message += "A lot"; break; // TODO: Implement s128 to_string + case Token::ValueType::Float: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Double: message += std::to_string(std::get(integerLiteral->getValue())); break; + case Token::ValueType::Boolean: message += std::get(integerLiteral->getValue()) ? "true" : "false"; break; + case Token::ValueType::CustomType: message += "< Custom Type >"; break; + } + } + else if (auto stringLiteral = dynamic_cast(param); stringLiteral != nullptr) + message += stringLiteral->getString(); + } + + this->emmitInfo(message); + + return nullptr; + }); + } + +} \ No newline at end of file diff --git a/source/lang/evaluator.cpp b/plugins/libimhex/source/lang/evaluator.cpp similarity index 95% rename from source/lang/evaluator.cpp rename to plugins/libimhex/source/lang/evaluator.cpp index adff9918c..941ea3e77 100644 --- a/source/lang/evaluator.cpp +++ b/plugins/libimhex/source/lang/evaluator.cpp @@ -2,6 +2,7 @@ #include "lang/token.hpp" #include "helpers/utils.hpp" +#include "helpers/content_registry.hpp" #include #include @@ -13,29 +14,7 @@ namespace hex::lang { Evaluator::Evaluator(prv::Provider* &provider, std::endian defaultDataEndian) : m_provider(provider), m_defaultDataEndian(defaultDataEndian) { - this->addFunction("findSequence", Function::MoreParametersThan | 1, [this](auto params) { - return this->builtin_findSequence(params); - }); - - this->addFunction("readUnsigned", 2, [this](auto params) { - return this->builtin_readUnsigned(params); - }); - - this->addFunction("readSigned", 2, [this](auto params) { - return this->builtin_readSigned(params); - }); - - 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); - }); + this->registerBuiltinFunctions(); } ASTNodeIntegerLiteral* Evaluator::evaluateScopeResolution(ASTNodeScopeResolution *node) { @@ -137,7 +116,7 @@ namespace hex::lang { throwEvaluateError("tried to use non-integer value in numeric expression"); } - ASTNodeIntegerLiteral* Evaluator::evaluateFunctionCall(ASTNodeFunctionCall *node) { + ASTNode* Evaluator::evaluateFunctionCall(ASTNodeFunctionCall *node) { std::vector evaluatedParams; ScopeExit paramCleanup([&] { for (auto ¶m : evaluatedParams) @@ -151,20 +130,20 @@ namespace hex::lang { evaluatedParams.push_back(stringLiteral->clone()); } - if (!this->m_functions.contains(node->getFunctionName().data())) + if (!ContentRegistry::PatternLanguageFunctions::getEntries().contains(node->getFunctionName().data())) throwEvaluateError(hex::format("no function named '%s' found", node->getFunctionName().data())); - auto &function = this->m_functions[node->getFunctionName().data()]; + auto &function = ContentRegistry::PatternLanguageFunctions::getEntries()[node->getFunctionName().data()]; - if (function.parameterCount == Function::UnlimitedParameters) { + if (function.parameterCount == ContentRegistry::PatternLanguageFunctions::UnlimitedParameters) { ; // Don't check parameter count } - 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)); - } 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)); + else if (function.parameterCount & ContentRegistry::PatternLanguageFunctions::LessParametersThan) { + if (evaluatedParams.size() >= (function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::LessParametersThan)) + throwEvaluateError(hex::format("too many parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::LessParametersThan)); + } else if (function.parameterCount & ContentRegistry::PatternLanguageFunctions::MoreParametersThan) { + if (evaluatedParams.size() <= (function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::MoreParametersThan)) + throwEvaluateError(hex::format("too few parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount & ~ContentRegistry::PatternLanguageFunctions::MoreParametersThan)); } else if (function.parameterCount != evaluatedParams.size()) { throwEvaluateError(hex::format("invalid number of parameters for function '%s'. Expected %d", node->getFunctionName().data(), function.parameterCount)); } @@ -305,8 +284,10 @@ namespace hex::lang { if (returnValue == nullptr) throwEvaluateError("function returning void used in expression"); + else if (auto integerNode = dynamic_cast(returnValue); integerNode != nullptr) + return integerNode; else - return returnValue; + throwEvaluateError("function not returning a numeric value used in expression"); } else throwEvaluateError("invalid operand"); diff --git a/source/lang/lexer.cpp b/plugins/libimhex/source/lang/lexer.cpp similarity index 100% rename from source/lang/lexer.cpp rename to plugins/libimhex/source/lang/lexer.cpp diff --git a/source/lang/parser.cpp b/plugins/libimhex/source/lang/parser.cpp similarity index 100% rename from source/lang/parser.cpp rename to plugins/libimhex/source/lang/parser.cpp diff --git a/source/lang/preprocessor.cpp b/plugins/libimhex/source/lang/preprocessor.cpp similarity index 100% rename from source/lang/preprocessor.cpp rename to plugins/libimhex/source/lang/preprocessor.cpp diff --git a/source/lang/validator.cpp b/plugins/libimhex/source/lang/validator.cpp similarity index 100% rename from source/lang/validator.cpp rename to plugins/libimhex/source/lang/validator.cpp diff --git a/source/lang/builtin_functions.cpp b/source/lang/builtin_functions.cpp deleted file mode 100644 index f13953aa8..000000000 --- a/source/lang/builtin_functions.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include "lang/evaluator.hpp" - -namespace hex::lang { - - #define BUILTIN_FUNCTION(name) ASTNodeIntegerLiteral* Evaluator::TOKEN_CONCAT(builtin_, name)(std::vector params) - - #define LITERAL_COMPARE(literal, cond) std::visit([&, this](auto &&literal) { return (cond) != 0; }, literal) - - BUILTIN_FUNCTION(findSequence) { - auto& occurrenceIndex = asType(params[0])->getValue(); - std::vector sequence; - for (u32 i = 1; i < params.size(); i++) { - sequence.push_back(std::visit([](auto &&value) -> u8 { - if (value <= 0xFF) - return value; - else - throwEvaluateError("sequence bytes need to fit into 1 byte"); - }, asType(params[i])->getValue())); - } - - std::vector bytes(sequence.size(), 0x00); - u32 occurrences = 0; - for (u64 offset = 0; offset < this->m_provider->getSize() - sequence.size(); offset++) { - this->m_provider->read(offset, bytes.data(), bytes.size()); - - if (bytes == sequence) { - if (LITERAL_COMPARE(occurrenceIndex, occurrences < occurrenceIndex)) { - occurrences++; - continue; - } - - return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, offset }); - } - } - - throwEvaluateError("failed to find sequence"); - } - - BUILTIN_FUNCTION(readUnsigned) { - auto address = asType(params[0])->getValue(); - auto size = asType(params[1])->getValue(); - - if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize())) - throwEvaluateError("address out of range"); - - return std::visit([this](auto &&address, auto &&size) { - if (size <= 0 || size > 16) - throwEvaluateError("invalid read size"); - - u8 value[(u8)size]; - this->m_provider->read(address, value, size); - - switch ((u8)size) { - case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned8Bit, hex::changeEndianess(*reinterpret_cast(value), 1, this->getCurrentEndian()) }); - case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned16Bit, hex::changeEndianess(*reinterpret_cast(value), 2, this->getCurrentEndian()) }); - case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, this->getCurrentEndian()) }); - case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, this->getCurrentEndian()) }); - case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Unsigned128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, this->getCurrentEndian()) }); - default: throwEvaluateError("invalid read size"); - } - }, address, size); - } - - BUILTIN_FUNCTION(readSigned) { - auto address = asType(params[0])->getValue(); - auto size = asType(params[1])->getValue(); - - if (LITERAL_COMPARE(address, address >= this->m_provider->getActualSize())) - throwEvaluateError("address out of range"); - - return std::visit([this](auto &&address, auto &&size) { - if (size <= 0 || size > 16) - throwEvaluateError("invalid read size"); - - u8 value[(u8)size]; - this->m_provider->read(address, value, size); - - switch ((u8)size) { - case 1: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed8Bit, hex::changeEndianess(*reinterpret_cast(value), 1, this->getCurrentEndian()) }); - case 2: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed16Bit, hex::changeEndianess(*reinterpret_cast(value), 2, this->getCurrentEndian()) }); - case 4: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed32Bit, hex::changeEndianess(*reinterpret_cast(value), 4, this->getCurrentEndian()) }); - case 8: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed64Bit, hex::changeEndianess(*reinterpret_cast(value), 8, this->getCurrentEndian()) }); - case 16: return new ASTNodeIntegerLiteral({ Token::ValueType::Signed128Bit, hex::changeEndianess(*reinterpret_cast(value), 16, this->getCurrentEndian()) }); - default: throwEvaluateError("invalid read size"); - } - }, address, size); - } - - BUILTIN_FUNCTION(assert) { - auto condition = asType(params[0])->getValue(); - auto message = asType(params[1])->getString(); - - if (LITERAL_COMPARE(condition, condition == 0)) - throwEvaluateError(hex::format("assert failed \"%s\"", message.data())); - - return nullptr; - } - - BUILTIN_FUNCTION(warnAssert) { - auto condition = asType(params[0])->getValue(); - auto message = asType(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(param); integerLiteral != nullptr) { - switch (integerLiteral->getType()) { - case Token::ValueType::Character: message += std::get(integerLiteral->getValue()); break; - case Token::ValueType::Unsigned8Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Signed8Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Unsigned16Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Signed16Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Unsigned32Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Signed32Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Unsigned64Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Signed64Bit: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Unsigned128Bit: message += "A lot"; break; // TODO: Implement u128 to_string - case Token::ValueType::Signed128Bit: message += "A lot"; break; // TODO: Implement s128 to_string - case Token::ValueType::Float: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Double: message += std::to_string(std::get(integerLiteral->getValue())); break; - case Token::ValueType::Boolean: message += std::get(integerLiteral->getValue()) ? "true" : "false"; break; - case Token::ValueType::CustomType: message += "< Custom Type >"; break; - } - } - else if (auto stringLiteral = dynamic_cast(param); stringLiteral != nullptr) - message += stringLiteral->getString(); - } - - this->emmitInfo(message); - - return nullptr; - } - - - #undef BUILTIN_FUNCTION - -} \ No newline at end of file