/* 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, * maintaining a "call" function and basic virtual functions for lifecyle * management. */ class Function { public: /** * Virtual clone function (e.g. used in the variant class). */ virtual Function *clone() const = 0; /** * Virtual destructor. */ virtual ~Function() {} /** * 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({}); } // TODO: Use () operator instead of the call function }; /** * The Argument class is used to describe the type of a function * argument. */ struct Argument { const VariantType type; const bool hasDefault; const Variant defaultValue; Argument(VariantType type) : type(type), hasDefault(false){}; Argument(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 signature; /** * 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; /** * Used internally to update the errorIndex and the errorMessage fields. */ std::pair> setError(int idx, const std::string &msg, std::vector &res); /** * Resets the error state. */ void resetError(); public: /** * Constructor of the argument validator class. * * @param descriptors is a list of Arguments which should be used * for the validation. */ ArgumentValidator(const std::vector &signature) : signature(signature) { } /** * 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}; } }; /** * A validating function */ class ValidatingFunction : public Function { private: /** * Specifies whether the validating function should actually run or just * pass the arguments through. */ bool validate; /** * Signature for which the function should be validated. */ const std::vector signature; protected: virtual Variant validatedCall(const std::vector &args) const = 0; virtual Variant call(const std::vector &args) const override; using Function::call; public: ValidatingFunction() : validate(false) {} ValidatingFunction(const std::vector &signature) : validate(true), signature(signature) { } }; using HostFunctionCallback = Variant (*)(const std::vector &args, void *data); using GetterCallback = Variant (*)(void *data); using SetterCallback = void (*)(Variant arg, void *data); class HostFunction : public ValidatingFunction { private: HostFunctionCallback callback; void *data; protected: virtual Variant validatedCall( const std::vector &args) const override { return callback(args, data); } public: HostFunction(HostFunctionCallback callback, std::vector signature, void *data = nullptr) : ValidatingFunction(signature), callback(callback), data(data) { } HostFunction(HostFunctionCallback callback, void *data = nullptr) : ValidatingFunction(), callback(callback), data(data) { } Function *clone() const override { return new HostFunction(*this); } using ValidatingFunction::call; }; class Getter : public ValidatingFunction { private: GetterCallback callback; void *data; protected: virtual Variant validatedCall( const std::vector &args) const override { if (!callback) { // TODO: Use another exception class here throw "Getter not defined"; } return callback(data); } public: Getter(GetterCallback callback, void *data = nullptr) : ValidatingFunction(std::vector{}), callback(callback), data(data){}; Function *clone() const override { return new Getter(*this); } Variant call() const { return ValidatingFunction::call(); } Variant operator()() const { return call(); } bool exists() const { return callback != nullptr; } }; class Setter : public ValidatingFunction { private: SetterCallback callback; void *data; protected: virtual Variant validatedCall( const std::vector &args) const override { if (!callback) { // TODO: Use another exception class here throw "Setter not defined"; } callback(args[0], data); return Variant::Null; } public: Setter(VariantType type, SetterCallback callback, void *data = nullptr) : ValidatingFunction({Argument{type}}), callback(callback), data(data){}; Function *clone() const override { return new Setter(*this); } void call(Variant arg) const { ValidatingFunction::call({arg}); } void operator()(Variant arg) const { return call(arg); } bool exists() const { return callback != nullptr; } }; } } #endif /* _OUSIA_FUNCTION_HPP_ */