Initial work on implicit casting when calling a function
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-08-18 12:13:13 +02:00
parent 61d89bd21b
commit 0fde3d46df
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 74 additions and 35 deletions

View File

@ -585,14 +585,12 @@ namespace Porygon::Binder {
} }
auto functionType = std::dynamic_pointer_cast<const GenericFunctionScriptType>(type); auto functionType = std::dynamic_pointer_cast<const GenericFunctionScriptType>(type);
auto givenParameters = expression->GetParameters(); auto givenParameters = expression->GetParameters();
auto givenParameterTypes = vector<shared_ptr<const ScriptType>>(givenParameters->size());
vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size()); vector<BoundExpression *> boundParameters = vector<BoundExpression *>(givenParameters->size());
for (size_t i = 0; i < givenParameters->size(); i++){ for (size_t i = 0; i < givenParameters->size(); i++){
boundParameters[i] = this -> BindExpression(givenParameters->at(i)); boundParameters[i] = this -> BindExpression(givenParameters->at(i));
givenParameterTypes[i] = boundParameters[i]->GetType();
} }
auto functionOption = functionType->GetFunctionOption(givenParameterTypes); auto functionOption = functionType->GetFunctionOption(this->_scriptData->Diagnostics, boundParameters);
if (functionOption == nullptr){ if (functionOption == nullptr){
this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters, this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters,
expression->GetStartPosition(), expression->GetStartPosition(),

View File

@ -7,7 +7,6 @@
#include "../../ScriptTypes/ScriptType.hpp" #include "../../ScriptTypes/ScriptType.hpp"
#include "../BoundOperators.hpp" #include "../BoundOperators.hpp"
#include "../BoundVariables/BoundVariableKey.hpp" #include "../BoundVariables/BoundVariableKey.hpp"
#include "../../ScriptTypes/FunctionScriptType.hpp"
using namespace std; using namespace std;

View File

@ -2,6 +2,7 @@
#define PORYGONLANG_BOUNDFUNCTIONCALLEXPRESSION_HPP #define PORYGONLANG_BOUNDFUNCTIONCALLEXPRESSION_HPP
#include "BoundExpression.hpp" #include "BoundExpression.hpp"
#include "../../ScriptTypes/FunctionScriptType.hpp"
namespace Porygon::Binder { namespace Porygon::Binder {
class BoundFunctionCallExpression : public Porygon::Binder::BoundExpression { class BoundFunctionCallExpression : public Porygon::Binder::BoundExpression {

View File

@ -11,7 +11,7 @@ namespace Porygon::Diagnostics {
// Parse diagnostics // Parse diagnostics
UnexpectedToken, UnexpectedToken,
// Bind diagnostics // Bind errors
NoBinaryOperationFound, NoBinaryOperationFound,
NoUnaryOperationFound, NoUnaryOperationFound,
CantAssignVariable, CantAssignVariable,
@ -27,7 +27,10 @@ namespace Porygon::Diagnostics {
NumericalForArgumentNotANumber, NumericalForArgumentNotANumber,
CantIterateExpression, CantIterateExpression,
InvalidFunctionParameters, InvalidFunctionParameters,
ModuleDoesntExist ModuleDoesntExist,
// Bind warnings
DataLossOnImplicitCast,
}; };
} }
#endif //PORYGONLANG_DIAGNOSTICCODE_HPP #endif //PORYGONLANG_DIAGNOSTICCODE_HPP

View File

@ -0,0 +1,12 @@
#ifndef PORYGONLANG_CASTRESULT_HPP
#define PORYGONLANG_CASTRESULT_HPP
namespace Porygon{
enum class CastResult{
Success,
Failure,
DataLoss,
};
}
#endif //PORYGONLANG_CASTRESULT_HPP

View File

@ -4,6 +4,8 @@
#include <utility> #include <utility>
#include "ScriptType.hpp" #include "ScriptType.hpp"
#include "../Binder/BoundExpressions/BoundExpression.hpp"
#include "../Diagnostics/DiagnosticsHolder.hpp"
namespace Porygon { namespace Porygon {
class GenericFunctionOption{ class GenericFunctionOption{
@ -33,15 +35,25 @@ namespace Porygon {
return _parameterTypes; return _parameterTypes;
} }
bool IsValid(const vector<shared_ptr<const ScriptType>>& parameters){ bool IsValid(const shared_ptr<Diagnostics::DiagnosticsHolder>& diagnostics,
const vector<Binder::BoundExpression *>& parameters){
if (parameters.size() != _parameterTypes.size()){ if (parameters.size() != _parameterTypes.size()){
return false; return false;
} }
for (size_t i = 0; i < parameters.size(); i++){ for (size_t i = 0; i < parameters.size(); i++){
if (_parameterTypes[i]->GetClass() == TypeClass::All) if (_parameterTypes[i]->GetClass() == TypeClass::All)
continue; continue;
if (parameters[i]->operator!=(_parameterTypes[i].get())){ auto parameter = parameters[i];
return false; const auto& parameterType = parameter->GetType();
if (parameterType->operator!=(_parameterTypes[i].get())){
auto castResult = parameterType->CastableTo(_parameterTypes[i], false);
if (castResult == CastResult::Failure){
return false;
}
else if (castResult == CastResult::DataLoss){
diagnostics->LogWarning(Diagnostics::DiagnosticCode::DataLossOnImplicitCast, parameter->GetStartPosition(),
parameter->GetLength());
}
} }
} }
return true; return true;
@ -91,9 +103,10 @@ namespace Porygon {
return this; return this;
} }
GenericFunctionOption* GetFunctionOption(const vector<shared_ptr<const ScriptType>>& parameters) const{ GenericFunctionOption* GetFunctionOption(const shared_ptr<Diagnostics::DiagnosticsHolder>& diagnostics,
const vector<Binder::BoundExpression *>& parameters) const{
for (auto o: *_options){ for (auto o: *_options){
if (o->IsValid(parameters)){ if (o->IsValid(diagnostics, parameters)){
return o; return o;
} }
} }

View File

@ -9,6 +9,7 @@
#include <memory> #include <memory>
#include "../Binder/BoundVariables/BoundVariableKey.hpp" #include "../Binder/BoundVariables/BoundVariableKey.hpp"
#include "../Utilities/HashedString.hpp" #include "../Utilities/HashedString.hpp"
#include "CastResult.hpp"
using namespace std; using namespace std;
@ -34,7 +35,7 @@ namespace Porygon{
virtual ~ScriptType() = default; virtual ~ScriptType() = default;
[[nodiscard]] const TypeClass GetClass() const{ [[nodiscard]] inline TypeClass GetClass() const{
return _class; return _class;
} }
@ -74,6 +75,10 @@ namespace Porygon{
virtual shared_ptr<const ScriptType> GetIteratorKeyType() const{ virtual shared_ptr<const ScriptType> GetIteratorKeyType() const{
throw "This type told the binder it can be iterated, but it does not implement the resulting type."; throw "This type told the binder it can be iterated, but it does not implement the resulting type.";
} }
[[nodiscard]] virtual CastResult CastableTo(const shared_ptr<const ScriptType>& castType, bool explicitCast) const{
return CastResult::Failure;
}
}; };
class NumericScriptType : public ScriptType{ class NumericScriptType : public ScriptType{
@ -94,6 +99,34 @@ namespace Porygon{
[[nodiscard]] inline bool IsFloat() const{ [[nodiscard]] inline bool IsFloat() const{
return _isFloat; return _isFloat;
} }
bool operator ==(const ScriptType& b) const final{
if (b.GetClass() != TypeClass::Number)
return false;
auto bNum = dynamic_cast<const NumericScriptType&>(b);
if (bNum.IsAwareOfFloat() && IsAwareOfFloat()){
return bNum.IsFloat() == IsFloat();
}
return true;
};
bool operator !=(const ScriptType& b) const final{
return ! (operator==(b));
}
bool operator !=(const ScriptType* b) const final{
return ! (operator==(*b));
}
[[nodiscard]] CastResult CastableTo(const shared_ptr<const ScriptType>& castType, bool explicitCast) const final{
if (!explicitCast){
if (castType->GetClass() != TypeClass::Number )
return CastResult::Failure;
auto bNum = dynamic_pointer_cast<const NumericScriptType>(castType);
if (bNum->IsFloat() && !IsFloat()) return CastResult::Success;
if (!bNum->IsFloat() && IsFloat()) return CastResult::DataLoss;
}
return CastResult::Success;
}
}; };
class StringScriptType : public ScriptType{ class StringScriptType : public ScriptType{

View File

@ -165,15 +165,13 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("acos"), HashedString::ConstHash("acos"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_acos)) , FUNCTION(_acos))
}, },
{ {
HashedString::ConstHash("asin"), HashedString::ConstHash("asin"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_asin)) , FUNCTION(_asin))
}, },
@ -181,11 +179,7 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("atan"), HashedString::ConstHash("atan"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE, INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE, FLOAT_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, FLOAT_TYPE}))
, FUNCTION(_atan)) , FUNCTION(_atan))
}, },
@ -193,14 +187,13 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("ceil"), HashedString::ConstHash("ceil"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(INTEGER_TYPE, {FLOAT_TYPE}))
, FUNCTION(_ceil)) , FUNCTION(_ceil))
}, },
{ {
HashedString::ConstHash("cos"), HashedString::ConstHash("cos"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_cos)) , FUNCTION(_cos))
}, },
@ -208,7 +201,6 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("deg"), HashedString::ConstHash("deg"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_deg)) , FUNCTION(_deg))
}, },
@ -216,7 +208,6 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("exp"), HashedString::ConstHash("exp"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_exp)) , FUNCTION(_exp))
}, },
@ -224,16 +215,13 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("floor"), HashedString::ConstHash("floor"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(INTEGER_TYPE, {FLOAT_TYPE}))
, FUNCTION(_floor)) , FUNCTION(_floor))
}, },
{ {
HashedString::ConstHash("fmod"), HashedString::ConstHash("fmod"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE, INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE, FLOAT_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, FLOAT_TYPE}))
, FUNCTION(_fmod)) , FUNCTION(_fmod))
}, },
@ -247,11 +235,7 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("log"), HashedString::ConstHash("log"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE, INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE, FLOAT_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE, FLOAT_TYPE}))
, FUNCTION(_log)) , FUNCTION(_log))
}, },
@ -277,7 +261,6 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("rad"), HashedString::ConstHash("rad"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_rad)) , FUNCTION(_rad))
}, },
@ -285,7 +268,6 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("sin"), HashedString::ConstHash("sin"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_sin)) , FUNCTION(_sin))
}, },
@ -293,7 +275,6 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("sqrt"), HashedString::ConstHash("sqrt"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_sqrt)) , FUNCTION(_sqrt))
}, },
@ -301,7 +282,6 @@ namespace Porygon::StandardLibraries {
HashedString::ConstHash("tan"), HashedString::ConstHash("tan"),
new UserData::UserDataField( new UserData::UserDataField(
(new GenericFunctionScriptType()) (new GenericFunctionScriptType())
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {INTEGER_TYPE}))
->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE})) ->RegisterFunctionOption(0, CreateFunctionOption(FLOAT_TYPE, {FLOAT_TYPE}))
, FUNCTION(_tan)) , FUNCTION(_tan))
}, },