1
0
mirror of synced 2024-11-25 00:00:27 +01:00

patterns: Added function if statements, improved returns

This commit is contained in:
WerWolv 2021-06-20 23:46:13 +02:00
parent 7f0bdc95da
commit c9fae32ddf
4 changed files with 136 additions and 64 deletions

View File

@ -68,6 +68,7 @@ namespace hex::lang {
ASTNodeIntegerLiteral* evaluateTernaryExpression(ASTNodeTernaryExpression *node);
ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node);
void evaluateFunctionDefinition(ASTNodeFunctionDefinition *node);
std::optional<ASTNode*> evaluateFunctionBody(const std::vector<ASTNode*> &body);
PatternData* findPattern(std::vector<PatternData*> currMembers, const ASTNodeRValue::Path &path);
PatternData* evaluateAttributes(ASTNode *currNode, PatternData *currPattern);

View File

@ -73,8 +73,10 @@ namespace hex::lang {
void parseAttribute(Attributable *currNode);
ASTNode* parseFunctionDefintion();
ASTNode* parseVariableAssignment();
ASTNode* parseReturnStatement();
ASTNode* parseFunctionStatement();
ASTNode* parseFunctionVariableAssignment();
ASTNode* parseFunctionReturnStatement();
ASTNode* parseFunctionConditional();
ASTNode* parseConditional();
ASTNode* parseWhileStatement();
ASTNode* parseType(s32 startIndex);

View File

@ -480,47 +480,7 @@ namespace hex::lang {
}
evaluator.m_currOffset = startOffset;
for (auto &statement : body) {
ON_SCOPE_EXIT { evaluator.m_currOffset = startOffset; };
if (auto functionCallNode = dynamic_cast<ASTNodeFunctionCall*>(statement); functionCallNode != nullptr) {
auto result = evaluator.evaluateFunctionCall(functionCallNode);
delete result;
} else if (auto varDeclNode = dynamic_cast<ASTNodeVariableDecl*>(statement); varDeclNode != nullptr) {
auto pattern = evaluator.evaluateVariable(varDeclNode);
evaluator.createLocalVariable(varDeclNode->getName(), pattern);
} else if (auto assignmentNode = dynamic_cast<ASTNodeAssignment*>(statement); assignmentNode != nullptr) {
if (auto numericExpressionNode = dynamic_cast<ASTNodeNumericExpression*>(assignmentNode->getRValue()); numericExpressionNode != nullptr) {
auto value = evaluator.evaluateMathematicalExpression(numericExpressionNode);
ON_SCOPE_EXIT { delete value; };
std::visit([&](auto &&value) {
evaluator.setLocalVariableValue(assignmentNode->getLValueName(), &value, sizeof(value));
}, value->getValue());
} else {
evaluator.getConsole().abortEvaluation("invalid rvalue used in assignment");
}
} else if (auto assignmentNode = dynamic_cast<ASTNodeAssignment*>(statement); assignmentNode != nullptr) {
if (auto numericExpressionNode = dynamic_cast<ASTNodeNumericExpression*>(assignmentNode->getRValue()); numericExpressionNode != nullptr) {
auto value = evaluator.evaluateMathematicalExpression(numericExpressionNode);
ON_SCOPE_EXIT { delete value; };
std::visit([&](auto &&value) {
evaluator.setLocalVariableValue(assignmentNode->getLValueName(), &value, sizeof(value));
}, value->getValue());
} else {
evaluator.getConsole().abortEvaluation("invalid rvalue used in assignment");
}
} else if (auto returnNode = dynamic_cast<ASTNodeReturnStatement*>(statement); returnNode != nullptr) {
if (auto numericExpressionNode = dynamic_cast<ASTNodeNumericExpression*>(returnNode->getRValue()); numericExpressionNode != nullptr) {
return evaluator.evaluateMathematicalExpression(numericExpressionNode);
} else {
evaluator.getConsole().abortEvaluation("invalid rvalue used in return statement");
}
}
}
return nullptr;
return evaluator.evaluateFunctionBody(body).value_or(nullptr);
}
};
@ -530,6 +490,68 @@ namespace hex::lang {
this->m_definedFunctions.insert({ std::string(node->getName()), function });
}
std::optional<ASTNode*> Evaluator::evaluateFunctionBody(const std::vector<ASTNode*> &body) {
std::optional<ASTNode*> returnResult;
auto startOffset = this->m_currOffset;
for (auto &statement : body) {
ON_SCOPE_EXIT { this->m_currOffset = startOffset; };
if (auto functionCallNode = dynamic_cast<ASTNodeFunctionCall*>(statement); functionCallNode != nullptr) {
auto result = this->evaluateFunctionCall(functionCallNode);
delete result;
} else if (auto varDeclNode = dynamic_cast<ASTNodeVariableDecl*>(statement); varDeclNode != nullptr) {
auto pattern = this->evaluateVariable(varDeclNode);
this->createLocalVariable(varDeclNode->getName(), pattern);
} else if (auto assignmentNode = dynamic_cast<ASTNodeAssignment*>(statement); assignmentNode != nullptr) {
if (auto numericExpressionNode = dynamic_cast<ASTNodeNumericExpression*>(assignmentNode->getRValue()); numericExpressionNode != nullptr) {
auto value = this->evaluateMathematicalExpression(numericExpressionNode);
ON_SCOPE_EXIT { delete value; };
std::visit([&](auto &&value) {
this->setLocalVariableValue(assignmentNode->getLValueName(), &value, sizeof(value));
}, value->getValue());
} else {
this->getConsole().abortEvaluation("invalid rvalue used in assignment");
}
} else if (auto returnNode = dynamic_cast<ASTNodeReturnStatement*>(statement); returnNode != nullptr) {
if (returnNode->getRValue() == nullptr) {
returnResult = nullptr;
} else if (auto numericExpressionNode = dynamic_cast<ASTNodeNumericExpression*>(returnNode->getRValue()); numericExpressionNode != nullptr) {
returnResult = this->evaluateMathematicalExpression(numericExpressionNode);
} else {
this->getConsole().abortEvaluation("invalid rvalue used in return statement");
}
} else if (auto conditionalNode = dynamic_cast<ASTNodeConditionalStatement*>(statement); conditionalNode != nullptr) {
if (auto numericExpressionNode = dynamic_cast<ASTNodeNumericExpression*>(conditionalNode->getCondition()); numericExpressionNode != nullptr) {
auto condition = this->evaluateMathematicalExpression(numericExpressionNode);
u32 localVariableStartCount = this->m_localVariables.back()->size();
u32 localVariableStackStartSize = this->m_localStack.size();
if (std::visit([](auto &&value) { return value != 0; }, condition->getValue()))
returnResult = this->evaluateFunctionBody(conditionalNode->getTrueBody());
else
returnResult = this->evaluateFunctionBody(conditionalNode->getFalseBody());
for (u32 i = localVariableStartCount; i < this->m_localVariables.size(); i++)
delete (*this->m_localVariables.back())[i];
this->m_localVariables.back()->resize(localVariableStartCount);
this->m_localStack.resize(localVariableStackStartSize);
} else {
this->getConsole().abortEvaluation("invalid rvalue used in return statement");
}
}
if (returnResult.has_value())
return returnResult.value();
}
return { };
}
PatternData* Evaluator::evaluateAttributes(ASTNode *currNode, PatternData *currPattern) {
auto attributableNode = dynamic_cast<Attributable*>(currNode);
if (attributableNode == nullptr)

View File

@ -388,31 +388,41 @@ namespace hex::lang {
};
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
ASTNode *statement;
if (MATCHES(sequence(IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN)))
statement = parseFunctionCall();
else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN) && sequence<Not>(SEPARATOR_SQUAREBRACKETOPEN)))
statement = parseMemberArrayVariable();
else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER)))
statement = parseMemberVariable();
else if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT)))
statement = parseVariableAssignment();
else if (MATCHES(sequence(KEYWORD_RETURN)))
statement = parseReturnStatement();
else
throwParseError("invalid sequence", 0);
body.push_back(statement);
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
throwParseError("missing ';' at end of expression", -1);
body.push_back(this->parseFunctionStatement());
}
bodyCleanup.release();
return new ASTNodeFunctionDefinition(functionName, params, body);
}
ASTNode* Parser::parseVariableAssignment() {
ASTNode* Parser::parseFunctionStatement() {
bool needsSemicolon = true;
ASTNode *statement;
if (MATCHES(sequence(IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN)))
statement = parseFunctionCall();
else if (MATCHES((optional(KEYWORD_BE), optional(KEYWORD_LE)) && variant(IDENTIFIER, VALUETYPE_ANY) && sequence(IDENTIFIER)))
statement = parseMemberVariable();
else if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT)))
statement = parseFunctionVariableAssignment();
else if (MATCHES(sequence(KEYWORD_RETURN)))
statement = parseFunctionReturnStatement();
else if (MATCHES(sequence(KEYWORD_IF, SEPARATOR_ROUNDBRACKETOPEN))) {
statement = parseFunctionConditional();
needsSemicolon = false;
}
else
throwParseError("invalid sequence", 0);
if (needsSemicolon && !MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) {
delete statement;
throwParseError("missing ';' at end of expression", -1);
}
return statement;
}
ASTNode* Parser::parseFunctionVariableAssignment() {
const auto &lvalue = getValue<std::string>(-2);
auto rvalue = this->parseMathematicalExpression();
@ -420,8 +430,45 @@ namespace hex::lang {
return new ASTNodeAssignment(lvalue, rvalue);
}
ASTNode* Parser::parseReturnStatement() {
return new ASTNodeReturnStatement(this->parseMathematicalExpression());
ASTNode* Parser::parseFunctionReturnStatement() {
if (peek(SEPARATOR_ENDOFEXPRESSION))
return new ASTNodeReturnStatement(nullptr);
else
return new ASTNodeReturnStatement(this->parseMathematicalExpression());
}
ASTNode* Parser::parseFunctionConditional() {
auto condition = parseMathematicalExpression();
std::vector<ASTNode*> trueBody, falseBody;
auto cleanup = SCOPE_GUARD {
delete condition;
for (auto &statement : trueBody)
delete statement;
for (auto &statement : falseBody)
delete statement;
};
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE, SEPARATOR_CURLYBRACKETOPEN))) {
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
trueBody.push_back(parseFunctionStatement());
}
} else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
trueBody.push_back(parseFunctionStatement());
} else
throwParseError("expected body of conditional statement");
if (MATCHES(sequence(KEYWORD_ELSE, SEPARATOR_CURLYBRACKETOPEN))) {
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
falseBody.push_back(parseFunctionStatement());
}
} else if (MATCHES(sequence(KEYWORD_ELSE))) {
falseBody.push_back(parseFunctionStatement());
}
cleanup.release();
return new ASTNodeConditionalStatement(condition, trueBody, falseBody);
}
/* Control flow */