Implements most of the remaining core standard functions
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-08-15 18:12:29 +02:00
parent 7523fb4294
commit 13b382def2
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
6 changed files with 173 additions and 25 deletions

View File

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

View File

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

View File

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

View File

@ -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<GenericFunctionScriptType> GetAssertFuncType(){
return GetFuncType(make_shared<ScriptType>(TypeClass::Bool),
{{make_shared<ScriptType>(TypeClass::Bool)},
{make_shared<ScriptType>(TypeClass::Bool), make_shared<StringScriptType>(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<GenericFunctionScriptType> GetErrorFuncType(){
return GetFuncType(make_shared<ScriptType>(TypeClass::Nil), {{make_shared<StringScriptType>(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<GenericFunctionScriptType> GetPrintFuncType(){
return GetFuncType(make_shared<ScriptType>(TypeClass::Nil), {{make_shared<StringScriptType>(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<GenericFunctionScriptType> GetToIntFuncType(){
return GetFuncType(make_shared<NumericScriptType>(true, false), {{make_shared<StringScriptType>(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<GenericFunctionScriptType> GetToFloatFuncType(){
return GetFuncType(make_shared<NumericScriptType>(true, true),
{{make_shared<StringScriptType>(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<GenericFunctionScriptType> GetToStringFuncType(){
return GetFuncType(make_shared<StringScriptType>(false, 0),
{{make_shared<ScriptType>(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<GenericFunctionScriptType> GetTypeFuncType(){
return GetFuncType(make_shared<StringScriptType>(false, 0),
{{make_shared<ScriptType>(TypeClass::All)}});
}
//endregion
//region IsFloat
static const Evaluation::EvalValue* _isFloat(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
auto parameter = dynamic_cast<const Evaluation::NumericEvalValue*>(parameters[0]);
return new Evaluation::BooleanEvalValue(parameter->IsFloat());
}
static shared_ptr<GenericFunctionScriptType> GetIsFloatFuncType(){
return GetFuncType(make_shared<ScriptType>(TypeClass::Bool),
{{make_shared<NumericScriptType>(false, false)}});
}
//endregion
//region Generic handling
static shared_ptr<GenericFunctionScriptType> GetFuncType(const shared_ptr<ScriptType>& result, const vector<vector<shared_ptr<ScriptType>>>& options){
auto funcType = make_shared<GenericFunctionScriptType>();
@ -56,25 +139,6 @@ namespace Porygon::StandardLibraries{
return funcType;
}
static shared_ptr<GenericFunctionScriptType> GetErrorFuncType(){
return GetFuncType(make_shared<ScriptType>(TypeClass::Nil), {{make_shared<StringScriptType>(false, 0)}});
}
static shared_ptr<GenericFunctionScriptType> GetAssertFuncType(){
return GetFuncType(make_shared<ScriptType>(TypeClass::Bool),
{{make_shared<ScriptType>(TypeClass::Bool)},
{make_shared<ScriptType>(TypeClass::Bool), make_shared<StringScriptType>(false, 0)}});
}
static shared_ptr<GenericFunctionScriptType> GetPrintFuncType(){
return GetFuncType(make_shared<ScriptType>(TypeClass::Nil), {{make_shared<StringScriptType>(false, 0)}});
}
static shared_ptr<GenericFunctionScriptType> GetToIntFuncType(){
return GetFuncType(make_shared<NumericScriptType>(true, false), {{make_shared<StringScriptType>(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});
}
};
}

View File

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

View File

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