Implements support for functions with the same name, but different parameters
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
This commit is contained in:
parent
24c560b52d
commit
db2d731b06
|
@ -3,8 +3,9 @@
|
|||
#include "Binder.hpp"
|
||||
#include "../TableScriptType.hpp"
|
||||
#include "BoundExpressions/BoundTableExpression.hpp"
|
||||
#include "BoundExpressions/BoundFunctionCallExpression.hpp"
|
||||
#include "../UserData/UserDataScriptType.hpp"
|
||||
#include <memory>
|
||||
#include "../FunctionScriptType.hpp"
|
||||
|
||||
using namespace Porygon::Parser;
|
||||
|
||||
|
@ -158,19 +159,38 @@ namespace Porygon::Binder {
|
|||
|
||||
auto identifier = functionStatement->GetIdentifier();
|
||||
auto returnType = make_shared<ScriptType>(TypeClass::Nil);
|
||||
auto type = make_shared<FunctionScriptType>(returnType, parameterTypes, parameterKeys, scopeIndex);
|
||||
this->_currentFunction = type;
|
||||
auto option = new ScriptFunctionOption(returnType, parameterTypes, parameterKeys);
|
||||
this->_currentFunction = option;
|
||||
|
||||
auto assignment = this->_scope->AssignVariable(identifier, type);
|
||||
if (assignment.GetResult() != VariableAssignmentResult::Ok) {
|
||||
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
|
||||
statement->GetLength());
|
||||
return new BoundBadStatement();
|
||||
shared_ptr<GenericFunctionScriptType> type;
|
||||
auto scope = this -> _scope -> Exists(identifier);
|
||||
BoundVariableKey* assignmentKey;
|
||||
if (scope >= 0){
|
||||
auto var = this -> _scope -> GetVariable(scope, identifier);
|
||||
auto varType =var->GetType();
|
||||
if (varType->GetClass() != TypeClass::Function){
|
||||
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
|
||||
statement->GetLength());
|
||||
}
|
||||
type = dynamic_pointer_cast<GenericFunctionScriptType>(varType);
|
||||
type->RegisterFunctionOption(option);
|
||||
assignmentKey = new BoundVariableKey(identifier, scope, false);
|
||||
} else{
|
||||
type = make_shared<GenericFunctionScriptType>();
|
||||
type->RegisterFunctionOption(option);
|
||||
auto assignment = this->_scope->AssignVariable(identifier, type);
|
||||
if (assignment.GetResult() != VariableAssignmentResult::Ok) {
|
||||
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::CantAssignVariable, statement->GetStartPosition(),
|
||||
statement->GetLength());
|
||||
return new BoundBadStatement();
|
||||
}
|
||||
assignmentKey = assignment.GetKey();
|
||||
}
|
||||
|
||||
auto boundBlock = this->BindBlockStatement(functionStatement->GetBlock());
|
||||
this->_scope->GoOuterScope();
|
||||
this->_currentFunction = nullptr;
|
||||
return new BoundFunctionDeclarationStatement(type, assignment.GetKey(), (BoundBlockStatement *) boundBlock);
|
||||
return new BoundFunctionDeclarationStatement(type, assignmentKey, (BoundBlockStatement *) boundBlock);
|
||||
}
|
||||
|
||||
BoundStatement *Binder::BindReturnStatement(const ParsedStatement *statement) {
|
||||
|
@ -558,28 +578,23 @@ namespace Porygon::Binder {
|
|||
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
||||
}
|
||||
auto functionType = std::dynamic_pointer_cast<GenericFunctionScriptType>(type);
|
||||
auto parameterTypes = functionType->GetParameterTypes();
|
||||
auto givenParameters = expression->GetParameters();
|
||||
if (parameterTypes.size() != givenParameters->size()) {
|
||||
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ParameterCountMismatch,
|
||||
auto givenParameterTypes = vector<shared_ptr<ScriptType>>(givenParameters->size());
|
||||
vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size());
|
||||
for (int i = 0; i < givenParameters->size(); i++){
|
||||
boundParameters[i] = this -> BindExpression(givenParameters->at(i));
|
||||
givenParameterTypes[i] = boundParameters[i]->GetType();
|
||||
}
|
||||
|
||||
auto functionOption = functionType->GetFunctionOption(givenParameterTypes);
|
||||
if (functionOption == nullptr){
|
||||
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
|
||||
expression->GetStartPosition(),
|
||||
expression->GetLength());
|
||||
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
||||
}
|
||||
vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size());
|
||||
for (int i = 0; i < givenParameters->size(); i++) {
|
||||
auto parameter = givenParameters->at(i);
|
||||
auto boundParameter = this->BindExpression(parameter);
|
||||
if (boundParameter->GetType().get()->operator!=(parameterTypes.at(i).get())) {
|
||||
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::ParameterTypeMismatch,
|
||||
parameter->GetStartPosition(),
|
||||
parameter->GetLength());
|
||||
return new BoundBadExpression(expression->GetStartPosition(), expression->GetLength());
|
||||
}
|
||||
boundParameters[i] = boundParameter;
|
||||
}
|
||||
|
||||
return new BoundFunctionCallExpression(functionExpression, boundParameters, functionType.get()->GetReturnType(),
|
||||
return new BoundFunctionCallExpression(functionExpression, boundParameters, functionOption, functionOption->GetReturnType(),
|
||||
expression->GetStartPosition(), expression->GetLength());
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "../Script.hpp"
|
||||
#include "BoundVariables/BoundScope.hpp"
|
||||
#include "../Parser/ParsedExpressions/ParsedTableExpression.hpp"
|
||||
#include "../FunctionScriptType.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace Porygon::Parser;
|
||||
|
@ -14,7 +15,7 @@ namespace Porygon::Binder {
|
|||
class Binder {
|
||||
Porygon::Script *_scriptData;
|
||||
BoundScope *_scope;
|
||||
shared_ptr<FunctionScriptType> _currentFunction;
|
||||
GenericFunctionOption* _currentFunction;
|
||||
|
||||
~Binder();
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../../ScriptType.hpp"
|
||||
#include "../BoundOperators.hpp"
|
||||
#include "../BoundVariables/BoundVariableKey.hpp"
|
||||
#include "../../FunctionScriptType.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -227,36 +228,6 @@ namespace Porygon::Binder {
|
|||
}
|
||||
};
|
||||
|
||||
class BoundFunctionCallExpression : public BoundExpression {
|
||||
const BoundExpression *_functionExpression;
|
||||
const vector<BoundExpression *> _parameters;
|
||||
public:
|
||||
BoundFunctionCallExpression(BoundExpression *functionExpression, vector<BoundExpression *> parameters,
|
||||
shared_ptr<ScriptType> result,
|
||||
unsigned int start, unsigned int length)
|
||||
: BoundExpression(start, length, std::move(result)), _functionExpression(functionExpression),
|
||||
_parameters(std::move(parameters)) {}
|
||||
|
||||
~BoundFunctionCallExpression() final {
|
||||
delete _functionExpression;
|
||||
for (auto p : _parameters) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
const BoundExpressionKind GetKind() const final {
|
||||
return BoundExpressionKind::FunctionCall;
|
||||
}
|
||||
|
||||
const BoundExpression *GetFunctionExpression() const {
|
||||
return _functionExpression;
|
||||
}
|
||||
|
||||
const vector<BoundExpression *> *GetParameters() const {
|
||||
return &_parameters;
|
||||
}
|
||||
};
|
||||
|
||||
class BoundIndexExpression : public BoundExpression {
|
||||
const BoundExpression *_indexableExpression;
|
||||
const BoundExpression *_indexExpression;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include "BoundFunctionCallExpression.hpp"
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef PORYGONLANG_BOUNDFUNCTIONCALLEXPRESSION_HPP
|
||||
#define PORYGONLANG_BOUNDFUNCTIONCALLEXPRESSION_HPP
|
||||
|
||||
#include "BoundExpression.hpp"
|
||||
|
||||
namespace Porygon::Binder {
|
||||
class BoundFunctionCallExpression : public Porygon::Binder::BoundExpression {
|
||||
const BoundExpression *_functionExpression;
|
||||
const vector<BoundExpression *> _parameters;
|
||||
const Porygon::GenericFunctionOption *_option;
|
||||
public:
|
||||
BoundFunctionCallExpression(BoundExpression *functionExpression, vector<BoundExpression *> parameters,
|
||||
Porygon::GenericFunctionOption *option, shared_ptr<Porygon::ScriptType> result,
|
||||
unsigned int start, unsigned int length)
|
||||
: BoundExpression(start, length, move(result)), _functionExpression(functionExpression),
|
||||
_parameters(move(parameters)), _option(option) {}
|
||||
|
||||
~BoundFunctionCallExpression() final {
|
||||
delete _functionExpression;
|
||||
for (auto p : _parameters) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
const Porygon::Binder::BoundExpressionKind GetKind() const final {
|
||||
return Porygon::Binder::BoundExpressionKind::FunctionCall;
|
||||
}
|
||||
|
||||
const BoundExpression *GetFunctionExpression() const {
|
||||
return _functionExpression;
|
||||
}
|
||||
|
||||
const vector<BoundExpression *> *GetParameters() const {
|
||||
return &_parameters;
|
||||
}
|
||||
|
||||
const Porygon::GenericFunctionOption *GetFunctionOption() const {
|
||||
return _option;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include "BoundExpression.hpp"
|
||||
|
||||
#endif //PORYGONLANG_BOUNDFUNCTIONCALLEXPRESSION_HPP
|
|
@ -1,19 +1,18 @@
|
|||
#include <utility>
|
||||
|
||||
|
||||
#ifndef PORYGONLANG_BOUNDFUNCTIONDECLARATIONSTATEMENT_HPP
|
||||
#define PORYGONLANG_BOUNDFUNCTIONDECLARATIONSTATEMENT_HPP
|
||||
|
||||
#include <memory>
|
||||
#include "BoundStatement.hpp"
|
||||
#include "../../FunctionScriptType.hpp"
|
||||
|
||||
namespace Porygon::Binder {
|
||||
class BoundFunctionDeclarationStatement : public BoundStatement {
|
||||
const BoundVariableKey *_key;
|
||||
const std::shared_ptr<BoundBlockStatement> _block;
|
||||
const std::shared_ptr<FunctionScriptType> _type;
|
||||
const std::shared_ptr<GenericFunctionScriptType> _type;
|
||||
public:
|
||||
BoundFunctionDeclarationStatement(std::shared_ptr<FunctionScriptType> type, BoundVariableKey *key,
|
||||
BoundFunctionDeclarationStatement(std::shared_ptr<GenericFunctionScriptType> type, BoundVariableKey *key,
|
||||
BoundBlockStatement *block)
|
||||
: _key(key), _block(block), _type(std::move(type)) {
|
||||
}
|
||||
|
@ -34,12 +33,10 @@ namespace Porygon::Binder {
|
|||
return _block;
|
||||
}
|
||||
|
||||
const std::shared_ptr<FunctionScriptType> GetType() const {
|
||||
const std::shared_ptr<GenericFunctionScriptType> GetType() const {
|
||||
return _type;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include "BoundStatement.hpp"
|
||||
|
||||
#endif //PORYGONLANG_BOUNDFUNCTIONDECLARATIONSTATEMENT_HPP
|
||||
|
|
|
@ -17,8 +17,6 @@ namespace Porygon::Diagnostics {
|
|||
CantAssignVariable,
|
||||
VariableNotFound,
|
||||
ExpressionIsNotAFunction,
|
||||
ParameterCountMismatch,
|
||||
ParameterTypeMismatch,
|
||||
CantIndex,
|
||||
InvalidReturnType,
|
||||
ConditionNotABool,
|
||||
|
@ -27,7 +25,8 @@ namespace Porygon::Diagnostics {
|
|||
UserDataFieldNoGetter,
|
||||
UserDataFieldNoSetter,
|
||||
NumericalForArgumentNotANumber,
|
||||
CantIterateExpression
|
||||
CantIterateExpression,
|
||||
InvalidFunctionParameters
|
||||
};
|
||||
}
|
||||
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP
|
||||
|
|
|
@ -48,16 +48,16 @@ size_t DiagnosticsHolder::GetLineFromPosition(size_t i) {
|
|||
if (bottomLimit == topLimit){
|
||||
return bottomLimit;
|
||||
}
|
||||
size_t half = (topLimit - bottomLimit) / 2;
|
||||
size_t half = bottomLimit + ((topLimit - bottomLimit) / 2);
|
||||
size_t pos = _lineStarts[half];
|
||||
size_t length = _lineLength[half];
|
||||
if (pos < i && pos + length > i){
|
||||
return half;
|
||||
}
|
||||
if (pos > i){
|
||||
bottomLimit = half;
|
||||
} else if (pos < i){
|
||||
topLimit = half;
|
||||
} else if (pos < i){
|
||||
bottomLimit = half;
|
||||
} else{
|
||||
return half;
|
||||
}
|
||||
|
|
|
@ -4,24 +4,63 @@
|
|||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <unordered_map>
|
||||
#include "../../ScriptType.hpp"
|
||||
#include "EvalValue.hpp"
|
||||
#include "../../Binder/BoundStatements/BoundStatement.hpp"
|
||||
#include "../EvaluationScope/EvaluationScope.hpp"
|
||||
#include "../../FunctionScriptType.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Porygon::Evaluation {
|
||||
class GenericFunctionOption{
|
||||
public:
|
||||
virtual ~GenericFunctionOption() = default;
|
||||
};
|
||||
|
||||
class EvaluationScriptFunctionOption : public GenericFunctionOption{
|
||||
const std::shared_ptr<BoundBlockStatement> _innerBlock;
|
||||
const std::shared_ptr<EvaluationScope> _scope;
|
||||
|
||||
public:
|
||||
EvaluationScriptFunctionOption(const shared_ptr<BoundBlockStatement> innerBlock, const shared_ptr<EvaluationScope> scope)
|
||||
: _innerBlock(innerBlock), _scope(scope) {
|
||||
|
||||
}
|
||||
|
||||
const std::shared_ptr<BoundBlockStatement> &GetInnerBlock() const {
|
||||
return _innerBlock;
|
||||
}
|
||||
|
||||
const std::shared_ptr<EvaluationScope> &GetScope() const {
|
||||
return _scope;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class GenericFunctionEvalValue : public EvalValue{
|
||||
protected:
|
||||
const std::shared_ptr<GenericFunctionScriptType> _type;
|
||||
const std::size_t _hash;
|
||||
|
||||
std::vector<shared_ptr<GenericFunctionOption>> _options;
|
||||
public:
|
||||
GenericFunctionEvalValue(shared_ptr<GenericFunctionScriptType> type, size_t hash)
|
||||
: _type(move(type)),
|
||||
_hash(hash){
|
||||
}
|
||||
|
||||
const shared_ptr<EvalValue> Clone() const final {
|
||||
auto t = make_shared<GenericFunctionEvalValue>(_type, _hash);
|
||||
for (const auto& o: _options){
|
||||
t->_options.push_back(o);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
void RegisterOption(GenericFunctionOption* option){
|
||||
_options.push_back(shared_ptr<GenericFunctionOption>(option));
|
||||
}
|
||||
|
||||
const std::shared_ptr<ScriptType> GetType() const {
|
||||
|
@ -41,42 +80,9 @@ namespace Porygon::Evaluation {
|
|||
const std::size_t GetHashCode() const final {
|
||||
return _hash;
|
||||
}
|
||||
};
|
||||
|
||||
class ScriptFunctionEvalValue : public GenericFunctionEvalValue {
|
||||
const std::shared_ptr<BoundBlockStatement> _innerBlock;
|
||||
const std::shared_ptr<EvaluationScope> _scope;
|
||||
|
||||
explicit ScriptFunctionEvalValue(shared_ptr<BoundBlockStatement> innerBlock,
|
||||
shared_ptr<EvaluationScope> scope,
|
||||
shared_ptr<FunctionScriptType> type, size_t hash)
|
||||
: GenericFunctionEvalValue(move(type), hash),
|
||||
_innerBlock(std::move(innerBlock)),
|
||||
_scope(std::move(scope)){
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ScriptFunctionEvalValue(std::shared_ptr<BoundBlockStatement> innerBlock,
|
||||
std::shared_ptr<EvaluationScope> scope,
|
||||
std::shared_ptr<FunctionScriptType> type)
|
||||
: GenericFunctionEvalValue(move(type), rand()),
|
||||
_innerBlock(std::move(innerBlock)),
|
||||
_scope(std::move(scope)){
|
||||
}
|
||||
|
||||
|
||||
const shared_ptr<EvalValue> Clone() const final {
|
||||
// We don't run make_shared here as it can't call private constructors
|
||||
return shared_ptr<ScriptFunctionEvalValue>(new ScriptFunctionEvalValue(_innerBlock, _scope,
|
||||
dynamic_pointer_cast<FunctionScriptType>(_type), _hash));
|
||||
}
|
||||
|
||||
const std::shared_ptr<BoundBlockStatement> &GetInnerBlock() const {
|
||||
return _innerBlock;
|
||||
}
|
||||
|
||||
const std::shared_ptr<EvaluationScope> &GetScope() const {
|
||||
return _scope;
|
||||
const shared_ptr<GenericFunctionOption> GetOption(const size_t id) const{
|
||||
return this->_options.at(id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,10 +8,12 @@
|
|||
#include "EvalValues/ScriptFunctionEvalValue.hpp"
|
||||
#include "EvalValues/TableEvalValue.hpp"
|
||||
#include "../Binder/BoundExpressions/BoundTableExpression.hpp"
|
||||
#include "../Binder/BoundExpressions/BoundFunctionCallExpression.hpp"
|
||||
#include "../TableScriptType.hpp"
|
||||
#include "../UserData/UserDataFunction.hpp"
|
||||
#include "../Utilities/StringUtils.hpp"
|
||||
#include "EvalValues/NumericalTableEvalValue.hpp"
|
||||
#include "../FunctionScriptType.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace Porygon::Binder;
|
||||
|
@ -96,11 +98,16 @@ namespace Porygon::Evaluation {
|
|||
auto type = statement->GetType();
|
||||
auto key = statement->GetKey();
|
||||
auto block = statement->GetBlock();
|
||||
auto value = make_shared<ScriptFunctionEvalValue>(block, this->_evaluationScope, type);
|
||||
auto option = new Evaluation::EvaluationScriptFunctionOption(block, this->_evaluationScope);
|
||||
|
||||
if (key->IsCreation()) {
|
||||
auto value = make_shared<GenericFunctionEvalValue>(type, rand());
|
||||
value->RegisterOption(option);
|
||||
this->_evaluationScope->CreateVariable(key, value);
|
||||
} else {
|
||||
this->_evaluationScope->SetVariable(key, value);
|
||||
auto var = dynamic_pointer_cast<GenericFunctionEvalValue>(this -> _evaluationScope ->GetVariable(key));
|
||||
var->RegisterOption(option);
|
||||
this->_evaluationScope->SetVariable(key, var);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,20 +377,23 @@ namespace Porygon::Evaluation {
|
|||
}
|
||||
|
||||
auto type = std::dynamic_pointer_cast<GenericFunctionScriptType>(function->GetType());
|
||||
if (type -> IsScriptFunction()){
|
||||
auto parameterTypes = type->GetParameterTypes();
|
||||
auto scriptFunctionType = std::dynamic_pointer_cast<FunctionScriptType>(type);
|
||||
auto func = dynamic_pointer_cast<GenericFunctionEvalValue>(function);
|
||||
auto option = functionCall ->GetFunctionOption();
|
||||
auto opt = func->GetOption(option->GetOptionId());
|
||||
if (option -> IsScriptFunction()){
|
||||
auto parameterTypes = option->GetParameterTypes();
|
||||
auto scriptFunctionType = (ScriptFunctionOption*)option;
|
||||
auto parameterKeys = scriptFunctionType->GetParameterKeys();
|
||||
auto originalScope = this->_evaluationScope;
|
||||
auto scriptFunction = dynamic_pointer_cast<ScriptFunctionEvalValue>(function);
|
||||
this->_evaluationScope = scriptFunction->GetScope();
|
||||
auto scriptOption = dynamic_pointer_cast<EvaluationScriptFunctionOption>(opt);
|
||||
this->_evaluationScope = scriptOption->GetScope();
|
||||
|
||||
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++) {
|
||||
auto parameter = parameters[i];
|
||||
auto key = parameterKeys.at(i);
|
||||
this->_evaluationScope->CreateVariable(key.get(), parameter->Clone());
|
||||
}
|
||||
this->EvaluateBlockStatement(scriptFunction->GetInnerBlock().get());
|
||||
this->EvaluateBlockStatement(scriptOption->GetInnerBlock().get());
|
||||
this->_evaluationScope = originalScope;
|
||||
|
||||
this->_hasReturned = false;
|
||||
|
@ -391,30 +401,33 @@ namespace Porygon::Evaluation {
|
|||
this->_returnValue = nullptr;
|
||||
return r;
|
||||
} else{
|
||||
auto userDataFunction = dynamic_pointer_cast<UserData::UserDataFunction>(function);
|
||||
auto scriptOption = dynamic_pointer_cast<UserData::UserDataFunction>(opt);
|
||||
EvalValue* arr[parameters.size()];
|
||||
for (int i = 0; i < parameters.size(); i++){
|
||||
arr[i] = parameters[i].get();
|
||||
}
|
||||
return shared_ptr<EvalValue>(userDataFunction -> Call(arr, parameters.size()));
|
||||
return shared_ptr<EvalValue>(scriptOption -> Call(arr, parameters.size()));
|
||||
}
|
||||
}
|
||||
|
||||
const shared_ptr<EvalValue> Evaluator::EvaluateFunction(const ScriptFunctionEvalValue *function,
|
||||
const shared_ptr<EvalValue> Evaluator::EvaluateFunction(const GenericFunctionEvalValue *function,
|
||||
const vector<EvalValue *> ¶meters) {
|
||||
auto type = std::dynamic_pointer_cast<FunctionScriptType>(function->GetType());
|
||||
auto parameterTypes = type->GetParameterTypes();
|
||||
auto parameterKeys = type->GetParameterKeys();
|
||||
auto type = std::dynamic_pointer_cast<GenericFunctionScriptType>(function->GetType());
|
||||
auto option = (ScriptFunctionOption*)type-> GetFirstOption();
|
||||
|
||||
auto parameterTypes = option->GetParameterTypes();
|
||||
auto parameterKeys = option->GetParameterKeys();
|
||||
|
||||
auto originalScope = this->_evaluationScope;
|
||||
this->_evaluationScope = function->GetScope();
|
||||
auto scriptOption = dynamic_pointer_cast<EvaluationScriptFunctionOption>(function->GetOption(0));
|
||||
this->_evaluationScope = scriptOption->GetScope();
|
||||
|
||||
for (int i = 0; i < parameterTypes.size() && i < parameterKeys.size() && i < parameters.size(); i++) {
|
||||
auto parameter = parameters[i];
|
||||
auto key = parameterKeys.at(i);
|
||||
this->_evaluationScope->CreateVariable(key.get(), parameter->Clone());
|
||||
}
|
||||
this->EvaluateBlockStatement(function->GetInnerBlock().get());
|
||||
this->EvaluateBlockStatement(scriptOption->GetInnerBlock().get());
|
||||
this->_evaluationScope = originalScope;
|
||||
this->_hasReturned = false;
|
||||
auto r = this->_returnValue;
|
||||
|
|
|
@ -68,7 +68,7 @@ namespace Porygon::Evaluation{
|
|||
}
|
||||
|
||||
EvalValue* Evaluate(const BoundScriptStatement* statement);
|
||||
const shared_ptr<EvalValue> EvaluateFunction(const ScriptFunctionEvalValue *function,
|
||||
const shared_ptr<EvalValue> EvaluateFunction(const GenericFunctionEvalValue *function,
|
||||
const vector<EvalValue *> ¶meters);
|
||||
|
||||
EvalValue* GetLastValue(){
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include "FunctionScriptType.hpp"
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
#ifndef PORYGONLANG_FUNCTIONSCRIPTTYPE_HPP
|
||||
#define PORYGONLANG_FUNCTIONSCRIPTTYPE_HPP
|
||||
|
||||
#include "ScriptType.hpp"
|
||||
|
||||
namespace Porygon {
|
||||
class GenericFunctionOption{
|
||||
shared_ptr<ScriptType> _returnType;
|
||||
vector<shared_ptr<ScriptType>> _parameterTypes;
|
||||
size_t _option = 0;
|
||||
public:
|
||||
GenericFunctionOption(shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes){
|
||||
_returnType = move(returnType);
|
||||
_parameterTypes = move(parameterTypes);
|
||||
}
|
||||
|
||||
virtual ~GenericFunctionOption() = default;
|
||||
|
||||
const shared_ptr<ScriptType> GetReturnType() const {
|
||||
return _returnType;
|
||||
}
|
||||
|
||||
void SetOption(size_t v){
|
||||
_option = v;
|
||||
}
|
||||
|
||||
void SetReturnType(shared_ptr<ScriptType> t) {
|
||||
_returnType = move(t);
|
||||
}
|
||||
|
||||
const vector<shared_ptr<ScriptType>> GetParameterTypes() const {
|
||||
return _parameterTypes;
|
||||
}
|
||||
|
||||
const bool IsValid(const vector<shared_ptr<ScriptType>>& parameters){
|
||||
if (parameters.size() != _parameterTypes.size()){
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < parameters.size(); i++){
|
||||
if (parameters[i]->operator!=(_parameterTypes[i].get())){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const size_t GetOptionId() const{
|
||||
return _option;
|
||||
}
|
||||
|
||||
virtual const bool IsScriptFunction() const = 0;
|
||||
};
|
||||
|
||||
class GenericFunctionScriptType : public Porygon::ScriptType {
|
||||
vector<GenericFunctionOption *> _options;
|
||||
public:
|
||||
GenericFunctionScriptType()
|
||||
: ScriptType(Porygon::TypeClass::Function){};
|
||||
|
||||
explicit GenericFunctionScriptType(GenericFunctionOption * option)
|
||||
: ScriptType(Porygon::TypeClass::Function){
|
||||
this -> RegisterFunctionOption(option);
|
||||
};
|
||||
|
||||
virtual ~GenericFunctionScriptType() final{
|
||||
for (auto o: _options){
|
||||
delete o;
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterFunctionOption (GenericFunctionOption * opt){
|
||||
opt->SetOption(_options.size());
|
||||
_options.push_back(opt);
|
||||
}
|
||||
|
||||
GenericFunctionOption* GetFunctionOption(const vector<shared_ptr<ScriptType>>& parameters){
|
||||
for (auto o: _options){
|
||||
if (o->IsValid(parameters)){
|
||||
return o;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GenericFunctionOption* GetFirstOption(){
|
||||
return _options[0];
|
||||
}
|
||||
};
|
||||
|
||||
class ScriptFunctionOption : public GenericFunctionOption {
|
||||
vector<shared_ptr<Porygon::Binder::BoundVariableKey>> _parameterKeys;
|
||||
public:
|
||||
ScriptFunctionOption(shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes,
|
||||
vector<shared_ptr<Porygon::Binder::BoundVariableKey>> parameterKeys)
|
||||
: GenericFunctionOption(move(returnType), std::move(parameterTypes)) {
|
||||
_parameterKeys = move(parameterKeys);
|
||||
}
|
||||
|
||||
const vector<shared_ptr<Porygon::Binder::BoundVariableKey>> GetParameterKeys() const {
|
||||
return _parameterKeys;
|
||||
}
|
||||
|
||||
const bool IsScriptFunction() const final {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include "ScriptType.hpp"
|
||||
|
||||
#endif //PORYGONLANG_FUNCTIONSCRIPTTYPE_HPP
|
|
@ -85,7 +85,7 @@ bool Porygon::Script::HasFunction(const u16string &key) {
|
|||
}
|
||||
|
||||
shared_ptr<EvalValue> Porygon::Script::CallFunction(const u16string &key, const vector<EvalValue *>& variables) {
|
||||
auto var = (ScriptFunctionEvalValue*)GetVariable(key);
|
||||
auto var = (GenericFunctionEvalValue*)GetVariable(key);
|
||||
return this->_evaluator->EvaluateFunction(var, variables);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,10 @@ namespace Porygon{
|
|||
for (int i = 0; i < parameterCount; i++){
|
||||
vector[i] = shared_ptr<ScriptType>(parameters[i]);
|
||||
}
|
||||
return new UserData::UserDataFunctionType(shared_ptr<ScriptType>(returnType), vector);
|
||||
auto option = new UserData::UserDataFunctionOption(shared_ptr<ScriptType>(returnType), vector);
|
||||
auto type = new GenericFunctionScriptType();
|
||||
type->RegisterFunctionOption(option);
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
#include <utility>
|
||||
|
||||
#include <utility>
|
||||
|
||||
|
||||
#ifndef PORYGONLANG_SCRIPTTYPE_HPP
|
||||
#define PORYGONLANG_SCRIPTTYPE_HPP
|
||||
|
@ -110,55 +106,6 @@ namespace Porygon{
|
|||
}
|
||||
};
|
||||
|
||||
class GenericFunctionScriptType : public ScriptType{
|
||||
shared_ptr<ScriptType> _returnType;
|
||||
vector<shared_ptr<ScriptType>> _parameterTypes;
|
||||
public:
|
||||
GenericFunctionScriptType(std::shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes)
|
||||
: ScriptType(TypeClass::Function){
|
||||
_returnType = std::move(returnType);
|
||||
_parameterTypes = std::move(parameterTypes);
|
||||
}
|
||||
|
||||
const shared_ptr<ScriptType> GetReturnType() const{
|
||||
return _returnType;
|
||||
}
|
||||
|
||||
void SetReturnType(shared_ptr<ScriptType> t){
|
||||
_returnType = std::move(t);
|
||||
}
|
||||
|
||||
const vector<shared_ptr<ScriptType>> GetParameterTypes() const{
|
||||
return _parameterTypes;
|
||||
}
|
||||
|
||||
virtual const bool IsScriptFunction() const = 0;
|
||||
};
|
||||
|
||||
class FunctionScriptType : public GenericFunctionScriptType{
|
||||
vector<shared_ptr<Binder::BoundVariableKey>> _parameterKeys;
|
||||
int _scopeIndex;
|
||||
public:
|
||||
FunctionScriptType(std::shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes,
|
||||
vector<shared_ptr<Binder::BoundVariableKey>> parameterKeys, int scopeIndex)
|
||||
: GenericFunctionScriptType(std::move(returnType), parameterTypes){
|
||||
_parameterKeys = std::move(parameterKeys);
|
||||
_scopeIndex = scopeIndex;
|
||||
}
|
||||
|
||||
const vector<shared_ptr<Binder::BoundVariableKey>> GetParameterKeys() const{
|
||||
return _parameterKeys;
|
||||
}
|
||||
|
||||
const int GetScopeIndex() const{
|
||||
return _scopeIndex;
|
||||
}
|
||||
|
||||
const bool IsScriptFunction() const final{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class NumericalTableScriptType : public ScriptType{
|
||||
shared_ptr<ScriptType> _valueType;
|
||||
// Consider adding a check whether the table actually contains a type if every key is static.
|
||||
|
|
|
@ -32,19 +32,28 @@ namespace Porygon::StandardLibraries{
|
|||
static void RegisterVariables(std::map<Utilities::HashedString, Binder::BoundVariable *>* bound,
|
||||
std::map<Utilities::HashedString, shared_ptr<Evaluation::EvalValue>>* values){
|
||||
// Register error function
|
||||
auto errorFuncType = make_shared<UserData::UserDataFunctionType>(
|
||||
auto errorFuncTypeOption = new UserData::UserDataFunctionOption(
|
||||
make_shared<ScriptType>(TypeClass::Nil),
|
||||
vector<shared_ptr<ScriptType>>{make_shared<StringScriptType>(false, 0)});
|
||||
auto errorFunc = make_shared<UserData::UserDataFunction>(_error, nullptr);
|
||||
auto errorFuncType = make_shared<GenericFunctionScriptType>();
|
||||
errorFuncType->RegisterFunctionOption(errorFuncTypeOption);
|
||||
auto errorFuncOption = new UserData::UserDataFunction(_error, nullptr);
|
||||
auto errorFunc = make_shared<Evaluation::GenericFunctionEvalValue>(errorFuncType, rand());
|
||||
errorFunc->RegisterOption(errorFuncOption);
|
||||
auto errorLookup = Utilities::HashedString::CreateLookup(u"error");
|
||||
bound->insert({errorLookup, new Binder::BoundVariable(errorFuncType)});
|
||||
values->insert({errorLookup, errorFunc});
|
||||
|
||||
// Register assert function
|
||||
auto assertFuncType = make_shared<UserData::UserDataFunctionType>(
|
||||
auto assertFuncTypeOption = new UserData::UserDataFunctionOption(
|
||||
make_shared<ScriptType>(TypeClass::Bool),
|
||||
vector<shared_ptr<ScriptType>>{make_shared<ScriptType>(TypeClass::Bool)});
|
||||
auto assertFunc = make_shared<UserData::UserDataFunction>(_assert, nullptr);
|
||||
auto assertFuncType = make_shared<GenericFunctionScriptType>();
|
||||
assertFuncType->RegisterFunctionOption(assertFuncTypeOption);
|
||||
auto assertFuncOption = new UserData::UserDataFunction(_assert, nullptr);
|
||||
auto assertFunc = make_shared<Evaluation::GenericFunctionEvalValue>(assertFuncType, rand());
|
||||
assertFunc->RegisterOption(assertFuncOption);
|
||||
|
||||
auto assertLookup = Utilities::HashedString::CreateLookup(u"assert");
|
||||
bound->insert({assertLookup, new Binder::BoundVariable(assertFuncType)});
|
||||
values->insert({assertLookup, assertFunc});
|
||||
|
|
|
@ -24,6 +24,12 @@ namespace Porygon::StandardLibraries{
|
|||
InternalScope(){
|
||||
BasicLibrary::RegisterVariables(&_boundVariables, &_variables);
|
||||
}
|
||||
|
||||
~InternalScope(){
|
||||
for (const auto& b: _boundVariables){
|
||||
delete b.second;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static InternalScope _internal;
|
||||
|
|
|
@ -6,7 +6,10 @@ using namespace Porygon::Evaluation;
|
|||
namespace Porygon::UserData{
|
||||
extern "C" {
|
||||
EvalValue * CreateFunctionEvalValue(Evaluation::EvalValue* (*func)(void* , EvalValue* [], int ), void* obj) {
|
||||
return new UserDataFunction(func, obj);
|
||||
auto opt = new UserDataFunction(func, obj);
|
||||
auto t = new GenericFunctionEvalValue(make_shared<GenericFunctionScriptType>(), rand());
|
||||
t->RegisterOption(opt);
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,32 +4,28 @@
|
|||
#include <utility>
|
||||
#include "../Evaluator/EvalValues/ScriptFunctionEvalValue.hpp"
|
||||
#include "UserDataFunctionType.hpp"
|
||||
#include "../FunctionScriptType.hpp"
|
||||
|
||||
namespace Porygon::UserData{
|
||||
class UserDataFunction : public Evaluation::GenericFunctionEvalValue {
|
||||
Evaluation::EvalValue* (*_call)(void* obj, EvalValue* parameters[], int parameterCount);
|
||||
class UserDataFunction : public Evaluation::GenericFunctionOption {
|
||||
Evaluation::EvalValue* (*_call)(void* obj, Evaluation::EvalValue* parameters[], int parameterCount);
|
||||
void *_obj;
|
||||
|
||||
UserDataFunction(Evaluation::EvalValue* (*call)(void* obj, EvalValue* parameters[], int parameterCount), void* obj,
|
||||
shared_ptr<GenericFunctionScriptType> type, size_t hash) : GenericFunctionEvalValue(std::move(type), hash){
|
||||
UserDataFunction(Evaluation::EvalValue* (*call)(void* obj, Evaluation::EvalValue* parameters[], int parameterCount), void* obj,
|
||||
shared_ptr<GenericFunctionScriptType> type, size_t hash) : GenericFunctionOption(){
|
||||
_call = call;
|
||||
_obj = obj;
|
||||
}
|
||||
public:
|
||||
UserDataFunction(Evaluation::EvalValue* (*call)(void* obj, EvalValue* parameters[], int parameterCount), void* obj) :
|
||||
GenericFunctionEvalValue(make_shared<UserDataFunctionType>(nullptr, vector<shared_ptr<ScriptType>>{}), rand()){
|
||||
UserDataFunction(Evaluation::EvalValue* (*call)(void* obj, Evaluation::EvalValue* parameters[], int parameterCount), void* obj) :
|
||||
GenericFunctionOption(){
|
||||
_call = call;
|
||||
_obj = obj;
|
||||
}
|
||||
|
||||
EvalValue* Call(EvalValue* parameters[], int parameterCount){
|
||||
Evaluation::EvalValue* Call(Evaluation::EvalValue* parameters[], int parameterCount){
|
||||
return _call(_obj, parameters, parameterCount);
|
||||
}
|
||||
|
||||
const shared_ptr<EvalValue> Clone() const final {
|
||||
// We don't run make_shared here as it can't call private constructors
|
||||
return shared_ptr<UserDataFunction>(new UserDataFunction(_call, _obj, _type, _hash));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,26 +3,27 @@
|
|||
|
||||
#include <utility>
|
||||
#include "../ScriptType.hpp"
|
||||
#include "../FunctionScriptType.hpp"
|
||||
|
||||
namespace Porygon::UserData{
|
||||
class UserDataFunctionType : public GenericFunctionScriptType{
|
||||
class UserDataFunctionOption : public GenericFunctionOption{
|
||||
public:
|
||||
UserDataFunctionType(std::shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes)
|
||||
: GenericFunctionScriptType(std::move(returnType), std::move(parameterTypes)){
|
||||
UserDataFunctionOption(std::shared_ptr<ScriptType> returnType, vector<shared_ptr<ScriptType>> parameterTypes)
|
||||
: GenericFunctionOption(std::move(returnType), std::move(parameterTypes)) {
|
||||
|
||||
}
|
||||
static UserDataFunctionType* FromRawPointers(ScriptType* returnType, vector<ScriptType*> parameterTypes){
|
||||
static UserDataFunctionOption* FromRawPointers(ScriptType* returnType, vector<ScriptType*> parameterTypes){
|
||||
auto rt = shared_ptr<ScriptType>(returnType);
|
||||
auto p = vector<shared_ptr<ScriptType>>(parameterTypes.size());
|
||||
for (int i = 0; i < parameterTypes.size(); i++){
|
||||
p[i] = shared_ptr<ScriptType>(parameterTypes[i]);
|
||||
}
|
||||
return new UserDataFunctionType(rt, p);
|
||||
return new UserDataFunctionOption(rt, p);
|
||||
}
|
||||
|
||||
static UserDataFunctionType* FromRawPointers(ScriptType* returnType){
|
||||
static UserDataFunctionOption* FromRawPointers(ScriptType* returnType){
|
||||
auto rt = shared_ptr<ScriptType>(returnType);
|
||||
return new UserDataFunctionType(rt, {});
|
||||
return new UserDataFunctionOption(rt, {});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -67,14 +67,18 @@
|
|||
#define PORYGON_FUNCTION(fieldName, returnType, ...) \
|
||||
{ \
|
||||
Porygon::Utilities::HashedString::ConstHash(#fieldName), \
|
||||
new Porygon::UserData::UserDataField(Porygon::UserData::UserDataFunctionType::FromRawPointers(returnType, {__VA_ARGS__} ), \
|
||||
new Porygon::UserData::UserDataField( \
|
||||
new Porygon::GenericFunctionScriptType( \
|
||||
Porygon::UserData::UserDataFunctionOption::FromRawPointers(returnType, {__VA_ARGS__} )), \
|
||||
\
|
||||
\
|
||||
[](void* obj) -> Porygon::Evaluation::EvalValue* { \
|
||||
return new Porygon::UserData::UserDataFunction( \
|
||||
auto t = new Porygon::Evaluation::GenericFunctionEvalValue(make_shared<GenericFunctionScriptType>(), rand()); \
|
||||
t->RegisterOption(new Porygon::UserData::UserDataFunction( \
|
||||
[](void* obj, Porygon::Evaluation::EvalValue* par[], int parameterCount) \
|
||||
-> Porygon::Evaluation::EvalValue*{return ((T_USERDATA*)obj)->invoke__##fieldName(obj, par, parameterCount);}, \
|
||||
obj);}, \
|
||||
obj)); \
|
||||
return t;}, \
|
||||
nullptr) \
|
||||
},
|
||||
|
||||
|
|
|
@ -150,5 +150,33 @@ return
|
|||
delete script;
|
||||
}
|
||||
|
||||
TEST_CASE( "Allow declaration of multiple functions with different signatures", "[integration]" ) {
|
||||
Script* script = Script::Create(
|
||||
R"(
|
||||
function add(number a, number b)
|
||||
return a + b
|
||||
end
|
||||
|
||||
function add(string a, string b)
|
||||
return a + b
|
||||
end
|
||||
|
||||
intResult = add(5, 500)
|
||||
stringResult = add('foo', 'bar')
|
||||
)"
|
||||
);
|
||||
REQUIRE(!script->Diagnostics -> HasErrors());
|
||||
script->Evaluate();
|
||||
auto intVar = script -> GetVariable(u"intResult");
|
||||
REQUIRE(intVar != nullptr);
|
||||
CHECK(intVar->EvaluateInteger() == 505);
|
||||
auto stringVar = script -> GetVariable(u"stringResult");
|
||||
REQUIRE(stringVar != nullptr);
|
||||
CHECK(stringVar->EvaluateString() == u"foobar");
|
||||
|
||||
|
||||
delete script;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue