summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndreas Stöckel <astoecke@techfak.uni-bielefeld.de>2014-10-24 13:25:04 +0000
committerandreas <andreas@daaaf23c-2e50-4459-9457-1e69db5a47bf>2014-10-24 13:25:04 +0000
commit4a9912f516bf096c6f8c6259b3fc6ba4b95b8d69 (patch)
treee4b578c76e27ade40de5d2cae2efbd2b17d18e59 /src
parentc654793a3a513a9c8ffcd1aa9c3962b6a72e61bd (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.cpp52
-rw-r--r--src/core/script/Function.hpp67
-rw-r--r--src/core/script/Variant.cpp7
-rw-r--r--src/core/script/Variant.hpp4
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);
};