From f6cf4d96ddf40c3ca441cdfd33e734ea972d22b8 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Wed, 29 May 2019 14:55:03 +0200 Subject: [PATCH] Implements variable assignment evaluation --- src/Binder/Binder.cpp | 2 +- src/Binder/BoundStatements/BoundStatement.hpp | 16 ++++++- src/Binder/BoundVariables/BoundScope.hpp | 4 ++ .../EvaluationScope/EvaluationScope.cpp | 2 + .../EvaluationScope/EvaluationScope.hpp | 44 +++++++++++++++++++ src/Evaluator/Evaluator.cpp | 16 +++++++ src/Evaluator/Evaluator.hpp | 13 +++++- src/Evaluator/UnaryEvaluation.cpp | 2 +- src/Script.cpp | 5 ++- src/Script.hpp | 4 +- tests/integration/Variables.cpp | 4 ++ 11 files changed, 104 insertions(+), 8 deletions(-) create mode 100644 src/Evaluator/EvaluationScope/EvaluationScope.cpp create mode 100644 src/Evaluator/EvaluationScope/EvaluationScope.hpp diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 303cbf8..7da3ea5 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -11,7 +11,7 @@ BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s, Bou for (int i = 0; i < statements.size(); i++){ boundStatements[i] = binder.BindStatement(statements[i]); } - return new BoundScriptStatement(boundStatements); + return new BoundScriptStatement(boundStatements, scriptScope->GetDeepestScope()); } Binder::~Binder() { diff --git a/src/Binder/BoundStatements/BoundStatement.hpp b/src/Binder/BoundStatements/BoundStatement.hpp index d161604..ec5646a 100644 --- a/src/Binder/BoundStatements/BoundStatement.hpp +++ b/src/Binder/BoundStatements/BoundStatement.hpp @@ -54,13 +54,19 @@ public: }; class BoundScriptStatement : public BoundBlockStatement{ + int _deepestScope; public: - explicit BoundScriptStatement(vector statements) : BoundBlockStatement(std::move(statements)){ + explicit BoundScriptStatement(vector statements, int deepestScope) : BoundBlockStatement(std::move(statements)){ + _deepestScope = deepestScope; } BoundStatementKind GetKind() final{ return BoundStatementKind ::Script; } + + int GetDeepestScope(){ + return _deepestScope; + } }; class BoundExpressionStatement : public BoundStatement{ @@ -98,6 +104,14 @@ public: BoundStatementKind GetKind() final{ return BoundStatementKind ::Assignment; } + + BoundVariableKey* GetKey(){ + return _key; + } + + BoundExpression* GetExpression(){ + return _expression; + } }; #endif //PORYGONLANG_BOUNDSTATEMENT_HPP diff --git a/src/Binder/BoundVariables/BoundScope.hpp b/src/Binder/BoundVariables/BoundScope.hpp index 02faf3a..3e0ca0d 100644 --- a/src/Binder/BoundVariables/BoundScope.hpp +++ b/src/Binder/BoundVariables/BoundScope.hpp @@ -28,6 +28,10 @@ public: BoundVariable* GetVariable(int scope, int identifier); VariableAssignment CreateExplicitLocal(int identifier, const ScriptType& type); VariableAssignment AssignVariable(int identifier, const ScriptType& type); + + int GetDeepestScope(){ + return _deepestScope; + } }; diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.cpp b/src/Evaluator/EvaluationScope/EvaluationScope.cpp new file mode 100644 index 0000000..4961418 --- /dev/null +++ b/src/Evaluator/EvaluationScope/EvaluationScope.cpp @@ -0,0 +1,2 @@ + +#include "EvaluationScope.hpp" diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.hpp b/src/Evaluator/EvaluationScope/EvaluationScope.hpp new file mode 100644 index 0000000..273ee6f --- /dev/null +++ b/src/Evaluator/EvaluationScope/EvaluationScope.hpp @@ -0,0 +1,44 @@ + +#ifndef PORYGONLANG_EVALUATIONSCOPE_HPP +#define PORYGONLANG_EVALUATIONSCOPE_HPP + +#include +#include +#include "../EvalValues/EvalValue.hpp" + +class EvaluationScope { + unordered_map* _scriptScope; + vector> _localScope; +public: + explicit EvaluationScope(unordered_map* scriptVariables, int deepestScope){ + _scriptScope = scriptVariables; + _localScope = vector>(deepestScope); + } + + ~EvaluationScope(){ + _localScope.clear(); + } + + void CreateVariable(int scope, int id, EvalValue* value){ + if (scope == 0){ + _scriptScope->insert_or_assign(id, value); + } else{ + _localScope[scope - 1].insert({id, value}); + } + } + + void SetVariable(int scope, int id, EvalValue* value){ + if (scope == 0){ + _scriptScope->insert_or_assign(id, value); + } else{ + _localScope[scope - 1][id] = value; + } + } + + EvalValue* GetVariable(int scope, int id){ + return _localScope[scope - 1][id]; + } +}; + + +#endif //PORYGONLANG_EVALUATIONSCOPE_HPP diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index 9d3a905..0cdf00e 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -2,8 +2,10 @@ #include "Evaluator.hpp" #include "EvaluationException.hpp" #include "../Script.hpp" +#include "EvaluationScope/EvaluationScope.hpp" void Evaluator::Evaluate(BoundScriptStatement *statement) { + this->_evaluationScope = new EvaluationScope(this->_scriptData->_scriptVariables, statement->GetDeepestScope()); EvaluateBlockStatement(statement); } @@ -12,6 +14,10 @@ void Evaluator::EvaluateStatement(BoundStatement *statement) { case BoundStatementKind ::Script: throw; // Should never happen case BoundStatementKind ::Block: return this -> EvaluateBlockStatement((BoundBlockStatement*)statement); case BoundStatementKind ::Expression: return this -> EvaluateExpressionStatement((BoundExpressionStatement*)statement); + case BoundStatementKind ::Assignment: return this -> EvaluateAssignmentStatement((BoundAssignmentStatement*)statement); + + case BoundStatementKind::Bad: + throw; } } @@ -28,6 +34,16 @@ void Evaluator::EvaluateExpressionStatement(BoundExpressionStatement *statement) this->_scriptData->_lastValue = this -> EvaluateExpression(statement->GetExpression()); } +void Evaluator::EvaluateAssignmentStatement(BoundAssignmentStatement *statement) { + auto value = this -> EvaluateExpression(statement->GetExpression()); + auto key = statement->GetKey(); + if (key->IsCreation()){ + this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), value); + } else{ + this->_evaluationScope->SetVariable(key->GetScopeId(), key->GetIdentifier(), value); + } +} + EvalValue *Evaluator::EvaluateExpression(BoundExpression *expression) { auto type = expression -> GetType(); switch (type->GetClass()){ diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index 2df4e5e..c93e1b0 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -9,7 +9,7 @@ #include "EvalValues/EvalValue.hpp" #include "EvalValues/NumericEvalValue.hpp" #include "EvalValues/StringEvalValue.hpp" - +#include "EvaluationScope/EvaluationScope.hpp" using namespace boost; @@ -17,10 +17,12 @@ class Evaluator { EvalValue* _result; Script* _scriptData; + EvaluationScope* _evaluationScope; void EvaluateStatement(BoundStatement* statement); void EvaluateBlockStatement(BoundBlockStatement* statement); void EvaluateExpressionStatement(BoundExpressionStatement* statement); + void EvaluateAssignmentStatement(BoundAssignmentStatement* statement); EvalValue* EvaluateExpression(BoundExpression* expression); NumericEvalValue* EvaluateIntegerExpression(BoundExpression* expression); @@ -34,10 +36,17 @@ class Evaluator { NumericEvalValue* EvaluateIntegerUnary(BoundUnaryExpression* expression); BooleanEvalValue *EvaluateBooleanUnary(BoundUnaryExpression *expression); public: - Evaluator(Script* script){ + explicit Evaluator(Script* script){ _scriptData = script; _result = nullptr; + _evaluationScope = nullptr; } + + ~Evaluator(){ + delete _result; + delete _evaluationScope; + } + void Evaluate(BoundScriptStatement* statement); }; diff --git a/src/Evaluator/UnaryEvaluation.cpp b/src/Evaluator/UnaryEvaluation.cpp index 86011c7..10312bf 100644 --- a/src/Evaluator/UnaryEvaluation.cpp +++ b/src/Evaluator/UnaryEvaluation.cpp @@ -36,4 +36,4 @@ BooleanEvalValue *Evaluator::EvaluateBooleanUnary(BoundUnaryExpression *expressi case BoundUnaryOperation::Negation: throw; } -} \ No newline at end of file +} diff --git a/src/Script.cpp b/src/Script.cpp index 68dcdea..dd6414b 100644 --- a/src/Script.cpp +++ b/src/Script.cpp @@ -16,6 +16,7 @@ Script::Script() { _evaluator = new Evaluator(this); _lastValue = nullptr; BoundScript = nullptr; + _scriptVariables = new unordered_map(0); } void Script::Evaluate() { @@ -27,6 +28,8 @@ Script::~Script() { delete this -> BoundScript; delete this -> _lastValue; delete this -> _evaluator; + this->_scriptVariables->clear(); + delete this->_scriptVariables; } void Script::Parse(string script) { @@ -43,7 +46,7 @@ void Script::Parse(string script) { auto bindScope = new BoundScope(&scriptScope); this->BoundScript = Binder::Bind(this, parseResult, bindScope); for (const auto& v : scriptScope){ - this->_scopeVariables.insert({v.first, nullptr}); + this->_scriptVariables -> insert({v.first, nullptr}); delete v.second; } scriptScope.clear(); diff --git a/src/Script.hpp b/src/Script.hpp index 2ff91b0..626982c 100644 --- a/src/Script.hpp +++ b/src/Script.hpp @@ -21,7 +21,7 @@ class Script { EvalValue* _lastValue; Evaluator* _evaluator; - unordered_map _scopeVariables; + unordered_map* _scriptVariables; explicit Script(); @@ -40,7 +40,7 @@ public: }; EvalValue* GetVariable(const string& key){ - return _scopeVariables.at(HashedString(key).GetHash()); + return _scriptVariables -> at(HashedString(key).GetHash()); } }; diff --git a/tests/integration/Variables.cpp b/tests/integration/Variables.cpp index 6b0bace..d391166 100644 --- a/tests/integration/Variables.cpp +++ b/tests/integration/Variables.cpp @@ -7,6 +7,10 @@ TEST_CASE( "Create script variable", "[integration]" ) { REQUIRE(!script->Diagnostics -> HasErrors()); auto variable = script->GetVariable("foo"); REQUIRE(variable == nullptr); + script->Evaluate(); + variable = script->GetVariable("foo"); + REQUIRE(variable != nullptr); + REQUIRE(variable->EvaluateBool()); delete script; }