Make functions be able to call themselves
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
7d75131822
commit
7ed53193de
|
@ -77,34 +77,34 @@ 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();
|
return new BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement*)boundBlock);
|
||||||
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 BoundBadStatement();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundStatement *Binder::BindReturnStatement(ParsedStatement* statement){
|
BoundStatement *Binder::BindReturnStatement(ParsedStatement* statement){
|
||||||
|
@ -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());
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue