From a9def6c5399c74361f5991a1d3abfffe3cff2ce4 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 14 Jun 2019 17:12:27 +0200 Subject: [PATCH] Implements setting table values --- src/Binder/Binder.cpp | 13 +++++++++ src/Binder/Binder.hpp | 1 + src/Binder/BoundStatements/BoundStatement.hpp | 28 +++++++++++++++++++ src/Evaluator/EvalValues/EvalValue.hpp | 14 ++++++---- src/Evaluator/EvalValues/NumericEvalValue.hpp | 4 +-- src/Evaluator/EvalValues/StringEvalValue.hpp | 2 +- src/Evaluator/EvalValues/TableEvalValue.hpp | 5 ++++ src/Evaluator/Evaluator.cpp | 12 ++++++++ src/Evaluator/Evaluator.hpp | 1 + .../ParsedStatements/ParsedStatement.hpp | 28 +++++++++++++++++++ src/Parser/Parser.cpp | 22 +++++++++++---- src/Parser/Parser.hpp | 3 +- src/UserData/UserDataValue.hpp | 6 ++++ tests/integration/UserData.cpp | 17 +++++++++++ 14 files changed, 141 insertions(+), 15 deletions(-) diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 2d4968b..2c8c8b2 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -29,6 +29,7 @@ BoundStatement* Binder::BindStatement(const ParsedStatement* statement){ case ParsedStatementKind ::Block: return this -> BindBlockStatement(statement); case ParsedStatementKind ::Expression: return this -> BindExpressionStatement(statement); case ParsedStatementKind::Assignment: return this -> BindAssignmentStatement(statement); + case ParsedStatementKind::IndexAssignment: return this -> BindIndexAssignmentStatement(statement); case ParsedStatementKind ::FunctionDeclaration: return this->BindFunctionDeclarationStatement(statement); case ParsedStatementKind::Return: return this -> BindReturnStatement(statement); case ParsedStatementKind::Conditional: return this -> BindConditionalStatement(statement); @@ -70,6 +71,17 @@ BoundStatement* Binder::BindAssignmentStatement(const ParsedStatement *statement } } +BoundStatement *Binder::BindIndexAssignmentStatement(const ParsedStatement *statement) { + auto s = (ParsedIndexAssignmentStatement*) statement; + auto boundIndexExpression = this -> BindIndexExpression((IndexExpression*)s->GetIndexExpression()); + auto valueExpression = this -> BindExpression(s->GetValueExpression()); + if (boundIndexExpression->GetType()->operator!=(valueExpression->GetType().get())){ + this -> _scriptData -> Diagnostics -> LogError(DiagnosticCode::InvalidTableValueType, statement->GetStartPosition(), statement->GetLength()); + return new BoundBadStatement(); + } + return new BoundIndexAssignmentStatement(boundIndexExpression, valueExpression); +} + std::shared_ptr ParseTypeIdentifier(HashedString s){ switch (s.GetHash()){ case HashedString::ConstHash("number"): return std::make_shared(false, false); @@ -442,3 +454,4 @@ BoundExpression *Binder::BindTableExpression(const ParsedTableExpression *expres return new BoundTableExpression((BoundBlockStatement*)block, tableType, expression->GetStartPosition(), expression->GetLength()); } + diff --git a/src/Binder/Binder.hpp b/src/Binder/Binder.hpp index aa10a5e..e72c7c6 100644 --- a/src/Binder/Binder.hpp +++ b/src/Binder/Binder.hpp @@ -20,6 +20,7 @@ class Binder { BoundStatement *BindBlockStatement(const ParsedStatement *statement); BoundStatement *BindExpressionStatement(const ParsedStatement *statement); BoundStatement *BindAssignmentStatement(const ParsedStatement *statement); + BoundStatement *BindIndexAssignmentStatement(const ParsedStatement *statement); BoundStatement *BindFunctionDeclarationStatement(const ParsedStatement * statement); BoundStatement *BindReturnStatement(const ParsedStatement *statement); BoundStatement *BindConditionalStatement(const ParsedStatement *statement); diff --git a/src/Binder/BoundStatements/BoundStatement.hpp b/src/Binder/BoundStatements/BoundStatement.hpp index 666fe7b..d470eca 100644 --- a/src/Binder/BoundStatements/BoundStatement.hpp +++ b/src/Binder/BoundStatements/BoundStatement.hpp @@ -18,6 +18,7 @@ enum class BoundStatementKind{ Block, Expression, Assignment, + IndexAssignment, FunctionDeclaration, Return, Conditional, @@ -124,6 +125,33 @@ public: } }; +class BoundIndexAssignmentStatement : public BoundStatement{ + const BoundExpression* _indexExpression; + const BoundExpression* _valueExpression; +public: + BoundIndexAssignmentStatement(BoundExpression* index, BoundExpression* value) + : _indexExpression(index), _valueExpression(value) + { + } + + ~BoundIndexAssignmentStatement() final{ + delete _indexExpression; + delete _valueExpression; + } + + const BoundStatementKind GetKind() const final{ + return BoundStatementKind ::IndexAssignment; + } + + const BoundExpression* GetIndexExpression() const { + return _indexExpression; + } + + const BoundExpression* GetValueExpression() const { + return _valueExpression; + } +}; + class BoundReturnStatement : public BoundStatement{ const BoundExpression* _expression; public: diff --git a/src/Evaluator/EvalValues/EvalValue.hpp b/src/Evaluator/EvalValues/EvalValue.hpp index 8875df3..959383f 100644 --- a/src/Evaluator/EvalValues/EvalValue.hpp +++ b/src/Evaluator/EvalValues/EvalValue.hpp @@ -22,16 +22,16 @@ public: virtual shared_ptr Clone() = 0; - virtual long EvaluateInteger(){ + virtual long EvaluateInteger() const{ throw EvaluationException("Can't evaluate this EvalValue as integer."); } - virtual double EvaluateFloat(){ + virtual double EvaluateFloat() const{ throw EvaluationException("Can't evaluate this EvalValue as float."); } - virtual bool EvaluateBool(){ + virtual bool EvaluateBool() const{ throw EvaluationException("Can't evaluate this EvalValue as bool."); } - virtual std::string* EvaluateString(){ + virtual const std::string* EvaluateString() const { throw EvaluationException("Can't evaluate this EvalValue as string."); } @@ -40,6 +40,10 @@ public: virtual shared_ptr IndexValue(EvalValue* val){ throw EvaluationException("Can't index this EvalValue"); } + + virtual void SetIndexValue(EvalValue *key, shared_ptr value){ + throw EvaluationException("Can't index this EvalValue"); + } }; class BooleanEvalValue : public EvalValue{ @@ -58,7 +62,7 @@ public: return TypeClass ::Bool; } - bool EvaluateBool() final{ + bool EvaluateBool() const final{ return _value; } diff --git a/src/Evaluator/EvalValues/NumericEvalValue.hpp b/src/Evaluator/EvalValues/NumericEvalValue.hpp index f2c4ba4..651f363 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.hpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.hpp @@ -40,7 +40,7 @@ public: return false; } - long EvaluateInteger() final{ + long EvaluateInteger() const final{ return _value; } @@ -65,7 +65,7 @@ public: return true; } - double EvaluateFloat() final{ + double EvaluateFloat() const final{ return _value; } diff --git a/src/Evaluator/EvalValues/StringEvalValue.hpp b/src/Evaluator/EvalValues/StringEvalValue.hpp index 561ec6d..a37c80b 100644 --- a/src/Evaluator/EvalValues/StringEvalValue.hpp +++ b/src/Evaluator/EvalValues/StringEvalValue.hpp @@ -27,7 +27,7 @@ public: return this->_hash == b->GetHashCode(); }; - string* EvaluateString() final{ + const string* EvaluateString() const final{ return &_value; } diff --git a/src/Evaluator/EvalValues/TableEvalValue.hpp b/src/Evaluator/EvalValues/TableEvalValue.hpp index dfaa620..8af71f0 100644 --- a/src/Evaluator/EvalValues/TableEvalValue.hpp +++ b/src/Evaluator/EvalValues/TableEvalValue.hpp @@ -45,6 +45,11 @@ public: auto hash = HashedString::ConstHash(val); return this -> _table -> at(hash); } + + void SetIndexValue(EvalValue *key, shared_ptr value) final{ + auto hash = key->GetHashCode(); + this -> _table->at(hash) = value; + } }; diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index d54a742..b83a239 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -26,6 +26,8 @@ void Evaluator::EvaluateStatement(const BoundStatement *statement) { 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::IndexAssignment: + return this -> EvaluateIndexAssignmentStatement((BoundIndexAssignmentStatement*)statement); case BoundStatementKind ::FunctionDeclaration: return this->EvaluateFunctionDeclarationStatement((BoundFunctionDeclarationStatement*)statement); case BoundStatementKind::Return: return this -> EvaluateReturnStatement((BoundReturnStatement*)statement); case BoundStatementKind::Conditional: return this -> EvaluateConditionalStatement((BoundConditionalStatement*)statement); @@ -58,6 +60,15 @@ void Evaluator::EvaluateAssignmentStatement(const BoundAssignmentStatement *stat } } +void Evaluator::EvaluateIndexAssignmentStatement(const BoundIndexAssignmentStatement *statement) { + auto indexExpression = statement -> GetIndexExpression(); + auto value = this -> EvaluateExpression(statement -> GetValueExpression()); + auto index = ((BoundIndexExpression*)indexExpression); + auto table = this -> EvaluateExpression(index -> GetIndexableExpression()); + auto key = this -> EvaluateExpression(index->GetIndexExpression()); + table -> SetIndexValue(key.get(), value); +} + void Evaluator::EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement) { auto type = statement->GetType(); auto key = statement->GetKey(); @@ -300,3 +311,4 @@ shared_ptr Evaluator::EvaluateUserDataExpression(const BoundExpressio default: throw; } } + diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index fcf9956..ebd5421 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -26,6 +26,7 @@ class Evaluator { void EvaluateBlockStatement(const BoundBlockStatement *statement); void EvaluateExpressionStatement(const BoundExpressionStatement* statement); void EvaluateAssignmentStatement(const BoundAssignmentStatement* statement); + void EvaluateIndexAssignmentStatement(const BoundIndexAssignmentStatement* statement); void EvaluateFunctionDeclarationStatement(const BoundFunctionDeclarationStatement *statement); void EvaluateReturnStatement(const BoundReturnStatement *statement); void EvaluateConditionalStatement(const BoundConditionalStatement *statement); diff --git a/src/Parser/ParsedStatements/ParsedStatement.hpp b/src/Parser/ParsedStatements/ParsedStatement.hpp index 07d3220..5736e03 100644 --- a/src/Parser/ParsedStatements/ParsedStatement.hpp +++ b/src/Parser/ParsedStatements/ParsedStatement.hpp @@ -19,6 +19,7 @@ enum class ParsedStatementKind{ Block, Expression, Assignment, + IndexAssignment, FunctionDeclaration, Return, Conditional @@ -180,6 +181,33 @@ public: } }; +class ParsedIndexAssignmentStatement : public ParsedStatement{ + const ParsedExpression* _indexExpression; + const ParsedExpression* _valueExpression; +public: + ParsedIndexAssignmentStatement(ParsedExpression* indexExpression, ParsedExpression* valueExpression, unsigned int start, + unsigned int length) + : ParsedStatement(start, length), + _indexExpression(indexExpression), _valueExpression(valueExpression){} + + ~ParsedIndexAssignmentStatement() final{ + delete _indexExpression; + delete _valueExpression; + } + + const ParsedStatementKind GetKind() const final{ + return ParsedStatementKind ::IndexAssignment; + } + + const ParsedExpression* GetIndexExpression() const{ + return _indexExpression; + } + + const ParsedExpression* GetValueExpression() const{ + return _valueExpression; + } +}; + class ParsedReturnStatement : public ParsedStatement{ const ParsedExpression* _expression; public: diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 2cd6a31..987baf0 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -1,6 +1,4 @@ #include - - #include #include "Parser.hpp" #include "ParsedStatements/ParsedStatement.hpp" @@ -38,19 +36,23 @@ const IToken *Parser::Next() { ParsedStatement* Parser::ParseStatement(const IToken* current){ auto currentKind = current->GetKind(); switch (currentKind){ - case TokenKind ::LocalKeyword: return this -> ParseAssignment(current); + case TokenKind ::LocalKeyword: return this->ParseVariableAssignment(current); case TokenKind ::FunctionKeyword: return this -> ParseFunctionDeclaration(current); case TokenKind ::ReturnKeyword: return this->ParseReturnStatement(current); case TokenKind ::IfKeyword: return this -> ParseIfStatement(current); default: break; } if (this->Peek()->GetKind() == TokenKind::AssignmentToken){ - return ParseAssignment(current); + return ParseVariableAssignment(current); } - return new ParsedExpressionStatement(this -> ParseExpression(current)); + auto expression = this -> ParseExpression(current); + if (expression->GetKind() == ParsedExpressionKind::Indexer && this -> Peek()->GetKind() == TokenKind::AssignmentToken){ + return this -> ParseIndexAssignment(expression); + } + return new ParsedExpressionStatement(expression); } -ParsedStatement *Parser::ParseAssignment(const IToken *current) { +ParsedStatement *Parser::ParseVariableAssignment(const IToken *current) { bool isLocal = false; const IToken* identifier; if (current -> GetKind() == TokenKind::LocalKeyword){ @@ -75,6 +77,14 @@ ParsedStatement *Parser::ParseAssignment(const IToken *current) { return new ParsedAssignmentStatement(isLocal, ((IdentifierToken*)identifier) -> GetValue(), expression, start, expression->GetEndPosition() - start); } +ParsedStatement *Parser::ParseIndexAssignment(ParsedExpression *indexer) { + this -> Next(); // Consume assignment token + auto valueExpression = this -> ParseExpression(this -> Next()); + auto start = indexer->GetStartPosition(); + return new ParsedIndexAssignmentStatement(indexer, valueExpression, start, valueExpression->GetEndPosition() - start); +} + + ParsedStatement *Parser::ParseBlock(const vector& endTokens, const vector& openStatements) { auto statements = openStatements; auto start = this->_position; diff --git a/src/Parser/Parser.hpp b/src/Parser/Parser.hpp index f862a50..3952956 100644 --- a/src/Parser/Parser.hpp +++ b/src/Parser/Parser.hpp @@ -27,7 +27,8 @@ class Parser { const IToken* Next(); ParsedStatement* ParseStatement(const IToken* current); - ParsedStatement* ParseAssignment(const IToken* current); + ParsedStatement* ParseVariableAssignment(const IToken *current); + ParsedStatement* ParseIndexAssignment(ParsedExpression *indexer); ParsedStatement *ParseBlock(const vector& endTokens, const vector& openStatements = {}); ParsedStatement* ParseFunctionDeclaration(const IToken* current); ParsedStatement *ParseReturnStatement(const IToken *current); diff --git a/src/UserData/UserDataValue.hpp b/src/UserData/UserDataValue.hpp index 1185f24..df56f7f 100644 --- a/src/UserData/UserDataValue.hpp +++ b/src/UserData/UserDataValue.hpp @@ -44,6 +44,12 @@ public: auto field = _userData->GetField(fieldId); return shared_ptr(field->Get(_obj)); } + + void SetIndexValue(EvalValue *key, shared_ptr value) final{ + auto fieldId = key->GetHashCode(); + auto field = _userData->GetField(fieldId); + field -> Set(_obj, value.get()); + } }; diff --git a/tests/integration/UserData.cpp b/tests/integration/UserData.cpp index 87e8548..a69824f 100644 --- a/tests/integration/UserData.cpp +++ b/tests/integration/UserData.cpp @@ -44,5 +44,22 @@ end delete script; } +TEST_CASE( "Sets UserData value", "[integration]" ) { + UserDataStorage::RegisterType(HashedString::ConstHash("testObject"), UserDataTestObject::CreateData()); + Script* script = Script::Create(R"( +function testFunc(testObject obj) + obj["foo"] = 5000 +end +)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto obj = new UserDataTestObject(); + auto parameter = new UserDataValue(HashedString::ConstHash("testObject"), obj); + script->CallFunction("testFunc", {parameter}); + REQUIRE(obj->foo == 5000); + delete script; +} + + #endif