From 3477ddd18cf64dd1344df36e1e6701f70848c98f Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Wed, 12 Jun 2019 17:56:47 +0200 Subject: [PATCH] Rework function evaluation scope to handle tables --- .../EvalValues/ScriptFunctionEvalValue.hpp | 20 ++++++++++++++----- .../EvaluationScope/EvaluationScope.cpp | 9 ++++++--- .../EvaluationScope/EvaluationScope.hpp | 2 +- src/Evaluator/Evaluator.cpp | 16 +++++++-------- src/Evaluator/Evaluator.hpp | 6 +----- tests/integration/Functions.cpp | 16 ++++++++------- tests/integration/Tables.cpp | 18 +++++++++++++++++ 7 files changed, 57 insertions(+), 30 deletions(-) diff --git a/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp b/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp index c53e910..adc38d6 100644 --- a/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp +++ b/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp @@ -1,5 +1,7 @@ #include +#include + #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 _innerBlock; std::shared_ptr _type; + std::shared_ptr _scope; std::size_t _hash; - explicit ScriptFunctionEvalValue(std::shared_ptr innerBlock, std::shared_ptr type, size_t hash) + explicit ScriptFunctionEvalValue(std::shared_ptr innerBlock, std::shared_ptr scope, + std::shared_ptr type, size_t hash) : _type(std::move(type)) { _innerBlock = std::move(innerBlock); + _scope = std::move(scope); _hash = hash; } public: - explicit ScriptFunctionEvalValue(std::shared_ptr innerBlock, std::shared_ptr type) + explicit ScriptFunctionEvalValue(std::shared_ptr innerBlock, std::shared_ptr scope, + std::shared_ptr type) : _type(std::move(type)) { _innerBlock = std::move(innerBlock); + _scope = std::move(scope); _hash = rand(); } @@ -35,7 +43,7 @@ public: } shared_ptr Clone() final{ - return shared_ptr(new ScriptFunctionEvalValue(_innerBlock, _type, _hash)); + return shared_ptr(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 GetScope(){ + return _scope; + } }; diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.cpp b/src/Evaluator/EvaluationScope/EvaluationScope.cpp index e96c614..483345f 100644 --- a/src/Evaluator/EvaluationScope/EvaluationScope.cpp +++ b/src/Evaluator/EvaluationScope/EvaluationScope.cpp @@ -37,12 +37,15 @@ shared_ptr 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>>(); + } + scope->_currentScope = this -> _currentScope; return scope; } diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.hpp b/src/Evaluator/EvaluationScope/EvaluationScope.hpp index 22fbdcc..d05d891 100644 --- a/src/Evaluator/EvaluationScope/EvaluationScope.hpp +++ b/src/Evaluator/EvaluationScope/EvaluationScope.hpp @@ -20,7 +20,7 @@ public: void InnerScope(bool clearScope = true); shared_ptr GetVariable(int scope, int id); - EvaluationScope* CreateBranchingScope(int index); + EvaluationScope* CreateBranchingScope(int scopeIndex); int GetCurrentScope(){ return _currentScope; diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index c08d13f..b0050d2 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -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(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(block, type); + auto evaluator = shared_ptr(this->_evaluationScope->CreateBranchingScope(this->_evaluationScope->GetCurrentScope() + 1)); + auto value = make_shared(block, evaluator, type); if (key->IsCreation()){ this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), value); } else{ @@ -174,6 +175,7 @@ shared_ptr Evaluator::EvaluateStringExpression(BoundExpression shared_ptr 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 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(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 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 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(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 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 Evaluator::EvaluateComplexTableExpression(BoundExpression for (auto i : *declaredVars){ variables->insert({i.first, nullptr}); } - auto evaluator = new EvaluationScope(variables.get(), type -> GetDeepestScope()); + auto evaluator = make_shared(variables.get(), type -> GetDeepestScope()); auto currentEvaluator = this -> _evaluationScope; this -> _evaluationScope = evaluator; this -> EvaluateBlockStatement(tableExpression->GetBlock(), false); diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index e4ac7f5..171cc72 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -20,7 +20,7 @@ class Evaluator { shared_ptr _lastValue; Script* _scriptData; - EvaluationScope* _evaluationScope; + shared_ptr _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 EvaluateFunction(ScriptFunctionEvalValue* func, vector parameters); diff --git a/tests/integration/Functions.cpp b/tests/integration/Functions.cpp index ee9fd0f..e77e741 100644 --- a/tests/integration/Functions.cpp +++ b/tests/integration/Functions.cpp @@ -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", {}); diff --git a/tests/integration/Tables.cpp b/tests/integration/Tables.cpp index 0d8f181..70cd299 100644 --- a/tests/integration/Tables.cpp +++ b/tests/integration/Tables.cpp @@ -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