summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt48
-rw-r--r--Doxyfile.in8
-rw-r--r--dependencies.txt38
-rw-r--r--src/core/script/Function.hpp243
-rw-r--r--src/core/script/Object.cpp83
-rw-r--r--src/core/script/Object.hpp132
-rw-r--r--src/core/script/Variant.cpp254
-rw-r--r--src/core/script/Variant.hpp229
-rw-r--r--test/core/script/Function.cpp47
-rw-r--r--test/core/script/Variant.cpp17
10 files changed, 802 insertions, 297 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index df4155f..268a391 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,15 +18,47 @@
# Basic Project Definitions and Dependencies #
################################################################################
-PROJECT(basicwriter)
+PROJECT(ousia)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.9)
# Option for enabling testing. Turn on with 'cmake -Dtest=ON'.
OPTION(test "Build all tests." OFF) # Makes boolean 'test' available.
+# Option for building the documentation.
+FIND_PACKAGE(Doxygen)
+OPTION(BUILD_DOCUMENTATION "Create and install the HTML based API documentation (requires Doxygen)" ${DOXYGEN_FOUND})
+
# Enable C++11 and all warnings
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -Wall -pedantic -std=c++11")
+# Use PkgConfig to find mozjs-24
+FIND_PACKAGE(PkgConfig REQUIRED)
+PKG_CHECK_MODULES(MOZJS REQUIRED mozjs-24)
+
+################################################################################
+# Inclusion of doxygen #
+################################################################################
+
+IF(BUILD_DOCUMENTATION)
+ IF(NOT DOXYGEN_FOUND)
+ MESSAGE(FATAL_ERROR "Doxygen is needed to build the documentation.")
+ ENDIF()
+
+ SET(DOXYFILE_IN ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in)
+ SET(DOXYFILE ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile)
+
+ CONFIGURE_FILE(${DOXYFILE_IN} ${DOXYFILE} @ONLY)
+
+ ADD_CUSTOM_TARGET(doc
+ COMMAND ${DOXYGEN_EXECUTABLE} ${doxyfile}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen"
+ VERBATIM)
+
+ INSTALL(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html DESTINATION share/doc)
+ENDIF()
+
+
################################################################################
# Inclusion of gtest #
################################################################################
@@ -46,9 +78,19 @@ ENDIF()
# Commands for building Ousía #
################################################################################
-# Includ directories
+# Include directories
INCLUDE_DIRECTORIES(
src/
+ ${MOZJS_INCLUDE_DIRS}
+)
+
+# Link directories
+LINK_DIRECTORIES(
+ ${MOZJS_LIBRARY_DIRS}
+)
+
+ADD_DEFINITIONS(
+ ${MOZJS_CFLAGS_OTHER}
)
# ousia_utils library
@@ -61,7 +103,7 @@ ADD_LIBRARY(ousia_script
src/core/script/Function.cpp
src/core/script/Variant.cpp
src/core/script/ScriptEngine.cpp
- src/core/script/
+ src/core/script/Object.cpp
)
# Link the ousia executable against ousia_core
diff --git a/Doxyfile.in b/Doxyfile.in
new file mode 100644
index 0000000..9e9c812
--- /dev/null
+++ b/Doxyfile.in
@@ -0,0 +1,8 @@
+PROJECT_NAME = "@CMAKE_PROJECT_NAME@"
+PROJECT_NUMBER = @VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_PATCH@
+STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@/src
+INPUT = @PROJECT_SOURCE_DIR@/src
+OUTPUT_DIRECTORY = @PROJECT_BINARY_DIR@/doc
+FILE_PATTERNS = *.hpp \
+ *.cpp
+RECURSIVE = YES
diff --git a/dependencies.txt b/dependencies.txt
index 9957d04..d77be63 100644
--- a/dependencies.txt
+++ b/dependencies.txt
@@ -1,6 +1,40 @@
+Hard dependencies
+=================
+
The following packages have to be installed (for Fedora)
- cmake
-# - qt5-qtbase-devel (not needed for now)
-# - qt5-qtscript-devel (not needed for now)
+- mozjs24-devel
+
+Documentation
+=============
+
+In order to build the documentation (make doc)
+
+- doxygen
+
+Tools
+=====
+
+Automated code formating (clang-format)
+---------------------------------------
+
+Download Pre-built binary of "LLVM" from
+
+http://llvm.org/releases/download.html
+
+use the "clang-format" program in the bin/ directory. The following gedit tool can be used for automated code formating:
+
+(Active "External Tools" plugin, add the following lines to ./config/gedit/tools/, without indentation)
+
+ #!/bin/sh
+ # [Gedit Tool]
+ # Input=document
+ # Shortcut=<Shift><Alt>f
+ # Applicability=all
+ # Save-files=nothing
+ # Output=replace-document
+ # Name=Clang Format
+
+ cd $GEDIT_CURRENT_DOCUMENT_DIR && <INSERT CORRECT PATH HERE>/clang-format
diff --git a/src/core/script/Function.hpp b/src/core/script/Function.hpp
index 4c13dbc..2e92f08 100644
--- a/src/core/script/Function.hpp
+++ b/src/core/script/Function.hpp
@@ -29,12 +29,23 @@ 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.
+ * 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
@@ -51,26 +62,27 @@ public:
*
* @return a Variant containing the return value.
*/
- Variant call() const { return call({}); }
+ Variant call() const
+ {
+ return call({});
+ }
+ // TODO: Use () operator instead of the call function
};
/**
- * The ArgumentDescriptor class is used to describe the type of a function
+ * The Argument class is used to describe the type of a function
* argument.
*/
-struct ArgumentDescriptor {
-
+struct Argument {
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) {};
+ Argument(VariantType type) : type(type), hasDefault(false){};
+ Argument(VariantType type, const Variant &defaultValue)
+ : type(type), hasDefault(true), defaultValue(defaultValue){};
};
/**
@@ -78,21 +90,18 @@ struct ArgumentDescriptor {
* 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) {};
+ ArgumentValidatorError(int index, const std::string &msg)
+ : index(index), msg(msg){};
- virtual const char* what() const noexcept override
+ virtual const char *what() const noexcept override
{
return msg.c_str();
}
-
};
/**
@@ -100,12 +109,11 @@ public:
* arguments passed to a function match the description.
*/
class ArgumentValidator {
-
private:
/**
* List containing the argument descriptors.
*/
- const std::vector<ArgumentDescriptor> descriptors;
+ const std::vector<Argument> descriptors;
/**
* Argument index in the input array, at which the last error occured.
@@ -118,20 +126,22 @@ private:
std::string errorMessage;
std::pair<bool, std::vector<Variant>> setError(int idx,
- const std::string &msg, std::vector<Variant> &res);
+ const std::string &msg,
+ std::vector<Variant> &res);
void resetError();
public:
-
/**
* Constructor of the argument validator class.
*
- * @param descriptors is a list of ArgumentDescriptors which should be used
+ * @param descriptors is a list of Arguments which should be used
* for the validation.
*/
- ArgumentValidator(const std::vector<ArgumentDescriptor> &descriptors) :
- descriptors(descriptors) {}
+ ArgumentValidator(const std::vector<Argument> &descriptors)
+ : descriptors(descriptors)
+ {
+ }
/**
* Validates and augments the given argument list (e.g. adds the default
@@ -143,7 +153,8 @@ public:
* list of arguments. If false is returned, use the error function to get
* more information about the error.
*/
- std::pair<bool, std::vector<Variant>> validate(const std::vector<Variant> &args);
+ std::pair<bool, std::vector<Variant>> validate(
+ const std::vector<Variant> &args);
/**
* Returns an ArgumentValidatorError instance containing the argument index
@@ -157,68 +168,174 @@ public:
*/
ArgumentValidatorError error()
{
- return ArgumentValidatorError(errorIndex, errorMessage);
+ return ArgumentValidatorError{errorIndex, errorMessage};
}
-
};
/**
- * The HostFunction class represents a function that resides in the script host.
+ * A validating function
*/
-template<class T>
-class HostFunction : public Function {
-
+class ValidatingFunction : 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;
- }
+protected:
+ virtual Variant validatedCall(const std::vector<Variant> &args) const = 0;
virtual Variant call(const std::vector<Variant> &args) const override
{
if (validator) {
- std::pair<bool, std::vector<Variant>> res = validator->validate(args);
+ 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);
+ return validatedCall(res.second);
}
+ return validatedCall(args);
}
using Function::call;
+public:
+ ValidatingFunction() : validator(nullptr)
+ {
+ }
+
+ ValidatingFunction(std::vector<Argument> signature)
+ : validator(new ArgumentValidator(signature))
+ {
+ }
+
+ ~ValidatingFunction() override
+ {
+ delete validator;
+ }
};
-template<class T>
-static HostFunction<T> createHostFunction(T callback,
- std::vector<ArgumentDescriptor> signature, void *data = nullptr)
-{
- return HostFunction<T>(callback, signature, data);
-}
+using HostFunctionCallback = Variant (*)(const std::vector<Variant> &args,
+ void *data);
+using GetterCallback = Variant (*)(void *data);
+using SetterCallback = void (*)(Variant arg, void *data);
-template<class T>
-static HostFunction<T> createHostFunction(T callback, void *data = nullptr)
-{
- return HostFunction<T>(callback, data);
-}
+class HostFunction : public ValidatingFunction {
+private:
+ HostFunctionCallback callback;
+ void *data;
+
+protected:
+ virtual Variant validatedCall(
+ const std::vector<Variant> &args) const override
+ {
+ return callback(args, data);
+ }
+
+public:
+ HostFunction(HostFunctionCallback callback, std::vector<Argument> 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<Variant> &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<Argument>{}),
+ 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()
+ {
+ return callback != nullptr;
+ }
+};
+
+class Setter : public ValidatingFunction {
+private:
+ SetterCallback callback;
+ void *data;
+
+protected:
+ virtual Variant validatedCall(
+ const std::vector<Variant> &args) const override
+ {
+ if (!callback) {
+ // TODO: Use another exception class here
+ throw "Setter not defined";
+ }
+ callback(args[0], data);
+ return VarNull;
+ }
+
+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()
+ {
+ return callback != nullptr;
+ }
+};
}
}
diff --git a/src/core/script/Object.cpp b/src/core/script/Object.cpp
new file mode 100644
index 0000000..8d858bc
--- /dev/null
+++ b/src/core/script/Object.cpp
@@ -0,0 +1,83 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "Object.hpp"
+
+namespace ousia {
+namespace script {
+
+bool Object::hasElement(std::string name) const
+{
+ return (properties.find(name) != properties.end()) ||
+ (methods.find(name) != methods.end());
+}
+
+void Object::addProperty(std::string name, const Property &property)
+{
+ if (hasElement(name)) {
+ // TODO Throw another exception class here
+ throw "Element already exists";
+ }
+ properties.emplace(name, property);
+}
+
+void Object::addProperty(std::string name, const Getter &get, const Setter &set)
+{
+ addProperty(name, Property{get, set});
+}
+
+void Object::addProperty(std::string name, VariantType type,
+ const GetterCallback get, const SetterCallback set)
+{
+ addProperty(name, Property{type, get, set, data});
+}
+
+void Object::addReadonlyProperty(std::string name, const Getter &get)
+{
+ addProperty(name, Property{get, Setter{VariantType::null, nullptr}});
+}
+
+void Object::addReadonlyProperty(std::string name, const GetterCallback get)
+{
+ addProperty(
+ name, Property{Getter{get, data}, Setter{VariantType::null, nullptr}});
+}
+
+void Object::addMethod(std::string name, const HostFunction &fun)
+{
+ if (hasElement(name)) {
+ // TODO Throw another exception class here
+ throw "Element already exists";
+ }
+ methods.emplace(name, fun);
+}
+
+void Object::addMethod(std::string name, const HostFunctionCallback fun)
+{
+ addMethod(name, HostFunction{fun, data});
+}
+
+void Object::addMethod(std::string name, const HostFunctionCallback fun,
+ const std::vector<Argument> &signature)
+{
+ addMethod(name, HostFunction{fun, signature, data});
+}
+
+}
+}
+
diff --git a/src/core/script/Object.hpp b/src/core/script/Object.hpp
new file mode 100644
index 0000000..20e0f0f
--- /dev/null
+++ b/src/core/script/Object.hpp
@@ -0,0 +1,132 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _OBJECT_HPP_
+#define _OBJECT_HPP_
+
+#include <string>
+#include <map>
+
+#include "Function.hpp"
+
+namespace ousia {
+namespace script {
+
+/**
+ * The Property struct represents an object property with corresponding getter
+ * and setter function.
+ */
+struct Property {
+ /**
+ * Constructor of the Property struct. Copies the given getter and setter.
+ *
+ * @param get is the getter that should be used for the property.
+ * @param set is the setter that should be used for the property.
+ */
+ Property(const Getter &get, const Setter &set) : get(get), set(set){};
+
+ /**
+ * Constructor of the Property struct. Creates new Getter and Setter
+ * instances from the given parameters.
+ *
+ * @param type is the VariantType used within the getter function.
+ * @param get is the pointer to the getter function.
+ * @param set is the pointer to the setter function.
+ * @param data is the used-defined data that should be used.
+ */
+ Property(VariantType type, const GetterCallback get,
+ const SetterCallback set, void *data = nullptr)
+ : get(get, data), set(type, set, data){};
+
+ /**
+ * Getter function.
+ */
+ const Getter get;
+
+ /**
+ * Setter function.
+ */
+ const Setter set;
+};
+
+/**
+ * The Object type represents an object on the script host. An object consits of
+ * properties with corresponding getter and setter functions and a number of
+ * methods which can be called on the object.
+ */
+class Object {
+private:
+ /**
+ * Pointer to user defined data that is automatically passed to the
+ * underlying functions.
+ */
+ void *data;
+
+ /**
+ * Map used internally for storing all properties along with their
+ * corresponding
+ * name.
+ */
+ std::map<std::string, Property> properties;
+
+ /**
+ * Map used internally for storing all methods along with their
+ * corresponding name.
+ */
+ std::map<std::string, HostFunction> methods;
+
+public:
+ Object() : data(nullptr){};
+
+ Object(void *data) : data(data){};
+
+ bool hasElement(std::string name) const;
+
+ void addProperty(std::string name, const Property &property);
+
+ void addProperty(std::string name, const Getter &get, const Setter &set);
+
+ void addProperty(std::string name, VariantType type,
+ const GetterCallback get, const SetterCallback set);
+
+ void addReadonlyProperty(std::string name, const Getter &get);
+
+ void addReadonlyProperty(std::string name, const GetterCallback get);
+
+ void addMethod(std::string name, const HostFunction &fun);
+
+ void addMethod(std::string name, const HostFunctionCallback fun);
+
+ void addMethod(std::string name, const HostFunctionCallback fun,
+ const std::vector<Argument> &signature);
+
+ const std::map<std::string, Property> &getProperties()
+ {
+ return properties;
+ }
+
+ const std::map<std::string, HostFunction> &getMethods()
+ {
+ return methods;
+ }
+};
+}
+}
+
+#endif /* _OBJECT_HPP_ */
+
diff --git a/src/core/script/Variant.cpp b/src/core/script/Variant.cpp
index 3858b68..75f46ba 100644
--- a/src/core/script/Variant.cpp
+++ b/src/core/script/Variant.cpp
@@ -17,13 +17,242 @@
*/
#include "Variant.hpp"
+#include "Function.hpp"
+#include "Object.hpp"
namespace ousia {
namespace script {
-/* Class VariantTypeException */
+/* Class Variant */
+
+Variant::Variant(const Variant &v) : type(v.type)
+{
+ switch (v.type) {
+ case VariantType::null:
+ break;
+ case VariantType::boolean:
+ booleanValue = v.booleanValue;
+ break;
+ case VariantType::integer:
+ integerValue = v.integerValue;
+ break;
+ case VariantType::number:
+ numberValue = v.numberValue;
+ break;
+ case VariantType::string:
+ objectValue =
+ new std::string(*static_cast<std::string *>(v.objectValue));
+ break;
+ case VariantType::array:
+ objectValue = new std::vector<Variant>(
+ *static_cast<std::vector<Variant> *>(v.objectValue));
+ break;
+ case VariantType::map:
+ objectValue = new std::map<std::string, Variant>(
+ *static_cast<std::map<std::string, Variant> *>(v.objectValue));
+ break;
+ case VariantType::function:
+ objectValue = static_cast<Function *>(v.objectValue)->clone();
+ break;
+ case VariantType::object:
+ objectValue = new Object(*static_cast<Object *>(v.objectValue));
+ break;
+ case VariantType::buffer:
+ // TODO
+ break;
+ }
+}
+
+Variant::Variant(Variant &&v) : type(v.type)
+{
+ switch (type) {
+ case VariantType::null:
+ break;
+ case VariantType::boolean:
+ booleanValue = v.booleanValue;
+ break;
+ case VariantType::integer:
+ integerValue = v.integerValue;
+ break;
+ case VariantType::number:
+ numberValue = v.numberValue;
+ break;
+ case VariantType::string:
+ case VariantType::array:
+ case VariantType::map:
+ case VariantType::function:
+ case VariantType::object:
+ case VariantType::buffer:
+ objectValue = v.objectValue;
+ v.objectValue = nullptr;
+ break;
+ }
+}
+
+Variant::Variant() : type(VariantType::null)
+{
+}
+
+Variant::Variant(bool b) : type(VariantType::boolean), booleanValue(b)
+{
+}
+
+Variant::Variant(int64_t i) : type(VariantType::integer), integerValue(i)
+{
+}
+
+Variant::Variant(double d) : type(VariantType::number), numberValue(d)
+{
+}
+
+Variant::Variant(const char *s)
+ : type(VariantType::string), objectValue(new std::string(s))
+{
+}
+
+Variant::Variant(const std::vector<Variant> &a)
+ : type(VariantType::array), objectValue(new std::vector<Variant>(a))
+{
+}
+
+Variant::Variant(const std::map<std::string, Variant> &m)
+ : type(VariantType::map), objectValue(new std::map<std::string, Variant>(m))
+{
+}
+
+Variant::Variant(const Function *f)
+ : type(VariantType::function), objectValue(f->clone())
+{
+}
+
+Variant::Variant(const Object &o)
+ : type(VariantType::object), objectValue(new Object(o))
+{
+}
+
+Variant::~Variant()
+{
+ switch (type) {
+ case VariantType::string:
+ delete static_cast<std::string *>(objectValue);
+ break;
+ case VariantType::array:
+ delete static_cast<std::vector<Variant> *>(objectValue);
+ break;
+ case VariantType::map:
+ delete static_cast<std::map<std::string, Variant> *>(objectValue);
+ break;
+ case VariantType::function:
+ delete static_cast<Function*>(objectValue);
+ break;
+ case VariantType::object:
+ delete static_cast<Object*>(objectValue);
+ break;
+ default:
+ break;
+ }
+}
-const char* Variant::getTypeName(VariantType type)
+bool Variant::getBooleanValue() const
+{
+ switch (type) {
+ case VariantType::null:
+ return false;
+ case VariantType::boolean:
+ return booleanValue;
+ case VariantType::integer:
+ return integerValue != 0;
+ case VariantType::number:
+ return numberValue != 0.0;
+ case VariantType::string:
+ return !getStringValue().empty();
+ case VariantType::array:
+ return !getArrayValue().empty();
+ case VariantType::map:
+ return !getMapValue().empty();
+ default:
+ throw VariantTypeException{type, VariantType::boolean};
+ }
+}
+
+int64_t Variant::getIntegerValue() const
+{
+ switch (type) {
+ case VariantType::boolean:
+ return booleanValue ? 1 : 0;
+ case VariantType::integer:
+ return integerValue;
+ case VariantType::number:
+ return static_cast<int64_t>(numberValue);
+ default:
+ throw VariantTypeException{type, VariantType::integer};
+ }
+}
+
+double Variant::getNumberValue() const
+{
+ switch (type) {
+ case VariantType::boolean:
+ return booleanValue ? 1.0 : 0.0;
+ case VariantType::integer:
+ return static_cast<double>(integerValue);
+ case VariantType::number:
+ return numberValue;
+ default:
+ throw VariantTypeException{type, VariantType::number};
+ }
+}
+
+const std::string &Variant::getStringValue() const
+{
+ switch (type) {
+ case VariantType::string:
+ return *(static_cast<std::string *>(objectValue));
+ default:
+ throw VariantTypeException{type, VariantType::string};
+ }
+}
+
+const std::vector<Variant> &Variant::getArrayValue() const
+{
+ switch (type) {
+ case VariantType::array:
+ return *(static_cast<std::vector<Variant> *>(objectValue));
+ default:
+ throw VariantTypeException{type, VariantType::array};
+ }
+}
+
+const std::map<std::string, Variant> &Variant::getMapValue() const
+{
+ switch (type) {
+ case VariantType::map:
+ return *(static_cast<std::map<std::string, Variant> *>(
+ objectValue));
+ default:
+ throw VariantTypeException{type, VariantType::map};
+ }
+}
+
+const Function *Variant::getFunctionValue() const
+{
+ switch (type) {
+ case VariantType::function: return static_cast<Function *>(objectValue);
+ default:
+ throw VariantTypeException{type, VariantType::function};
+ }
+}
+
+const Object &Variant::getObjectValue() const
+{
+ switch (type) {
+ case VariantType::object: return *(static_cast<Object *>(objectValue));
+ default:
+ throw VariantTypeException{type, VariantType::function};
+ }
+}
+
+const char *Variant::getTypeName(VariantType type)
{
switch (type) {
case VariantType::null:
@@ -50,22 +279,26 @@ const char* Variant::getTypeName(VariantType type)
return "unknown";
}
+/* Class VariantTypeException */
+
VariantTypeException::VariantTypeException(VariantType actualType,
- VariantType requestedType) :
- msg(std::string("Cannot get value of variant of type \"")
- + Variant::getTypeName(actualType)
- + std::string("\" as \"") + Variant::getTypeName(requestedType)
- + std::string("\"")),
- actualType(actualType), requestedType(requestedType) {}
+ VariantType requestedType)
+ : msg(std::string("Cannot get value of variant of type \"") +
+ Variant::getTypeName(actualType) + std::string("\" as \"") +
+ Variant::getTypeName(requestedType) + std::string("\"")),
+ actualType(actualType),
+ requestedType(requestedType)
+{
+}
-const char* VariantTypeException::what() const noexcept
+const char *VariantTypeException::what() const noexcept
{
return msg.c_str();
}
/* Global scope operator */
-std::ostream& operator<< (std::ostream& os, const Variant &v)
+std::ostream &operator<<(std::ostream &os, const Variant &v)
{
switch (v.type) {
case VariantType::null:
@@ -121,7 +354,6 @@ std::ostream& operator<< (std::ostream& os, const Variant &v)
}
return os;
}
-
}
}
diff --git a/src/core/script/Variant.hpp b/src/core/script/Variant.hpp
index 923c8ca..295c044 100644
--- a/src/core/script/Variant.hpp
+++ b/src/core/script/Variant.hpp
@@ -29,6 +29,10 @@
namespace ousia {
namespace script {
+/* Class forward declarations */
+class Object;
+class Function;
+
/**
* Enum containing the possible types a variant may have.
*/
@@ -50,7 +54,6 @@ enum class VariantType : int16_t {
* is not supported for the current variant type.
*/
class VariantTypeException : public std::exception {
-
private:
/**
* Internally used string holding the exception message.
@@ -82,8 +85,7 @@ public:
*
* @return the error message as C string.
*/
- virtual const char* what() const noexcept override;
-
+ virtual const char *what() const noexcept override;
};
/**
@@ -91,9 +93,7 @@ public:
* between the host application and the script engine. Variants are immutable.
*/
class Variant {
-
private:
-
const VariantType type;
union {
@@ -104,213 +104,46 @@ private:
};
public:
-
- Variant(const Variant &v) :
- type(v.type)
- {
- switch (v.type) {
- case VariantType::null:
- break;
- case VariantType::boolean:
- booleanValue = v.booleanValue;
- break;
- case VariantType::integer:
- integerValue = v.integerValue;
- break;
- case VariantType::number:
- numberValue = v.numberValue;
- break;
- case VariantType::string:
- objectValue = new std::string(
- *static_cast<std::string*>(v.objectValue));
- break;
- case VariantType::array:
- objectValue = new std::vector<Variant>(
- *static_cast<std::vector<Variant>*>(v.objectValue));
- break;
- case VariantType::map:
- objectValue = new std::map<std::string, Variant>(
- *static_cast<std::map<std::string, Variant>*>(v.objectValue));
- break;
- case VariantType::function:
- case VariantType::object:
- case VariantType::buffer:
- // TODO
- break;
- }
- }
-
- Variant(Variant &&v) :
- type(v.type)
- {
- switch (type) {
- case VariantType::null:
- break;
- case VariantType::boolean:
- booleanValue = v.booleanValue;
- break;
- case VariantType::integer:
- integerValue = v.integerValue;
- break;
- case VariantType::number:
- numberValue = v.numberValue;
- break;
- case VariantType::string:
- case VariantType::array:
- case VariantType::map:
- case VariantType::function:
- case VariantType::object:
- case VariantType::buffer:
- objectValue = v.objectValue;
- v.objectValue = nullptr;
- break;
- }
- }
-
- ~Variant()
- {
- switch (type) {
- case VariantType::string:
- delete static_cast<std::string*>(objectValue);
- break;
- case VariantType::array:
- delete static_cast<std::vector<Variant>*>(objectValue);
- break;
- case VariantType::map:
- delete static_cast<std::map<std::string, Variant>*>(objectValue);
- break;
- default:
- break;
- }
- }
-
- Variant& operator=(const Variant &v) = delete;
- Variant& operator=(Variant &&v) = delete;
-
- Variant() :
- type(VariantType::null) {}
-
- Variant(bool b) :
- type(VariantType::boolean),
- booleanValue(b) {}
-
- Variant(int64_t i) :
- type(VariantType::integer),
- integerValue(i) {}
-
- Variant(double d) :
- type(VariantType::number),
- numberValue(d) {}
-
- Variant(const char *s) :
- type(VariantType::string),
- objectValue(new std::string(s)) {}
-
- Variant(const std::vector<Variant> &a) :
- type(VariantType::array),
- objectValue(new std::vector<Variant>(a)) {}
-
- Variant(const std::map<std::string, Variant> &m) :
- type(VariantType::map),
- objectValue(new std::map<std::string, Variant>(m)) {}
+ Variant(const Variant &v);
+ Variant(Variant &&v);
+
+ Variant();
+ Variant(bool b);
+ Variant(int64_t i);
+ Variant(double d);
+ Variant(const char *s);
+ Variant(const std::vector<Variant> &a);
+ Variant(const std::map<std::string, Variant> &m);
+ Variant(const Function *f);
+ Variant(const Object &o);
+ ~Variant();
+
+ Variant &operator=(const Variant &v) = delete;
+ Variant &operator=(Variant &&v) = delete;
VariantType getType() const
{
return type;
}
- bool getBooleanValue() const
- {
- switch (type) {
- case VariantType::null:
- return false;
- case VariantType::boolean:
- return booleanValue;
- case VariantType::integer:
- return integerValue != 0;
- case VariantType::number:
- return numberValue != 0.0;
- case VariantType::string:
- return !getStringValue().empty();
- case VariantType::array:
- return !getArrayValue().empty();
- case VariantType::map:
- return !getMapValue().empty();
- default:
- throw VariantTypeException{type, VariantType::boolean};
- }
- }
-
- int64_t getIntegerValue() const
- {
- switch (type) {
- case VariantType::boolean:
- return booleanValue ? 1 : 0;
- case VariantType::integer:
- return integerValue;
- case VariantType::number:
- return static_cast<int64_t>(numberValue);
- default:
- throw VariantTypeException{type, VariantType::integer};
- }
- }
+ bool getBooleanValue() const;
+ int64_t getIntegerValue() const;
+ double getNumberValue() const;
+ const std::string &getStringValue() const;
+ const std::vector<Variant> &getArrayValue() const;
+ const std::map<std::string, Variant> &getMapValue() const;
+ const Function *getFunctionValue() const;
+ const Object &getObjectValue() const;
- double getNumberValue() const
- {
- switch (type) {
- case VariantType::boolean:
- return booleanValue ? 1.0 : 0.0;
- case VariantType::integer:
- return static_cast<double>(integerValue);
- case VariantType::number:
- return numberValue;
- default:
- throw VariantTypeException{type, VariantType::number};
- }
- }
-
- const std::string& getStringValue() const
- {
- switch (type) {
- case VariantType::string:
- return *(static_cast<std::string*>(objectValue));
- default:
- throw VariantTypeException{type, VariantType::string};
- }
- }
-
- const std::vector<Variant>& getArrayValue() const
- {
- switch (type) {
- case VariantType::array:
- return *(static_cast<std::vector<Variant>*>(objectValue));
- default:
- throw VariantTypeException{type, VariantType::array};
- }
- }
-
- const std::map<std::string, Variant>& getMapValue() const
- {
- switch (type) {
- case VariantType::map:
- return *(static_cast<std::map<std::string, Variant>*>(objectValue));
- default:
- throw VariantTypeException{type, VariantType::map};
- }
- }
-
- static const char* getTypeName(VariantType type);
-
- friend std::ostream& operator<< (std::ostream& os, const Variant &v);
+ static const char *getTypeName(VariantType type);
+ friend std::ostream &operator<<(std::ostream &os, const Variant &v);
};
-
/**
* Shorthand for a constant representing a "null" as a variant.
*/
static const Variant VarNull;
-
}
}
diff --git a/test/core/script/Function.cpp b/test/core/script/Function.cpp
index bd2c9d6..cd6bd84 100644
--- a/test/core/script/Function.cpp
+++ b/test/core/script/Function.cpp
@@ -25,38 +25,45 @@ namespace script {
TEST(HostFunction, callDirect)
{
- // Local variable
int v = 0;
-
- // Host function which sets the local variable
- auto f = createHostFunction(
- [&v](const std::vector<Variant> &args, void *data) {
- v = args[0].getIntegerValue();
- return VarNull;
- }, {ArgumentDescriptor{VariantType::integer}});
-
- // Call the host function
+ HostFunction f{[](const std::vector<Variant> &args, void *data) {
+ *(static_cast<int*>(data)) = args[0].getIntegerValue();
+ return VarNull;
+ }, {Argument{VariantType::integer}}, &v};
ASSERT_EQ(VariantType::null, f.call({{(int64_t)42}}).getType());
ASSERT_EQ(42, v);
}
TEST(HostFunction, callDefaults)
{
- // Local variable
int v = 0;
-
- // Host function which sets the local variable
- auto f = createHostFunction(
- [&v](const std::vector<Variant> &args, void *data) {
- v = args[0].getIntegerValue();
- return Variant{"Hallo Welt"};
- }, {ArgumentDescriptor{VariantType::integer, {(int64_t)42}}});
-
- // Call the host function
+ HostFunction f{[](const std::vector<Variant> &args, void *data) {
+ *(static_cast<int*>(data)) = args[0].getIntegerValue();
+ return Variant{"Hallo Welt"};
+ }, {Argument{VariantType::integer, {(int64_t)42}}}, &v};
ASSERT_EQ("Hallo Welt", f.call().getStringValue());
ASSERT_EQ(42, v);
}
+TEST(Setter, call)
+{
+ int v = 0;
+ Setter f{VariantType::integer, [](Variant arg, void *data) {
+ *(static_cast<int*>(data)) = arg.getIntegerValue();
+ }, &v};
+ f.call({(int64_t)42});
+ ASSERT_EQ(42, v);
+}
+
+TEST(Getter, call)
+{
+ int v = 42;
+ Getter f{[](void *data) {
+ return Variant{int64_t(*(static_cast<int*>(data)))};
+ }, &v};
+ ASSERT_EQ(v, f.call().getIntegerValue());
+}
+
}
}
diff --git a/test/core/script/Variant.cpp b/test/core/script/Variant.cpp
index cf8f3c7..f229e3a 100644
--- a/test/core/script/Variant.cpp
+++ b/test/core/script/Variant.cpp
@@ -19,6 +19,8 @@
#include <gtest/gtest.h>
#include <core/script/Variant.hpp>
+#include <core/script/Function.hpp>
+#include <core/script/Object.hpp>
namespace ousia {
namespace script {
@@ -81,6 +83,21 @@ TEST(Variant, getMapValue)
ASSERT_EQ("entry2", (*map.find("key2")).second.getStringValue());
}
+TEST(Variant, getFunctionValue)
+{
+ int64_t i = 0;
+ HostFunction f{[](const std::vector<Variant> &args, void *data) {
+ *((int64_t*)data) = args[0].getIntegerValue();
+ return Variant{"Hello World"};
+ }, &i};
+
+ Variant v{&f};
+ ASSERT_TRUE(v.getFunctionValue() != nullptr);
+ ASSERT_EQ("Hello World", v.getFunctionValue()->call({{(int64_t)42}}).getStringValue());
+ ASSERT_EQ(42, i);
+}
+
+
}
}