Implements variable usage, tweaks and fixes for variable assignment

This commit is contained in:
Deukhoofd 2019-05-30 15:23:48 +02:00
parent 257eb942c7
commit 6fad5a0a7d
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
17 changed files with 145 additions and 4 deletions

View File

@ -72,6 +72,8 @@ BoundExpression* Binder::BindExpression(ParsedExpression* expression){
return new BoundLiteralStringExpression(((LiteralStringExpression*)expression)->GetValue(), expression->GetStartPosition(), expression->GetLength());
case ParsedExpressionKind ::LiteralBool:
return new BoundLiteralBoolExpression(((LiteralBoolExpression*)expression)->GetValue(), expression->GetStartPosition(), expression->GetLength());
case ParsedExpressionKind ::Variable:
return this -> BindVariableExpression((VariableExpression*)expression);
case ParsedExpressionKind ::Binary:
return this -> BindBinaryOperator((BinaryExpression*)expression);
@ -86,6 +88,18 @@ BoundExpression* Binder::BindExpression(ParsedExpression* expression){
}
}
BoundExpression* Binder::BindVariableExpression(VariableExpression* expression){
auto key = expression->GetValue();
auto scope = this->_scope->Exists(key.GetHash());
if (scope == -1){
this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::VariableNotFound, expression->GetStartPosition(), expression->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
}
auto var = this->_scope->GetVariable(scope, key.GetHash());
auto type = var->GetType();
return new BoundVariableExpression(scope, key.GetHash(), type, expression->GetStartPosition(), expression->GetLength());
}
BoundExpression* Binder::BindBinaryOperator(BinaryExpression* expression){
auto boundLeft = this -> BindExpression(expression->GetLeft());
auto boundRight = this -> BindExpression(expression->GetRight());

View File

@ -19,6 +19,7 @@ class Binder {
BoundStatement *BindAssignmentStatement(ParsedStatement *statement);
BoundExpression *BindExpression(ParsedExpression *expression);
BoundExpression *BindVariableExpression(VariableExpression *expression);
BoundExpression *BindBinaryOperator(BinaryExpression *expression);
BoundExpression *BindUnaryOperator(UnaryExpression *expression);
public:

View File

@ -7,6 +7,7 @@
#include <string>
#include "../../ScriptType.hpp"
#include "../BoundOperators.hpp"
#include "../BoundVariables/BoundVariableKey.hpp"
using namespace std;
@ -17,6 +18,7 @@ enum class BoundExpressionKind{
LiteralFloat,
LiteralString,
LiteralBool,
Variable,
Unary,
Binary,
@ -129,6 +131,36 @@ public:
}
};
class BoundVariableExpression : public BoundExpression{
int _scope;
int _id;
ScriptType _type;
public:
BoundVariableExpression(int scope, int id, const ScriptType& type, unsigned int start, unsigned int length)
: BoundExpression(start, length, nullptr), _type(type){
_scope = scope;
_id = id;
}
~BoundVariableExpression() override = default;
ScriptType* GetType() final{
return &_type;
};
BoundExpressionKind GetKind() final{
return BoundExpressionKind ::Variable;
}
int GetScope(){
return _scope;
}
int GetId(){
return _id;
}
};
class BoundBinaryExpression : public BoundExpression {
BoundExpression* _left;
BoundExpression* _right;

View File

@ -57,7 +57,7 @@ BoundVariable *BoundScope::GetVariable(int scope, int identifier) {
}
return nullptr;
} else{
auto s = this->_localScope.at(scope);
auto s = this->_localScope.at(scope - 1);
auto find = s -> find(identifier);
if (find != s -> end()){
return find -> second;
@ -72,7 +72,7 @@ VariableAssignment BoundScope::CreateExplicitLocal(int identifier, const ScriptT
return VariableAssignment(VariableAssignmentResult::ExplicitLocalVariableExists, nullptr);
}
scope -> insert({identifier, new BoundVariable(type)});
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, this->_currentScope - 1, true));
return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, this->_currentScope, true));
}
VariableAssignment BoundScope::AssignVariable(int identifier, const ScriptType& type) {

View File

@ -7,7 +7,7 @@
class BoundVariable{
ScriptType _type;
public:
explicit BoundVariable(ScriptType type) : _type(type){
explicit BoundVariable(const ScriptType& type) : _type(type){
}
~BoundVariable(){
}

View File

@ -14,6 +14,7 @@ enum class DiagnosticCode{
NoBinaryOperationFound,
NoUnaryOperationFound,
CantAssignVariable,
VariableNotFound,
};
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP

View File

@ -9,6 +9,7 @@
class EvalValue{
public:
EvalValue() = default;
virtual ~EvalValue() = default;
virtual ScriptType* GetType() = 0;
@ -18,6 +19,8 @@ public:
return ! (this->operator==(b));
}
virtual EvalValue* Clone() = 0;
virtual long EvaluateInteger(){
throw EvaluationException("Can't evaluate this EvalValue as integer.");
}
@ -41,6 +44,10 @@ public:
_type = new ScriptType(TypeClass::Bool);
}
EvalValue* Clone() final{
return new BooleanEvalValue(_value);
}
~BooleanEvalValue() final{
delete _type;
}

View File

@ -50,6 +50,10 @@ public:
strs << _value;
return strs.str();
}
EvalValue* Clone() final{
return new IntegerEvalValue(_value);
}
};
class FloatEvalValue : public NumericEvalValue{
@ -74,6 +78,10 @@ public:
strs << _value;
return strs.str();
}
EvalValue* Clone() final{
return new FloatEvalValue(_value);
}
};
#endif //PORYGONLANG_NUMERICEVALVALUE_HPP

View File

@ -32,6 +32,9 @@ public:
return _value;
}
EvalValue* Clone() final{
return new StringEvalValue(_value);
}
};

View File

@ -4,6 +4,7 @@
EvaluationScope::EvaluationScope(unordered_map<int, EvalValue *> *scriptVariables, int deepestScope) {
_scriptScope = scriptVariables;
_localScope = vector<unordered_map<int, EvalValue*>>(deepestScope);
_currentScope = -1;
}
EvaluationScope::~EvaluationScope() {
@ -27,5 +28,21 @@ void EvaluationScope::SetVariable(int scope, int id, EvalValue *value) {
}
EvalValue *EvaluationScope::GetVariable(int scope, int id) {
if (scope == 0){
return _scriptScope->at(id);
}
return _localScope[scope - 1][id];
}
void EvaluationScope::OuterScope() {
_currentScope++;
}
void EvaluationScope::InnerScope() {
auto scope = this->_localScope[_currentScope];
for (auto v: scope){
delete v.second;
}
_currentScope--;
}

View File

@ -9,12 +9,15 @@
class EvaluationScope {
unordered_map<int, EvalValue*>* _scriptScope;
vector<unordered_map<int, EvalValue*>> _localScope;
int _currentScope;
public:
explicit EvaluationScope(unordered_map<int, EvalValue*>* scriptVariables, int deepestScope);
~EvaluationScope();
void CreateVariable(int scope, int id, EvalValue* value);
void SetVariable(int scope, int id, EvalValue* value);
void OuterScope();
void InnerScope();
EvalValue* GetVariable(int scope, int id);
};

View File

@ -22,9 +22,11 @@ void Evaluator::EvaluateStatement(BoundStatement *statement) {
}
void Evaluator::EvaluateBlockStatement(BoundBlockStatement* statement) {
this->_evaluationScope->OuterScope();
for (auto s: statement->GetStatements()){
this -> EvaluateStatement(s);
}
this->_evaluationScope->InnerScope();
}
void Evaluator::EvaluateExpressionStatement(BoundExpressionStatement *statement) {
@ -54,12 +56,17 @@ EvalValue *Evaluator::EvaluateExpression(BoundExpression *expression) {
}
}
EvalValue* Evaluator::GetVariable(BoundVariableExpression* expression){
return this->_evaluationScope->GetVariable(expression->GetScope(), expression->GetId())->Clone();
}
NumericEvalValue* Evaluator::EvaluateIntegerExpression(BoundExpression *expression) {
switch (expression->GetKind()){
case BoundExpressionKind ::LiteralInteger: return new IntegerEvalValue(((BoundLiteralIntegerExpression*)expression)->GetValue());
case BoundExpressionKind ::LiteralFloat: return new FloatEvalValue(((BoundLiteralFloatExpression*)expression)->GetValue());
case BoundExpressionKind::Unary: return this -> EvaluateIntegerUnary((BoundUnaryExpression*)expression);
case BoundExpressionKind ::Binary: return this -> EvaluateIntegerBinary((BoundBinaryExpression*)expression);
case BoundExpressionKind::Variable: return (NumericEvalValue*)this->GetVariable((BoundVariableExpression*)expression);
case BoundExpressionKind ::LiteralString:
case BoundExpressionKind ::LiteralBool:
@ -73,6 +80,7 @@ BooleanEvalValue* Evaluator::EvaluateBoolExpression(BoundExpression *expression)
case BoundExpressionKind::LiteralBool: return new BooleanEvalValue(((BoundLiteralBoolExpression*)expression)->GetValue());
case BoundExpressionKind::Unary: return this -> EvaluateBooleanUnary((BoundUnaryExpression*)expression);
case BoundExpressionKind::Binary: return this -> EvaluateBooleanBinary((BoundBinaryExpression*)expression);
case BoundExpressionKind::Variable: return (BooleanEvalValue*)this->GetVariable((BoundVariableExpression*)expression);
case BoundExpressionKind::Bad:
case BoundExpressionKind::LiteralInteger:
@ -89,6 +97,8 @@ StringEvalValue* Evaluator::EvaluateStringExpression(BoundExpression *expression
return new StringEvalValue(((BoundLiteralStringExpression*)expression)->GetValue());
case BoundExpressionKind::Binary:
return this -> EvaluateStringBinary((BoundBinaryExpression*)expression);
case BoundExpressionKind::Variable: return (StringEvalValue*)this->GetVariable((BoundVariableExpression*)expression);
case BoundExpressionKind::Bad:
case BoundExpressionKind::LiteralInteger:

View File

@ -35,6 +35,8 @@ class Evaluator {
NumericEvalValue* EvaluateIntegerUnary(BoundUnaryExpression* expression);
BooleanEvalValue *EvaluateBooleanUnary(BoundUnaryExpression *expression);
EvalValue *GetVariable(BoundVariableExpression *expression);
public:
explicit Evaluator(Script* script){
_scriptData = script;

View File

@ -5,6 +5,7 @@
#include "../Token.hpp"
#include "../UnaryOperatorKind.hpp"
#include "../BinaryOperatorKind.hpp"
#include "../../Utilities/HashedString.hpp"
enum class ParsedExpressionKind{
Bad,
@ -13,6 +14,7 @@ enum class ParsedExpressionKind{
LiteralFloat,
LiteralString,
LiteralBool,
Variable,
Unary,
Binary,
@ -113,6 +115,23 @@ public:
}
};
class VariableExpression : public ParsedExpression{
HashedString _value;
public:
ParsedExpressionKind GetKind() final{
return ParsedExpressionKind::Variable;
}
explicit VariableExpression(IdentifierToken* token) : ParsedExpression(token -> GetStartPosition(), token -> GetLength())
, _value(HashedString(token -> Value))
{
}
HashedString GetValue(){
return _value;
}
};
class ParenthesizedExpression : public ParsedExpression{
ParsedExpression* _expression;
public:

View File

@ -151,6 +151,7 @@ ParsedExpression *Parser::ParsePrimaryExpression(IToken *current) {
case TokenKind ::String: return new LiteralStringExpression((StringToken*)current);
case TokenKind ::TrueKeyword: return new LiteralBoolExpression(current);
case TokenKind ::FalseKeyword: return new LiteralBoolExpression(current);
case TokenKind ::Identifier: return new VariableExpression((IdentifierToken*)current);
case TokenKind ::OpenParenthesis: return this -> ParseParenthesizedExpression(current);
// If we find a bad token here, we should have already logged it in the lexer, so don't log another error.
case TokenKind ::BadToken: return new BadExpression(current->GetStartPosition(), current->GetLength());

View File

@ -28,7 +28,7 @@ Script::~Script() {
delete this -> BoundScript;
delete this -> _lastValue;
delete this -> _evaluator;
for (auto v : *this -> _scriptVariables){
for (auto v : *this->_scriptVariables){
delete v.second;
}
this->_scriptVariables->clear();

View File

@ -22,4 +22,27 @@ TEST_CASE( "Create local variable", "[integration]" ) {
delete script;
}
TEST_CASE( "Create script variable and use", "[integration]" ) {
Script* script = Script::Create("foo = false\n"
"bar = not foo");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
auto variable = script->GetVariable("bar");
REQUIRE(variable != nullptr);
CHECK(variable->EvaluateBool());
delete script;
}
TEST_CASE( "Create local variable and use", "[integration]" ) {
Script* script = Script::Create("local foo = false\n"
"bar = not foo");
REQUIRE(!script->Diagnostics -> HasErrors());
script->Evaluate();
auto variable = script->GetVariable("bar");
REQUIRE(variable != nullptr);
CHECK(variable->EvaluateBool());
delete script;
}
#endif