From 13b382def27b5d7a1851c14cf932a8fdb8253d25 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Thu, 15 Aug 2019 18:12:29 +0200 Subject: [PATCH] Implements most of the remaining core standard functions --- src/Evaluator/EvalValues/NumericEvalValue.hpp | 5 + src/ScriptTypes/FunctionScriptType.hpp | 2 + src/ScriptTypes/ScriptType.hpp | 3 +- src/StandardLibraries/BasicLibrary.hpp | 141 +++++++++++++++--- src/Utilities/StringUtils.hpp | 9 ++ tests/standardLibraries/BasicLibrary.cpp | 38 +++++ 6 files changed, 173 insertions(+), 25 deletions(-) diff --git a/src/Evaluator/EvalValues/NumericEvalValue.hpp b/src/Evaluator/EvalValues/NumericEvalValue.hpp index eed00e2..3d9aaf3 100644 --- a/src/Evaluator/EvalValues/NumericEvalValue.hpp +++ b/src/Evaluator/EvalValues/NumericEvalValue.hpp @@ -122,6 +122,11 @@ namespace Porygon::Evaluation { return _value; } + [[nodiscard]] + inline std::u16string EvaluateString() const final{ + return Utilities::StringUtils::FloatToString(_value); + } + [[nodiscard]] inline EvalValue* Clone() const final { return new FloatEvalValue(_value); diff --git a/src/ScriptTypes/FunctionScriptType.hpp b/src/ScriptTypes/FunctionScriptType.hpp index 21799d1..5604c01 100644 --- a/src/ScriptTypes/FunctionScriptType.hpp +++ b/src/ScriptTypes/FunctionScriptType.hpp @@ -38,6 +38,8 @@ namespace Porygon { return false; } for (size_t i = 0; i < parameters.size(); i++){ + if (_parameterTypes[i]->GetClass() == TypeClass::All) + continue; if (parameters[i]->operator!=(_parameterTypes[i].get())){ return false; } diff --git a/src/ScriptTypes/ScriptType.hpp b/src/ScriptTypes/ScriptType.hpp index 5cfa177..4eb71b6 100644 --- a/src/ScriptTypes/ScriptType.hpp +++ b/src/ScriptTypes/ScriptType.hpp @@ -22,6 +22,7 @@ namespace Porygon{ Function, UserData, Table, + All, }; class ScriptType{ @@ -33,7 +34,7 @@ namespace Porygon{ virtual ~ScriptType() = default; - const TypeClass GetClass() const{ + [[nodiscard]] const TypeClass GetClass() const{ return _class; } diff --git a/src/StandardLibraries/BasicLibrary.hpp b/src/StandardLibraries/BasicLibrary.hpp index 7bbe56d..d6173a1 100644 --- a/src/StandardLibraries/BasicLibrary.hpp +++ b/src/StandardLibraries/BasicLibrary.hpp @@ -13,14 +13,11 @@ #include "../UserData/UserDataFunction.hpp" #include "../UserData/UserDataFunctionType.hpp" #include "../ScriptOptions.hpp" +#include "../Evaluator/EvalValues/StringEvalValue.hpp" namespace Porygon::StandardLibraries{ class BasicLibrary{ - static const Evaluation::EvalValue* _error(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ - auto message = parameters[0]->EvaluateString(); - auto conv = Utilities::StringUtils::FromUTF8(message); - throw Evaluation::EvaluationException(conv); - } + //region Assert static const Evaluation::EvalValue* _assert(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ auto assertion = parameters[0]->EvaluateBool(); @@ -35,17 +32,103 @@ namespace Porygon::StandardLibraries{ return new Evaluation::BooleanEvalValue(true); } + static shared_ptr GetAssertFuncType(){ + return GetFuncType(make_shared(TypeClass::Bool), + {{make_shared(TypeClass::Bool)}, + {make_shared(TypeClass::Bool), make_shared(false, 0)}}); + } + //endregion + //region Error + + static const Evaluation::EvalValue* _error(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ + auto message = parameters[0]->EvaluateString(); + auto conv = Utilities::StringUtils::FromUTF8(message); + throw Evaluation::EvaluationException(conv); + } + static shared_ptr GetErrorFuncType(){ + return GetFuncType(make_shared(TypeClass::Nil), {{make_shared(false, 0)}}); + } + //endregion + //region Print + static const Evaluation::EvalValue* _print(void*, const ScriptOptions* options, const Evaluation::EvalValue* parameters[], int parameterCount){ auto message = parameters[0]->EvaluateString(); options->Print(message.c_str()); return new Evaluation::NilEvalValue(); } + static shared_ptr GetPrintFuncType(){ + return GetFuncType(make_shared(TypeClass::Nil), {{make_shared(false, 0)}}); + } + //endregion + //region ToInt static const Evaluation::EvalValue* _toInt(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ auto parameter = parameters[0]->EvaluateString(); auto parsed = Utilities::StringUtils::ParseInteger(parameter); return new Evaluation::IntegerEvalValue(parsed); } + static shared_ptr GetToIntFuncType(){ + return GetFuncType(make_shared(true, false), {{make_shared(false, 0)}}); + } + //endregion + //region ToFloat + + static const Evaluation::EvalValue* _toFloat(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ + auto parameter = parameters[0]->EvaluateString(); + auto parsed = Utilities::StringUtils::ParseFloat(parameter); + return new Evaluation::FloatEvalValue(parsed); + } + static shared_ptr GetToFloatFuncType(){ + return GetFuncType(make_shared(true, true), + {{make_shared(false, 0)}}); + } + //endregion + //region ToString + + static const Evaluation::EvalValue* _toString(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ + auto parameter = parameters[0]->EvaluateString(); + return new Evaluation::StringEvalValue(parameter); + } + static shared_ptr GetToStringFuncType(){ + return GetFuncType(make_shared(false, 0), + {{make_shared(TypeClass::All)}}); + } + //endregion + //region Type + + static const Evaluation::EvalValue* _type(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ + auto parameter = parameters[0]->GetTypeClass(); + switch (parameter){ + + case TypeClass::Error: return new Evaluation::StringEvalValue(u"error"); + case TypeClass::Nil: return new Evaluation::StringEvalValue(u"nil"); + case TypeClass::Number: return new Evaluation::StringEvalValue(u"number"); + case TypeClass::Bool: return new Evaluation::StringEvalValue(u"bool"); + case TypeClass::String: return new Evaluation::StringEvalValue(u"string"); + case TypeClass::Function: return new Evaluation::StringEvalValue(u"function"); + case TypeClass::UserData: return new Evaluation::StringEvalValue(u"userdata"); + case TypeClass::Table: return new Evaluation::StringEvalValue(u"table"); + case TypeClass::All: return new Evaluation::StringEvalValue(u"all"); + } + } + static shared_ptr GetTypeFuncType(){ + return GetFuncType(make_shared(false, 0), + {{make_shared(TypeClass::All)}}); + } + //endregion + //region IsFloat + + static const Evaluation::EvalValue* _isFloat(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){ + auto parameter = dynamic_cast(parameters[0]); + return new Evaluation::BooleanEvalValue(parameter->IsFloat()); + } + static shared_ptr GetIsFloatFuncType(){ + return GetFuncType(make_shared(TypeClass::Bool), + {{make_shared(false, false)}}); + } + //endregion + + //region Generic handling static shared_ptr GetFuncType(const shared_ptr& result, const vector>>& options){ auto funcType = make_shared(); @@ -56,25 +139,6 @@ namespace Porygon::StandardLibraries{ return funcType; } - static shared_ptr GetErrorFuncType(){ - return GetFuncType(make_shared(TypeClass::Nil), {{make_shared(false, 0)}}); - } - - static shared_ptr GetAssertFuncType(){ - return GetFuncType(make_shared(TypeClass::Bool), - {{make_shared(TypeClass::Bool)}, - {make_shared(TypeClass::Bool), make_shared(false, 0)}}); - } - - static shared_ptr GetPrintFuncType(){ - return GetFuncType(make_shared(TypeClass::Nil), {{make_shared(false, 0)}}); - } - - static shared_ptr GetToIntFuncType(){ - return GetFuncType(make_shared(true, false), {{make_shared(false, 0)}}); - } - - static Evaluation::EvalValue* GetFuncEvalValue( const Evaluation::EvalValue* (*func)(void* obj, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount), @@ -86,6 +150,7 @@ namespace Porygon::StandardLibraries{ } return f; } + //endregion public: @@ -118,6 +183,34 @@ namespace Porygon::StandardLibraries{ auto toIntFunc = BasicLibrary::GetFuncEvalValue(_toInt, toIntFuncType, 1); bound->insert({toIntLookup, new Binder::BoundVariable(toIntFuncType)}); values->insert({toIntLookup, toIntFunc}); + + // Register toFloat function + auto toFloatFuncType = BasicLibrary::GetToFloatFuncType(); + auto toFloatLookup = Utilities::HashedString::CreateLookup(u"tofloat"); + auto toFloatFunc = BasicLibrary::GetFuncEvalValue(_toFloat, toFloatFuncType, 1); + bound->insert({toFloatLookup, new Binder::BoundVariable(toFloatFuncType)}); + values->insert({toFloatLookup, toFloatFunc}); + + // Register ToString function + auto toStringFuncType = BasicLibrary::GetToStringFuncType(); + auto toStringLookup = Utilities::HashedString::CreateLookup(u"tostring"); + auto toStringFunc = BasicLibrary::GetFuncEvalValue(_toString, toStringFuncType, 1); + bound->insert({toStringLookup, new Binder::BoundVariable(toStringFuncType)}); + values->insert({toStringLookup, toStringFunc}); + + // Register Type function + auto typeFuncType = BasicLibrary::GetTypeFuncType(); + auto typeLookup = Utilities::HashedString::CreateLookup(u"type"); + auto typeFunc = BasicLibrary::GetFuncEvalValue(_type, typeFuncType, 1); + bound->insert({typeLookup, new Binder::BoundVariable(typeFuncType)}); + values->insert({typeLookup, typeFunc}); + + // Register IsFloat function + auto isFloatFuncType = BasicLibrary::GetTypeFuncType(); + auto isFloatLookup = Utilities::HashedString::CreateLookup(u"isfloat"); + auto isFloatFunc = BasicLibrary::GetFuncEvalValue(_isFloat, isFloatFuncType, 1); + bound->insert({isFloatLookup, new Binder::BoundVariable(isFloatFuncType)}); + values->insert({isFloatLookup, isFloatFunc}); } }; } diff --git a/src/Utilities/StringUtils.hpp b/src/Utilities/StringUtils.hpp index 70accbd..aa58b74 100644 --- a/src/Utilities/StringUtils.hpp +++ b/src/Utilities/StringUtils.hpp @@ -16,6 +16,10 @@ namespace Porygon::Utilities{ inline static std::u16string IntToString(long const &i) { return to_16.from_bytes(std::to_string(i)); } + inline static std::u16string FloatToString(double const &i) { + return to_16.from_bytes(std::to_string(i)); + } + inline static std::u16string ToUTF8(const std::string &s) { return to_16.from_bytes(s); } @@ -27,6 +31,11 @@ namespace Porygon::Utilities{ auto parsed = std::stol(FromUTF8(s)); return parsed; } + + inline static double ParseFloat(const std::u16string &s){ + auto parsed = std::stod(FromUTF8(s)); + return parsed; + } }; } diff --git a/tests/standardLibraries/BasicLibrary.cpp b/tests/standardLibraries/BasicLibrary.cpp index 4014670..649d92c 100644 --- a/tests/standardLibraries/BasicLibrary.cpp +++ b/tests/standardLibraries/BasicLibrary.cpp @@ -71,6 +71,44 @@ TEST_CASE( "toint func works", "[integration]" ) { delete script; } +TEST_CASE( "tofloat func works", "[integration]" ) { + Script* script = Script::Create(u"return tofloat('5.128')"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateFloat() == 5.128); + delete script; +} +TEST_CASE( "tostring func works", "[integration]" ) { + Script* script = Script::Create(u"return tostring(5.128)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateString() == u"5.128000"); + delete script; +} + +TEST_CASE( "type func works", "[integration]" ) { + Script* script = Script::Create(u"return type(5.128)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateString() == u"number"); + delete script; +} + +TEST_CASE( "isfloat returns true for floats", "[integration]" ) { + Script* script = Script::Create(u"return isfloat(5.128)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE(result->EvaluateBool()); + delete script; +} + +TEST_CASE( "isfloat returns false for integers", "[integration]" ) { + Script* script = Script::Create(u"return isfloat(5)"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto result = script->Evaluate(); + REQUIRE_FALSE(result->EvaluateBool()); + delete script; +} #endif