diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index 1965ace..72852a1 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -1,9 +1,11 @@ #include "Binder.hpp" -BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s) { +BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s, BoundScope* scriptScope) { auto binder = Binder(); - binder.ScriptData = script; + binder._scriptData = script; + + binder._scope = scriptScope; auto statements = s->GetStatements(); vector boundStatements (statements.size()); for (int i = 0; i < statements.size(); i++){ @@ -12,11 +14,18 @@ BoundScriptStatement *Binder::Bind(Script* script, ParsedScriptStatement *s) { return new BoundScriptStatement(boundStatements); } +Binder::~Binder() { + delete _scope; +} + BoundStatement* Binder::BindStatement(ParsedStatement* statement){ switch (statement -> GetKind()) { case ParsedStatementKind ::Script: throw; // This shouldn't happen. case ParsedStatementKind ::Block: return this -> BindBlockStatement(statement); case ParsedStatementKind ::Expression: return this -> BindExpressionStatement(statement); + case ParsedStatementKind::Assignment: return this -> BindAssignmentStatement(statement); + + case ParsedStatementKind::Bad: return new BoundBadStatement(); } } @@ -34,6 +43,20 @@ BoundStatement *Binder::BindExpressionStatement(ParsedStatement *statement) { return new BoundExpressionStatement(this -> BindExpression(exp)); } +BoundStatement* Binder::BindAssignmentStatement(ParsedStatement *statement){ + auto s = (ParsedAssignmentStatement*) statement; + auto boundExpression = this->BindExpression(s->GetExpression()); + auto assignment = this->_scope->AssignVariable(s->GetIdentifier().GetHash(), boundExpression->GetType()); + if (assignment.GetResult() == VariableAssignmentResult::Ok){ + auto key = assignment.GetKey(); + return new BoundAssignmentStatement(key, boundExpression); + } + else{ + this -> _scriptData -> Diagnostics -> LogError(DiagnosticCode::CantAssignVariable, statement->GetStartPosition(), statement->GetLength()); + return new BoundBadStatement(); + } +} + BoundExpression* Binder::BindExpression(ParsedExpression* expression){ switch (expression -> GetKind()){ case ParsedExpressionKind ::LiteralInteger: @@ -149,7 +172,7 @@ BoundExpression* Binder::BindBinaryOperator(BinaryExpression* expression){ expression->GetStartPosition(), expression->GetLength()); break; } - this -> ScriptData -> Diagnostics->LogError(DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(), expression->GetLength()); + this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::NoBinaryOperationFound, expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); } @@ -179,7 +202,8 @@ BoundExpression* Binder::BindUnaryOperator(UnaryExpression* expression){ default: break; } - this -> ScriptData -> Diagnostics->LogError(DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(), expression->GetLength()); + this -> _scriptData -> Diagnostics->LogError(DiagnosticCode::NoUnaryOperationFound, expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); -} \ No newline at end of file +} + diff --git a/src/Binder/Binder.hpp b/src/Binder/Binder.hpp index a08b1be..2ba7b8c 100644 --- a/src/Binder/Binder.hpp +++ b/src/Binder/Binder.hpp @@ -4,20 +4,25 @@ #include "../Parser/ParsedStatements/ParsedStatement.hpp" #include "BoundStatements/BoundStatement.hpp" #include "../Script.hpp" +#include "BoundVariables/BoundScope.hpp" class Binder { - Script* ScriptData; + Script* _scriptData; + BoundScope* _scope; + + ~Binder(); BoundStatement *BindStatement(ParsedStatement *statement); BoundStatement *BindBlockStatement(ParsedStatement *statement); BoundStatement *BindExpressionStatement(ParsedStatement *statement); + BoundStatement *BindAssignmentStatement(ParsedStatement *statement); BoundExpression *BindExpression(ParsedExpression *expression); BoundExpression *BindBinaryOperator(BinaryExpression *expression); BoundExpression *BindUnaryOperator(UnaryExpression *expression); public: - static BoundScriptStatement* Bind(Script* script, ParsedScriptStatement* s); + static BoundScriptStatement* Bind(Script* script, ParsedScriptStatement* s, BoundScope* scriptScope); }; diff --git a/src/Binder/BoundStatements/BoundStatement.hpp b/src/Binder/BoundStatements/BoundStatement.hpp index 9031a39..d161604 100644 --- a/src/Binder/BoundStatements/BoundStatement.hpp +++ b/src/Binder/BoundStatements/BoundStatement.hpp @@ -6,13 +6,16 @@ #include #include "../BoundExpressions/BoundExpression.hpp" +#include "../BoundVariables/BoundVariableKey.hpp" using namespace std; enum class BoundStatementKind{ + Bad, Script, Block, Expression, + Assignment, }; class BoundStatement{ @@ -21,6 +24,13 @@ public: virtual ~BoundStatement() = default; }; +class BoundBadStatement : public BoundStatement{ +public: + BoundStatementKind GetKind() final{ + return BoundStatementKind ::Bad; + } +}; + class BoundBlockStatement : public BoundStatement{ vector _statements; public: @@ -72,4 +82,22 @@ public: } }; +class BoundAssignmentStatement : public BoundStatement{ + BoundVariableKey* _key; + BoundExpression* _expression; +public: + BoundAssignmentStatement(BoundVariableKey* key, BoundExpression* expression){ + _key = key; + _expression = expression; + } + ~BoundAssignmentStatement() final{ + delete _key; + delete _expression; + } + + BoundStatementKind GetKind() final{ + return BoundStatementKind ::Assignment; + } +}; + #endif //PORYGONLANG_BOUNDSTATEMENT_HPP diff --git a/src/Binder/BoundVariables/BoundScope.cpp b/src/Binder/BoundVariables/BoundScope.cpp new file mode 100644 index 0000000..8f01473 --- /dev/null +++ b/src/Binder/BoundVariables/BoundScope.cpp @@ -0,0 +1,2 @@ + +#include "BoundScope.hpp" diff --git a/src/Binder/BoundVariables/BoundScope.hpp b/src/Binder/BoundVariables/BoundScope.hpp new file mode 100644 index 0000000..6a7d3f3 --- /dev/null +++ b/src/Binder/BoundVariables/BoundScope.hpp @@ -0,0 +1,88 @@ + +#ifndef PORYGONLANG_BOUNDSCOPE_HPP +#define PORYGONLANG_BOUNDSCOPE_HPP + +#include +#include +#include +#include "BoundVariable.hpp" +#include "BoundVariableKey.hpp" +#include "VariableAssigmentResult.hpp" +#include "../../Utilities/HashedString.hpp" + +using namespace std; + +class BoundScope { + unordered_map* _scriptScope; + vector> _localScope; + int _currentScope; +public: + explicit BoundScope(unordered_map *scriptScope){ + _scriptScope = scriptScope; + _currentScope = 1; + _localScope = vector>(1); + } + ~BoundScope(){ + _localScope.clear(); + } + + int Exists(int key){ + auto found = this -> _scriptScope -> find(key); + if (found != _scriptScope -> end()){ + return 0; + } + for (int i = _currentScope - 1; i >= 0; i--){ + auto scope = _localScope.at(i); + found = scope.find(key); + if (found != scope.end()){ + return i + 1; + } + } + return -1; + } + + BoundVariable* GetVariable(int scope, int identifier){ + if (scope == 0){ + auto find = this -> _scriptScope->find(identifier); + if (find != _scriptScope->end()){ + return find -> second; + } + return nullptr; + } else{ + auto s = this->_localScope.at(scope); + auto find = s.find(identifier); + if (find != s.end()){ + return find -> second; + } + return nullptr; + } + } + + VariableAssignment CreateExplicitLocal(HashedString& identifier, ScriptType* type){ + auto scope = this->_localScope.at(this->_currentScope); + if (scope.find(identifier.GetHash()) != scope.end()){ + return VariableAssignment(VariableAssignmentResult::ExplicitLocalVariableExists, nullptr); + } + scope.insert({identifier.GetHash(), new BoundVariable(type)}); + return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier.GetHash(), this->_currentScope, true)); + } + + VariableAssignment AssignVariable(int identifier, ScriptType* type){ + int exists = this->Exists(identifier); + if (exists == -1){ + // Creation + _scriptScope->insert({identifier, new BoundVariable(type)}); + return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, 0, true)); + } else{ + // Assigning + auto var = this->GetVariable(exists, identifier); + if (var->GetType() != type){ + return VariableAssignment(VariableAssignmentResult::VariableDefinedWithDifferentType, nullptr); + } + return VariableAssignment(VariableAssignmentResult::Ok, new BoundVariableKey(identifier, exists, false)); + } + } +}; + + +#endif //PORYGONLANG_BOUNDSCOPE_HPP diff --git a/src/Binder/BoundVariables/BoundVariable.hpp b/src/Binder/BoundVariables/BoundVariable.hpp new file mode 100644 index 0000000..b47c18b --- /dev/null +++ b/src/Binder/BoundVariables/BoundVariable.hpp @@ -0,0 +1,22 @@ + +#ifndef PORYGONLANG_BOUNDVARIABLE_HPP +#define PORYGONLANG_BOUNDVARIABLE_HPP + +#include "../../ScriptType.hpp" + +class BoundVariable{ + ScriptType* _type; +public: + explicit BoundVariable(ScriptType* type){ + _type = type; + } + ~BoundVariable(){ + delete _type; + } + + ScriptType* GetType(){ + return _type; + } +}; + +#endif //PORYGONLANG_BOUNDVARIABLE_HPP diff --git a/src/Binder/BoundVariables/BoundVariableKey.hpp b/src/Binder/BoundVariables/BoundVariableKey.hpp new file mode 100644 index 0000000..220476f --- /dev/null +++ b/src/Binder/BoundVariables/BoundVariableKey.hpp @@ -0,0 +1,33 @@ +#include + + +#ifndef PORYGONLANG_BOUNDVARIABLEKEY_HPP +#define PORYGONLANG_BOUNDVARIABLEKEY_HPP + +#include + +class BoundVariableKey{ + int _identifier; + unsigned int _scopeId; + bool _isCreation; +public: + BoundVariableKey(int id, unsigned int scope, bool creation){ + _identifier = std::move(id); + _scopeId = scope; + _isCreation = creation; + } + + int GetIdentifier(){ + return _identifier; + } + + unsigned int GetScopeId(){ + return _scopeId; + } + + bool IsCreation(){ + return _isCreation; + } +}; + +#endif //PORYGONLANG_BOUNDVARIABLEKEY_HPP diff --git a/src/Binder/BoundVariables/VariableAssigmentResult.hpp b/src/Binder/BoundVariables/VariableAssigmentResult.hpp new file mode 100644 index 0000000..7e449df --- /dev/null +++ b/src/Binder/BoundVariables/VariableAssigmentResult.hpp @@ -0,0 +1,31 @@ + +#ifndef PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP +#define PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP + +#include "BoundVariableKey.hpp" + +enum class VariableAssignmentResult{ + Ok, + ExplicitLocalVariableExists, + VariableDefinedWithDifferentType +}; + +class VariableAssignment{ + VariableAssignmentResult _result; + BoundVariableKey* _key; +public: + VariableAssignment(VariableAssignmentResult result, BoundVariableKey *key) { + _result = result; + _key = key; + } + + VariableAssignmentResult GetResult(){ + return _result; + } + + BoundVariableKey* GetKey(){ + return _key; + } +}; + +#endif //PORYGONLANG_VARIABLEASSIGMENTRESULT_HPP diff --git a/src/Diagnostics/DiagnosticCode.hpp b/src/Diagnostics/DiagnosticCode.hpp index a76b71f..c481752 100644 --- a/src/Diagnostics/DiagnosticCode.hpp +++ b/src/Diagnostics/DiagnosticCode.hpp @@ -13,6 +13,7 @@ enum class DiagnosticCode{ // Bind diagnostics NoBinaryOperationFound, NoUnaryOperationFound, + CantAssignVariable, }; #endif //PORYGONLANG_DIAGNOSTICCODE_HPP diff --git a/src/Parser/ParsedStatements/ParsedStatement.hpp b/src/Parser/ParsedStatements/ParsedStatement.hpp index 015d9c3..a69e4d0 100644 --- a/src/Parser/ParsedStatements/ParsedStatement.hpp +++ b/src/Parser/ParsedStatements/ParsedStatement.hpp @@ -1,3 +1,7 @@ +#include + +#include + #ifndef PORYGONLANG_PARSEDSTATEMENT_HPP @@ -8,6 +12,7 @@ #include #include "../ParsedExpressions/ParsedExpression.hpp" +#include "../../Utilities/HashedString.hpp" enum class ParsedStatementKind{ Bad, @@ -32,6 +37,10 @@ public: return _start; } + unsigned int GetLength(){ + return _length; + } + unsigned int GetEndPosition(){ return _start + _length - 1; } @@ -98,13 +107,13 @@ public: class ParsedAssignmentStatement : public ParsedStatement{ bool _local; - std::string _identifier; + HashedString _identifier; ParsedExpression* _expression; public: ParsedAssignmentStatement(bool local, std::string identifier, ParsedExpression* expression, unsigned int start, unsigned int length) - : ParsedStatement(start, length){ + : ParsedStatement(start, length), _identifier(HashedString(std::move(identifier))) + { _local = local; - _identifier = std::move(identifier); _expression = expression; } ~ParsedAssignmentStatement() final{ @@ -119,7 +128,7 @@ public: return _local; } - std::string GetIdentifier(){ + HashedString GetIdentifier(){ return _identifier; } diff --git a/src/Script.cpp b/src/Script.cpp index 60aea26..68dcdea 100644 --- a/src/Script.cpp +++ b/src/Script.cpp @@ -1,14 +1,13 @@ #include - - +#include #include "Script.hpp" #include "Parser/Lexer.hpp" #include "Parser/Parser.hpp" #include "Binder/Binder.hpp" -Script Script::Create(string script) { - auto s = Script(); - s.Parse(std::move(script)); +Script* Script::Create(string script) { + auto s = new Script(); + s -> Parse(std::move(script)); return s; } @@ -40,7 +39,14 @@ void Script::Parse(string script) { } lexResult.clear(); if (!Diagnostics->HasErrors()){ - this->BoundScript = Binder::Bind(this, parseResult); + unordered_map scriptScope; + auto bindScope = new BoundScope(&scriptScope); + this->BoundScript = Binder::Bind(this, parseResult, bindScope); + for (const auto& v : scriptScope){ + this->_scopeVariables.insert({v.first, nullptr}); + delete v.second; + } + scriptScope.clear(); } delete parseResult; } diff --git a/src/Script.hpp b/src/Script.hpp index 4ce2052..2ff91b0 100644 --- a/src/Script.hpp +++ b/src/Script.hpp @@ -5,13 +5,14 @@ #define PORYGONLANG_SCRIPT_HPP #include -#include +#include #include "Diagnostics/Diagnostics.hpp" #include "Binder/BoundStatements/BoundStatement.hpp" class Script; class Evaluator; #include "Evaluator/Evaluator.hpp" #include "Evaluator/EvalValues/EvalValue.hpp" +#include "Utilities/HashedString.hpp" using namespace std; @@ -19,15 +20,15 @@ class Script { friend class Evaluator; EvalValue* _lastValue; - Evaluator* _evaluator; + unordered_map _scopeVariables; explicit Script(); void Parse(string script); BoundScriptStatement* BoundScript; public: - static Script Create(string script); + static Script* Create(string script); Diagnostics* Diagnostics; ~Script(); @@ -37,6 +38,10 @@ public: EvalValue* GetLastValue(){ return _lastValue; }; + + EvalValue* GetVariable(const string& key){ + return _scopeVariables.at(HashedString(key).GetHash()); + } }; diff --git a/src/Utilities/HashedString.hpp b/src/Utilities/HashedString.hpp new file mode 100644 index 0000000..b276f55 --- /dev/null +++ b/src/Utilities/HashedString.hpp @@ -0,0 +1,24 @@ + +#ifndef PORYGONLANG_HASHEDSTRING_HPP +#define PORYGONLANG_HASHEDSTRING_HPP + +#include + +class HashedString{ + int _hash; + static unsigned constexpr const_hash(char const *input) { + return *input ? + static_cast(*input) + 33 * const_hash(input + 1) : + 5381; + } +public: + explicit HashedString(std::string s){ + _hash = const_hash(s.c_str()); + } + + const int GetHash(){ + return _hash; + } +}; + +#endif //PORYGONLANG_HASHEDSTRING_HPP diff --git a/tests/integration/DiagnosticsTests.cpp b/tests/integration/DiagnosticsTests.cpp index 977faa0..4b719e6 100644 --- a/tests/integration/DiagnosticsTests.cpp +++ b/tests/integration/DiagnosticsTests.cpp @@ -4,9 +4,9 @@ #include "../src/Script.hpp" TEST_CASE( "Diagnostic invalid character", "[integration]" ) { - Script script = Script::Create("1 + 1 @"); - REQUIRE(script.Diagnostics -> HasErrors()); - auto diags = script.Diagnostics -> GetDiagnostics(); + auto script = Script::Create("1 + 1 @"); + REQUIRE(script->Diagnostics -> HasErrors()); + auto diags = script->Diagnostics -> GetDiagnostics(); REQUIRE(diags.size() == 1); CHECK(diags[0].GetCode() == DiagnosticCode::UnexpectedCharacter); CHECK(diags[0].GetStartPosition() == 6); @@ -14,9 +14,9 @@ TEST_CASE( "Diagnostic invalid character", "[integration]" ) { } TEST_CASE( "Diagnostic invalid token", "[integration]" ) { - Script script = Script::Create("1 +/ 1"); - REQUIRE(script.Diagnostics -> HasErrors()); - auto diags = script.Diagnostics -> GetDiagnostics(); + auto script = Script::Create("1 +/ 1"); + REQUIRE(script->Diagnostics -> HasErrors()); + auto diags = script->Diagnostics -> GetDiagnostics(); REQUIRE(diags.size() == 1); CHECK(diags[0].GetCode() == DiagnosticCode::UnexpectedToken); CHECK(diags[0].GetStartPosition() == 3); diff --git a/tests/integration/EqualityOperationsTests.cpp b/tests/integration/EqualityOperationsTests.cpp index 6ac40dd..c60b6c0 100644 --- a/tests/integration/EqualityOperationsTests.cpp +++ b/tests/integration/EqualityOperationsTests.cpp @@ -4,55 +4,55 @@ #include "../src/Script.hpp" TEST_CASE( "True Equals True", "[integration]" ) { - Script script = Script::Create("true == true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true == true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "True Not Equals True", "[integration]" ) { - Script script = Script::Create("true == false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true == false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "True Nequals False", "[integration]" ) { - Script script = Script::Create("true ~= false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true ~= false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "True Not Nequals True", "[integration]" ) { - Script script = Script::Create("true ~= true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true ~= true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "False Equals False", "[integration]" ) { - Script script = Script::Create("false == false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("false == false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "10 Equals 10", "[integration]" ) { - Script script = Script::Create("10 == 10"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("10 == 10"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "10 Not Equals 5", "[integration]" ) { - Script script = Script::Create("10 == 5"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("10 == 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } diff --git a/tests/integration/LogicalOperationsTests.cpp b/tests/integration/LogicalOperationsTests.cpp index 024e86b..a25b9b5 100644 --- a/tests/integration/LogicalOperationsTests.cpp +++ b/tests/integration/LogicalOperationsTests.cpp @@ -3,92 +3,92 @@ #include "../src/Script.hpp" TEST_CASE( "Basic True", "[integration]" ) { - Script script = Script::Create("true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "Basic False", "[integration]" ) { - Script script = Script::Create("false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "True and True", "[integration]" ) { - Script script = Script::Create("true and true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true and true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "True and False", "[integration]" ) { - Script script = Script::Create("true and false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true and false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "False and True", "[integration]" ) { - Script script = Script::Create("false and true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("false and true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "False and False", "[integration]" ) { - Script script = Script::Create("false and false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("false and false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "True or True", "[integration]" ) { - Script script = Script::Create("true or true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true or true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "True or False", "[integration]" ) { - Script script = Script::Create("true or false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("true or false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "False or True", "[integration]" ) { - Script script = Script::Create("false or true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("false or true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } TEST_CASE( "False or False", "[integration]" ) { - Script script = Script::Create("false or false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("false or false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "Not True", "[integration]" ) { - Script script = Script::Create("not true"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("not true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(!lastValue->EvaluateBool()); } TEST_CASE( "Not False", "[integration]" ) { - Script script = Script::Create("not false"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("not false"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateBool()); } diff --git a/tests/integration/NumericalOperationsTests.cpp b/tests/integration/NumericalOperationsTests.cpp index b11e650..8563c0e 100644 --- a/tests/integration/NumericalOperationsTests.cpp +++ b/tests/integration/NumericalOperationsTests.cpp @@ -3,75 +3,75 @@ #include "../src/Script.hpp" TEST_CASE( "Integer Negation", "[integration]" ) { - Script script = Script::Create("-60"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("-60"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateInteger() == -60); } TEST_CASE( "Float Negation", "[integration]" ) { - Script script = Script::Create("-5.65"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("-5.65"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateFloat() == Approx(-5.65)); } TEST_CASE( "Integer Addition", "[integration]" ) { - Script script = Script::Create("1 + 5"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("1 + 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateInteger() == 6); } TEST_CASE( "Integer Subtraction", "[integration]" ) { - Script script = Script::Create("1 - 5"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("1 - 5"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateInteger() == -4); } TEST_CASE( "Integer Multiplication", "[integration]" ) { - Script script = Script::Create("5 * 8"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("5 * 8"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateInteger() == 40); } TEST_CASE( "Integer Division", "[integration]" ) { - Script script = Script::Create("40 / 8"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("40 / 8"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateInteger() == 5); } TEST_CASE( "Float Addition", "[integration]" ) { - Script script = Script::Create("1.2 + 5.34"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("1.2 + 5.34"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateFloat() == 6.54); } TEST_CASE( "Float Subtraction", "[integration]" ) { - Script script = Script::Create("1.8 - 5.14"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("1.8 - 5.14"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateFloat() == -3.34); } TEST_CASE( "Float Multiplication", "[integration]" ) { - Script script = Script::Create("5.2 * 8.9"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("5.2 * 8.9"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateFloat() == 46.28); } TEST_CASE( "Float Division", "[integration]" ) { - Script script = Script::Create("95.18 / 8.87"); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("95.18 / 8.87"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateFloat() == Approx(10.7305524239)); } #endif diff --git a/tests/integration/StringOperationsTests.cpp b/tests/integration/StringOperationsTests.cpp index db7d695..19fdfa5 100644 --- a/tests/integration/StringOperationsTests.cpp +++ b/tests/integration/StringOperationsTests.cpp @@ -5,18 +5,18 @@ TEST_CASE( "Simple String", "[integration]" ) { - Script script = Script::Create("\"foo bar\""); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("\"foo bar\""); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateString() == "foo bar"); } TEST_CASE( "String Concat", "[integration]" ) { - Script script = Script::Create("\"foo\" + \"bar\""); - REQUIRE(!script.Diagnostics -> HasErrors()); - script.Evaluate(); - auto lastValue = script.GetLastValue(); + auto script = Script::Create("\"foo\" + \"bar\""); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + auto lastValue = script->GetLastValue(); REQUIRE(lastValue->EvaluateString() == "foobar"); } diff --git a/tests/integration/Variables.cpp b/tests/integration/Variables.cpp new file mode 100644 index 0000000..daa9806 --- /dev/null +++ b/tests/integration/Variables.cpp @@ -0,0 +1,13 @@ +#ifdef TESTS_BUILD +#include +#include "../src/Script.hpp" + +TEST_CASE( "Create script variable", "[integration]" ) { + Script* script = Script::Create("foo = true"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto variable = script->GetVariable("foo"); + REQUIRE(variable == nullptr); +} + + +#endif diff --git a/tests/parser/ParserTests.cpp b/tests/parser/ParserTests.cpp index 1f9ce70..4455fe3 100644 --- a/tests/parser/ParserTests.cpp +++ b/tests/parser/ParserTests.cpp @@ -168,7 +168,7 @@ TEST_CASE( "Parse Global Assignment", "[parser]" ) { REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Assignment); auto assignment = (ParsedAssignmentStatement*)firstStatement; REQUIRE(!assignment -> IsLocal()); - REQUIRE(assignment->GetIdentifier() == "foo"); + REQUIRE(assignment->GetIdentifier().GetHash() == HashedString("foo").GetHash()); REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue()); } @@ -187,7 +187,7 @@ TEST_CASE( "Parse local Assignment", "[parser]" ) { REQUIRE(firstStatement -> GetKind() == ParsedStatementKind::Assignment); auto assignment = (ParsedAssignmentStatement*)firstStatement; REQUIRE(assignment -> IsLocal()); - REQUIRE(assignment->GetIdentifier() == "foo"); + REQUIRE(assignment->GetIdentifier().GetHash() == HashedString("foo").GetHash()); REQUIRE(((LiteralBoolExpression*)assignment->GetExpression()) -> GetValue()); }