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

View File

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

View File

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

View File

@ -20,7 +20,7 @@ class Evaluator {
shared_ptr<EvalValue> _lastValue; shared_ptr<EvalValue> _lastValue;
Script* _scriptData; Script* _scriptData;
EvaluationScope* _evaluationScope; shared_ptr<EvaluationScope> _evaluationScope;
void EvaluateStatement(BoundStatement* statement); void EvaluateStatement(BoundStatement* statement);
void EvaluateBlockStatement(BoundBlockStatement* statement, bool clearScope); void EvaluateBlockStatement(BoundBlockStatement* statement, bool clearScope);
@ -57,10 +57,6 @@ public:
_evaluationScope = nullptr; _evaluationScope = nullptr;
} }
~Evaluator(){
delete _evaluationScope;
}
void Evaluate(BoundScriptStatement* statement); void Evaluate(BoundScriptStatement* statement);
shared_ptr<EvalValue> EvaluateFunction(ScriptFunctionEvalValue* func, vector<EvalValue*> parameters); 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]" ) { TEST_CASE( "Functions can call themselves", "[integration]" ) {
Script* script = Script::Create( Script* script = Script::Create(
"val = 0\n" R"(
"function add() \n" val = 0
"if val < 5 then\n" function add()
"val = val + 1\n" if val < 5 then
"add()\n" val = val + 1
"end\n" add()
"end"); end
end
)");
REQUIRE(!script->Diagnostics -> HasErrors()); REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate(); script->Evaluate();
script->CallFunction("add", {}); script->CallFunction("add", {});

View File

@ -62,6 +62,24 @@ table = {
delete script; 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 #endif