Implements support for functions with the same name, but different parameters
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-06-29 19:59:42 +02:00
parent 24c560b52d
commit db2d731b06
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
23 changed files with 362 additions and 204 deletions

View File

@ -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());
}

View File

@ -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();

View File

@ -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;

View File

@ -0,0 +1 @@
#include "BoundFunctionCallExpression.hpp"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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);
}
};
}

View File

@ -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 *> &parameters) {
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;

View File

@ -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 *> &parameters);
EvalValue* GetLastValue(){

View File

@ -0,0 +1 @@
#include "FunctionScriptType.hpp"

112
src/FunctionScriptType.hpp Normal file
View File

@ -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

View File

@ -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);
}

View File

@ -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;
}
}
}

View File

@ -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.

View File

@ -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});

View File

@ -24,6 +24,12 @@ namespace Porygon::StandardLibraries{
InternalScope(){
BasicLibrary::RegisterVariables(&_boundVariables, &_variables);
}
~InternalScope(){
for (const auto& b: _boundVariables){
delete b.second;
}
}
};
static InternalScope _internal;

View File

@ -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;
}
}
}

View File

@ -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));
}
};
}

View File

@ -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, {});
}

View File

@ -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) \
},

View File

@ -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