Rework function evaluation scope to handle tables
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
c022c91777
commit
3477ddd18c
|
@ -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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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", {});
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue