diff options
author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2014-10-24 13:25:04 +0000 |
---|---|---|
committer | andreas <andreas@daaaf23c-2e50-4459-9457-1e69db5a47bf> | 2014-10-24 13:25:04 +0000 |
commit | 4a9912f516bf096c6f8c6259b3fc6ba4b95b8d69 (patch) | |
tree | e4b578c76e27ade40de5d2cae2efbd2b17d18e59 /src | |
parent | c654793a3a513a9c8ffcd1aa9c3962b6a72e61bd (diff) |
finished implementation of HostFunction
git-svn-id: file:///var/local/svn/basicwriter@74 daaaf23c-2e50-4459-9457-1e69db5a47bf
Diffstat (limited to 'src')
-rw-r--r-- | src/core/script/Function.cpp | 52 | ||||
-rw-r--r-- | src/core/script/Function.hpp | 67 | ||||
-rw-r--r-- | src/core/script/Variant.cpp | 7 | ||||
-rw-r--r-- | src/core/script/Variant.hpp | 4 |
4 files changed, 123 insertions, 7 deletions
diff --git a/src/core/script/Function.cpp b/src/core/script/Function.cpp index d72df4c..ce6e6b6 100644 --- a/src/core/script/Function.cpp +++ b/src/core/script/Function.cpp @@ -21,9 +21,57 @@ namespace ousia { namespace script { -std::pair<bool, std::vector<Variant>> validate(const std::vector<Variant> &args) +std::pair<bool, std::vector<Variant>> ArgumentValidator::setError(int idx, + const std::string &msg, std::vector<Variant> &res) { - return std::make_pair(true, std::vector<Variant>{}); + errorIndex = idx; + errorMessage = msg; + return std::make_pair(false, res); +} + +void ArgumentValidator::resetError() +{ + errorIndex = -1; + errorMessage = ""; +} + +std::pair<bool, std::vector<Variant>> ArgumentValidator::validate( + const std::vector<Variant> &args) +{ + std::vector<Variant> res; + + // Reset any old error + resetError(); + + // Sanity check: Do not allow too many arguments + if (args.size() > descriptors.size()) { + return setError(descriptors.size(), "Expected " + std::to_string(descriptors.size()) + + " arguments but got " + std::to_string(args.size()), res); + } + + // Iterate over the given arguments and check their type + res.reserve(descriptors.size()); + for (unsigned int i = 0; i < args.size(); i++) { + // TODO: Implicit type conversion + const VariantType tGiven = args[i].getType(); + const VariantType tExpected = descriptors[i].type; + if (tGiven != tExpected) { + return setError(i, std::string("Expected type ") + Variant::getTypeName(tExpected) + + " but got " + Variant::getTypeName(tGiven), res); + } + res.push_back(args[i]); + } + + // Make sure the remaining arguments have a default value, and if they have + // one, add it to the result + for (unsigned int i = args.size(); i < descriptors.size(); i++) { + if (!descriptors[i].hasDefault) { + return setError(i, "Expected argument " + std::to_string(i), res); + } + res.push_back(descriptors[i].defaultValue); + } + + return std::make_pair(true, res); } } diff --git a/src/core/script/Function.hpp b/src/core/script/Function.hpp index 35e2205..4c13dbc 100644 --- a/src/core/script/Function.hpp +++ b/src/core/script/Function.hpp @@ -46,6 +46,13 @@ public: */ virtual Variant call(const std::vector<Variant> &args) const = 0; + /** + * Calls the underlying function with no arguments. + * + * @return a Variant containing the return value. + */ + Variant call() const { return call({}); } + }; /** @@ -70,7 +77,7 @@ struct ArgumentDescriptor { * ArgumentValidatorError is an exception type used to represent argument * validator errors. */ -class ArgumentValidatorError : std::exception { +class ArgumentValidatorError : public std::exception { public: @@ -110,6 +117,11 @@ private: */ std::string errorMessage; + std::pair<bool, std::vector<Variant>> setError(int idx, + const std::string &msg, std::vector<Variant> &res); + + void resetError(); + public: /** @@ -153,6 +165,59 @@ public: /** * The HostFunction class represents a function that resides in the script host. */ +template<class T> +class HostFunction : public Function { + +private: + T callback; + ArgumentValidator *validator; + void *data; + +public: + + HostFunction(T callback, std::vector<ArgumentDescriptor> 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<Variant> &args) const override + { + if (validator) { + std::pair<bool, std::vector<Variant>> res = validator->validate(args); + if (!res.first) { + throw validator->error(); + } + return callback(res.second, data); + } else { + return callback(args, data); + } + } + + using Function::call; + +}; + +template<class T> +static HostFunction<T> createHostFunction(T callback, + std::vector<ArgumentDescriptor> signature, void *data = nullptr) +{ + return HostFunction<T>(callback, signature, data); +} + +template<class T> +static HostFunction<T> createHostFunction(T callback, void *data = nullptr) +{ + return HostFunction<T>(callback, data); +} + } } diff --git a/src/core/script/Variant.cpp b/src/core/script/Variant.cpp index b70f361..3858b68 100644 --- a/src/core/script/Variant.cpp +++ b/src/core/script/Variant.cpp @@ -23,7 +23,7 @@ namespace script { /* Class VariantTypeException */ -static const char* getVariantTypeName(VariantType type) +const char* Variant::getTypeName(VariantType type) { switch (type) { case VariantType::null: @@ -53,8 +53,9 @@ static const char* getVariantTypeName(VariantType type) VariantTypeException::VariantTypeException(VariantType actualType, VariantType requestedType) : msg(std::string("Cannot get value of variant of type \"") - + getVariantTypeName(actualType) - + std::string("\" as \"") + getVariantTypeName(requestedType)), + + Variant::getTypeName(actualType) + + std::string("\" as \"") + Variant::getTypeName(requestedType) + + std::string("\"")), actualType(actualType), requestedType(requestedType) {} const char* VariantTypeException::what() const noexcept diff --git a/src/core/script/Variant.hpp b/src/core/script/Variant.hpp index ee4a97a..923c8ca 100644 --- a/src/core/script/Variant.hpp +++ b/src/core/script/Variant.hpp @@ -49,7 +49,7 @@ enum class VariantType : int16_t { * Exception thrown whenever a variant is accessed via a getter function that * is not supported for the current variant type. */ -class VariantTypeException : std::exception { +class VariantTypeException : public std::exception { private: /** @@ -299,6 +299,8 @@ public: } } + static const char* getTypeName(VariantType type); + friend std::ostream& operator<< (std::ostream& os, const Variant &v); }; |