Rework function evaluation scope to handle tables
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-06-12 17:56:47 +02:00
parent c022c91777
commit 3477ddd18c
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
7 changed files with 57 additions and 30 deletions

View File

@ -1,5 +1,7 @@
#include <utility>
#include <utility>
#ifndef PORYGONLANG_SCRIPTFUNCTIONEVALVALUE_HPP
#define PORYGONLANG_SCRIPTFUNCTIONEVALVALUE_HPP
@ -9,24 +11,30 @@
#include "EvalValue.hpp"
#include "../../Binder/BoundStatements/BoundStatement.hpp"
#include "../Evaluator.hpp"
#include "../EvaluationScope/EvaluationScope.hpp"
class ScriptFunctionEvalValue : public EvalValue{
std::shared_ptr<BoundBlockStatement> _innerBlock;
std::shared_ptr<FunctionScriptType> _type;
std::shared_ptr<EvaluationScope> _scope;
std::size_t _hash;
explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock, std::shared_ptr<FunctionScriptType> type, size_t hash)
explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock, std::shared_ptr<EvaluationScope> scope,
std::shared_ptr<FunctionScriptType> type, size_t hash)
: _type(std::move(type))
{
_innerBlock = std::move(innerBlock);
_scope = std::move(scope);
_hash = hash;
}
public:
explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock, std::shared_ptr<FunctionScriptType> type)
explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock, std::shared_ptr<EvaluationScope> scope,
std::shared_ptr<FunctionScriptType> type)
: _type(std::move(type))
{
_innerBlock = std::move(innerBlock);
_scope = std::move(scope);
_hash = rand();
}
@ -35,7 +43,7 @@ public:
}
shared_ptr<EvalValue> Clone() final{
return shared_ptr<ScriptFunctionEvalValue>(new ScriptFunctionEvalValue(_innerBlock, _type, _hash));
return shared_ptr<ScriptFunctionEvalValue>(new ScriptFunctionEvalValue(_innerBlock, _scope, _type, _hash));
}
@ -49,11 +57,13 @@ public:
return _innerBlock;
}
std::size_t GetHashCode(){
std::size_t GetHashCode() final{
return _hash;
}
std::shared_ptr<EvaluationScope> GetScope(){
return _scope;
}
};

View File

@ -37,12 +37,15 @@ shared_ptr<EvalValue> EvaluationScope::GetVariable(int scope, int id) {
return _localScope[scope - 1]->at(id);
}
EvaluationScope* EvaluationScope::CreateBranchingScope(int index){
EvaluationScope* EvaluationScope::CreateBranchingScope(int scopeIndex){
auto scope = new EvaluationScope(this -> _scriptScope, this -> _localScope.size());
for (int i = 0; i < index; i++){
for (int i = 0; i <= scopeIndex; i++){
scope->_localScope[i] = this->_localScope[i];
}
scope->_currentScope = index;
for (int i = scopeIndex + 1; i < _localScope.size(); i++){
scope->_localScope[i] = make_shared<unordered_map<int, shared_ptr<EvalValue>>>();
}
scope->_currentScope = this -> _currentScope;
return scope;
}

View File

@ -20,7 +20,7 @@ public:
void InnerScope(bool clearScope = true);
shared_ptr<EvalValue> GetVariable(int scope, int id);
EvaluationScope* CreateBranchingScope(int index);
EvaluationScope* CreateBranchingScope(int scopeIndex);
int GetCurrentScope(){
return _currentScope;

View File

@ -12,7 +12,7 @@
using namespace std;
void Evaluator::Evaluate(BoundScriptStatement *statement) {
this->_evaluationScope = new EvaluationScope(this->_scriptData->_scriptVariables, statement->GetDeepestScope());
this->_evaluationScope = make_shared<EvaluationScope>(this->_scriptData->_scriptVariables, statement->GetDeepestScope());
EvaluateBlockStatement(statement, false);
}
@ -62,7 +62,8 @@ void Evaluator::EvaluateFunctionDeclarationStatement(BoundFunctionDeclarationSta
auto type = statement->GetType();
auto key = statement->GetKey();
auto block = statement->GetBlock();
auto value = make_shared<ScriptFunctionEvalValue>(block, type);
auto evaluator = shared_ptr<EvaluationScope>(this->_evaluationScope->CreateBranchingScope(this->_evaluationScope->GetCurrentScope() + 1));
auto value = make_shared<ScriptFunctionEvalValue>(block, evaluator, type);
if (key->IsCreation()){
this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), value);
} else{
@ -174,6 +175,7 @@ shared_ptr<StringEvalValue> Evaluator::EvaluateStringExpression(BoundExpression
shared_ptr<EvalValue> Evaluator::EvaluateFunctionExpression(BoundExpression * expression){
switch (expression->GetKind()){
case BoundExpressionKind ::Variable: return this->GetVariable((BoundVariableExpression*)expression);
case BoundExpressionKind ::Index: return this->EvaluateIndexExpression(expression);
default: throw;
}
}
@ -216,8 +218,7 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(BoundExpression*
auto parameterKeys = type->GetParameterKeys();
auto scope = type -> GetScopeIndex();
auto originalScope = this->_evaluationScope;
auto functionScope = this->_evaluationScope->CreateBranchingScope(scope);
this->_evaluationScope = functionScope;
this->_evaluationScope = shared_ptr<EvaluationScope>(function -> GetScope() -> CreateBranchingScope(scope));
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){
auto parameter = parameters[i];
@ -230,7 +231,6 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(BoundExpression*
}
this->EvaluateBlockStatement(function->GetInnerBlock().get(), true);
delete this->_evaluationScope;
this->_evaluationScope = originalScope;
this->_hasReturned = false;
auto r = this -> _returnValue;
@ -245,8 +245,7 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct
auto scope = type -> GetScopeIndex();
auto originalScope = this->_evaluationScope;
auto functionScope = this->_evaluationScope->CreateBranchingScope(scope);
this->_evaluationScope = functionScope;
this->_evaluationScope = shared_ptr<EvaluationScope>(function -> GetScope() -> CreateBranchingScope(scope));
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){
auto parameter = parameters[i];
@ -258,7 +257,6 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct
this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone());
}
this->EvaluateBlockStatement(function->GetInnerBlock().get(), true);
delete this->_evaluationScope;
this->_evaluationScope = originalScope;
this->_hasReturned = false;
auto r = this -> _returnValue;
@ -293,7 +291,7 @@ shared_ptr<EvalValue> Evaluator::EvaluateComplexTableExpression(BoundExpression
for (auto i : *declaredVars){
variables->insert({i.first, nullptr});
}
auto evaluator = new EvaluationScope(variables.get(), type -> GetDeepestScope());
auto evaluator = make_shared<EvaluationScope>(variables.get(), type -> GetDeepestScope());
auto currentEvaluator = this -> _evaluationScope;
this -> _evaluationScope = evaluator;
this -> EvaluateBlockStatement(tableExpression->GetBlock(), false);

View File

@ -20,7 +20,7 @@ class Evaluator {
shared_ptr<EvalValue> _lastValue;
Script* _scriptData;
EvaluationScope* _evaluationScope;
shared_ptr<EvaluationScope> _evaluationScope;
void EvaluateStatement(BoundStatement* statement);
void EvaluateBlockStatement(BoundBlockStatement* statement, bool clearScope);
@ -57,10 +57,6 @@ public:
_evaluationScope = nullptr;
}
~Evaluator(){
delete _evaluationScope;
}
void Evaluate(BoundScriptStatement* statement);
shared_ptr<EvalValue> EvaluateFunction(ScriptFunctionEvalValue* func, vector<EvalValue*> parameters);

View File

@ -86,13 +86,15 @@ TEST_CASE( "Define script function and return", "[integration]" ) {
TEST_CASE( "Functions can call themselves", "[integration]" ) {
Script* script = Script::Create(
"val = 0\n"
"function add() \n"
"if val < 5 then\n"
"val = val + 1\n"
"add()\n"
"end\n"
"end");
R"(
val = 0
function add()
if val < 5 then
val = val + 1
add()
end
end
)");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
script->CallFunction("add", {});

View File

@ -62,6 +62,24 @@ table = {
delete script;
}
TEST_CASE( "Complex table with function", "[integration]" ) {
Script* script = Script::Create(
R"(
table = {
local foo = 'test'
function getFoo()
return foo
end
}
result = table["getFoo"]()
)");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
auto variable = script->GetVariable("result");
REQUIRE(variable != nullptr);
delete script;
}
#endif