From 5e02b6b389614ff36d26670a2c54ab71763ac0b5 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Thu, 4 Jul 2019 15:56:42 +0200 Subject: [PATCH] Cleans up basic library handling, implements print function --- .../EvalValues/ScriptFunctionEvalValue.hpp | 14 ++-- src/FunctionScriptType.hpp | 2 +- src/GlobalScriptOptions.cpp | 12 +++ src/GlobalScriptOptions.hpp | 31 ++++++++ src/StandardLibraries/BasicLibrary.hpp | 73 ++++++++++++++----- src/UserData/UserDataFunction.hpp | 4 + tests/standardLibraries/BasicLibrary.cpp | 25 +++++++ 7 files changed, 135 insertions(+), 26 deletions(-) create mode 100644 src/GlobalScriptOptions.cpp create mode 100644 src/GlobalScriptOptions.hpp diff --git a/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp b/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp index a080201..cb6ff53 100644 --- a/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp +++ b/src/Evaluator/EvalValues/ScriptFunctionEvalValue.hpp @@ -24,10 +24,10 @@ namespace Porygon::Evaluation { const std::shared_ptr _scope; public: - EvaluationScriptFunctionOption(const shared_ptr innerBlock, const shared_ptr scope) - : _innerBlock(innerBlock), _scope(scope) { - + EvaluationScriptFunctionOption(shared_ptr innerBlock, shared_ptr scope) + : _innerBlock(std::move(innerBlock)), _scope(std::move(scope)) { } + ~EvaluationScriptFunctionOption() final = default; const std::shared_ptr &GetInnerBlock() const { return _innerBlock; @@ -36,15 +36,13 @@ namespace Porygon::Evaluation { const std::shared_ptr &GetScope() const { return _scope; } - - }; class GenericFunctionEvalValue : public EvalValue{ protected: - const std::shared_ptr _type; - const std::size_t _hash; - std::vector> _options; + const shared_ptr _type; + const size_t _hash; + vector> _options; public: GenericFunctionEvalValue(shared_ptr type, size_t hash) : _type(move(type)), diff --git a/src/FunctionScriptType.hpp b/src/FunctionScriptType.hpp index 5eebfd1..9cc4534 100644 --- a/src/FunctionScriptType.hpp +++ b/src/FunctionScriptType.hpp @@ -63,7 +63,7 @@ namespace Porygon { this -> RegisterFunctionOption(option); }; - virtual ~GenericFunctionScriptType() final{ + ~GenericFunctionScriptType() final{ for (auto o: _options){ delete o; } diff --git a/src/GlobalScriptOptions.cpp b/src/GlobalScriptOptions.cpp new file mode 100644 index 0000000..7ffbda2 --- /dev/null +++ b/src/GlobalScriptOptions.cpp @@ -0,0 +1,12 @@ +#include +#include "GlobalScriptOptions.hpp" +#include "Utilities/StringUtils.hpp" + +std::streambuf* Porygon::GlobalScriptOptions::_printBuffer = std::cout.rdbuf(); +std::ostream* Porygon::GlobalScriptOptions::_printStream = new std::ostream(Porygon::GlobalScriptOptions::_printBuffer); + +static void DefaultPrint(const std::u16string& s){ + Porygon::GlobalScriptOptions::GetPrintStream() << Porygon::Utilities::StringUtils::FromUTF8(s) << std::endl; +} + +void (*Porygon::GlobalScriptOptions::_print)(const std::u16string &) = DefaultPrint; diff --git a/src/GlobalScriptOptions.hpp b/src/GlobalScriptOptions.hpp new file mode 100644 index 0000000..d886c87 --- /dev/null +++ b/src/GlobalScriptOptions.hpp @@ -0,0 +1,31 @@ +#ifndef PORYGONLANG_GLOBALSCRIPTOPTIONS_HPP +#define PORYGONLANG_GLOBALSCRIPTOPTIONS_HPP + +#include + +namespace Porygon{ + class GlobalScriptOptions{ + static void (*_print)(const std::u16string& s); + static std::streambuf* _printBuffer; + static std::ostream* _printStream; + public: + static void Print(const std::u16string& s){ + GlobalScriptOptions::_print(s); + } + + static void SetPrintFunc(void (*print)(const std::u16string&)){ + GlobalScriptOptions::_print = print; + } + + static std::ostream& GetPrintStream(){ + return *GlobalScriptOptions::_printStream; + } + + static void SetPrintStream(std::ostream* stream){ + delete GlobalScriptOptions::_printStream; + GlobalScriptOptions::_printStream = stream; + } + }; +} + +#endif //PORYGONLANG_GLOBALSCRIPTOPTIONS_HPP diff --git a/src/StandardLibraries/BasicLibrary.hpp b/src/StandardLibraries/BasicLibrary.hpp index 2044487..3f2089e 100644 --- a/src/StandardLibraries/BasicLibrary.hpp +++ b/src/StandardLibraries/BasicLibrary.hpp @@ -10,6 +10,7 @@ #include "../Binder/BoundVariables/BoundVariable.hpp" #include "../UserData/UserDataFunction.hpp" #include "../UserData/UserDataFunctionType.hpp" +#include "../GlobalScriptOptions.hpp" namespace Porygon::StandardLibraries{ class BasicLibrary{ @@ -22,42 +23,80 @@ namespace Porygon::StandardLibraries{ static Evaluation::EvalValue* _assert(void*, Evaluation::EvalValue* parameters[], int parameterCount){ auto assertion = parameters[0]->EvaluateBool(); if (!assertion){ + if (parameterCount >= 2){ + auto error = parameters[1]->EvaluateString(); + auto conv = Utilities::StringUtils::FromUTF8(error); + throw Evaluation::EvaluationException(conv); + } throw Evaluation::EvaluationException("assertion failed!"); } return new Evaluation::BooleanEvalValue(true); } + static Evaluation::EvalValue* _print(void*, Evaluation::EvalValue* parameters[], int parameterCount){ + auto message = parameters[0]->EvaluateString(); + GlobalScriptOptions::Print(message); + return new Evaluation::NilEvalValue(); + } + + static shared_ptr GetFuncType(const shared_ptr& result, const vector>>& options){ + auto funcType = make_shared(); + for (const auto& o: options){ + auto option = new UserData::UserDataFunctionOption(result, o); + funcType->RegisterFunctionOption(option); + } + 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 GetFuncEvalValue( + Evaluation::EvalValue* (*func)(void* obj, Evaluation::EvalValue* parameters[], int parameterCount), + shared_ptr type, size_t optionLength){ + auto f = make_shared(type, rand()); + for (int i = 0; i < optionLength; i++){ + auto funcOption = new UserData::UserDataFunction(func, nullptr); + f->RegisterOption(funcOption); + } + return f; + } + public: static void RegisterVariables(std::map* bound, std::map>* values){ // Register error function - auto errorFuncTypeOption = new UserData::UserDataFunctionOption( - make_shared(TypeClass::Nil), - vector>{make_shared(false, 0)}); - auto errorFuncType = make_shared(); - errorFuncType->RegisterFunctionOption(errorFuncTypeOption); - auto errorFuncOption = new UserData::UserDataFunction(_error, nullptr); - auto errorFunc = make_shared(errorFuncType, rand()); - errorFunc->RegisterOption(errorFuncOption); + auto errorFuncType = BasicLibrary::GetErrorFuncType(); auto errorLookup = Utilities::HashedString::CreateLookup(u"error"); + auto errorFunc = BasicLibrary::GetFuncEvalValue(_error, errorFuncType, 1); bound->insert({errorLookup, new Binder::BoundVariable(errorFuncType)}); values->insert({errorLookup, errorFunc}); // Register assert function - auto assertFuncTypeOption = new UserData::UserDataFunctionOption( - make_shared(TypeClass::Bool), - vector>{make_shared(TypeClass::Bool)}); - auto assertFuncType = make_shared(); - assertFuncType->RegisterFunctionOption(assertFuncTypeOption); - auto assertFuncOption = new UserData::UserDataFunction(_assert, nullptr); - auto assertFunc = make_shared(assertFuncType, rand()); - assertFunc->RegisterOption(assertFuncOption); - + auto assertFuncType = BasicLibrary::GetAssertFuncType(); auto assertLookup = Utilities::HashedString::CreateLookup(u"assert"); + auto assertFunc = BasicLibrary::GetFuncEvalValue(_assert, assertFuncType, 2); bound->insert({assertLookup, new Binder::BoundVariable(assertFuncType)}); values->insert({assertLookup, assertFunc}); + // Register print function + auto printFuncType = BasicLibrary::GetPrintFuncType(); + auto printLookup = Utilities::HashedString::CreateLookup(u"print"); + auto printFunc = BasicLibrary::GetFuncEvalValue(_print, printFuncType, 1); + bound->insert({printLookup, new Binder::BoundVariable(printFuncType)}); + values->insert({printLookup, printFunc}); } }; } diff --git a/src/UserData/UserDataFunction.hpp b/src/UserData/UserDataFunction.hpp index 5635378..0714a41 100644 --- a/src/UserData/UserDataFunction.hpp +++ b/src/UserData/UserDataFunction.hpp @@ -23,6 +23,10 @@ namespace Porygon::UserData{ _obj = obj; } + ~UserDataFunction() final{ + + } + Evaluation::EvalValue* Call(Evaluation::EvalValue* parameters[], int parameterCount){ return _call(_obj, parameters, parameterCount); } diff --git a/tests/standardLibraries/BasicLibrary.cpp b/tests/standardLibraries/BasicLibrary.cpp index c4c2fc0..a6717b1 100644 --- a/tests/standardLibraries/BasicLibrary.cpp +++ b/tests/standardLibraries/BasicLibrary.cpp @@ -1,6 +1,7 @@ #ifdef TESTS_BUILD #include #include "../src/Script.hpp" +#include "../../src/GlobalScriptOptions.hpp" #include using namespace Porygon; @@ -38,6 +39,30 @@ TEST_CASE( "Assert func does not throw if argument is true", "[integration]" ) { delete script; } +TEST_CASE( "Assert func works with second argument", "[integration]" ) { + Script* script = Script::Create(u"assert(false, 'foobar')"); + REQUIRE(!script->Diagnostics -> HasErrors()); + try{ + script -> Evaluate(); + throw; + } catch (const EvaluationException& e){ + auto err = e.what(); + REQUIRE(std::strcmp(err, "An evaluation exception occurred: foobar") == 0); + } + delete script; +} + +TEST_CASE( "Print func works", "[integration]" ) { + Script* script = Script::Create(u"print('foobar')"); + REQUIRE(!script->Diagnostics -> HasErrors()); + auto stream = new std::stringstream(); + GlobalScriptOptions::SetPrintStream(stream); + script->Evaluate(); + auto printVal = stream->str(); + REQUIRE(printVal == "foobar\n"); + delete script; +} + #endif