Make functions be able to call themselves
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Deukhoofd 2019-06-08 16:02:21 +02:00
parent 7d75131822
commit 7ed53193de
No known key found for this signature in database
GPG Key ID: B4C087AC81641654
6 changed files with 49 additions and 29 deletions

View File

@ -77,35 +77,35 @@ std::shared_ptr<ScriptType> ParseTypeIdentifier(HashedString s){
BoundStatement *Binder::BindFunctionDeclarationStatement(ParsedStatement *statement) { BoundStatement *Binder::BindFunctionDeclarationStatement(ParsedStatement *statement) {
auto functionStatement = (ParsedFunctionDeclarationStatement*) statement; auto functionStatement = (ParsedFunctionDeclarationStatement*) statement;
auto parameters = functionStatement->GetParameters(); auto parameters = functionStatement->GetParameters();
auto parameterTypes = new vector<std::shared_ptr<ScriptType>>(parameters.size()); auto parameterTypes = vector<shared_ptr<ScriptType>>(parameters.size());
auto parameterKeys = new vector<std::shared_ptr<BoundVariableKey>>(parameters.size()); auto parameterKeys = vector<shared_ptr<BoundVariableKey>>(parameters.size());
this->_scope->GoInnerScope(); this->_scope->GoInnerScope();
for (int i = 0; i < parameters.size(); i++){ for (int i = 0; i < parameters.size(); i++){
auto var = parameters[i]; auto var = parameters[i];
auto parsedType = ParseTypeIdentifier(var->GetType()); auto parsedType = ParseTypeIdentifier(var->GetType());
parameterTypes->at(i) = parsedType; parameterTypes.at(i) = parsedType;
auto parameterAssignment = this->_scope->CreateExplicitLocal(var->GetIdentifier().GetHash(), parsedType); auto parameterAssignment = this->_scope->CreateExplicitLocal(var->GetIdentifier().GetHash(), parsedType);
if (parameterAssignment.GetResult() == VariableAssignmentResult::Ok){ if (parameterAssignment.GetResult() == VariableAssignmentResult::Ok){
parameterKeys -> at(i) = std::shared_ptr<BoundVariableKey>(parameterAssignment.GetKey()); parameterKeys.at(i) = std::shared_ptr<BoundVariableKey>(parameterAssignment.GetKey());
} }
else{ else{
//TODO: log error //TODO: log error
continue; continue;
} }
} }
auto identifier = functionStatement->GetIdentifier();
auto returnType = make_shared<ScriptType>(TypeClass::Nil);
auto type = make_shared<FunctionScriptType>(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()); auto boundBlock = this -> BindBlockStatement(functionStatement->GetBlock());
this->_scope->GoOuterScope(); this->_scope->GoOuterScope();
auto identifier = functionStatement->GetIdentifier();
auto returnType = std::make_shared<ScriptType>(TypeClass::Nil);
auto parameterTypesPtr = std::shared_ptr<std::vector<std::shared_ptr<ScriptType>>>(parameterTypes);
auto parameterKeysPtr = std::shared_ptr<std::vector<std::shared_ptr<BoundVariableKey>>>(parameterKeys);
auto type = make_shared<FunctionScriptType>(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 BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement*)boundBlock);
} }
return new BoundBadStatement();
}
BoundStatement *Binder::BindReturnStatement(ParsedStatement* statement){ BoundStatement *Binder::BindReturnStatement(ParsedStatement* statement){
auto expression = ((ParsedReturnStatement*)statement)->GetExpression(); auto expression = ((ParsedReturnStatement*)statement)->GetExpression();
@ -354,7 +354,7 @@ BoundExpression* Binder::BindFunctionCall(FunctionCallExpression* expression){
auto functionType = std::dynamic_pointer_cast<FunctionScriptType>(type); auto functionType = std::dynamic_pointer_cast<FunctionScriptType>(type);
auto parameterTypes = functionType->GetParameterTypes(); auto parameterTypes = functionType->GetParameterTypes();
auto givenParameters = expression->GetParameters(); auto givenParameters = expression->GetParameters();
if (parameterTypes->size() != givenParameters.size()){ if (parameterTypes.size() != givenParameters.size()){
this->_scriptData->Diagnostics->LogError(DiagnosticCode::ParameterCountMismatch, expression->GetStartPosition(), this->_scriptData->Diagnostics->LogError(DiagnosticCode::ParameterCountMismatch, expression->GetStartPosition(),
expression->GetLength()); expression->GetLength());
return new BoundBadExpression(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++){ for (int i = 0; i < givenParameters.size(); i++){
auto parameter = givenParameters[i]; auto parameter = givenParameters[i];
auto boundParameter = this -> BindExpression(parameter); 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(), this->_scriptData->Diagnostics->LogError(DiagnosticCode::ParameterTypeMismatch, parameter->GetStartPosition(),
parameter->GetLength()); parameter->GetLength());
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength()); return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());

View File

@ -5,7 +5,7 @@
#include "BoundStatements/BoundStatement.hpp" #include "BoundStatements/BoundStatement.hpp"
#include "../Script.hpp" #include "../Script.hpp"
#include "BoundVariables/BoundScope.hpp" #include "BoundVariables/BoundScope.hpp"
using namespace std;
class Binder { class Binder {
Script* _scriptData; Script* _scriptData;

View File

@ -188,13 +188,13 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunctionCallExpression(BoundExpression*
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType()); auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType());
auto parameterTypes = type->GetParameterTypes(); auto parameterTypes = type->GetParameterTypes();
auto parameterKeys = type->GetParameterKeys(); 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 parameter = parameters[i];
auto requiredType = parameterTypes->at(i); auto requiredType = parameterTypes.at(i);
if (*parameter->GetType() != requiredType.get()){ if (*parameter->GetType() != requiredType.get()){
throw EvaluationException("Passed wrong type to function."); 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->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone());
} }
this->EvaluateBlockStatement(function->GetInnerBlock().get()); this->EvaluateBlockStatement(function->GetInnerBlock().get());
@ -208,13 +208,13 @@ shared_ptr<EvalValue> Evaluator::EvaluateFunction(ScriptFunctionEvalValue *funct
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType()); auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType());
auto parameterTypes = type->GetParameterTypes(); auto parameterTypes = type->GetParameterTypes();
auto parameterKeys = type->GetParameterKeys(); 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 parameter = parameters[i];
auto requiredType = parameterTypes->at(i); auto requiredType = parameterTypes.at(i);
if (*parameter->GetType() != requiredType.get()){ if (*parameter->GetType() != requiredType.get()){
throw EvaluationException("Passed wrong type to function."); 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->_evaluationScope->CreateVariable(key->GetScopeId(), key->GetIdentifier(), parameter->Clone());
} }
this->EvaluateBlockStatement(function->GetInnerBlock().get()); this->EvaluateBlockStatement(function->GetInnerBlock().get());

View File

@ -344,6 +344,7 @@ ParsedExpression *Parser::ParseFunctionCallExpression(ParsedExpression* function
return new BadExpression(peeked->GetStartPosition(), peeked->GetLength()); return new BadExpression(peeked->GetStartPosition(), peeked->GetLength());
} }
} }
this -> Next();
auto start = functionExpression->GetStartPosition(); auto start = functionExpression->GetStartPosition();
return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start); return new FunctionCallExpression(functionExpression, parameters, start, peeked->GetEndPosition() - start);
} }

View File

@ -80,11 +80,11 @@ public:
class FunctionScriptType : public ScriptType{ class FunctionScriptType : public ScriptType{
shared_ptr<ScriptType> _returnType; shared_ptr<ScriptType> _returnType;
shared_ptr<vector<shared_ptr<ScriptType>>> _parameterTypes; vector<shared_ptr<ScriptType>> _parameterTypes;
shared_ptr<vector<shared_ptr<BoundVariableKey>>> _parameterKeys; vector<shared_ptr<BoundVariableKey>> _parameterKeys;
public: public:
FunctionScriptType(std::shared_ptr<ScriptType> returnType, shared_ptr<vector<shared_ptr<ScriptType>>> parameterTypes, FunctionScriptType(std::shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes,
shared_ptr<vector<shared_ptr<BoundVariableKey>>> parameterKeys) vector<shared_ptr<BoundVariableKey>> parameterKeys)
: ScriptType(TypeClass::Function){ : ScriptType(TypeClass::Function){
_returnType = std::move(returnType); _returnType = std::move(returnType);
_parameterTypes = std::move(parameterTypes); _parameterTypes = std::move(parameterTypes);
@ -94,11 +94,11 @@ public:
return _returnType; return _returnType;
} }
shared_ptr<vector<shared_ptr<ScriptType>>> GetParameterTypes(){ vector<shared_ptr<ScriptType>> GetParameterTypes(){
return _parameterTypes; return _parameterTypes;
} }
shared_ptr<vector<shared_ptr<BoundVariableKey>>> GetParameterKeys(){ vector<shared_ptr<BoundVariableKey>> GetParameterKeys(){
return _parameterKeys; return _parameterKeys;
} }
}; };

View File

@ -84,5 +84,24 @@ TEST_CASE( "Define script function and return", "[integration]" ) {
delete script; 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 #endif