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) { EvaluationScope::EvaluationScope(unordered_map<int, shared_ptr<EvalValue>> *scriptVariables, int deepestScope) {
_scriptScope = scriptVariables; _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; _currentScope = -1;
} }
@ -12,7 +15,10 @@ void EvaluationScope::CreateVariable(int scope, int id, const shared_ptr<EvalVal
if (scope == 0){ if (scope == 0){
_scriptScope->at(id) = value; _scriptScope->at(id) = value;
} else{ } 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){ if (scope == 0){
_scriptScope->at(id) = value; _scriptScope->at(id) = value;
} else{ } 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){ if (scope == 0){
return _scriptScope->at(id); return _scriptScope->at(id);
} }
return _localScope[scope - 1][id]; return _localScope[scope - 1]->at(id);
} }
void EvaluationScope::JumpToScope(int index){ EvaluationScope* EvaluationScope::CreateBranchingScope(int index){
_currentScope = 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() { void EvaluationScope::OuterScope() {
@ -41,7 +51,7 @@ void EvaluationScope::OuterScope() {
void EvaluationScope::InnerScope() { void EvaluationScope::InnerScope() {
auto scope = this->_localScope[_currentScope]; auto scope = this->_localScope[_currentScope];
scope.clear(); scope->clear();
_currentScope--; _currentScope--;
} }

View File

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

View File

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

View File

@ -104,4 +104,33 @@ TEST_CASE( "Functions can call themselves", "[integration]" ) {
delete script; 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 #endif