Rework of evaluation variable handling, to account for functions having branching variable states
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
4d452b33e0
commit
471632c6e4
|
@ -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--;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue