From 1d72e2eccd6307158f897ba06a463eadd7f05f4d Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Sun, 18 Aug 2019 13:17:53 +0200 Subject: [PATCH] Better handling of casting --- src/Binder/Binder.cpp | 2 +- .../BoundExpressions/BoundExpression.hpp | 23 +++++++++++++++++++ src/Evaluator/EvalValues/EvalValue.hpp | 5 ++++ src/Evaluator/EvalValues/NumericEvalValue.cpp | 20 ++++++++++++++++ src/Evaluator/EvalValues/NumericEvalValue.hpp | 20 +++++++--------- src/Evaluator/Evaluator.cpp | 8 +++++++ src/Evaluator/Evaluator.hpp | 1 + src/ScriptTypes/FunctionScriptType.hpp | 20 +++++++++------- 8 files changed, 78 insertions(+), 21 deletions(-) diff --git a/src/Binder/Binder.cpp b/src/Binder/Binder.cpp index d6540d1..6fb03af 100644 --- a/src/Binder/Binder.cpp +++ b/src/Binder/Binder.cpp @@ -590,7 +590,7 @@ namespace Porygon::Binder { boundParameters[i] = this -> BindExpression(givenParameters->at(i)); } - auto functionOption = functionType->GetFunctionOption(this->_scriptData->Diagnostics, boundParameters); + auto functionOption = functionType->GetFunctionOption(this->_scriptData->Diagnostics, &boundParameters); if (functionOption == nullptr){ this->_scriptData->Diagnostics->LogError(Diagnostics::DiagnosticCode::InvalidFunctionParameters, expression->GetStartPosition(), diff --git a/src/Binder/BoundExpressions/BoundExpression.hpp b/src/Binder/BoundExpressions/BoundExpression.hpp index a6f55d8..eb31d8f 100644 --- a/src/Binder/BoundExpressions/BoundExpression.hpp +++ b/src/Binder/BoundExpressions/BoundExpression.hpp @@ -28,6 +28,7 @@ namespace Porygon::Binder { NumericalTable, Table, Require, + ImplicitCast, }; class BoundExpression { @@ -332,6 +333,28 @@ namespace Porygon::Binder { } }; + class BoundImplicitCastExpression : public BoundExpression { + const BoundExpression* _expression; + public: + BoundImplicitCastExpression(BoundExpression* expression, shared_ptr castType) + : BoundExpression(expression->GetStartPosition(), expression->GetLength(), castType), + _expression(expression) + {} + + const BoundExpression* GetExpression() const{ + return _expression; + } + + ~BoundImplicitCastExpression() final { + delete _expression; + } + + [[nodiscard]] + inline BoundExpressionKind GetKind() const final { + return BoundExpressionKind::ImplicitCast; + } + }; + } #endif //PORYGONLANG_BOUNDEXPRESSION_HPP diff --git a/src/Evaluator/EvalValues/EvalValue.hpp b/src/Evaluator/EvalValues/EvalValue.hpp index d0f3488..6129054 100644 --- a/src/Evaluator/EvalValues/EvalValue.hpp +++ b/src/Evaluator/EvalValues/EvalValue.hpp @@ -87,6 +87,11 @@ namespace Porygon::Evaluation { virtual EvalValue* UnaryOperation(Binder::BoundUnaryOperation operation) const{ throw EvaluationException("Unary operations are not implemented for this type."); } + + [[nodiscard]] + virtual EvalValue* Cast(shared_ptr castType) const{ + throw new EvaluationException("Casting to invalid type."); + } }; class BooleanEvalValue : public EvalValue { diff --git a/src/Evaluator/EvalValues/NumericEvalValue.cpp b/src/Evaluator/EvalValues/NumericEvalValue.cpp index dbbd5a3..5f3d625 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.cpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.cpp @@ -176,4 +176,24 @@ namespace Porygon::Evaluation { } } } + + EvalValue *IntegerEvalValue::Cast(shared_ptr castType) const { + if (castType->GetClass() == TypeClass::Number){ + auto num = static_pointer_cast(castType); + if (num->IsFloat()){ + return new FloatEvalValue(GetIntegerValue()); + } + } + return EvalValue::Cast(castType); + } + + EvalValue *FloatEvalValue::Cast(shared_ptr castType) const { + if (castType->GetClass() == TypeClass::Number){ + auto num = static_pointer_cast(castType); + if (!num->IsFloat()){ + return new IntegerEvalValue(GetFloatValue()); + } + } + return EvalValue::Cast(castType); + } } \ No newline at end of file diff --git a/src/Evaluator/EvalValues/NumericEvalValue.hpp b/src/Evaluator/EvalValues/NumericEvalValue.hpp index da0ed48..26d5f1f 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.hpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.hpp @@ -68,11 +68,6 @@ namespace Porygon::Evaluation { return _value; } - [[nodiscard]] - inline double EvaluateFloat() const final { - return static_cast(_value); - } - [[nodiscard]] inline std::u16string EvaluateString() const final{ return Utilities::StringUtils::IntToString(_value); @@ -98,14 +93,17 @@ namespace Porygon::Evaluation { default: throw; } } + + [[nodiscard]] + EvalValue* Cast(shared_ptr castType) const final; }; class FloatEvalValue : public NumericEvalValue { const double _value; [[nodiscard]] - inline int64_t GetIntegerValue() const final { - return _value; + int64_t GetIntegerValue() const final { + throw EvaluationException("Attempting to retrieve int from float eval value."); } [[nodiscard]] @@ -127,11 +125,6 @@ namespace Porygon::Evaluation { return _value; } - [[nodiscard]] - inline int64_t EvaluateInteger() const final { - return static_cast(_value); - } - [[nodiscard]] inline std::u16string EvaluateString() const final{ return Utilities::StringUtils::FloatToString(_value); @@ -196,6 +189,9 @@ namespace Porygon::Evaluation { default: throw; } } + + [[nodiscard]] + EvalValue* Cast(shared_ptr castType) const final; }; } diff --git a/src/Evaluator/Evaluator.cpp b/src/Evaluator/Evaluator.cpp index cedc7b5..a25715b 100644 --- a/src/Evaluator/Evaluator.cpp +++ b/src/Evaluator/Evaluator.cpp @@ -257,6 +257,8 @@ namespace Porygon::Evaluation { return this->EvaluateComplexTableExpression(expression); case BoundExpressionKind::Require: return this -> EvaluateRequireExpression(expression); + case BoundExpressionKind::ImplicitCast: + return this -> EvaluateImplicitCastExpression(expression); } } @@ -412,4 +414,10 @@ namespace Porygon::Evaluation { return result.Take(); } } + + EvalValuePointer Evaluator::EvaluateImplicitCastExpression(const BoundExpression *pExpression) { + auto iCExpression = dynamic_cast(pExpression); + auto val = EvaluateExpression(iCExpression->GetExpression()); + return val->Cast(iCExpression->GetType()); + } } \ No newline at end of file diff --git a/src/Evaluator/Evaluator.hpp b/src/Evaluator/Evaluator.hpp index 3010de0..b64fac5 100644 --- a/src/Evaluator/Evaluator.hpp +++ b/src/Evaluator/Evaluator.hpp @@ -48,6 +48,7 @@ namespace Porygon::Evaluation{ EvalValuePointer EvaluateComplexTableExpression(const BoundExpression *expression); EvalValuePointer EvaluateRequireExpression(const BoundExpression* expression); + EvalValuePointer EvaluateImplicitCastExpression(const BoundExpression *pExpression); EvalValuePointer GetVariable(const BoundVariableExpression *expression); public: diff --git a/src/ScriptTypes/FunctionScriptType.hpp b/src/ScriptTypes/FunctionScriptType.hpp index 2d7b44f..b658986 100644 --- a/src/ScriptTypes/FunctionScriptType.hpp +++ b/src/ScriptTypes/FunctionScriptType.hpp @@ -36,23 +36,26 @@ namespace Porygon { } bool IsValid(const shared_ptr& diagnostics, - const vector& parameters){ - if (parameters.size() != _parameterTypes.size()){ + vector* parameters){ + if (parameters->size() != _parameterTypes.size()){ 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) continue; - auto parameter = parameters[i]; + auto parameter = parameters->at(i); 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()); + else{ + if (castResult == CastResult::DataLoss){ + diagnostics->LogWarning(Diagnostics::DiagnosticCode::DataLossOnImplicitCast, parameter->GetStartPosition(), + parameter->GetLength()); + } + parameters->at(i) = new Binder::BoundImplicitCastExpression(parameter, _parameterTypes[i]); } } } @@ -103,8 +106,9 @@ namespace Porygon { return this; } + [[nodiscard]] GenericFunctionOption* GetFunctionOption(const shared_ptr& diagnostics, - const vector& parameters) const{ + vector* parameters) const{ for (auto o: *_options){ if (o->IsValid(diagnostics, parameters)){ return o;