Better handling of userdata exceptions in other languages.
continuous-integration/drone/push Build is passing Details

This commit is contained in:
Deukhoofd 2019-09-28 13:08:32 +02:00
parent e7e5e64bbb
commit f8cbe502c9
Signed by: Deukhoofd
GPG Key ID: ADF2E9256009EDCE
8 changed files with 129 additions and 72 deletions

View File

@ -369,7 +369,10 @@ namespace Porygon::Evaluation {
arr[i] = parameters[i].Get();
}
delete function;
return scriptOption -> Call(this -> _scriptOptions, arr, parameters.size());
auto ret = scriptOption -> Call(this -> _scriptOptions, arr, parameters.size());
auto v = ret->Evaluate();
delete ret;
return v;
}
}

View File

@ -19,7 +19,9 @@ namespace Porygon::StandardLibraries{
class BasicLibrary{
//region Assert
static const Evaluation::EvalValue* _assert(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
typedef UserData::UserDataReturnValue Return;
static const UserData::UserDataReturnValue* _assert(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
auto assertion = parameters[0]->EvaluateBool();
if (!assertion){
if (parameterCount >= 2){
@ -29,7 +31,7 @@ namespace Porygon::StandardLibraries{
}
throw Evaluation::EvaluationException("assertion failed!");
}
return new Evaluation::BooleanEvalValue(true);
return new Return(new Evaluation::BooleanEvalValue(true));
}
static shared_ptr<GenericFunctionScriptType> GetAssertFuncType(){
@ -40,7 +42,7 @@ namespace Porygon::StandardLibraries{
//endregion
//region Error
static const Evaluation::EvalValue* _error(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
static const UserData::UserDataReturnValue* _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);
@ -51,10 +53,10 @@ namespace Porygon::StandardLibraries{
//endregion
//region Print
static const Evaluation::EvalValue* _print(void*, const ScriptOptions* options, const Evaluation::EvalValue* parameters[], int parameterCount){
static const UserData::UserDataReturnValue* _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();
return new Return(new Evaluation::NilEvalValue());
}
static shared_ptr<GenericFunctionScriptType> GetPrintFuncType(){
return GetFuncType(ScriptType::NilType, {{StringScriptType::Dynamic}});
@ -62,10 +64,10 @@ namespace Porygon::StandardLibraries{
//endregion
//region ToInt
static const Evaluation::EvalValue* _toInt(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
static const UserData::UserDataReturnValue* _toInt(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
auto parameter = parameters[0]->EvaluateString();
auto parsed = Utilities::StringUtils::ParseInteger(parameter);
return new Evaluation::NumericEvalValue(parsed);
return new Return(new Evaluation::NumericEvalValue(parsed));
}
static shared_ptr<GenericFunctionScriptType> GetToIntFuncType(){
return GetFuncType(NumericScriptType::AwareInt,
@ -74,10 +76,10 @@ namespace Porygon::StandardLibraries{
//endregion
//region ToFloat
static const Evaluation::EvalValue* _toFloat(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
static const UserData::UserDataReturnValue* _toFloat(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
auto parameter = parameters[0]->EvaluateString();
auto parsed = Utilities::StringUtils::ParseFloat(parameter);
return new Evaluation::NumericEvalValue(parsed);
return new Return(new Evaluation::NumericEvalValue(parsed));
}
static shared_ptr<GenericFunctionScriptType> GetToFloatFuncType(){
return GetFuncType(NumericScriptType::AwareFloat,
@ -86,9 +88,9 @@ namespace Porygon::StandardLibraries{
//endregion
//region ToString
static const Evaluation::EvalValue* _toString(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
static const UserData::UserDataReturnValue* _toString(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
auto parameter = parameters[0]->EvaluateString();
return new Evaluation::StringEvalValue(parameter);
return new Return(new Evaluation::StringEvalValue(parameter));
}
static shared_ptr<GenericFunctionScriptType> GetToStringFuncType(){
return GetFuncType(StringScriptType::Dynamic, {{make_shared<ScriptType>(TypeClass::Any)}});
@ -96,20 +98,20 @@ namespace Porygon::StandardLibraries{
//endregion
//region Type
static const Evaluation::EvalValue* _type(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
static const UserData::UserDataReturnValue* _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::UserDataCollection: return new Evaluation::StringEvalValue(u"userdata-collection");
case TypeClass::Table: return new Evaluation::StringEvalValue(u"table");
case TypeClass::Any: return new Evaluation::StringEvalValue(u"all");
case TypeClass::Error: return new Return(new Evaluation::StringEvalValue(u"error"));
case TypeClass::Nil: return new Return(new Evaluation::StringEvalValue(u"nil"));
case TypeClass::Number: return new Return(new Evaluation::StringEvalValue(u"number"));
case TypeClass::Bool: return new Return(new Evaluation::StringEvalValue(u"bool"));
case TypeClass::String: return new Return(new Evaluation::StringEvalValue(u"string"));
case TypeClass::Function: return new Return(new Evaluation::StringEvalValue(u"function"));
case TypeClass::UserData: return new Return(new Evaluation::StringEvalValue(u"userdata"));
case TypeClass::UserDataCollection: return new Return(new Evaluation::StringEvalValue(u"userdata-collection"));
case TypeClass::Table: return new Return(new Evaluation::StringEvalValue(u"table"));
case TypeClass::Any: return new Return(new Evaluation::StringEvalValue(u"all"));
}
throw exception();
}
@ -119,9 +121,9 @@ namespace Porygon::StandardLibraries{
//endregion
//region IsFloat
static const Evaluation::EvalValue* _isFloat(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
static const UserData::UserDataReturnValue* _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());
return new Return(new Evaluation::BooleanEvalValue(parameter->IsFloat()));
}
static shared_ptr<GenericFunctionScriptType> GetIsFloatFuncType(){
return GetFuncType(ScriptType::BoolType, {{NumericScriptType::Unaware}});
@ -140,10 +142,10 @@ namespace Porygon::StandardLibraries{
return funcType;
}
static Evaluation::EvalValue* GetFuncEvalValue(
const Evaluation::EvalValue* (*func)(void* obj, const ScriptOptions*,
const Evaluation::EvalValue* parameters[], int parameterCount),
const shared_ptr<GenericFunctionScriptType>& type, size_t optionLength){
static Evaluation::EvalValue* GetFuncEvalValue(const UserData::UserDataReturnValue* (*func)(void* obj, const ScriptOptions*,
const Evaluation::EvalValue* parameters[], int parameterCount),
const shared_ptr<GenericFunctionScriptType>& type, size_t optionLength)
{
auto f = new Evaluation::GenericFunctionEvalValue(type, Utilities::Random::Get());
for (size_t i = 0; i < optionLength; i++){
auto funcOption = new UserData::UserDataFunction(func, nullptr);

View File

@ -24,6 +24,7 @@ namespace Porygon::StandardLibraries {
using namespace Porygon::Evaluation;
using namespace Porygon::Utilities;
class MathLibrary {
typedef UserData::UserDataReturnValue Return;
//region templates
@ -31,7 +32,7 @@ namespace Porygon::StandardLibraries {
#define INTEGER_TYPE NumericScriptType::AwareInt
#define BOOL_TYPE ScriptType::BoolType
#define FUNCTION(fieldName) \
[](void* obj) -> const Porygon::Evaluation::EvalValue* { \
[](void* obj) -> const EvalValue* { \
auto t = new Porygon::Evaluation::GenericFunctionEvalValue(make_shared<GenericFunctionScriptType>(), \
Porygon::Utilities::Random::Get()); \
t->RegisterOption(new Porygon::UserData::UserDataFunction(fieldName, nullptr)); \
@ -39,83 +40,91 @@ namespace Porygon::StandardLibraries {
nullptr
//endregion
static const EvalValue* _abs(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
inline static const Return* RETURN(double d){
return new Return(new NumericEvalValue(d));
}
inline static const Return* RETURN(int64_t i){
return new Return(new NumericEvalValue(i));
}
static const Return* _abs(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
if (parameter->IsFloat()){
return new NumericEvalValue(std::abs(parameter->EvaluateFloat()));
return RETURN(std::abs(parameter->EvaluateFloat()));
} else{
return new NumericEvalValue(std::abs(parameter->EvaluateInteger()));
return RETURN(std::abs(parameter->EvaluateInteger()));
}
}
static const EvalValue* _acos(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _acos(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
return new NumericEvalValue(std::acos(parameter->EvaluateFloat()));
return RETURN(std::acos(parameter->EvaluateFloat()));
}
static const EvalValue* _asin(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _asin(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
return new NumericEvalValue(std::asin(parameter->EvaluateFloat()));
return RETURN(std::asin(parameter->EvaluateFloat()));
}
static const EvalValue* _atan(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _atan(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
if (parameterCount == 1){
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
return new NumericEvalValue(std::atan(parameter->EvaluateFloat()));
return RETURN(std::atan(parameter->EvaluateFloat()));
}
else{
auto parameter1 = dynamic_cast<const NumericEvalValue*>(parameters[0]);
auto parameter2 = dynamic_cast<const NumericEvalValue*>(parameters[1]);
return new NumericEvalValue(std::atan2(parameter1->EvaluateFloat(), parameter2->EvaluateFloat()));
return RETURN(std::atan2(parameter1->EvaluateFloat(), parameter2->EvaluateFloat()));
}
}
static const EvalValue* _ceil(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _ceil(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
auto f = parameter->EvaluateFloat();
return new NumericEvalValue(static_cast<int64_t>(std::ceil(f)));
return RETURN(static_cast<int64_t>(std::ceil(f)));
}
static const EvalValue* _cos(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _cos(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
auto f = parameter->EvaluateFloat();
return new NumericEvalValue(std::cos(f));
return RETURN(std::cos(f));
}
static const EvalValue* _deg(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _deg(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
auto f = parameter->EvaluateFloat();
return new NumericEvalValue(f * 180 / M_PI);
return RETURN(f * 180 / M_PI);
}
static const EvalValue* _exp(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _exp(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
auto f = parameter->EvaluateFloat();
return new NumericEvalValue(std::exp(f));
return RETURN(std::exp(f));
}
static const EvalValue* _floor(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _floor(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
auto f = parameter->EvaluateFloat();
return new NumericEvalValue(std::floor(f));
return RETURN(std::floor(f));
}
static const EvalValue* _fmod(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _fmod(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto f1 = dynamic_cast<const NumericEvalValue*>(parameters[0])->EvaluateFloat();
auto f2 = dynamic_cast<const NumericEvalValue*>(parameters[0])->EvaluateFloat();
return new NumericEvalValue(std::fmod(f1, f2));
return RETURN(std::fmod(f1, f2));
}
static const EvalValue* _huge;
static const EvalValue* _log(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
static const Return* _log(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount){
if (parameterCount == 1){
auto f = dynamic_cast<const NumericEvalValue*>(parameters[0])->EvaluateFloat();
return new NumericEvalValue(std::log(f));
return RETURN(std::log(f));
}
else{
auto f1 = dynamic_cast<const NumericEvalValue*>(parameters[0])->EvaluateFloat();
auto f2 = dynamic_cast<const NumericEvalValue*>(parameters[1])->EvaluateFloat();
return new NumericEvalValue(std::log(f2) / std::log(f1));
return RETURN(std::log(f2) / std::log(f1));
}
}
@ -123,31 +132,31 @@ namespace Porygon::StandardLibraries {
static const EvalValue* _minInteger;
static const EvalValue* _pi;
static const EvalValue* _rad(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _rad(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
auto f = parameter->EvaluateFloat();
return new NumericEvalValue(M_PI *(f / 180));
return RETURN(M_PI *(f / 180));
}
static const EvalValue* _sin(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _sin(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
return new NumericEvalValue(std::sin(parameter->EvaluateFloat()));
return RETURN(std::sin(parameter->EvaluateFloat()));
}
static const EvalValue* _sqrt(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _sqrt(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
return new NumericEvalValue(std::sqrt(parameter->EvaluateFloat()));
return RETURN(std::sqrt(parameter->EvaluateFloat()));
}
static const EvalValue* _tan(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _tan(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter = dynamic_cast<const NumericEvalValue*>(parameters[0]);
return new NumericEvalValue(std::tan(parameter->EvaluateFloat()));
return RETURN(std::tan(parameter->EvaluateFloat()));
}
static const EvalValue* _ult(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
static const Return* _ult(void*, const ScriptOptions*, const Evaluation::EvalValue* parameters[], int parameterCount) {
auto parameter1 = dynamic_cast<const NumericEvalValue*>(parameters[0])->EvaluateInteger();
auto parameter2 = dynamic_cast<const NumericEvalValue*>(parameters[1])->EvaluateInteger();
return new BooleanEvalValue(parameter1 < parameter2);
return new Return(new BooleanEvalValue(parameter1 < parameter2));
}
static UserData::UserDataFunctionOption* CreateFunctionOption(const shared_ptr<const ScriptType>& returnType,

View File

@ -6,7 +6,7 @@ using namespace Porygon::Evaluation;
namespace Porygon::UserData{
extern "C" {
const EvalValue * CreateFunctionEvalValue(const Evaluation::EvalValue* (*func)(void*, const ScriptOptions*,
const EvalValue * CreateFunctionEvalValue(const UserData::UserDataReturnValue* (*func)(void*, const ScriptOptions*,
const EvalValue* [], int ), void* obj) {
auto opt = new UserDataFunction(func, obj);
auto t = new GenericFunctionEvalValue(make_shared<GenericFunctionScriptType>(), Utilities::Random::Get());
@ -15,7 +15,7 @@ namespace Porygon::UserData{
}
void RegisterFunctionEvalValueOption(const GenericFunctionEvalValue* val,
const Evaluation::EvalValue* (*func)(void*, const ScriptOptions*, const EvalValue* [], int ), void* obj){
const UserData::UserDataReturnValue* (*func)(void*, const ScriptOptions*, const EvalValue* [], int ), void* obj){
auto opt = new UserDataFunction(func, obj);
val->RegisterOption(opt);
}

View File

@ -5,21 +5,22 @@
#include "UserDataFunctionType.hpp"
#include "../ScriptTypes/FunctionScriptType.hpp"
#include "../ScriptOptions.hpp"
#include "UserDataReturnValue.hpp"
namespace Porygon::UserData{
class UserDataFunction : public Evaluation::GenericFunctionOption {
const Evaluation::EvalValue* (*_call)(void* obj, const ScriptOptions*, const Evaluation::EvalValue* parameters[],
const UserDataReturnValue* (*_call)(void* obj, const ScriptOptions*, const Evaluation::EvalValue* parameters[],
int parameterCount);
void *_obj;
UserDataFunction(const Evaluation::EvalValue* (*call)(void* obj, const ScriptOptions*,
UserDataFunction(const UserDataReturnValue* (*call)(void* obj, const ScriptOptions*,
const Evaluation::EvalValue* parameters[], int parameterCount), void* obj,
const shared_ptr<GenericFunctionScriptType>& type, size_t hash) : GenericFunctionOption(){
_call = call;
_obj = obj;
}
public:
UserDataFunction(const Evaluation::EvalValue* (*call)(void* obj, const ScriptOptions*,
UserDataFunction(const UserDataReturnValue* (*call)(void* obj, const ScriptOptions*,
const Evaluation::EvalValue* parameters[], int parameterCount), void* obj) :
GenericFunctionOption(){
_call = call;
@ -29,7 +30,7 @@ namespace Porygon::UserData{
~UserDataFunction() final = default;
[[nodiscard]]
inline const Evaluation::EvalValue* Call(const ScriptOptions* script,
inline const UserDataReturnValue* Call(const ScriptOptions* script,
const Evaluation::EvalValue* parameters[], int parameterCount) const{
return _call(_obj, script, parameters, parameterCount);
}

View File

@ -0,0 +1,12 @@
#include "UserDataReturnValue.hpp"
extern "C"{
Porygon::UserData::UserDataReturnValue* ReturnValue(Porygon::Evaluation::EvalValue* value){
return new Porygon::UserData::UserDataReturnValue(value);
}
Porygon::UserData::UserDataReturnValue* ErrorValue(const char* message){
return new Porygon::UserData::UserDataReturnValue(message);
}
}

View File

@ -0,0 +1,29 @@
#ifndef PORYGONLANG_USERDATARETURNVALUE_HPP
#define PORYGONLANG_USERDATARETURNVALUE_HPP
#include "../Evaluator/EvalValues/EvalValue.hpp"
extern "C" {
namespace Porygon::UserData {
struct UserDataReturnValue {
bool _success;
union {
const char *_message;
const Evaluation::EvalValue *_value;
};
public:
UserDataReturnValue(Evaluation::EvalValue *value) : _success(true), _value(value) {}
UserDataReturnValue(const Evaluation::EvalValue *value) : _success(true), _value(value) {}
UserDataReturnValue(const char *message) : _success(false), _message(message) {}
inline const Evaluation::EvalValue *Evaluate() const{
if (_success) {
return _value;
}
throw Evaluation::EvaluationException(_message);
}
};
}
}
#endif //PORYGONLANG_USERDATARETURNVALUE_HPP

View File

@ -117,7 +117,8 @@ Porygon::Utilities::HashedString* Convert(const char* k){
Porygon::Utilities::Random::Get()); \
t->RegisterOption(new Porygon::UserData::UserDataFunction( \
[](void* obj, const ScriptOptions* opts, const Porygon::Evaluation::EvalValue* par[], int parameterCount) \
-> const Porygon::Evaluation::EvalValue*{return ((const T_USERDATA*)obj)->invoke__##fieldName(obj, opts, par, parameterCount);}, \
-> const Porygon::UserData::UserDataReturnValue*{ \
return new Porygon::UserData::UserDataReturnValue (((const T_USERDATA*)obj)->invoke__##fieldName(obj, opts, par, parameterCount));}, \
obj)); \
return t;}, \
nullptr) \