/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#ifndef _OUSIA_FUNCTION_HPP_
#define _OUSIA_FUNCTION_HPP_
#include
#include
#include
#include "Variant.hpp"
namespace ousia {
namespace script {
/**
* The abstract Function class is most basic version of a function handle --
* just a virtual "call" function which calls the underlying code.
*/
class Function {
public:
/**
* Abstract function which is meant to call the underlying function (be it
* a host or a script function) with the given arguments.
*
* @param args is a vector containing all arguments that shall be passed to
* the function.
* @return a Variant containing the return value.
*/
virtual Variant call(const std::vector &args) const = 0;
/**
* Calls the underlying function with no arguments.
*
* @return a Variant containing the return value.
*/
Variant call() const { return call({}); }
};
/**
* The ArgumentDescriptor class is used to describe the type of a function
* argument.
*/
struct ArgumentDescriptor {
const VariantType type;
const bool hasDefault;
const Variant defaultValue;
ArgumentDescriptor(VariantType type) :
type(type), hasDefault(false) {};
ArgumentDescriptor(VariantType type, const Variant &defaultValue) :
type(type), hasDefault(true), defaultValue(defaultValue) {};
};
/**
* ArgumentValidatorError is an exception type used to represent argument
* validator errors.
*/
class ArgumentValidatorError : public std::exception {
public:
const int index;
const std::string msg;
ArgumentValidatorError(int index, const std::string &msg) :
index(index), msg(msg) {};
virtual const char* what() const noexcept override
{
return msg.c_str();
}
};
/**
* The ArgumentValidator class is responsible for checking whether the given
* arguments passed to a function match the description.
*/
class ArgumentValidator {
private:
/**
* List containing the argument descriptors.
*/
const std::vector descriptors;
/**
* Argument index in the input array, at which the last error occured.
*/
int errorIndex = -1;
/**
* Error message for the last validation error.
*/
std::string errorMessage;
std::pair> setError(int idx,
const std::string &msg, std::vector &res);
void resetError();
public:
/**
* Constructor of the argument validator class.
*
* @param descriptors is a list of ArgumentDescriptors which should be used
* for the validation.
*/
ArgumentValidator(const std::vector &descriptors) :
descriptors(descriptors) {}
/**
* Validates and augments the given argument list (e.g. adds the default
* values).
*
* @param args contains the input arguments.
* @return a pair, where the first element specifies whether the arguments
* were validated sucessfully and the second argument contains the augmented
* list of arguments. If false is returned, use the error function to get
* more information about the error.
*/
std::pair> validate(const std::vector &args);
/**
* Returns an ArgumentValidatorError instance containing the argument index
* in the input array, at which the error occured and an explaining error
* message. As ArgumentValidatorError is derived from std::exception,
* the result of this function is throwable.
*
* @return an ArgumentValidatorError instance containing information about
* the last error. If no error occurred, the message will be empty and
* the argument index will be set to -1.
*/
ArgumentValidatorError error()
{
return ArgumentValidatorError(errorIndex, errorMessage);
}
};
/**
* The HostFunction class represents a function that resides in the script host.
*/
template
class HostFunction : public Function {
private:
T callback;
ArgumentValidator *validator;
void *data;
public:
HostFunction(T callback, std::vector signature,
void *data = nullptr) :
callback(callback), validator(new ArgumentValidator(signature)),
data(data) {}
HostFunction(T callback, void *data = nullptr) :
callback(callback), validator(nullptr), data(data) {}
~HostFunction()
{
delete validator;
}
virtual Variant call(const std::vector &args) const override
{
if (validator) {
std::pair> res = validator->validate(args);
if (!res.first) {
throw validator->error();
}
return callback(res.second, data);
} else {
return callback(args, data);
}
}
using Function::call;
};
template
static HostFunction createHostFunction(T callback,
std::vector signature, void *data = nullptr)
{
return HostFunction(callback, signature, data);
}
template
static HostFunction createHostFunction(T callback, void *data = nullptr)
{
return HostFunction(callback, data);
}
}
}
#endif /* _OUSIA_FUNCTION_HPP_ */