From 7ed53193de074326106c8ff6c4304cf357d30666 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sat, 8 Jun 2019 16:02:21 +0200 Subject: [PATCH] Make functions be able to call themselves --- src/Binder/Binder.cpp | 32 ++++++++++++++++---------------- src/Binder/Binder.hpp | 2 +- src/Evaluator/Evaluator.cpp | 12 ++++++------ src/Parser/Parser.cpp | 1 + src/ScriptType.hpp | 12 ++++++------ tests/integration/Functions.cpp | 19 +++++++++++++++++++ 6 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index a0ef6b6..2907239 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -77,34 +77,34 @@ std::shared_ptr ParseTypeIdentifier(HashedString s){ BoundStatement *Binder::BindFunctionDeclarationStatement(ParsedStatement *statement) { auto functionStatement = (ParsedFunctionDeclarationStatement*) statement; auto parameters = functionStatement->GetParameters(); - auto parameterTypes = new vector>(parameters.size()); - auto parameterKeys = new vector>(parameters.size()); + auto parameterTypes = vector>(parameters.size()); + auto parameterKeys = vector>(parameters.size()); + this->_scope->GoInnerScope(); for (int i = 0; i < parameters.size(); i++){ auto var = parameters[i]; auto parsedType = ParseTypeIdentifier(var->GetType()); - parameterTypes->at(i) = parsedType; + parameterTypes.at(i) = parsedType; auto parameterAssignment = this->_scope->CreateExplicitLocal(var->GetIdentifier().GetHash(), parsedType); if (parameterAssignment.GetResult() == VariableAssignmentResult::Ok){ - parameterKeys -> at(i) = std::shared_ptr(parameterAssignment.GetKey()); + parameterKeys.at(i) = std::shared_ptr(parameterAssignment.GetKey()); } else{ //TODO: log error continue; } } + + auto identifier = functionStatement->GetIdentifier(); + auto returnType = make_shared(TypeClass::Nil); + auto type = make_shared(returnType, parameterTypes, parameterKeys); + auto assignment = this->_scope->AssignVariable(identifier.GetHash(), type); + if (assignment.GetResult() != VariableAssignmentResult::Ok){ + return new BoundBadStatement(); + } auto boundBlock = this -> BindBlockStatement(functionStatement->GetBlock()); this->_scope->GoOuterScope(); - auto identifier = functionStatement->GetIdentifier(); - auto returnType = std::make_shared(TypeClass::Nil); - auto parameterTypesPtr = std::shared_ptr>>(parameterTypes); - auto parameterKeysPtr = std::shared_ptr>>(parameterKeys); - auto type = make_shared(returnType, parameterTypesPtr, parameterKeysPtr); - auto assignment = this->_scope->AssignVariable(identifier.GetHash(), type); - if (assignment.GetResult() == VariableAssignmentResult::Ok){ - return new BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement*)boundBlock); - } - return new BoundBadStatement(); + return new BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement*)boundBlock); } BoundStatement *Binder::BindReturnStatement(ParsedStatement* statement){ @@ -354,7 +354,7 @@ BoundExpression* Binder::BindFunctionCall(FunctionCallExpression* expression){ auto functionType = std::dynamic_pointer_cast(type); auto parameterTypes = functionType->GetParameterTypes(); auto givenParameters = expression->GetParameters(); - if (parameterTypes->size() != givenParameters.size()){ + if (parameterTypes.size() != givenParameters.size()){ this->_scriptData->Diagnostics->LogError(DiagnosticCode::ParameterCountMismatch, expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); @@ -363,7 +363,7 @@ BoundExpression* Binder::BindFunctionCall(FunctionCallExpression* expression){ for (int i = 0; i < givenParameters.size(); i++){ auto parameter = givenParameters[i]; auto boundParameter = this -> BindExpression(parameter); - if (boundParameter->GetType().get()->operator!=(parameterTypes.get()-> at(i).get())){ + if (boundParameter->GetType().get()->operator!=(parameterTypes.at(i).get())){ this->_scriptData->Diagnostics->LogError(DiagnosticCode::ParameterTypeMismatch, parameter->GetStartPosition(), parameter->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); diff --git a/src/Binder/Binder.hpp b/src/Binder/Binder.hpp index 118a34b..3cdc6bc 100644 --- a/src/Binder/Binder.hpp +++ b/src/Binder/Binder.hpp @@ -5,7 +5,7 @@ #include "BoundStatements/BoundStatement.hpp" #include "../Script.hpp" #include "BoundVariables/BoundScope.hpp" - +using namespace std; class Binder { Script* _scriptData; diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index 93efac6..90d96bf 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -188,13 +188,13 @@ shared_ptr Evaluator::EvaluateFunctionCallExpression(BoundExpression* auto type = std::dynamic_pointer_cast(function->GetType()); auto parameterTypes = type->GetParameterTypes(); auto parameterKeys = type->GetParameterKeys(); - for (int i = 0; i < parameterTypes->size() && i < parameterKeys->size() && i < parameters.size(); i++){ + for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){ auto parameter = parameters[i]; - auto requiredType = parameterTypes->at(i); + auto requiredType = parameterTypes.at(i); if (*parameter->GetType() != requiredType.get()){ throw EvaluationException("Passed wrong type to function."); } - auto key = parameterKeys->at(i); + auto key = parameterKeys.at(i); this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone()); } this->EvaluateBlockStatement(function->GetInnerBlock().get()); @@ -208,13 +208,13 @@ shared_ptr Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct auto type = std::dynamic_pointer_cast(function->GetType()); auto parameterTypes = type->GetParameterTypes(); auto parameterKeys = type->GetParameterKeys(); - for (int i = 0; i < parameterTypes->size() && i < parameterKeys->size() && i < parameters.size(); i++){ + for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++){ auto parameter = parameters[i]; - auto requiredType = parameterTypes->at(i); + auto requiredType = parameterTypes.at(i); if (*parameter->GetType() != requiredType.get()){ throw EvaluationException("Passed wrong type to function."); } - auto key = parameterKeys->at(i); + auto key = parameterKeys.at(i); this->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone()); } this->EvaluateBlockStatement(function->GetInnerBlock().get()); diff --git a/src/Parser/Parser.cpp b/src/Parser/Parser.cpp index a77ed1c..d91ba4a 100644 --- a/src/Parser/Parser.cpp +++ b/src/Parser/Parser.cpp @@ -344,6 +344,7 @@ ParsedExpression *Parser::ParseFunctionCallExpression(ParsedExpression* function return new BadExpression(peeked->GetStartPosition(), peeked->GetLength()); } } + this -> Next(); auto start = functionExpression->GetStartPosition(); return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start); } diff --git a/src/ScriptType.hpp b/src/ScriptType.hpp index d9d78c8..87acefd 100644 --- a/src/ScriptType.hpp +++ b/src/ScriptType.hpp @@ -80,11 +80,11 @@ public: class FunctionScriptType : public ScriptType{ shared_ptr _returnType; - shared_ptr>> _parameterTypes; - shared_ptr>> _parameterKeys; + vector> _parameterTypes; + vector> _parameterKeys; public: - FunctionScriptType(std::shared_ptr returnType, shared_ptr>> parameterTypes, - shared_ptr>> parameterKeys) + FunctionScriptType(std::shared_ptr returnType, vector> parameterTypes, + vector> parameterKeys) : ScriptType(TypeClass::Function){ _returnType = std::move(returnType); _parameterTypes = std::move(parameterTypes); @@ -94,11 +94,11 @@ public: return _returnType; } - shared_ptr>> GetParameterTypes(){ + vector> GetParameterTypes(){ return _parameterTypes; } - shared_ptr>> GetParameterKeys(){ + vector> GetParameterKeys(){ return _parameterKeys; } }; diff --git a/tests/integration/Functions.cpp b/tests/integration/Functions.cpp index 2afbe9c..d6296a3 100644 --- a/tests/integration/Functions.cpp +++ b/tests/integration/Functions.cpp @@ -84,5 +84,24 @@ TEST_CASE( "Define script function and return", "[integration]" ) { delete script; } +TEST_CASE( "Functions can call themselves", "[integration]" ) { + Script* script = Script::Create( + "val = 0\n" + "function add() \n" + "if val < 5 then\n" + "val = val + 1\n" + "add()\n" + "end\n" + "end"); + REQUIRE(!script->Diagnostics -> HasErrors()); + script->Evaluate(); + script->CallFunction("add", {}); + + auto variable = script->GetVariable("val"); + REQUIRE(variable->GetType()->GetClass() == TypeClass::Number); + REQUIRE(variable->EvaluateInteger() == 5); + + delete script; +} #endif