Rework of evaluation variable handling, to account for functions having branching variable states
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-06-08 18:33:56 +02:00
parent 4d452b33e0
commit 471632c6e4
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
4 changed files with 57 additions and 13 deletions

View File

@ -4,7 +4,10 @@
EvaluationScope::EvaluationScope(unordered_map<int, shared_ptr<EvalValue>> *scriptVariables, int deepestScope) {
_scriptScope = scriptVariables;
_localScope = vector<unordered_map<int, shared_ptr<EvalValue>>>(deepestScope);
_localScope = vector<shared_ptr<unordered_map<int, shared_ptr<EvalValue>>>>(deepestScope);
for (int i = 0; i < deepestScope; i++){
_localScope[i] = make_shared<unordered_map<int, shared_ptr<EvalValue>>>();
}
_currentScope = -1;
}
@ -12,7 +15,10 @@ void EvaluationScope::CreateVariable(int scope, int id, const shared_ptr<EvalVal
if (scope == 0){
_scriptScope->at(id) = value;
} else{
_localScope[scope - 1][id] = value;
auto insert = _localScope[scope - 1]->insert({id, value});
if (!insert.second){
_localScope[scope - 1]->at(id) = value;
}
}
}
@ -20,7 +26,7 @@ void EvaluationScope::SetVariable(int scope, int id, const shared_ptr<EvalValue>
if (scope == 0){
_scriptScope->at(id) = value;
} else{
_localScope[scope - 1][id] = value;
_localScope[scope - 1]->at(id) = value;
}
}
@ -28,11 +34,15 @@ shared_ptr<EvalValue> EvaluationScope::GetVariable(int scope, int id) {
if (scope == 0){
return _scriptScope->at(id);
}
return _localScope[scope - 1][id];
return _localScope[scope - 1]->at(id);
}
void EvaluationScope::JumpToScope(int index){
_currentScope = index;
EvaluationScope* EvaluationScope::CreateBranchingScope(int index){
auto scope = new EvaluationScope(this -> _scriptScope, this -> _localScope.size());
for (int i = 0; i < index; i++){
scope->_localScope[i] = this->_localScope[i];
}
return scope;
}
void EvaluationScope::OuterScope() {
@ -41,7 +51,7 @@ void EvaluationScope::OuterScope() {
void EvaluationScope::InnerScope() {
auto scope = this->_localScope[_currentScope];
scope.clear();
scope->clear();
_currentScope--;
}

View File

@ -8,7 +8,7 @@
class EvaluationScope {
unordered_map<int, shared_ptr<EvalValue>>* _scriptScope;
vector<unordered_map<int, shared_ptr<EvalValue>>> _localScope;
vector<shared_ptr<unordered_map<int, shared_ptr<EvalValue>>>> _localScope;
int _currentScope;
public:
explicit EvaluationScope(unordered_map<int, shared_ptr<EvalValue>>* scriptVariables, int deepestScope);
@ -20,11 +20,12 @@ public:
void InnerScope();
shared_ptr<EvalValue> GetVariable(int scope, int id);
void JumpToScope(int index);
EvaluationScope* CreateBranchingScope(int index);
int GetCurrentScope(){
return _currentScope;
}
};

View File

@ -102,7 +102,8 @@ shared_ptr<EvalValue> Evaluator::EvaluateExpression(BoundExpression *expression)
}
shared_ptr<EvalValue> Evaluator::GetVariable(BoundVariableExpression* expression){
return this->_evaluationScope->GetVariable(expression->GetScope(), expression->GetId())->Clone();
auto variable = this->_evaluationScope->GetVariable(expression->GetScope(), expression->GetId());
return variable->Clone();
}
shared_ptr<NumericEvalValue> Evaluator::EvaluateIntegerExpression(BoundExpression *expression) {
@ -179,6 +180,7 @@ shared_ptr<EvalValue> Evaluator::EvaluateNilExpression(BoundExpression * express
shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(BoundExpression* expression){
auto functionCall = (BoundFunctionCallExpression*)expression;
auto function = dynamic_pointer_cast<ScriptFunctionEvalValue>(this->EvaluateExpression(functionCall->GetFunctionExpression()));
auto boundParameters = functionCall->GetParameters();
auto parameters = vector<shared_ptr<EvalValue>>(boundParameters.size());
for (int i = 0; i < boundParameters.size(); i++){
@ -189,8 +191,9 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(BoundExpression*
auto parameterTypes = type->GetParameterTypes();
auto parameterKeys = type->GetParameterKeys();
auto scope = type -> GetScopeIndex();
auto originalScope = this->_evaluationScope->GetCurrentScope();
this->_evaluationScope->JumpToScope(scope);
auto originalScope = this->_evaluationScope;
auto functionScope = this->_evaluationScope->CreateBranchingScope(scope);
this->_evaluationScope = functionScope;
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){
auto parameter = parameters[i];
@ -201,8 +204,9 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(BoundExpression*
auto key = parameterKeys.at(i);
this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone());
}
this->_evaluationScope->OuterScope();
this->EvaluateBlockStatement(function->GetInnerBlock().get());
this->_evaluationScope->JumpToScope(originalScope);
this->_evaluationScope = originalScope;
this->_hasReturned = false;
auto r = this -> _returnValue;
this -> _returnValue = nullptr;

View File

@ -104,4 +104,33 @@ TEST_CASE( "Functions can call themselves", "[integration]" ) {
delete script;
}
TEST_CASE( "Functions respect scope", "[integration]" ) {
Script* script = Script::Create(
R"(
function test()
function foo()
local a = 10
end
if true then
if true then
local a = 50
foo()
result = a
end
end
end
test()
)"
);
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
auto variable = script->GetVariable("result");
REQUIRE(variable->GetType()->GetClass() == TypeClass::Number);
REQUIRE(variable->EvaluateInteger() == 50);
delete script;
}
#endif