From c022c91777d3507b95dc60bd1cde5f6ea4badb5d Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Wed, 12 Jun 2019 15:19:28 +0200 Subject: [PATCH] Implements complex tables --- src/Binder/Binder.cpp | 29 +++++++++--- src/Binder/Binder.hpp | 3 ++ .../BoundExpressions/BoundExpression.hpp | 7 +-- .../BoundExpressions/BoundTableExpression.hpp | 32 +++++++++++++ src/Binder/BoundVariables/BoundScope.cpp | 14 +++--- src/Binder/BoundVariables/BoundScope.hpp | 4 +- src/Evaluator/EvalValues/StringEvalValue.hpp | 5 +- src/Evaluator/EvalValues/TableEvalValue.hpp | 7 ++- .../EvaluationScope/EvaluationScope.cpp | 11 +++-- .../EvaluationScope/EvaluationScope.hpp | 6 +-- src/Evaluator/Evaluator.cpp | 44 +++++++++++++---- src/Evaluator/Evaluator.hpp | 4 +- .../ParsedExpressions/ParsedExpression.hpp | 1 + .../ParsedTableExpression.hpp | 31 ++++++++++++ src/Parser/Parser.cpp | 6 ++- src/Script.cpp | 2 +- src/Script.hpp | 2 +- src/ScriptType.hpp | 29 +++++++++--- src/TableScriptType.hpp | 47 +++++++++++++++++++ tests/integration/Tables.cpp | 19 ++++++++ tests/integration/Variables.cpp | 19 +++++++- 21 files changed, 272 insertions(+), 50 deletions(-) create mode 100644 src/Binder/BoundExpressions/BoundTableExpression.hpp create mode 100644 src/Parser/ParsedExpressions/ParsedTableExpression.hpp create mode 100644 src/TableScriptType.hpp diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index d79667a..f523d71 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -1,6 +1,6 @@ -#include - #include "Binder.hpp" +#include "../TableScriptType.hpp" +#include "BoundExpressions/BoundTableExpression.hpp" #include BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s, BoundScope* scriptScope) { @@ -71,7 +71,7 @@ std::shared_ptr ParseTypeIdentifier(HashedString s){ switch (s.GetHash()){ case HashedString::ConstHash("number"): return std::make_shared(false, false); case HashedString::ConstHash("bool"): return std::make_shared(TypeClass::Bool); - case HashedString::ConstHash("string"): return std::make_shared(TypeClass::String); + case HashedString::ConstHash("string"): return std::make_shared(false, 0); default: return std::make_shared(TypeClass::Error); // todo: change to userdata } } @@ -178,6 +178,8 @@ BoundExpression* Binder::BindExpression(ParsedExpression* expression){ return this->BindIndexExpression((IndexExpression*)expression); case ParsedExpressionKind::NumericalTable: return this -> BindNumericalTableExpression((ParsedNumericalTableExpression*)expression); + case ParsedExpressionKind ::Table: + return this -> BindTableExpression((ParsedTableExpression*)expression); case ParsedExpressionKind ::Bad: return new BoundBadExpression(expression->GetStartPosition(), expression-> GetLength()); @@ -220,7 +222,8 @@ BoundExpression* Binder::BindBinaryOperator(BinaryExpression* expression){ expression->GetStartPosition(), expression->GetLength()); } } else if (boundLeftType->GetClass() == TypeClass::String){ - return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation, std::make_shared(TypeClass::String), + return new BoundBinaryExpression(boundLeft, boundRight, BoundBinaryOperation::Concatenation, std::make_shared(false, + 0), expression->GetStartPosition(), expression->GetLength()); } break; @@ -412,7 +415,19 @@ BoundExpression* Binder::BindNumericalTableExpression(ParsedNumericalTableExpres if (valueType == nullptr){ valueType = std::make_shared(TypeClass::Nil); } - auto keyType = std::make_shared(TypeClass::Number); - auto tableType = std::make_shared(keyType, valueType); + auto tableType = std::make_shared(valueType); return new BoundNumericalTableExpression(boundExpressions, tableType, expression->GetStartPosition(), expression->GetLength()); -} \ No newline at end of file +} + +BoundExpression *Binder::BindTableExpression(ParsedTableExpression *expression) { + auto tableScope = new unordered_map(); + auto innerScope = new BoundScope(tableScope); + auto currentScope = this -> _scope; + this -> _scope = innerScope; + auto block = this -> BindBlockStatement(expression -> GetBlock()); + this -> _scope = currentScope; + + auto tableType = shared_ptr(new TableScriptType(tableScope, innerScope->GetDeepestScope())); + + return new BoundTableExpression((BoundBlockStatement*)block, tableType, expression->GetStartPosition(), expression->GetLength()); +} diff --git a/src/Binder/Binder.hpp b/src/Binder/Binder.hpp index bdeba8f..4fd60ab 100644 --- a/src/Binder/Binder.hpp +++ b/src/Binder/Binder.hpp @@ -5,6 +5,8 @@ #include "BoundStatements/BoundStatement.hpp" #include "../Script.hpp" #include "BoundVariables/BoundScope.hpp" +#include "../Parser/ParsedExpressions/ParsedTableExpression.hpp" + using namespace std; class Binder { @@ -29,6 +31,7 @@ class Binder { BoundExpression *BindFunctionCall(FunctionCallExpression *expression); BoundExpression *BindIndexExpression(IndexExpression *expression); BoundExpression *BindNumericalTableExpression(ParsedNumericalTableExpression *expression); + BoundExpression *BindTableExpression(ParsedTableExpression * expression); public: static BoundScriptStatement* Bind(Script* script, ParsedScriptStatement* s, BoundScope* scriptScope); diff --git a/src/Binder/BoundExpressions/BoundExpression.hpp b/src/Binder/BoundExpressions/BoundExpression.hpp index bf9796f..81ab63c 100644 --- a/src/Binder/BoundExpressions/BoundExpression.hpp +++ b/src/Binder/BoundExpressions/BoundExpression.hpp @@ -25,6 +25,7 @@ enum class BoundExpressionKind{ FunctionCall, Index, NumericalTable, + Table, }; class BoundExpression{ @@ -102,7 +103,7 @@ class BoundLiteralStringExpression : public BoundExpression{ string _value; public: BoundLiteralStringExpression(string value, unsigned int start, unsigned int length) - : BoundExpression(start, length, make_shared(TypeClass::String)){ + : BoundExpression(start, length, make_shared(true, HashedString::ConstHash(value.c_str()))){ _value = std::move(value); } @@ -276,11 +277,11 @@ class BoundNumericalTableExpression : public BoundExpression{ vector _expressions; public: BoundNumericalTableExpression(vector expressions, shared_ptr type, unsigned int start, unsigned int length) - : BoundExpression(start, length, type){ + : BoundExpression(start, length, std::move(type)){ _expressions = std::move(expressions); } - ~BoundNumericalTableExpression(){ + ~BoundNumericalTableExpression() final{ for (auto e: _expressions){ delete e; } diff --git a/src/Binder/BoundExpressions/BoundTableExpression.hpp b/src/Binder/BoundExpressions/BoundTableExpression.hpp new file mode 100644 index 0000000..b4a449e --- /dev/null +++ b/src/Binder/BoundExpressions/BoundTableExpression.hpp @@ -0,0 +1,32 @@ +#include + + +#ifndef PORYGONLANG_BOUNDTABLEEXPRESSION_HPP +#define PORYGONLANG_BOUNDTABLEEXPRESSION_HPP + +#include "../BoundStatements/BoundStatement.hpp" + +class BoundTableExpression : public BoundExpression{ + BoundBlockStatement* _block; +public: + BoundTableExpression(BoundBlockStatement* block, shared_ptr type, unsigned int start, unsigned int length) + : BoundExpression(start, length, std::move(type)){ + _block = block; + } + + ~BoundTableExpression() final{ + delete _block; + } + + BoundExpressionKind GetKind() final{ + return BoundExpressionKind ::Table; + } + + BoundBlockStatement* GetBlock(){ + return _block; + } +}; + +#include "BoundExpression.hpp" + +#endif //PORYGONLANG_BOUNDTABLEEXPRESSION_HPP diff --git a/src/Binder/BoundVariables/BoundScope.cpp b/src/Binder/BoundVariables/BoundScope.cpp index 2a72802..311d6cf 100644 --- a/src/Binder/BoundVariables/BoundScope.cpp +++ b/src/Binder/BoundVariables/BoundScope.cpp @@ -3,8 +3,8 @@ #include "BoundScope.hpp" -BoundScope::BoundScope(unordered_map *scriptScope) { - _scriptScope = scriptScope; +BoundScope::BoundScope(unordered_map *tableScope) { + _tableScope = tableScope; _currentScope = 1; _deepestScope = 1; auto localUpmostScope = new unordered_map(); @@ -41,8 +41,8 @@ void BoundScope::GoOuterScope() { } int BoundScope::Exists(int key) { - auto found = this -> _scriptScope -> find(key); - if (found != _scriptScope -> end()){ + auto found = this -> _tableScope -> find(key); + if (found != _tableScope -> end()){ return 0; } for (int i = _currentScope - 1; i >= 0; i--){ @@ -57,8 +57,8 @@ int BoundScope::Exists(int key) { BoundVariable *BoundScope::GetVariable(int scope, int identifier) { if (scope == 0){ - auto find = this -> _scriptScope->find(identifier); - if (find != _scriptScope->end()){ + auto find = this -> _tableScope->find(identifier); + if (find != _tableScope->end()){ return find -> second; } return nullptr; @@ -85,7 +85,7 @@ VariableAssignment BoundScope::AssignVariable(int identifier, const std::shared_ int exists = this->Exists(identifier); if (exists == -1){ // Creation - _scriptScope->insert({identifier, new BoundVariable(type)}); + _tableScope->insert({identifier, new BoundVariable(type)}); return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, 0, true)); } else{ // Assigning diff --git a/src/Binder/BoundVariables/BoundScope.hpp b/src/Binder/BoundVariables/BoundScope.hpp index 2db5949..bad447e 100644 --- a/src/Binder/BoundVariables/BoundScope.hpp +++ b/src/Binder/BoundVariables/BoundScope.hpp @@ -14,12 +14,12 @@ using namespace std; class BoundScope { - unordered_map* _scriptScope; + unordered_map* _tableScope; vector*> _localScope; int _currentScope; int _deepestScope; public: - explicit BoundScope(unordered_map *scriptScope); + explicit BoundScope(unordered_map *tableScope); ~BoundScope(); void GoInnerScope(); diff --git a/src/Evaluator/EvalValues/StringEvalValue.hpp b/src/Evaluator/EvalValues/StringEvalValue.hpp index c673d9c..5f4acac 100644 --- a/src/Evaluator/EvalValues/StringEvalValue.hpp +++ b/src/Evaluator/EvalValues/StringEvalValue.hpp @@ -4,6 +4,7 @@ #include #include "EvalValue.hpp" +#include "../../Utilities/HashedString.hpp" using namespace std; @@ -14,8 +15,8 @@ class StringEvalValue : public EvalValue{ public: explicit StringEvalValue(string s){ _value = move(s); - _type = std::make_shared(TypeClass::String); - _hash = std::hash{}(_value); + _hash = HashedString::ConstHash (_value.c_str()); + _type = std::make_shared(true, _hash); } std::shared_ptr GetType() final{ diff --git a/src/Evaluator/EvalValues/TableEvalValue.hpp b/src/Evaluator/EvalValues/TableEvalValue.hpp index d18f739..c3b5009 100644 --- a/src/Evaluator/EvalValues/TableEvalValue.hpp +++ b/src/Evaluator/EvalValues/TableEvalValue.hpp @@ -1,5 +1,3 @@ -#include - #ifndef PORYGONLANG_TABLEEVALVALUE_HPP #define PORYGONLANG_TABLEEVALVALUE_HPP #include @@ -45,6 +43,11 @@ public: auto hash = val->GetHashCode(); return this -> _table->at(hash); } + + shared_ptr IndexValue(const char* val){ + auto hash = HashedString::ConstHash(val); + return this -> _table -> at(hash); + } }; diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.cpp b/src/Evaluator/EvaluationScope/EvaluationScope.cpp index a59cb72..e96c614 100644 --- a/src/Evaluator/EvaluationScope/EvaluationScope.cpp +++ b/src/Evaluator/EvaluationScope/EvaluationScope.cpp @@ -2,7 +2,7 @@ #include "EvaluationScope.hpp" #include -EvaluationScope::EvaluationScope(unordered_map> *scriptVariables, int deepestScope) { +EvaluationScope::EvaluationScope(unordered_map> *scriptVariables, int deepestScope) { _scriptScope = scriptVariables; _localScope = vector>>>(deepestScope); for (int i = 0; i < deepestScope; i++){ @@ -42,6 +42,7 @@ EvaluationScope* EvaluationScope::CreateBranchingScope(int index){ for (int i = 0; i < index; i++){ scope->_localScope[i] = this->_localScope[i]; } + scope->_currentScope = index; return scope; } @@ -49,9 +50,11 @@ void EvaluationScope::OuterScope() { _currentScope++; } -void EvaluationScope::InnerScope() { - auto scope = this->_localScope[_currentScope]; - scope->clear(); +void EvaluationScope::InnerScope(bool clearScope) { + if (clearScope){ + auto scope = this->_localScope[_currentScope]; + scope->clear(); + } _currentScope--; } diff --git a/src/Evaluator/EvaluationScope/EvaluationScope.hpp b/src/Evaluator/EvaluationScope/EvaluationScope.hpp index 584e0c8..22fbdcc 100644 --- a/src/Evaluator/EvaluationScope/EvaluationScope.hpp +++ b/src/Evaluator/EvaluationScope/EvaluationScope.hpp @@ -7,17 +7,17 @@ #include "../EvalValues/EvalValue.hpp" class EvaluationScope { - unordered_map>* _scriptScope; + unordered_map>* _scriptScope; vector>>> _localScope; int _currentScope; public: - explicit EvaluationScope(unordered_map>* scriptVariables, int deepestScope); + explicit EvaluationScope(unordered_map>* scriptVariables, int deepestScope); ~EvaluationScope() = default; void CreateVariable(int scope, int id, const shared_ptr& value); void SetVariable(int scope, int id, const shared_ptr& value); void OuterScope(); - void InnerScope(); + void InnerScope(bool clearScope = true); shared_ptr GetVariable(int scope, int id); EvaluationScope* CreateBranchingScope(int index); diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index d7adaf0..c08d13f 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -6,12 +6,14 @@ #include "EvaluationScope/EvaluationScope.hpp" #include "EvalValues/ScriptFunctionEvalValue.hpp" #include "EvalValues/TableEvalValue.hpp" +#include "../Binder/BoundExpressions/BoundTableExpression.hpp" +#include "../TableScriptType.hpp" using namespace std; void Evaluator::Evaluate(BoundScriptStatement *statement) { this->_evaluationScope = new EvaluationScope(this->_scriptData->_scriptVariables, statement->GetDeepestScope()); - EvaluateBlockStatement(statement); + EvaluateBlockStatement(statement, false); } void Evaluator::EvaluateStatement(BoundStatement *statement) { @@ -19,7 +21,7 @@ void Evaluator::EvaluateStatement(BoundStatement *statement) { return; switch (statement->GetKind()){ case BoundStatementKind ::Script: throw; // Should never happen - case BoundStatementKind ::Block: return this -> EvaluateBlockStatement((BoundBlockStatement*)statement); + case BoundStatementKind ::Block: return this -> EvaluateBlockStatement((BoundBlockStatement*)statement, true); case BoundStatementKind ::Expression: return this -> EvaluateExpressionStatement((BoundExpressionStatement*)statement); case BoundStatementKind ::Assignment: return this -> EvaluateAssignmentStatement((BoundAssignmentStatement*)statement); case BoundStatementKind ::FunctionDeclaration: return this->EvaluateFunctionDeclarationStatement((BoundFunctionDeclarationStatement*)statement); @@ -31,14 +33,14 @@ void Evaluator::EvaluateStatement(BoundStatement *statement) { } } -void Evaluator::EvaluateBlockStatement(BoundBlockStatement* statement) { +void Evaluator::EvaluateBlockStatement(BoundBlockStatement* statement, bool clearScope) { this->_evaluationScope->OuterScope(); for (auto s: statement->GetStatements()){ this -> EvaluateStatement(s); if (this->_hasReturned) break; } - this->_evaluationScope->InnerScope(); + this->_evaluationScope->InnerScope(clearScope); } void Evaluator::EvaluateExpressionStatement(BoundExpressionStatement *statement) { @@ -122,6 +124,7 @@ shared_ptr Evaluator::EvaluateIntegerExpression(BoundExpressio case BoundExpressionKind ::LiteralBool: case BoundExpressionKind ::Bad: case BoundExpressionKind::NumericalTable: + case BoundExpressionKind::Table: throw; } } @@ -140,6 +143,7 @@ shared_ptr Evaluator::EvaluateBoolExpression(BoundExpression * case BoundExpressionKind::LiteralFloat: case BoundExpressionKind::LiteralString: case BoundExpressionKind::NumericalTable: + case BoundExpressionKind::Table: throw; } @@ -161,6 +165,7 @@ shared_ptr Evaluator::EvaluateStringExpression(BoundExpression case BoundExpressionKind::LiteralBool: case BoundExpressionKind::Unary: case BoundExpressionKind::NumericalTable: + case BoundExpressionKind::Table: throw; } @@ -187,8 +192,9 @@ shared_ptr Evaluator::EvaluateTableExpression(BoundExpression * expre case BoundExpressionKind ::Variable: return this->GetVariable((BoundVariableExpression*)expression); case BoundExpressionKind ::Index: return this->EvaluateIndexExpression(expression); case BoundExpressionKind ::NumericalTable: return this-> EvaluateNumericTableExpression(expression); + case BoundExpressionKind ::Table: return this -> EvaluateComplexTableExpression(expression); default: - return nullptr; + throw; } } @@ -222,8 +228,7 @@ shared_ptr Evaluator::EvaluateFunctionCallExpression(BoundExpression* auto key = parameterKeys.at(i); this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone()); } - this->_evaluationScope->OuterScope(); - this->EvaluateBlockStatement(function->GetInnerBlock().get()); + this->EvaluateBlockStatement(function->GetInnerBlock().get(), true); delete this->_evaluationScope; this->_evaluationScope = originalScope; @@ -237,6 +242,12 @@ shared_ptr Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct auto type = std::dynamic_pointer_cast(function->GetType()); auto parameterTypes = type->GetParameterTypes(); auto parameterKeys = type->GetParameterKeys(); + + auto scope = type -> GetScopeIndex(); + auto originalScope = this->_evaluationScope; + auto functionScope = this->_evaluationScope->CreateBranchingScope(scope); + this->_evaluationScope = functionScope; + for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){ auto parameter = parameters[i]; auto requiredType = parameterTypes.at(i); @@ -246,7 +257,9 @@ shared_ptr Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct auto key = parameterKeys.at(i); this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone()); } - this->EvaluateBlockStatement(function->GetInnerBlock().get()); + this->EvaluateBlockStatement(function->GetInnerBlock().get(), true); + delete this->_evaluationScope; + this->_evaluationScope = originalScope; this->_hasReturned = false; auto r = this -> _returnValue; this -> _returnValue = nullptr; @@ -272,3 +285,18 @@ shared_ptr Evaluator::EvaluateNumericTableExpression(BoundExpression return make_shared(valuesPointer, tableExpression->GetType()); } +shared_ptr Evaluator::EvaluateComplexTableExpression(BoundExpression *expression) { + auto tableExpression = (BoundTableExpression*)expression; + auto type = dynamic_pointer_cast(tableExpression->GetType()); + auto declaredVars = type -> GetValues(); + auto variables = make_shared>>(declaredVars->size()); + for (auto i : *declaredVars){ + variables->insert({i.first, nullptr}); + } + auto evaluator = new EvaluationScope(variables.get(), type -> GetDeepestScope()); + auto currentEvaluator = this -> _evaluationScope; + this -> _evaluationScope = evaluator; + this -> EvaluateBlockStatement(tableExpression->GetBlock(), false); + this -> _evaluationScope = currentEvaluator; + return shared_ptr(new TableEvalValue(variables, tableExpression->GetType())); +} diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index 46880a7..e4ac7f5 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -23,7 +23,7 @@ class Evaluator { EvaluationScope* _evaluationScope; void EvaluateStatement(BoundStatement* statement); - void EvaluateBlockStatement(BoundBlockStatement* statement); + void EvaluateBlockStatement(BoundBlockStatement* statement, bool clearScope); void EvaluateExpressionStatement(BoundExpressionStatement* statement); void EvaluateAssignmentStatement(BoundAssignmentStatement* statement); void EvaluateFunctionDeclarationStatement(BoundFunctionDeclarationStatement *statement); @@ -67,6 +67,8 @@ public: EvalValue* GetLastValue(){ return _lastValue.get(); } + + shared_ptr EvaluateComplexTableExpression(BoundExpression *expression); }; diff --git a/src/Parser/ParsedExpressions/ParsedExpression.hpp b/src/Parser/ParsedExpressions/ParsedExpression.hpp index 0e2a523..c0accbb 100644 --- a/src/Parser/ParsedExpressions/ParsedExpression.hpp +++ b/src/Parser/ParsedExpressions/ParsedExpression.hpp @@ -24,6 +24,7 @@ enum class ParsedExpressionKind{ FunctionCall, Indexer, NumericalTable, + Table, }; class ParsedExpression { diff --git a/src/Parser/ParsedExpressions/ParsedTableExpression.hpp b/src/Parser/ParsedExpressions/ParsedTableExpression.hpp new file mode 100644 index 0000000..f565ab7 --- /dev/null +++ b/src/Parser/ParsedExpressions/ParsedTableExpression.hpp @@ -0,0 +1,31 @@ + +#ifndef PORYGONLANG_PARSEDTABLEEXPRESSION_HPP +#define PORYGONLANG_PARSEDTABLEEXPRESSION_HPP + +#include "ParsedExpression.hpp" +#include "../ParsedStatements/ParsedStatement.hpp" + +class ParsedTableExpression : public ParsedExpression{ + ParsedBlockStatement* _block; +public: + ParsedTableExpression(ParsedBlockStatement* block, unsigned int start, unsigned int length) + : ParsedExpression(start, length){ + _block = block; + } + + ~ParsedTableExpression() final{ + delete _block; + } + + ParsedBlockStatement* GetBlock(){ + return _block; + } + + ParsedExpressionKind GetKind() final{ + return ParsedExpressionKind::Table; + } +}; + +#include "ParsedExpression.hpp" + +#endif //PORYGONLANG_PARSEDTABLEEXPRESSION_HPP diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index 95561f3..c3829b9 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -5,6 +5,7 @@ #include "UnaryOperatorKind.hpp" #include "BinaryOperatorKind.hpp" #include "TypedVariableIdentifier.hpp" +#include "ParsedExpressions/ParsedTableExpression.hpp" ParsedScriptStatement* Parser::Parse() { @@ -372,6 +373,7 @@ ParsedExpression* Parser::ParseTableExpression(IToken* current){ auto start = current->GetStartPosition(); return new ParsedNumericalTableExpression({}, start, this -> Peek()->GetEndPosition() - start); } + auto start = current->GetStartPosition(); auto firstItem = this->ParseStatement(this -> Next()); // If the first item is an expression, and is followed by a comma, we're dealing with a simple {1, 2, 3} kind of array if (firstItem->GetKind() == ParsedStatementKind::Expression && @@ -389,7 +391,6 @@ ParsedExpression* Parser::ParseTableExpression(IToken* current){ hasErrors = true; } } - auto start = current->GetStartPosition(); if (hasErrors){ return new BadExpression(start, n->GetEndPosition() - start); } @@ -400,7 +401,8 @@ ParsedExpression* Parser::ParseTableExpression(IToken* current){ auto block = (ParsedBlockStatement*)this -> ParseBlock({TokenKind ::CloseCurlyBracket}); auto statements = block->GetStatements(); statements->insert(statements->begin(), firstItem); - throw "not implemented TODO"; + auto closeToken = this -> PeekAt(-1); + return new ParsedTableExpression(block, start, closeToken->GetEndPosition() - start); } } diff --git a/src/Script.cpp b/src/Script.cpp index 4fbe3b1..bdf76cf 100644 --- a/src/Script.cpp +++ b/src/Script.cpp @@ -17,7 +17,7 @@ Script::Script() { Diagnostics = new DiagnosticsHolder(); _evaluator = new Evaluator(this); _boundScript = nullptr; - _scriptVariables = new unordered_map>(0); + _scriptVariables = new unordered_map>(0); } void Script::Evaluate() { diff --git a/src/Script.hpp b/src/Script.hpp index f0d125d..4ef499b 100644 --- a/src/Script.hpp +++ b/src/Script.hpp @@ -18,7 +18,7 @@ class Script { friend class Evaluator; Evaluator* _evaluator; - unordered_map>* _scriptVariables; + unordered_map>* _scriptVariables; BoundScriptStatement* _boundScript; shared_ptr _returnType; diff --git a/src/ScriptType.hpp b/src/ScriptType.hpp index 6b92a1e..c84835d 100644 --- a/src/ScriptType.hpp +++ b/src/ScriptType.hpp @@ -6,6 +6,7 @@ #include #include #include "Binder/BoundVariables/BoundVariableKey.hpp" +#include "Utilities/HashedString.hpp" using namespace std; @@ -73,6 +74,24 @@ public: } }; +class StringScriptType : public ScriptType{ + bool _isKnownAtBind; + int _hashValue; +public: + explicit StringScriptType(bool knownAtBind, int hashValue): ScriptType(TypeClass::String){ + _isKnownAtBind = knownAtBind; + _hashValue = hashValue; + } + + bool IsKnownAtBind(){ + return _isKnownAtBind; + } + + int GetHashValue(){ + return _hashValue; + } +}; + class FunctionScriptType : public ScriptType{ shared_ptr _returnType; vector> _parameterTypes; @@ -104,24 +123,22 @@ public: } }; -class TableScriptType : public ScriptType{ - shared_ptr _keyType; +class NumericalTableScriptType : public ScriptType{ shared_ptr _valueType; // Consider adding a check whether the table actually contains a type if every key is static. public: - TableScriptType(shared_ptr keyType, shared_ptr valueType) : ScriptType(TypeClass::Table){ - _keyType = std::move(keyType); + explicit NumericalTableScriptType(shared_ptr valueType) : ScriptType(TypeClass::Table){ _valueType = std::move(valueType); } bool CanBeIndexedWith(ScriptType* indexer) final{ - return _keyType.get()->operator==(indexer); + return indexer->GetClass() == TypeClass ::Number; } shared_ptr GetIndexedType(ScriptType* indexer) final{ return _valueType; } - }; + #endif //PORYGONLANG_SCRIPTTYPE_HPP diff --git a/src/TableScriptType.hpp b/src/TableScriptType.hpp new file mode 100644 index 0000000..058babe --- /dev/null +++ b/src/TableScriptType.hpp @@ -0,0 +1,47 @@ + +#ifndef PORYGONLANG_TABLESCRIPTTYPE_HPP +#define PORYGONLANG_TABLESCRIPTTYPE_HPP +#include +#include "Binder/BoundVariables/BoundVariable.hpp" + +class TableScriptType : public ScriptType{ + unordered_map* _values; + int _deepestScope; +public: + explicit TableScriptType(unordered_map* values, int deepestScope) : ScriptType(TypeClass::Table){ + _values = values; + _deepestScope = deepestScope; + } + + ~TableScriptType() final{ + for (auto i : *_values){ + delete i.second; + } + delete _values; + } + + bool CanBeIndexedWith(ScriptType* indexer) final{ + return indexer->GetClass() == TypeClass ::String; + } + + shared_ptr GetIndexedType(ScriptType* indexer) final{ + auto stringKey = (StringScriptType*)indexer; + if (stringKey->IsKnownAtBind()){ + return _values-> at(stringKey->GetHashValue())->GetType(); + } + throw "TODO: indexing with dynamic keys"; + } + + unordered_map* GetValues(){ + return _values; + } + + int GetDeepestScope(){ + return _deepestScope; + } + +}; + +#include "ScriptType.hpp" + +#endif //PORYGONLANG_TABLESCRIPTTYPE_HPP diff --git a/tests/integration/Tables.cpp b/tests/integration/Tables.cpp index 0a2364a..0d8f181 100644 --- a/tests/integration/Tables.cpp +++ b/tests/integration/Tables.cpp @@ -1,6 +1,7 @@ #ifdef TESTS_BUILD #include #include "../src/Script.hpp" +#include "../../src/Evaluator/EvalValues/TableEvalValue.hpp" TEST_CASE( "Create empty table", "[integration]" ) { Script* script = Script::Create("table = {}"); @@ -43,6 +44,24 @@ result = table[3] delete script; } +TEST_CASE( "Create complex table", "[integration]" ) { + Script* script = Script::Create( + R"( +table = { + foo = 'test' + bar = 100 +} +)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto variable = script->GetVariable("table"); + REQUIRE(variable != nullptr); + auto table = (TableEvalValue*)variable; + CHECK(*table->IndexValue("foo")->EvaluateString() == "test"); + CHECK(table->IndexValue("bar")->EvaluateInteger() == 100); + delete script; +} + #endif diff --git a/tests/integration/Variables.cpp b/tests/integration/Variables.cpp index d25610a..0161f39 100644 --- a/tests/integration/Variables.cpp +++ b/tests/integration/Variables.cpp @@ -44,5 +44,22 @@ TEST_CASE( "Create local variable and use", "[integration]" ) { delete script; } - +TEST_CASE( "Local variables in upmost scope persist", "[integration]" ) { + Script* script = Script::Create(R"( +result = 0 +local foo = 0 +function bar() + foo = foo + 1 + result = foo +end +)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + script -> CallFunction("bar", {}); + script -> CallFunction("bar", {}); + auto variable = script->GetVariable("result"); + REQUIRE(variable != nullptr); + CHECK(variable->EvaluateInteger() == 2); + delete script; +} #endif