Implements variable usage, tweaks and fixes for variable assignment
This commit is contained in:
parent
257eb942c7
commit
6fad5a0a7d
|
@ -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());
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
class BoundVariable{
|
||||
ScriptType _type;
|
||||
public:
|
||||
explicit BoundVariable(ScriptType type) : _type(type){
|
||||
explicit BoundVariable(const ScriptType& type) : _type(type){
|
||||
}
|
||||
~BoundVariable(){
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ enum class DiagnosticCode{
|
|||
NoBinaryOperationFound,
|
||||
NoUnaryOperationFound,
|
||||
CantAssignVariable,
|
||||
VariableNotFound,
|
||||
};
|
||||
|
||||
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -32,6 +32,9 @@ public:
|
|||
return _value;
|
||||
}
|
||||
|
||||
EvalValue* Clone() final{
|
||||
return new StringEvalValue(_value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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--;
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue