c051f5d3e7
* patterns: Rewrite most of the evaluator to mainly use polymorphism instead of just RTTI * patterns: Fixed a couple of AST memory leaks * patterns: Parse string operations correctly * patterns: Various fixes and cleanup * patterns: Implement primitive function definitions Function parameters now need to provide their type in the definition * patterns: Added function variable definition and assignment * patterns: Added remaining function statements * patterns: Added unsized and while-sized arrays * patterns: Added multi variable declarations to functions * patterns: Added std::format built-in function * patterns: Allow passing custom types to functions * patterns: Added attributes and new "format" attribute * patterns: Use libfmt for std::print instead of custom version * patterns: Remove unnecessary string compare function * pattern: Fix preprocessor directives * patterns: Fix unit tests * patterns: Added cast expression * patterns: Handle endianess in function parameters * patterns: Added casting to different endian * patterns: Added 'str' type for functions
123 lines
4.9 KiB
C++
123 lines
4.9 KiB
C++
#include <hex/pattern_language/evaluator.hpp>
|
|
#include <hex/pattern_language/ast_node.hpp>
|
|
|
|
namespace hex::pl {
|
|
|
|
void Evaluator::createVariable(const std::string &name, ASTNode *type) {
|
|
auto &variables = *this->getScope(0).scope;
|
|
for (auto &variable : variables) {
|
|
if (variable->getVariableName() == name) {
|
|
LogConsole::abortEvaluation(hex::format("variable with name '{}' already exists", name));
|
|
}
|
|
}
|
|
|
|
auto pattern = type->createPatterns(this).front();
|
|
|
|
pattern->setVariableName(name);
|
|
pattern->setOffset(this->getStack().size());
|
|
pattern->setLocal(true);
|
|
|
|
this->getStack().emplace_back();
|
|
variables.push_back(pattern);
|
|
}
|
|
|
|
void Evaluator::setVariable(const std::string &name, const Token::Literal& value) {
|
|
PatternData *pattern = nullptr;
|
|
|
|
auto &variables = *this->getScope(0).scope;
|
|
for (auto &variable : variables) {
|
|
if (variable->getVariableName() == name) {
|
|
pattern = variable;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pattern == nullptr)
|
|
LogConsole::abortEvaluation(hex::format("no variable with name '{}' found", name));
|
|
|
|
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;
|
|
else
|
|
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 {
|
|
if (dynamic_cast<PatternDataUnsigned*>(pattern))
|
|
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
|
|
LogConsole::abortEvaluation(hex::format("cannot cast type 'string' to type '{}'", pattern->getTypeName()));
|
|
}
|
|
}, value);
|
|
|
|
this->getStack().back() = castedLiteral;
|
|
}
|
|
|
|
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode*> &ast) {
|
|
this->m_stack.clear();
|
|
this->m_customFunctions.clear();
|
|
this->m_scopes.clear();
|
|
|
|
for (auto &func : this->m_customFunctionDefinitions)
|
|
delete func;
|
|
this->m_customFunctionDefinitions.clear();
|
|
|
|
std::vector<PatternData*> patterns;
|
|
|
|
try {
|
|
pushScope(nullptr, patterns);
|
|
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));
|
|
} else {
|
|
auto newPatterns = node->createPatterns(this);
|
|
patterns.insert(patterns.end(), newPatterns.begin(), newPatterns.end());
|
|
}
|
|
|
|
}
|
|
popScope();
|
|
} catch (const LogConsole::EvaluateError &error) {
|
|
this->m_console.log(LogConsole::Level::Error, error.second);
|
|
|
|
if (error.first != 0)
|
|
this->m_console.setHardError(error);
|
|
|
|
for (auto &pattern : patterns)
|
|
delete pattern;
|
|
patterns.clear();
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
return patterns;
|
|
}
|
|
|
|
} |