2021-09-08 15:18:24 +02:00
|
|
|
#include <hex/pattern_language/evaluator.hpp>
|
2021-09-21 21:29:18 +02:00
|
|
|
#include <hex/pattern_language/ast_node.hpp>
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
namespace hex::pl {
|
2020-12-06 21:40:57 +01:00
|
|
|
|
2021-12-18 22:56:36 +01:00
|
|
|
void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value, bool outVariable) {
|
2021-09-21 21:29:18 +02:00
|
|
|
auto &variables = *this->getScope(0).scope;
|
|
|
|
for (auto &variable : variables) {
|
|
|
|
if (variable->getVariableName() == name) {
|
|
|
|
LogConsole::abortEvaluation(hex::format("variable with name '{}' already exists", name));
|
2021-04-21 10:17:42 +02:00
|
|
|
}
|
2021-01-05 14:42:08 +01:00
|
|
|
}
|
|
|
|
|
2021-09-27 18:32:48 +02:00
|
|
|
auto startOffset = this->dataOffset();
|
2021-09-21 21:29:18 +02:00
|
|
|
auto pattern = type->createPatterns(this).front();
|
2021-09-27 18:32:48 +02:00
|
|
|
this->dataOffset() = startOffset;
|
2021-01-05 14:42:08 +01:00
|
|
|
|
2021-09-23 23:43:16 +02:00
|
|
|
if (pattern == nullptr) {
|
|
|
|
// Handle auto variables
|
|
|
|
if (!value.has_value())
|
|
|
|
LogConsole::abortEvaluation("cannot determine type of auto variable", type);
|
|
|
|
|
2021-10-04 20:26:34 +02:00
|
|
|
if (std::get_if<u128>(&value.value()) != nullptr)
|
2021-10-02 15:22:38 +02:00
|
|
|
pattern = new PatternDataUnsigned(0, sizeof(u128), this);
|
2021-10-04 20:26:34 +02:00
|
|
|
else if (std::get_if<s128>(&value.value()) != nullptr)
|
2021-10-02 15:22:38 +02:00
|
|
|
pattern = new PatternDataSigned(0, sizeof(s128), this);
|
2021-10-04 20:26:34 +02:00
|
|
|
else if (std::get_if<double>(&value.value()) != nullptr)
|
2021-10-02 15:22:38 +02:00
|
|
|
pattern = new PatternDataFloat(0, sizeof(double), this);
|
2021-10-04 20:26:34 +02:00
|
|
|
else if (std::get_if<bool>(&value.value()) != nullptr)
|
2021-10-02 15:22:38 +02:00
|
|
|
pattern = new PatternDataBoolean(0, this);
|
2021-10-04 20:26:34 +02:00
|
|
|
else if (std::get_if<char>(&value.value()) != nullptr)
|
2021-10-02 15:22:38 +02:00
|
|
|
pattern = new PatternDataCharacter(0, this);
|
2021-10-04 20:26:34 +02:00
|
|
|
else if (std::get_if<PatternData*>(&value.value()) != nullptr)
|
|
|
|
pattern = std::get<PatternData*>(value.value())->clone();
|
|
|
|
else if (std::get_if<std::string>(&value.value()) != nullptr)
|
2021-10-02 15:22:38 +02:00
|
|
|
pattern = new PatternDataString(0, 1, this);
|
|
|
|
else
|
|
|
|
__builtin_unreachable();
|
2021-09-23 23:43:16 +02:00
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
pattern->setVariableName(name);
|
|
|
|
pattern->setLocal(true);
|
2021-10-08 21:39:30 +02:00
|
|
|
pattern->setOffset(this->getStack().size());
|
2021-01-09 21:47:11 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
this->getStack().emplace_back();
|
|
|
|
variables.push_back(pattern);
|
2021-12-18 22:56:36 +01:00
|
|
|
|
|
|
|
if (outVariable)
|
|
|
|
this->m_outVariables[name] = pattern->getOffset();
|
2021-01-07 01:19:54 +01:00
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
void Evaluator::setVariable(const std::string &name, const Token::Literal& value) {
|
|
|
|
PatternData *pattern = nullptr;
|
2021-01-07 01:19:54 +01:00
|
|
|
|
2021-10-18 22:04:54 +02:00
|
|
|
{
|
|
|
|
auto &variables = *this->getScope(0).scope;
|
|
|
|
for (auto &variable : variables) {
|
|
|
|
if (variable->getVariableName() == name) {
|
|
|
|
pattern = variable;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pattern == nullptr) {
|
|
|
|
auto &variables = *this->getGlobalScope().scope;
|
|
|
|
for (auto &variable : variables) {
|
|
|
|
if (variable->getVariableName() == name) {
|
|
|
|
if (!variable->isLocal())
|
|
|
|
LogConsole::abortEvaluation(hex::format("cannot modify global variable '{}' which has been placed in memory", name));
|
|
|
|
|
|
|
|
pattern = variable;
|
|
|
|
break;
|
|
|
|
}
|
2021-01-07 01:19:54 +01:00
|
|
|
}
|
2021-06-20 21:22:31 +02:00
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
if (pattern == nullptr)
|
|
|
|
LogConsole::abortEvaluation(hex::format("no variable with name '{}' found", name));
|
2021-06-20 21:22:31 +02:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
Token::Literal castedLiteral = std::visit(overloaded {
|
|
|
|
[&](double &value) -> Token::Literal {
|
|
|
|
if (dynamic_cast<PatternDataUnsigned*>(pattern))
|
|
|
|
return u128(value);
|
|
|
|
else if (dynamic_cast<PatternDataSigned*>(pattern))
|
|
|
|
return s128(value);
|
|
|
|
else if (dynamic_cast<PatternDataFloat*>(pattern))
|
|
|
|
return value;
|
2021-06-20 23:46:13 +02:00
|
|
|
else
|
2021-09-21 21:29:18 +02:00
|
|
|
LogConsole::abortEvaluation(hex::format("cannot cast type 'double' to type '{}'", pattern->getTypeName()));
|
|
|
|
},
|
|
|
|
[&](const std::string &value) -> Token::Literal {
|
|
|
|
if (dynamic_cast<PatternDataString*>(pattern))
|
|
|
|
return value;
|
|
|
|
else
|
|
|
|
LogConsole::abortEvaluation(hex::format("cannot cast type 'string' to type '{}'", pattern->getTypeName()));
|
|
|
|
},
|
|
|
|
[&](PatternData * const &value) -> Token::Literal {
|
|
|
|
if (value->getTypeName() == pattern->getTypeName())
|
|
|
|
return value;
|
|
|
|
else
|
|
|
|
LogConsole::abortEvaluation(hex::format("cannot cast type '{}' to type '{}'", value->getTypeName(), pattern->getTypeName()));
|
|
|
|
},
|
|
|
|
[&](auto &&value) -> Token::Literal {
|
2022-01-11 19:35:28 +01:00
|
|
|
if (dynamic_cast<PatternDataUnsigned*>(pattern) || dynamic_cast<PatternDataEnum*>(pattern))
|
2021-09-21 21:29:18 +02:00
|
|
|
return u128(value);
|
|
|
|
else if (dynamic_cast<PatternDataSigned*>(pattern))
|
|
|
|
return s128(value);
|
|
|
|
else if (dynamic_cast<PatternDataCharacter*>(pattern))
|
|
|
|
return char(value);
|
|
|
|
else if (dynamic_cast<PatternDataBoolean*>(pattern))
|
|
|
|
return bool(value);
|
|
|
|
else if (dynamic_cast<PatternDataFloat*>(pattern))
|
|
|
|
return double(value);
|
|
|
|
else
|
2022-01-11 19:35:28 +01:00
|
|
|
LogConsole::abortEvaluation(hex::format("cannot cast integer literal to type '{}'", pattern->getTypeName()));
|
2021-06-21 00:21:38 +02:00
|
|
|
}
|
2021-09-21 21:29:18 +02:00
|
|
|
}, value);
|
2021-06-21 00:21:38 +02:00
|
|
|
|
2021-09-25 00:03:32 +02:00
|
|
|
this->getStack()[pattern->getOffset()] = castedLiteral;
|
2021-12-18 22:56:36 +01:00
|
|
|
|
2021-06-20 23:46:13 +02:00
|
|
|
}
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode*> &ast) {
|
|
|
|
this->m_stack.clear();
|
|
|
|
this->m_customFunctions.clear();
|
|
|
|
this->m_scopes.clear();
|
2021-10-07 11:34:46 +02:00
|
|
|
this->m_aborted = false;
|
2021-01-21 17:49:30 +01:00
|
|
|
|
2021-12-19 12:32:15 +01:00
|
|
|
if (this->m_allowDangerousFunctions == DangerousFunctionPermission::Deny)
|
|
|
|
this->m_allowDangerousFunctions = DangerousFunctionPermission::Ask;
|
|
|
|
|
|
|
|
this->m_dangerousFunctionCalled = false;
|
|
|
|
|
2021-12-10 11:55:27 +01:00
|
|
|
ON_SCOPE_EXIT {
|
|
|
|
this->m_envVariables.clear();
|
|
|
|
};
|
|
|
|
|
2021-10-02 13:41:56 +02:00
|
|
|
this->dataOffset() = 0x00;
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_currPatternCount = 0;
|
2021-10-02 13:41:56 +02:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
for (auto &func : this->m_customFunctionDefinitions)
|
|
|
|
delete func;
|
|
|
|
this->m_customFunctionDefinitions.clear();
|
2021-01-21 17:49:30 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
std::vector<PatternData*> patterns;
|
2021-01-23 14:00:09 +01:00
|
|
|
|
Pattern Language rewrite (#111)
* Initial parser rewrite effort
Lexer and Token cleanup, Parser started over
* Greatly improved parser syntax
* Reimplemented using declarations and variable placement parsing
* Added back unions and structs
* Added enums as well as mathematical expressions (+, -, *, /, <<, >>, &, |, ^)
* Code style improvement
* Implemented arrays and fixed memory issues
* Fixed more memory issues in parser, reimplemented validator, evaluator and patterns
* Fixed builtin types, arrays and reimplemented strings
* Improved error messages
* Made character a distinct type, used for chars and strings
* Implemented padding, fixed arrays
* Added bitfields
* Added rvalue parsing, no evaluating yet
* Added .idea folder to gitignore
* Fixed build on MacOS
* Added custom implementation of integral concept if not available
* Rebased onto master
* Fixed array variable decl crash
* Added rvalues and dot syntax
* Lower case all pattern language error messages
* Fixed typo in variable name
* Fixed bug where preprocessor would not ignore commented out directives
* Reimplemented pointers
* Fixed rebase issues
2021-01-02 20:27:11 +01:00
|
|
|
try {
|
2021-12-30 14:44:46 +01:00
|
|
|
this->setCurrentControlFlowStatement(ControlFlowStatement::None);
|
2021-09-21 21:29:18 +02:00
|
|
|
pushScope(nullptr, patterns);
|
2021-10-08 18:47:05 +02:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
for (auto node : ast) {
|
|
|
|
if (dynamic_cast<ASTNodeTypeDecl*>(node)) {
|
|
|
|
;// Don't create patterns from type declarations
|
|
|
|
} else if (dynamic_cast<ASTNodeFunctionCall*>(node)) {
|
|
|
|
delete node->evaluate(this);
|
|
|
|
} else if (dynamic_cast<ASTNodeFunctionDefinition*>(node)) {
|
|
|
|
this->m_customFunctionDefinitions.push_back(node->evaluate(this));
|
2021-10-18 22:04:54 +02:00
|
|
|
} else if (auto varDeclNode = dynamic_cast<ASTNodeVariableDecl*>(node)) {
|
|
|
|
auto pattern = node->createPatterns(this).front();
|
|
|
|
|
|
|
|
if (varDeclNode->getPlacementOffset() == nullptr) {
|
|
|
|
auto type = varDeclNode->getType()->evaluate(this);
|
|
|
|
ON_SCOPE_EXIT { delete type; };
|
|
|
|
|
2021-12-18 22:56:36 +01:00
|
|
|
auto &name = pattern->getVariableName();
|
|
|
|
this->createVariable(name, type, std::nullopt, varDeclNode->isOutVariable());
|
|
|
|
|
|
|
|
if (varDeclNode->isInVariable() && this->m_inVariables.contains(name))
|
|
|
|
this->setVariable(name, this->m_inVariables[name]);
|
|
|
|
|
2021-10-18 22:04:54 +02:00
|
|
|
delete pattern;
|
|
|
|
} else {
|
|
|
|
patterns.push_back(pattern);
|
|
|
|
}
|
2021-09-21 21:29:18 +02:00
|
|
|
} else {
|
|
|
|
auto newPatterns = node->createPatterns(this);
|
|
|
|
patterns.insert(patterns.end(), newPatterns.begin(), newPatterns.end());
|
2021-04-13 20:40:21 +02:00
|
|
|
}
|
2021-10-08 18:47:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (this->m_customFunctions.contains("main")) {
|
|
|
|
auto mainFunction = this->m_customFunctions["main"];
|
|
|
|
|
|
|
|
if (mainFunction.parameterCount > 0)
|
|
|
|
LogConsole::abortEvaluation("main function may not accept any arguments");
|
2021-04-13 20:40:21 +02:00
|
|
|
|
2021-10-08 18:47:05 +02:00
|
|
|
auto result = mainFunction.func(this, { });
|
|
|
|
if (result) {
|
|
|
|
auto returnCode = Token::literalToSigned(*result);
|
|
|
|
|
|
|
|
if (returnCode != 0)
|
|
|
|
LogConsole::abortEvaluation(hex::format("non-success value returned from main: {}", returnCode));
|
|
|
|
}
|
2021-04-13 20:40:21 +02:00
|
|
|
}
|
2021-10-08 18:47:05 +02:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
popScope();
|
|
|
|
} catch (const LogConsole::EvaluateError &error) {
|
|
|
|
this->m_console.log(LogConsole::Level::Error, error.second);
|
2021-04-13 20:40:21 +02:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
if (error.first != 0)
|
|
|
|
this->m_console.setHardError(error);
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
for (auto &pattern : patterns)
|
|
|
|
delete pattern;
|
|
|
|
patterns.clear();
|
2021-01-08 15:03:53 +01:00
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
this->m_currPatternCount = 0;
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
return std::nullopt;
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|
|
|
|
|
2021-10-18 22:04:54 +02:00
|
|
|
// Remove global local variables
|
|
|
|
std::erase_if(patterns, [](PatternData *pattern) {
|
|
|
|
return pattern->isLocal();
|
|
|
|
});
|
|
|
|
|
2021-09-21 21:29:18 +02:00
|
|
|
return patterns;
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|
|
|
|
|
2021-10-02 15:22:38 +02:00
|
|
|
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--;
|
|
|
|
}
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|