Cleans up basic library handling, implements print function
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-07-04 15:56:42 +02:00
parent db2d731b06
commit 5e02b6b389
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
7 changed files with 135 additions and 26 deletions

View File

@ -24,10 +24,10 @@ namespace Porygon::Evaluation {
const std::shared_ptr<EvaluationScope> _scope; const std::shared_ptr<EvaluationScope> _scope;
public: public:
EvaluationScriptFunctionOption(const shared_ptr<BoundBlockStatement> innerBlock, const shared_ptr<EvaluationScope> scope) EvaluationScriptFunctionOption(shared_ptr<BoundBlockStatement> innerBlock, shared_ptr<EvaluationScope> scope)
: _innerBlock(innerBlock), _scope(scope) { : _innerBlock(std::move(innerBlock)), _scope(std::move(scope)) {
} }
~EvaluationScriptFunctionOption() final = default;
const std::shared_ptr<BoundBlockStatement> &GetInnerBlock() const { const std::shared_ptr<BoundBlockStatement> &GetInnerBlock() const {
return _innerBlock; return _innerBlock;
@ -36,15 +36,13 @@ namespace Porygon::Evaluation {
const std::shared_ptr<EvaluationScope> &GetScope() const { const std::shared_ptr<EvaluationScope> &GetScope() const {
return _scope; return _scope;
} }
}; };
class GenericFunctionEvalValue : public EvalValue{ class GenericFunctionEvalValue : public EvalValue{
protected: protected:
const std::shared_ptr<GenericFunctionScriptType> _type; const shared_ptr<GenericFunctionScriptType> _type;
const std::size_t _hash; const size_t _hash;
std::vector<shared_ptr<GenericFunctionOption>> _options; vector<shared_ptr<GenericFunctionOption>> _options;
public: public:
GenericFunctionEvalValue(shared_ptr<GenericFunctionScriptType> type, size_t hash) GenericFunctionEvalValue(shared_ptr<GenericFunctionScriptType> type, size_t hash)
: _type(move(type)), : _type(move(type)),

View File

@ -63,7 +63,7 @@ namespace Porygon {
this -> RegisterFunctionOption(option); this -> RegisterFunctionOption(option);
}; };
virtual ~GenericFunctionScriptType() final{ ~GenericFunctionScriptType() final{
for (auto o: _options){ for (auto o: _options){
delete o; delete o;
} }

View File

@ -0,0 +1,12 @@
#include <iostream>
#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;

View File

@ -0,0 +1,31 @@
#ifndef PORYGONLANG_GLOBALSCRIPTOPTIONS_HPP
#define PORYGONLANG_GLOBALSCRIPTOPTIONS_HPP
#include <string>
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

View File

@ -10,6 +10,7 @@
#include "../Binder/BoundVariables/BoundVariable.hpp" #include "../Binder/BoundVariables/BoundVariable.hpp"
#include "../UserData/UserDataFunction.hpp" #include "../UserData/UserDataFunction.hpp"
#include "../UserData/UserDataFunctionType.hpp" #include "../UserData/UserDataFunctionType.hpp"
#include "../GlobalScriptOptions.hpp"
namespace Porygon::StandardLibraries{ namespace Porygon::StandardLibraries{
class BasicLibrary{ class BasicLibrary{
@ -22,42 +23,80 @@ namespace Porygon::StandardLibraries{
static Evaluation::EvalValue* _assert(void*, Evaluation::EvalValue* parameters[], int parameterCount){ static Evaluation::EvalValue* _assert(void*, Evaluation::EvalValue* parameters[], int parameterCount){
auto assertion = parameters[0]->EvaluateBool(); auto assertion = parameters[0]->EvaluateBool();
if (!assertion){ 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!"); throw Evaluation::EvaluationException("assertion failed!");
} }
return new Evaluation::BooleanEvalValue(true); 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<GenericFunctionScriptType> GetFuncType(const shared_ptr<ScriptType>& result, const vector<vector<shared_ptr<ScriptType>>>& options){
auto funcType = make_shared<GenericFunctionScriptType>();
for (const auto& o: options){
auto option = new UserData::UserDataFunctionOption(result, o);
funcType->RegisterFunctionOption(option);
}
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<Evaluation::EvalValue> GetFuncEvalValue(
Evaluation::EvalValue* (*func)(void* obj, Evaluation::EvalValue* parameters[], int parameterCount),
shared_ptr<GenericFunctionScriptType> type, size_t optionLength){
auto f = make_shared<Evaluation::GenericFunctionEvalValue>(type, rand());
for (int i = 0; i < optionLength; i++){
auto funcOption = new UserData::UserDataFunction(func, nullptr);
f->RegisterOption(funcOption);
}
return f;
}
public: public:
static void RegisterVariables(std::map<Utilities::HashedString, Binder::BoundVariable *>* bound, static void RegisterVariables(std::map<Utilities::HashedString, Binder::BoundVariable *>* bound,
std::map<Utilities::HashedString, shared_ptr<Evaluation::EvalValue>>* values){ std::map<Utilities::HashedString, shared_ptr<Evaluation::EvalValue>>* values){
// Register error function // Register error function
auto errorFuncTypeOption = new UserData::UserDataFunctionOption( auto errorFuncType = BasicLibrary::GetErrorFuncType();
make_shared<ScriptType>(TypeClass::Nil),
vector<shared_ptr<ScriptType>>{make_shared<StringScriptType>(false, 0)});
auto errorFuncType = make_shared<GenericFunctionScriptType>();
errorFuncType->RegisterFunctionOption(errorFuncTypeOption);
auto errorFuncOption = new UserData::UserDataFunction(_error, nullptr);
auto errorFunc = make_shared<Evaluation::GenericFunctionEvalValue>(errorFuncType, rand());
errorFunc->RegisterOption(errorFuncOption);
auto errorLookup = Utilities::HashedString::CreateLookup(u"error"); auto errorLookup = Utilities::HashedString::CreateLookup(u"error");
auto errorFunc = BasicLibrary::GetFuncEvalValue(_error, errorFuncType, 1);
bound->insert({errorLookup, new Binder::BoundVariable(errorFuncType)}); bound->insert({errorLookup, new Binder::BoundVariable(errorFuncType)});
values->insert({errorLookup, errorFunc}); values->insert({errorLookup, errorFunc});
// Register assert function // Register assert function
auto assertFuncTypeOption = new UserData::UserDataFunctionOption( auto assertFuncType = BasicLibrary::GetAssertFuncType();
make_shared<ScriptType>(TypeClass::Bool),
vector<shared_ptr<ScriptType>>{make_shared<ScriptType>(TypeClass::Bool)});
auto assertFuncType = make_shared<GenericFunctionScriptType>();
assertFuncType->RegisterFunctionOption(assertFuncTypeOption);
auto assertFuncOption = new UserData::UserDataFunction(_assert, nullptr);
auto assertFunc = make_shared<Evaluation::GenericFunctionEvalValue>(assertFuncType, rand());
assertFunc->RegisterOption(assertFuncOption);
auto assertLookup = Utilities::HashedString::CreateLookup(u"assert"); auto assertLookup = Utilities::HashedString::CreateLookup(u"assert");
auto assertFunc = BasicLibrary::GetFuncEvalValue(_assert, assertFuncType, 2);
bound->insert({assertLookup, new Binder::BoundVariable(assertFuncType)}); bound->insert({assertLookup, new Binder::BoundVariable(assertFuncType)});
values->insert({assertLookup, assertFunc}); 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});
} }
}; };
} }

View File

@ -23,6 +23,10 @@ namespace Porygon::UserData{
_obj = obj; _obj = obj;
} }
~UserDataFunction() final{
}
Evaluation::EvalValue* Call(Evaluation::EvalValue* parameters[], int parameterCount){ Evaluation::EvalValue* Call(Evaluation::EvalValue* parameters[], int parameterCount){
return _call(_obj, parameters, parameterCount); return _call(_obj, parameters, parameterCount);
} }

View File

@ -1,6 +1,7 @@
#ifdef TESTS_BUILD #ifdef TESTS_BUILD
#include <catch.hpp> #include <catch.hpp>
#include "../src/Script.hpp" #include "../src/Script.hpp"
#include "../../src/GlobalScriptOptions.hpp"
#include <cstring> #include <cstring>
using namespace Porygon; using namespace Porygon;
@ -38,6 +39,30 @@ TEST_CASE( "Assert func does not throw if argument is true", "[integration]" ) {
delete script; 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 #endif