patterns: Added basic support for in/out variables

This commit is contained in:
WerWolv
2021-12-18 22:56:36 +01:00
parent c56408640f
commit ea92e17ca0
10 changed files with 411 additions and 153 deletions

View File

@@ -714,8 +714,8 @@ namespace hex::pl {
class ASTNodeVariableDecl : public ASTNode, public Attributable {
public:
ASTNodeVariableDecl(std::string name, ASTNode *type, ASTNode *placementOffset = nullptr)
: ASTNode(), m_name(std::move(name)), m_type(type), m_placementOffset(placementOffset) { }
ASTNodeVariableDecl(std::string name, ASTNode *type, ASTNode *placementOffset = nullptr, bool inVariable = false, bool outVariable = false)
: ASTNode(), m_name(std::move(name)), m_type(type), m_placementOffset(placementOffset), m_inVariable(inVariable), m_outVariable(outVariable) { }
ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) {
this->m_name = other.m_name;
@@ -740,6 +740,9 @@ namespace hex::pl {
[[nodiscard]] constexpr ASTNode* getType() const { return this->m_type; }
[[nodiscard]] constexpr auto getPlacementOffset() const { return this->m_placementOffset; }
[[nodiscard]] constexpr bool isInVariable() const { return this->m_inVariable; }
[[nodiscard]] constexpr bool isOutVariable() const { return this->m_outVariable; }
[[nodiscard]] std::vector<PatternData*> createPatterns(Evaluator *evaluator) const override {
if (this->m_placementOffset != nullptr) {
auto offset = dynamic_cast<ASTNodeLiteral *>(this->m_placementOffset->evaluate(evaluator));
@@ -770,6 +773,8 @@ namespace hex::pl {
std::string m_name;
ASTNode *m_type;
ASTNode *m_placementOffset;
bool m_inVariable, m_outVariable;
};
class ASTNodeArrayVariableDecl : public ASTNode, public Attributable {
@@ -1459,7 +1464,8 @@ namespace hex::pl {
std::visit(overloaded {
[&](std::string &assignmentValue) { },
[&](auto &&assignmentValue) { std::memcpy(&value, &assignmentValue, pattern->getSize()); }
[&](PatternData *assignmentValue) { },
[&](auto &&assignmentValue) { value = assignmentValue; }
}, literal);
}
else

View File

@@ -64,6 +64,21 @@ namespace hex::pl {
this->m_provider = provider;
}
void setInVariables(const std::map<std::string, Token::Literal> &inVariables) {
this->m_inVariables = inVariables;
}
[[nodiscard]]
std::map<std::string, Token::Literal> getOutVariables() const {
std::map<std::string, Token::Literal> result;
for (const auto &[name, offset] : this->m_outVariables) {
result.insert({ name, this->getStack()[offset] });
}
return result;
}
[[nodiscard]]
prv::Provider *getProvider() const {
return this->m_provider;
@@ -137,7 +152,12 @@ namespace hex::pl {
return this->m_stack;
}
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt);
[[nodiscard]]
const std::vector<Token::Literal>& getStack() const {
return this->m_stack;
}
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt, bool outVariable = false);
void setVariable(const std::string &name, const Token::Literal& value);
void abort() {
@@ -185,7 +205,10 @@ namespace hex::pl {
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_customFunctions;
std::vector<ASTNode*> m_customFunctionDefinitions;
std::vector<Token::Literal> m_stack;
std::map<std::string, Token::Literal> m_envVariables;
std::map<std::string, Token::Literal> m_inVariables;
std::map<std::string, size_t> m_outVariables;
friend class PatternCreationLimiter;
};

View File

@@ -30,15 +30,27 @@ namespace hex::pl {
PatternLanguage();
~PatternLanguage();
std::optional<std::vector<PatternData*>> executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = { });
std::optional<std::vector<PatternData*>> executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars = { });
[[nodiscard]]
std::optional<std::vector<ASTNode*>> parseString(const std::string &code);
[[nodiscard]]
std::optional<std::vector<PatternData*>> executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = { }, const std::map<std::string, Token::Literal> &inVariables = { });
[[nodiscard]]
std::optional<std::vector<PatternData*>> executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars = { }, const std::map<std::string, Token::Literal> &inVariables = { });
[[nodiscard]]
const std::vector<ASTNode*>& getCurrentAST() const;
void abort();
[[nodiscard]]
const std::vector<std::pair<LogConsole::Level, std::string>>& getConsoleLog();
[[nodiscard]]
const std::optional<std::pair<u32, std::string>>& getError();
[[nodiscard]]
std::map<std::string, Token::Literal> getOutVariables() const;
[[nodiscard]]
u32 getCreatedPatternCount();
[[nodiscard]]
u32 getMaximumPatternCount();
private:

View File

@@ -40,7 +40,9 @@ namespace hex::pl {
For,
Function,
Return,
Namespace
Namespace,
In,
Out
};
enum class Operator {
@@ -285,6 +287,8 @@ namespace hex::pl {
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
#define KEYWORD_IN COMPONENT(Keyword, In)
#define KEYWORD_OUT COMPONENT(Keyword, Out)
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""

View File

@@ -3,7 +3,7 @@
namespace hex::pl {
void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value) {
void Evaluator::createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value, bool outVariable) {
auto &variables = *this->getScope(0).scope;
for (auto &variable : variables) {
if (variable->getVariableName() == name) {
@@ -44,6 +44,9 @@ namespace hex::pl {
this->getStack().emplace_back();
variables.push_back(pattern);
if (outVariable)
this->m_outVariables[name] = pattern->getOffset();
}
void Evaluator::setVariable(const std::string &name, const Token::Literal& value) {
@@ -115,6 +118,7 @@ namespace hex::pl {
}, value);
this->getStack()[pattern->getOffset()] = castedLiteral;
}
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode*> &ast) {
@@ -153,7 +157,12 @@ namespace hex::pl {
auto type = varDeclNode->getType()->evaluate(this);
ON_SCOPE_EXIT { delete type; };
this->createVariable(pattern->getVariableName(), type);
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]);
delete pattern;
} else {
patterns.push_back(pattern);

View File

@@ -416,6 +416,10 @@ namespace hex::pl {
tokens.emplace_back(TOKEN(Keyword, Return));
else if (identifier == "namespace")
tokens.emplace_back(TOKEN(Keyword, Namespace));
else if (identifier == "in")
tokens.emplace_back(TOKEN(Keyword, In));
else if (identifier == "out")
tokens.emplace_back(TOKEN(Keyword, Out));
// Check for built-in types
else if (identifier == "u8")

View File

@@ -1024,16 +1024,22 @@ namespace hex::pl {
// (parseType) Identifier @ Integer
ASTNode* Parser::parseVariablePlacement(ASTNodeTypeDecl *type) {
bool inVariable = false;
bool outVariable = false;
auto name = getValue<Token::Identifier>(-1).get();
ASTNode *placementOffset;
ASTNode *placementOffset = nullptr;
if (MATCHES(sequence(OPERATOR_AT))) {
placementOffset = parseMathematicalExpression();
} else {
placementOffset = nullptr;
} else if (MATCHES(sequence(KEYWORD_IN))) {
inVariable = true;
}
else if (MATCHES(sequence(KEYWORD_OUT))) {
outVariable = true;
}
return create(new ASTNodeVariableDecl(name, type, placementOffset));
return create(new ASTNodeVariableDecl(name, type, placementOffset, inVariable, outVariable));
}
// (parseType) Identifier[[(parseMathematicalExpression)]] @ Integer

View File

@@ -94,25 +94,8 @@ namespace hex::pl {
delete this->m_validator;
}
std::optional<std::vector<PatternData*>> PatternLanguage::executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars) {
this->m_currError.reset();
this->m_evaluator->getConsole().clear();
this->m_evaluator->setProvider(provider);
this->m_evaluator->setDefaultEndian(std::endian::native);
this->m_evaluator->setEvaluationDepth(32);
this->m_evaluator->setArrayLimit(0x1000);
this->m_evaluator->setPatternLimit(0x2000);
this->m_evaluator->setLoopLimit(0x1000);
for (const auto &[name, value] : envVars)
this->m_evaluator->setEnvVariable(name, value);
for (auto &node : this->m_currAST)
delete node;
this->m_currAST.clear();
auto preprocessedCode = this->m_preprocessor->preprocess(string);
std::optional<std::vector<ASTNode*>> PatternLanguage::parseString(const std::string &code) {
auto preprocessedCode = this->m_preprocessor->preprocess(code);
if (!preprocessedCode.has_value()) {
this->m_currError = this->m_preprocessor->getError();
return { };
@@ -130,6 +113,31 @@ namespace hex::pl {
return { };
}
return ast;
}
std::optional<std::vector<PatternData*>> PatternLanguage::executeString(prv::Provider *provider, const std::string &code, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables) {
this->m_currError.reset();
this->m_evaluator->getConsole().clear();
this->m_evaluator->setProvider(provider);
this->m_evaluator->setDefaultEndian(std::endian::native);
this->m_evaluator->setEvaluationDepth(32);
this->m_evaluator->setArrayLimit(0x1000);
this->m_evaluator->setPatternLimit(0x2000);
this->m_evaluator->setLoopLimit(0x1000);
this->m_evaluator->setInVariables(inVariables);
for (const auto &[name, value] : envVars)
this->m_evaluator->setEnvVariable(name, value);
for (auto &node : this->m_currAST)
delete node;
this->m_currAST.clear();
auto ast = this->parseString(code);
if (!ast)
return { };
this->m_currAST = ast.value();
auto patterns = this->m_evaluator->evaluate(ast.value());
@@ -141,16 +149,25 @@ namespace hex::pl {
return patterns;
}
std::optional<std::vector<PatternData*>> PatternLanguage::executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars) {
std::optional<std::vector<PatternData*>> PatternLanguage::executeFile(prv::Provider *provider, const std::string &path, const std::map<std::string, Token::Literal> &envVars, const std::map<std::string, Token::Literal> &inVariables) {
File file(path, File::Mode::Read);
return this->executeString(provider, file.readString(), envVars);
return this->executeString(provider, file.readString(), envVars, inVariables);
}
void PatternLanguage::abort() {
this->m_evaluator->abort();
}
const std::vector<ASTNode*> &PatternLanguage::getCurrentAST() const {
return this->m_currAST;
}
[[nodiscard]]
std::map<std::string, Token::Literal> PatternLanguage::getOutVariables() const {
return this->m_evaluator->getOutVariables();
}
const std::vector<std::pair<LogConsole::Level, std::string>>& PatternLanguage::getConsoleLog() {
return this->m_evaluator->getConsole().getLog();