diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.cpp b/src/Evaluator/EvaluationScope/EvaluationScope.cpp index c1eeffa..a59cb72 100644 --- a/src/Evaluator/EvaluationScope/EvaluationScope.cpp +++ b/src/Evaluator/EvaluationScope/EvaluationScope.cpp @@ -4,7 +4,10 @@ EvaluationScope::EvaluationScope(unordered_map> *scriptVariables, int deepestScope) { _scriptScope = scriptVariables; - _localScope = vector>>(deepestScope); + _localScope = vector>>>(deepestScope); + for (int i = 0; i < deepestScope; i++){ + _localScope[i] = make_shared>>(); + } _currentScope = -1; } @@ -12,7 +15,10 @@ void EvaluationScope::CreateVariable(int scope, int id, const shared_ptrat(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 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 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--; } diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.hpp b/src/Evaluator/EvaluationScope/EvaluationScope.hpp index 15bf66f..584e0c8 100644 --- a/src/Evaluator/EvaluationScope/EvaluationScope.hpp +++ b/src/Evaluator/EvaluationScope/EvaluationScope.hpp @@ -8,7 +8,7 @@ class EvaluationScope { unordered_map>* _scriptScope; - vector>> _localScope; + vector>>> _localScope; int _currentScope; public: explicit EvaluationScope(unordered_map>* scriptVariables, int deepestScope); @@ -20,11 +20,12 @@ public: void InnerScope(); shared_ptr GetVariable(int scope, int id); - void JumpToScope(int index); + EvaluationScope* CreateBranchingScope(int index); int GetCurrentScope(){ return _currentScope; } + }; diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index e8fce5d..ba8016a 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -102,7 +102,8 @@ shared_ptr Evaluator::EvaluateExpression(BoundExpression *expression) } shared_ptr 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 Evaluator::EvaluateIntegerExpression(BoundExpression *expression) { @@ -179,6 +180,7 @@ shared_ptr Evaluator::EvaluateNilExpression(BoundExpression * express shared_ptr Evaluator::EvaluateFunctionCallExpression(BoundExpression* expression){ auto functionCall = (BoundFunctionCallExpression*)expression; auto function = dynamic_pointer_cast(this->EvaluateExpression(functionCall->GetFunctionExpression())); + auto boundParameters = functionCall->GetParameters(); auto parameters = vector>(boundParameters.size()); for (int i = 0; i < boundParameters.size(); i++){ @@ -189,8 +191,9 @@ shared_ptr 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 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; diff --git a/tests/integration/Functions.cpp b/tests/integration/Functions.cpp index d6296a3..ee9fd0f 100644 --- a/tests/integration/Functions.cpp +++ b/tests/integration/Functions.cpp @@ -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