changeset 533:9bf71bfe02fe

Js: remove everything, just keep some extras
author David Demelier <markand@malikania.fr>
date Fri, 03 Jun 2016 13:57:20 +0200
parents 33f98fda1884
children 444f1a036938
files CMakeLists.txt modules/js/CMakeLists.txt modules/js/duktape.hpp modules/js/js.hpp modules/js/test/main.cpp
diffstat 5 files changed, 429 insertions(+), 2236 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Thu Jun 02 16:56:44 2016 +0200
+++ b/CMakeLists.txt	Fri Jun 03 13:57:20 2016 +0200
@@ -54,4 +54,4 @@
 add_subdirectory(modules/options)
 add_subdirectory(modules/unicode)
 add_subdirectory(modules/xdg)
-add_subdirectory(modules/zip)
+# add_subdirectory(modules/zip)
--- a/modules/js/CMakeLists.txt	Thu Jun 02 16:56:44 2016 +0200
+++ b/modules/js/CMakeLists.txt	Fri Jun 03 13:57:20 2016 +0200
@@ -20,6 +20,6 @@
 
 code_define_module(
 	NAME js
-	SOURCES js.hpp
+	SOURCES duktape.hpp
 	LIBRARIES duktape
 )
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/js/duktape.hpp	Fri Jun 03 13:57:20 2016 +0200
@@ -0,0 +1,425 @@
+/*
+ * duktape.hpp -- Duktape extras
+ *
+ * Copyright (c) 2016 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DUKTAPE_HPP
+#define DUKTAPE_HPP
+
+/**
+ * \file duktape.hpp
+ * \brief Bring some extras to Duktape C library.
+ * \author David Demelier <markand@malikania.fr>
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include <duktape.h>
+
+/**
+ * \class StackAssert
+ * \brief Stack sanity checker.
+ *
+ * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor
+ * will examinate if the stack size matches the user expected size.
+ *
+ * When compiled with NDEBUG, this class does nothing.
+ *
+ * To use it, just declare an lvalue at the beginning of your function.
+ */
+class StackAssert {
+#if !defined(NDEBUG)
+private:
+	duk_context *m_context;
+	unsigned m_expected;
+	unsigned m_begin;
+#endif
+
+public:
+	/**
+	 * Create the stack checker.
+	 *
+	 * No-op if NDEBUG is set.
+	 *
+	 * \param ctx the context
+	 * \param expected the size expected relative to the already existing values
+	 */
+	inline StackAssert(duk_context *ctx, unsigned expected = 0) noexcept
+#if !defined(NDEBUG)
+		: m_context(ctx)
+		, m_expected(expected)
+		, m_begin(static_cast<unsigned>(duk_get_top(ctx)))
+#endif
+	{
+#if defined(NDEBUG)
+		(void)ctx;
+		(void)expected;
+#endif
+	}
+
+	/**
+	 * Verify the expected size.
+	 *
+	 * No-op if NDEBUG is set.
+	 */
+	inline ~StackAssert() noexcept
+	{
+#if !defined(NDEBUG)
+		if (static_cast<unsigned>(duk_get_top(m_context)) - m_begin != m_expected) {
+			std::fprintf(stderr, "Corrupt stack detection in StackAssert:\n");
+			std::fprintf(stderr, "  Size at start:            %u\n", m_begin);
+			std::fprintf(stderr, "  Size at end:              %d\n", duk_get_top(m_context));
+			std::fprintf(stderr, "  Expected (user):          %u\n", m_expected);
+			std::fprintf(stderr, "  Expected (adjusted):      %u\n", m_expected + m_begin);
+			std::fprintf(stderr, "  Number of stale values:   %u\n", duk_get_top(m_context) - m_begin - m_expected);
+			std::abort();
+		}
+#endif
+	}
+};
+
+/**
+ * \class Exception
+ * \brief Error description.
+ *
+ * This class fills the fields got in an Error object.
+ */
+class Exception : public std::exception {
+public:
+	std::string name;		//!< name of error
+	std::string message;		//!< error message
+	std::string stack;		//!< stack if available
+	std::string fileName;		//!< filename if applicable
+	int lineNumber{0};		//!< line number if applicable
+
+	/**
+	 * Get the error message. This effectively returns message field.
+	 *
+	 * \return the message
+	 */
+	const char *what() const noexcept override
+	{
+		return message.c_str();
+	}
+};
+
+/**
+ * \brief RAII based Duktape handler.
+ *
+ * This class is implicitly convertible to duk_context for convenience.
+ */
+class UniqueContext {
+private:
+	using Deleter = void (*)(duk_context *);
+	using Handle = std::unique_ptr<duk_context, Deleter>;
+
+	Handle m_handle;
+
+	UniqueContext(const UniqueContext &) = delete;
+	UniqueContext &operator=(const UniqueContext &) = delete;
+
+public:
+	/**
+	 * Create default context.
+	 */
+	inline UniqueContext()
+		: m_handle(duk_create_heap_default(), duk_destroy_heap)
+	{
+	}
+
+	/**
+	 * Default move constructor.
+	 */
+	UniqueContext(UniqueContext &&) noexcept = default;
+
+	/**
+	 * Convert the context to the native Duktape/C type.
+	 *
+	 * \return the duk_context
+	 */
+	inline operator duk_context *() noexcept
+	{
+		return m_handle.get();
+	}
+
+	/**
+	 * Convert the context to the native Duktape/C type.
+	 *
+	 * \return the duk_context
+	 */
+	inline operator duk_context *() const noexcept
+	{
+		return m_handle.get();
+	}
+
+	/**
+	 * Default move assignment operator.
+	 *
+	 * \return this
+	 */
+	UniqueContext &operator=(UniqueContext &&) noexcept = delete;
+};
+
+/**
+ * \class Error
+ * \brief Base ECMAScript error class.
+ * \warning Override the function create for your own exceptions
+ */
+class Error {
+private:
+	int m_type{DUK_ERR_ERROR};
+	std::string m_message;
+
+protected:
+	/**
+	 * Constructor with a type of error specified, specially designed for derived errors.
+	 *
+	 * \param type of error (e.g. DUK_ERR_ERROR)
+	 * \param message the message
+	 */
+	inline Error(int type, std::string message) noexcept
+		: m_type(type)
+		, m_message(std::move(message))
+	{
+	}
+
+public:
+	/**
+	 * Constructor with a message.
+	 *
+	 * \param message the message
+	 */
+	inline Error(std::string message) noexcept
+		: m_message(std::move(message))
+	{
+	}
+
+	/**
+	 * Create the exception on the stack.
+	 *
+	 * \note the default implementation search for the global variables
+	 * \param ctx the context
+	 */
+	virtual void raise(duk_context *ctx) const
+	{
+		duk_error(ctx, m_type, "%s", m_message.c_str());
+	}
+};
+
+/**
+ * \class EvalError
+ * \brief Error in eval() function.
+ */
+class EvalError : public Error {
+public:
+	/**
+	 * Construct an EvalError.
+	 *
+	 * \param message the message
+	 */
+	inline EvalError(std::string message) noexcept
+		: Error(DUK_ERR_EVAL_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class RangeError
+ * \brief Value is out of range.
+ */
+class RangeError : public Error {
+public:
+	/**
+	 * Construct an RangeError.
+	 *
+	 * \param message the message
+	 */
+	inline RangeError(std::string message) noexcept
+		: Error(DUK_ERR_RANGE_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class ReferenceError
+ * \brief Trying to use a variable that does not exist.
+ */
+class ReferenceError : public Error {
+public:
+	/**
+	 * Construct an ReferenceError.
+	 *
+	 * \param message the message
+	 */
+	inline ReferenceError(std::string message) noexcept
+		: Error(DUK_ERR_REFERENCE_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class SyntaxError
+ * \brief Syntax error in the script.
+ */
+class SyntaxError : public Error {
+public:
+	/**
+	 * Construct an SyntaxError.
+	 *
+	 * \param message the message
+	 */
+	inline SyntaxError(std::string message) noexcept
+		: Error(DUK_ERR_SYNTAX_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class TypeError
+ * \brief Invalid type given.
+ */
+class TypeError : public Error {
+public:
+	/**
+	 * Construct an TypeError.
+	 *
+	 * \param message the message
+	 */
+	inline TypeError(std::string message) noexcept
+		: Error(DUK_ERR_TYPE_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * \class URIError
+ * \brief URI manipulation failure.
+ */
+class URIError : public Error {
+public:
+	/**
+	 * Construct an URIError.
+	 *
+	 * \param message the message
+	 */
+	inline URIError(std::string message) noexcept
+		: Error(DUK_ERR_URI_ERROR, std::move(message))
+	{
+	}
+};
+
+/**
+ * Get the error object when a JavaScript error has been thrown (e.g. eval failure).
+ *
+ * \param ctx the context
+ * \param index the index
+ * \param pop if true, also remove the exception from the stack
+ * \return the information
+ */
+inline Exception exception(duk_context *ctx, int index, bool pop = true)
+{
+	Exception ex;
+
+	index = duk_normalize_index(ctx, index);
+
+	duk_get_prop_string(ctx, index, "name");
+	ex.name = duk_to_string(ctx, -1);
+	duk_get_prop_string(ctx, index, "message");
+	ex.message = duk_to_string(ctx, -1);
+	duk_get_prop_string(ctx, index, "fileName");
+	ex.fileName = duk_to_string(ctx, -1);
+	duk_get_prop_string(ctx, index, "lineNumber");
+	ex.lineNumber = duk_to_int(ctx, -1);
+	duk_get_prop_string(ctx, index, "stack");
+	ex.stack = duk_to_string(ctx, -1);
+	duk_pop_n(ctx, 5);
+
+	if (pop)
+		duk_remove(ctx, index);
+
+	return ex;
+}
+
+/**
+ * Enumerate an object or an array at the specified index.
+ *
+ * \param ctx the context
+ * \param index the object or array index
+ * \param flags the optional flags to pass to duk_enum
+ * \param getvalue set to true if you want to extract the value
+ * \param func the function to call for each properties
+ */
+template <typename Func>
+void enumerate(duk_context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
+{
+	duk_enum(ctx, index, flags);
+
+	while (duk_next(ctx, -1, getvalue)) {
+		func(ctx);
+		duk_pop_n(ctx, 1 + (getvalue ? 1 : 0));
+	}
+
+	duk_pop(ctx);
+}
+
+/**
+ * Throw an ECMAScript exception.
+ *
+ * \param ctx the context
+ * \param ex the exception
+ */
+template <typename Exception>
+void raise(duk_context *ctx, const Exception &ex)
+{
+	ex.raise(ctx);
+}
+
+/**
+ * Get a string, return 0 if not a string.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the string
+ */
+inline std::string duk_get_stdstring(duk_context *ctx, int index)
+{
+	duk_size_t size;
+	const char *text = duk_get_lstring(ctx, index, &size);
+
+	return std::string(text, size);
+}
+
+/**
+ * Require a string, throws a JavaScript exception if not a string.
+ *
+ * \param ctx the context
+ * \param index the index
+ * \return the string
+ */
+inline std::string duk_require_stdstring(duk_context *ctx, int index)
+{
+	duk_size_t size;
+	const char *text = duk_require_lstring(ctx, index, &size);
+
+	return std::string(text, size);
+}
+
+#endif // !DUKTAPE_HPP
--- a/modules/js/js.hpp	Thu Jun 02 16:56:44 2016 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1693 +0,0 @@
-/*
- * js.hpp -- JavaScript C++14 wrapper for Duktape
- *
- * Copyright (c) 2016 David Demelier <markand@malikania.fr>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef JS_HPP
-#define JS_HPP
-
-/**
- * \file js.hpp
- * \brief Bring JavaScript using Duktape.
- * \author David Demelier <markand@malikania.fr>
- */
-
-#include <cstdio>
-#include <cstdlib>
-#include <memory>
-#include <string>
-#include <unordered_map>
-#include <utility>
-
-#include <duktape.h>
-
-/**
- * Duktape C++ namespace wrapper.
- */
-namespace duk {
-
-/**
- * \brief Typedef without pointer.
- */
-using Context = ::duk_context;
-
-/**
- * \brief Typedef for duk_double_t.
- */
-using Double = ::duk_double_t;
-
-/**
- * \brief Typedef for duk_idx_t.
- */
-using Index = ::duk_idx_t;
-
-/**
- * \brief Typedef for duk_ret_t.
- */
-using Ret = ::duk_ret_t;
-
-/**
- * \brief Typedef for duk_size_t.
- */
-using Size = ::duk_size_t;
-
-/**
- * \brief Typedef for duk_int_t.
- */
-using Int = ::duk_int_t;
-
-/**
- * \brief Typedef for duk_uint_t;
- */
-using Uint = ::duk_uint_t;
-
-/**
- * \class StackAssert
- * \brief Stack sanity checker.
- *
- * Instanciate this class where you need to manipulate the Duktape stack outside a Duktape/C function, its destructor
- * will examinate if the stack size matches the user expected size.
- *
- * When compiled with NDEBUG, this class does nothing.
- *
- * To use it, just declare an lvalue at the beginning of your function.
- */
-class StackAssert {
-#if !defined(NDEBUG)
-private:
-	Context *m_context;
-	unsigned m_expected;
-	unsigned m_begin;
-#endif
-
-public:
-	/**
-	 * Create the stack checker.
-	 *
-	 * No-op if NDEBUG is set.
-	 *
-	 * \param ctx the context
-	 * \param expected the size expected relative to the already existing values
-	 */
-	inline StackAssert(Context *ctx, unsigned expected = 0) noexcept
-#if !defined(NDEBUG)
-		: m_context(ctx)
-		, m_expected(expected)
-		, m_begin(static_cast<unsigned>(duk_get_top(ctx)))
-#endif
-	{
-#if defined(NDEBUG)
-		(void)ctx;
-		(void)expected;
-#endif
-	}
-
-	/**
-	 * Verify the expected size.
-	 *
-	 * No-op if NDEBUG is set.
-	 */
-	inline ~StackAssert() noexcept
-	{
-#if !defined(NDEBUG)
-		if (static_cast<unsigned>(duk_get_top(m_context)) - m_begin != m_expected) {
-			std::fprintf(stderr, "Corrupt stack detection in StackAssert:\n");
-			std::fprintf(stderr, "  Size at start:            %u\n", m_begin);
-			std::fprintf(stderr, "  Size at end:              %d\n", duk_get_top(m_context));
-			std::fprintf(stderr, "  Expected (user):          %u\n", m_expected);
-			std::fprintf(stderr, "  Expected (adjusted):      %u\n", m_expected + m_begin);
-			std::fprintf(stderr, "  Number of stale values:   %u\n", duk_get_top(m_context) - m_begin - m_expected);
-			std::abort();
-		}
-#endif
-	}
-};
-
-/**
- * \class Function
- * \brief Duktape/C function definition.
- *
- * This class wraps the std::function as a Duktape/C function by storing a copied pointer.
- */
-class Function {
-public:
-	/**
-	 * The function pointer, must not be null.
-	 */
-	duk_c_function function;
-
-	/**
-	 * Number of args that the function takes
-	 */
-	duk_idx_t nargs{0};
-
-	/**
-	 * Constructor for compatibility.
-	 *
-	 * \param f the function
-	 * \param n the number of arguments
-	 */
-	inline Function(duk_c_function f, duk_idx_t n = 0) noexcept
-		: function(f)
-		, nargs(n)
-	{
-	}
-};
-
-/**
- * \brief Map of functions.
- */
-using FunctionMap = std::unordered_map<std::string, Function>;
-
-/**
- * \class Exception
- * \brief Error description.
- *
- * This class fills the fields got in an Error object.
- */
-class Exception : public std::exception {
-public:
-	std::string name;		//!< name of error
-	std::string message;		//!< error message
-	std::string stack;		//!< stack if available
-	std::string fileName;		//!< filename if applicable
-	int lineNumber{0};		//!< line number if applicable
-
-	/**
-	 * Get the error message. This effectively returns message field.
-	 *
-	 * \return the message
-	 */
-	const char *what() const noexcept override
-	{
-		return message.c_str();
-	}
-};
-
-/**
- * \brief RAII based Duktape handler.
- *
- * This class is implicitly convertible to duk_context for convenience.
- */
-class UniqueContext {
-private:
-	using Deleter = void (*)(duk_context *);
-	using Handle = std::unique_ptr<duk_context, Deleter>;
-
-	Handle m_handle;
-
-	UniqueContext(const UniqueContext &) = delete;
-	UniqueContext &operator=(const UniqueContext &) = delete;
-
-public:
-	/**
-	 * Create default context.
-	 */
-	inline UniqueContext()
-		: m_handle(duk_create_heap_default(), duk_destroy_heap)
-	{
-	}
-
-	/**
-	 * Default move constructor.
-	 */
-	UniqueContext(UniqueContext &&) noexcept = default;
-
-	/**
-	 * Convert the context to the native Duktape/C type.
-	 *
-	 * \return the duk_context
-	 */
-	inline operator duk_context *() noexcept
-	{
-		return m_handle.get();
-	}
-
-	/**
-	 * Convert the context to the native Duktape/C type.
-	 *
-	 * \return the duk_context
-	 */
-	inline operator duk_context *() const noexcept
-	{
-		return m_handle.get();
-	}
-
-	/**
-	 * Default move assignment operator.
-	 *
-	 * \return this
-	 */
-	UniqueContext &operator=(Context &&) noexcept = delete;
-};
-
-/**
- * \name Duktape C functions
- * \brief The following functions are wrappers on top of the Duktape C functions.
- *
- * They are as close as possible to the original functions.
- */
-
-/**
- * \{
- */
-
-/**
- * Wrapper for [duk_allow](http://duktape.org/api.html#duk_allow).
- *
- * \param ctx the context
- * \param size the requested size
- * \return the pointer
- */
-inline void *alloc(Context *ctx, Size size)
-{
-	return duk_alloc(ctx, size);
-}
-
-/**
- * Wrapper for [duk_allow_raw](http://duktape.org/api.html#duk_allow_raw).
- *
- * \param ctx the context
- * \param size the requested size
- * \return the pointer
- */
-inline void *allocRaw(Context *ctx, Size size)
-{
-	return duk_alloc_raw(ctx, size);
-}
-
-/**
- * Wrapper for [duk_base64_decode](http://duktape.org/api.html#duk_base64_decode).
- *
- * \param ctx the context
- * \param index the index
- */
-inline void base64Decode(Context *ctx, Index index)
-{
-	duk_base64_decode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_base64_encode](http://duktape.org/api.html#duk_base64_encode).
- *
- * \param ctx the context
- * \param index the index
- * \return the base64 string
- */
-inline std::string base64Encode(Context *ctx, Index index)
-{
-	return duk_base64_encode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_call](http://duktape.org/api.html#duk_call).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- */
-inline void call(Context *ctx, Index nargs = 0)
-{
-	duk_call(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_call_method](http://duktape.org/api.html#duk_call_method).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- */
-inline void callMethod(Context *ctx, Index nargs = 0)
-{
-	duk_call_method(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_call_prop](http://duktape.org/api.html#duk_call_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param nargs the number of arguments
- */
-inline void callProperty(Context *ctx, Index index, Index nargs = 0)
-{
-	duk_call_prop(ctx, index, nargs);
-}
-
-/**
- * Wrapper for [duk_char_code_at](http://duktape.org/api.html#duk_char_code_at).
- *
- * \param ctx the context
- * \param index the index
- * \param charOffset the offset
- * \return the code point
- */
-inline duk_codepoint_t charCodeAt(Context *ctx, Index index, duk_size_t charOffset)
-{
-	return duk_char_code_at(ctx, index, charOffset);
-}
-
-/**
- * Wrapper for [duk_check_stack](http://duktape.org/api.html#duk_check_stack).
- *
- * \param ctx the context
- * \param extra the extra space
- * \return true if space is available
- */
-inline bool checkStack(Context *ctx, Index extra)
-{
-	return duk_check_stack(ctx, extra) != 0;
-}
-
-/**
- * Wrapper for [duk_check_stack_top](http://duktape.org/api.html#duk_check_stack_top).
- *
- * \param ctx the context
- * \param top the extra space
- * \return true if space is available
- */
-inline bool checkStackTop(Context *ctx, Index top)
-{
-	return duk_check_stack_top(ctx, top) != 0;
-}
-
-/**
- * Wrapper for [duk_check_type](http://duktape.org/api.html#duk_check_type).
- *
- * \param ctx the context
- * \param index the value index
- * \param type the desired type
- * \return true if object is given type
- */
-inline bool checkType(Context *ctx, Index index, int type)
-{
-	return duk_check_type(ctx, index, type) != 0;
-}
-
-/**
- * Wrapper for [duk_check_type_mask](http://duktape.org/api.html#duk_check_type_mask).
- *
- * \param ctx the context
- * \param index the value index
- * \param mask the desired mask
- * \return true if object is one of the type
- */
-inline bool checkTypeMask(Context *ctx, Index index, unsigned mask)
-{
-	return duk_check_type_mask(ctx, index, mask) != 0;
-}
-
-/**
- * Wrapper for [duk_compact](http://duktape.org/api.html#duk_compact).
- *
- * \param ctx the context
- * \param objIndex the object index
- */
-inline void compact(Context *ctx, Index objIndex)
-{
-	duk_compact(ctx, objIndex);
-}
-
-/**
- * Wrapper for [duk_concat](http://duktape.org/api.html#duk_concat).
- *
- * \param ctx the context
- * \param count the number of values
- */
-inline void concat(Context *ctx, Index count)
-{
-	duk_concat(ctx, count);
-}
-
-/**
- * Wrapper for [duk_copy](http://duktape.org/api.html#duk_copy).
- *
- * \param ctx the context
- * \param from the from index
- * \param to the destination
- */
-inline void copy(Context *ctx, Index from, Index to)
-{
-	duk_copy(ctx, from, to);
-}
-
-/**
- * Wrapper for [duk_new](http://duktape.org/api.html#duk_new).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- */
-inline void create(Context *ctx, int nargs = 0)
-{
-	duk_new(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_def_prop](http://duktape.org/api.html#duk_def_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param flags the flags
- */
-inline void defineProperty(Context *ctx, Index index, unsigned flags)
-{
-	duk_def_prop(ctx, index, flags);
-}
-
-/**
- * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \return true if deleted
- */
-inline bool deleteProperty(Context *ctx, Index index)
-{
-	return duk_del_prop(ctx, index) != 0;
-}
-
-/**
- * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param position the property index
- * \return true if deleted
- */
-inline bool deleteProperty(Context *ctx, Index index, unsigned position)
-{
-	return duk_del_prop_index(ctx, index, position) != 0;
-}
-
-/**
- * Wrapper for [duk_del_prop](http://duktape.org/api.html#duk_del_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \return true if deleted
- */
-inline bool deleteProperty(Context *ctx, Index index, const std::string &name)
-{
-	return duk_del_prop_string(ctx, index, name.c_str()) != 0;
-}
-
-/**
- * Wrapper for [duk_dup](http://duktape.org/api.html#duk_dup).
- *
- * \param ctx the context
- * \param index the value to copy
- */
-inline void dup(Context *ctx, int index = -1)
-{
-	duk_dup(ctx, index);
-}
-
-/**
- * Wrapper for [duk_equals](http://duktape.org/api.html#duk_equals).
- *
- * \param ctx the context
- * \param index1 the first value
- * \param index2 the second value
- * \return true if they equal
- */
-inline bool equals(Context *ctx, Index index1, Index index2)
-{
-	return duk_equals(ctx, index1, index2) != 0;
-}
-
-/**
- * Wrapper for [duk_eval](http://duktape.org/api.html#duk_eval).
- *
- * \param ctx the context
- */
-inline void eval(Context *ctx)
-{
-	duk_eval(ctx);
-}
-
-/**
- * Wrapper for [duk_eval_file](http://duktape.org/api.html#duk_eval_file).
- *
- * \param ctx the context
- * \param path the path
- * \param result true to get the result at the top of the stack
- */
-inline void evalFile(Context *ctx, const std::string &path, bool result = true)
-{
-	return result ? duk_eval_file(ctx, path.c_str()) : duk_eval_file_noresult(ctx, path.c_str());
-}
-
-/**
- * Wrapper for [duk_eval_string](http://duktape.org/api.html#duk_eval_string).
- *
- * \param ctx the context
- * \param src the source script
- * \param result true to get the result at the top of the stack
- */
-inline void evalString(Context *ctx, const std::string &src, bool result = true)
-{
-	return result ? duk_eval_string(ctx, src.c_str()) : duk_eval_string_noresult(ctx, src.c_str());
-}
-
-/**
- * Wrapper for [duk_gc](http://duktape.org/api.html#duk_gc).
- *
- * \param ctx the context
- * \param flags the flags
- */
-inline void gc(Context *ctx, unsigned flags = 0)
-{
-	duk_gc(ctx, flags);
-}
-
-/**
- * Wrapper for [duk_get_global_string](http://duktape.org/api.html#duk_get_global_string).
- *
- * \param ctx the context
- * \param key the property
- */
-inline bool getGlobal(Context *ctx, const std::string &key)
-{
-	return duk_get_global_string(ctx, key.c_str());
-}
-
-/**
- * Wrapper for [duk_get_prop_string](http://duktape.org/api.html#duk_get_prop_string).
- *
- * \param ctx the context
- * \param key the property
- */
-inline bool getProperty(Context *ctx, Index index, const std::string &key)
-{
-	return duk_get_prop_string(ctx, index, key.c_str());
-}
-
-/**
- * Wrapper for [duk_get_prop_index](http://duktape.org/api.html#duk_get_prop_index).
- *
- * \param ctx the context
- * \param position the property
- */
-inline bool getProperty(Context *ctx, Index index, unsigned position)
-{
-	return duk_get_prop_index(ctx, index, position);
-}
-
-/**
- * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \return true if has
- */
-inline bool hasProperty(Context *ctx, Index index)
-{
-	return duk_has_prop(ctx, index) != 0;
-}
-
-/**
- * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param position the property index
- * \return true if has
- */
-inline bool hasProperty(Context *ctx, Index index, unsigned position)
-{
-	return duk_has_prop_index(ctx, index, position) != 0;
-}
-
-/**
- * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- * \return true if has
- */
-inline bool hasProperty(Context *ctx, int index, const std::string &name)
-{
-	return duk_has_prop_string(ctx, index, name.c_str()) != 0;
-}
-
-/**
- * Wrapper for [duk_insert](http://duktape.org/api.html#duk_insert).
- *
- * \param ctx the context
- * \param to the destination
- * \note Wrapper of duk_insert
- */
-inline void insert(Context *ctx, Index to)
-{
-	duk_insert(ctx, to);
-}
-
-/**
- * Wrapper for [duk_instanceof](http://duktape.org/api.html#duk_instanceof).
- *
- * \param ctx the context
- * \param idx1 the value to test
- * \param idx2 the instance requested
- * \return true if idx1 is instance of idx2
- */
-inline bool instanceof(Context *ctx, Index idx1, Index idx2)
-{
-	return duk_instanceof(ctx, idx1, idx2) != 0;
-}
-
-/**
- * Wrapper for [duk_is_constructor_call](http://duktape.org/api.html#duk_is_constructor_call).
- *
- * \param ctx the context
- * \return true if it's a constructor call (new operator)
- */
-inline bool isConstructorCall(Context *ctx)
-{
-	return duk_is_constructor_call(ctx) != 0;
-}
-
-/**
- * Wrapper for [duk_join](http://duktape.org/api.html#duk_join).
- *
- * \param ctx the context
- * \param count the number of values
- */
-inline void join(Context *ctx, Index count)
-{
-	duk_join(ctx, count);
-}
-
-/**
- * Wrapper for [duk_json_decode](http://duktape.org/api.html#duk_json_decode).
- *
- * \param ctx the context
- * \param index the index
- */
-inline void jsonDecode(Context *ctx, Index index)
-{
-	duk_json_decode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_json_encode](http://duktape.org/api.html#duk_json_encode).
- *
- * \param ctx the context
- * \param index the index
- * \return the JSON string
- */
-inline std::string jsonEncode(Context *ctx, Index index)
-{
-	return duk_json_encode(ctx, index);
-}
-
-/**
- * Wrapper for [duk_normalize_index](http://duktape.org/api.html#duk_normalize_index).
- *
- * \param ctx the context
- * \param index the index
- * \return the absolute index
- */
-inline Index normalizeIndex(Context *ctx, Index index)
-{
-	return duk_normalize_index(ctx, index);
-}
-
-/**
- * Wrapper for [duk_pcall](http://duktape.org/api.html#duk_pcall).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- * \return non zero on failure
- */
-inline int pcall(Context *ctx, Index nargs = 0)
-{
-	return duk_pcall(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_pcall_method](http://duktape.org/api.html#duk_pcall_method).
- *
- * \param ctx the context
- * \param nargs the number of arguments
- * \return non zero on failure
- */
-inline int pcallMethod(Context *ctx, Index nargs = 0)
-{
-	return duk_pcall_method(ctx, nargs);
-}
-
-/**
- * Wrapper for [duk_pcall_prop](http://duktape.org/api.html#duk_pcall_prop).
- *
- * \param ctx the context
- * \param index the object index
- * \param nargs the number of arguments
- * \return non zero on failure
- */
-inline int pcallProperty(Context *ctx, Index index, Index nargs = 0)
-{
-	return duk_pcall_prop(ctx, index, nargs);
-}
-
-/**
- * Wrapper for [duk_peval](http://duktape.org/api.html#duk_peval).
- *
- * \param ctx the context
- * \return non zero on failure
- */
-inline int peval(Context *ctx)
-{
-	return duk_peval(ctx);
-}
-
-/**
- * Wrapper for [duk_peval_file](http://duktape.org/api.html#duk_peval_file).
- *
- * \param ctx the context
- * \param path the path
- * \param result true to get the result at the top of the stack
- * \return non zero on failure
- */
-inline int pevalFile(Context *ctx, const std::string &path, bool result = true)
-{
-	return result ? duk_peval_file(ctx, path.c_str()) : duk_peval_file_noresult(ctx, path.c_str());
-}
-
-/**
- * Wrapper for [duk_peval_string](http://duktape.org/api.html#duk_peval_string).
- *
- * \param ctx the context
- * \param src the source script
- * \param result true to get the result at the top of the stack
- * \return non zero on failure
- */
-inline int pevalString(Context *ctx, const std::string &src, bool result = true)
-{
-	return result ? duk_peval_string(ctx, src.c_str()) : duk_peval_string_noresult(ctx, src.c_str());
-}
-
-/**
- * Wrapper for [duk_pop_n](http://duktape.org/api.html#duk_pop_n).
- *
- * \param ctx the context
- * \param count the number of values to pop
- */
-inline void pop(Context *ctx, Index count = 1)
-{
-	duk_pop_n(ctx, count);
-}
-
-/**
- * Wrapper for [duk_put_global_string](http://duktape.org/api.html#duk_put_global_string).
- *
- * \param ctx the context
- * \param key the property
- */
-inline bool putGlobal(Context *ctx, const std::string &key)
-{
-	return duk_put_global_string(ctx, key.c_str());
-}
-
-/**
- * Wrapper for [duk_put_prop](http://duktape.org/api.html#duk_put_prop).
- *
- * \param ctx the context
- * \param index the object index
- */
-inline void putProperty(Context *ctx, Index index)
-{
-	duk_put_prop(ctx, index);
-}
-
-/**
- * Wrapper for [duk_put_prop_string](http://duktape.org/api.html#duk_put_prop_string).
- *
- * \param ctx the context
- * \param index the object index
- * \param name the property name
- */
-inline void putProperty(Context *ctx, Index index, const std::string &name)
-{
-	duk_put_prop_string(ctx, index, name.c_str());
-}
-
-/**
- * Wrapper for [duk_put_prop_index](http://duktape.org/api.html#duk_put_prop_index).
- *
- * \param ctx the context
- * \param index the object index
- * \param position the array position
- */
-inline void putProperty(Context *ctx, Index index, unsigned position)
-{
-	duk_put_prop_index(ctx, index, position);
-}
-
-/**
- * Wrapper for [duk_remove](http://duktape.org/api.html#duk_remove).
- *
- * \param ctx the context
- * \param index the value to remove
- */
-inline void remove(Context *ctx, Index index)
-{
-	duk_remove(ctx, index);
-}
-
-/**
- * Wrapper for [duk_replace](http://duktape.org/api.html#duk_replace).
- *
- * \param ctx the context
- * \param index the value to replace by the value at the top of the stack
- */
-inline void replace(Context *ctx, Index index)
-{
-	duk_replace(ctx, index);
-}
-
-/**
- * Wrapper for [duk_set_finalizer](http://duktape.org/api.html#duk_set_finalizer).
- *
- * \param ctx the context
- * \param index the value index
- */
-inline void setFinalizer(Context *ctx, Index index)
-{
-	duk_set_finalizer(ctx, index);
-}
-
-/**
- * Wrapper for [duk_set_prototype](http://duktape.org/api.html#duk_set_prototype).
- *
- * \param ctx the context
- * \param index the value index
- */
-inline void setPrototype(Context *ctx, Index index)
-{
-	duk_set_prototype(ctx, index);
-}
-
-/**
- * Wrapper for [duk_swap](http://duktape.org/api.html#duk_swap).
- *
- * \param ctx the context
- * \param index1 the first index
- * \param index2 the second index
- */
-inline void swap(Context *ctx, Index index1, Index index2)
-{
-	duk_swap(ctx, index1, index2);
-}
-
-/**
- * Wrapper for [duk_swap_top](http://duktape.org/api.html#duk_swap_top).
- *
- * \param ctx the context
- * \param index the index
- */
-inline void swapTop(Context *ctx, Index index)
-{
-	duk_swap_top(ctx, index);
-}
-
-/**
- * Wrapper for [duk_get_top](http://duktape.org/api.html#duk_get_top).
- *
- * \param ctx the context
- * \return the stack size
- */
-inline int top(Context *ctx)
-{
-	return duk_get_top(ctx);
-}
-
-/**
- * Wrapper for [duk_throw](http://duktape.org/api.html#duk_throw).
- *
- * \param ctx the context
- */
-inline void raise(Context *ctx)
-{
-	duk_throw(ctx);
-}
-
-/**
- *Wrapper for [duk_error](http://duktape.org/api.html#duk_error).
- *
- * \param ctx the context
- * \param type the error type (e.g. DUK_ERR_REFERENCE_ERROR)
- * \param fmt the format string
- * \param args the arguments
- */
-template <typename... Args>
-inline void raise(Context *ctx, int type, const char *fmt, Args&&... args)
-{
-	duk_error(ctx, type, fmt, std::forward<Args>(args)...);
-}
-
-/**
- * Wrapper for [duk_get_type](http://duktape.org/api.html#duk_get_type).
- *
- * \param ctx the context
- * \param index the index
- * \return the type
- */
-inline int type(Context *ctx, Index index)
-{
-	return duk_get_type(ctx, index);
-}
-
-/**
- * \}
- */
-
-/**
- * \name Extended functions
- * \brief Extended functions for libjs.
- *
- * The following functions are largely modified or extensions to Duktape.
- */
-
-/**
- * \{
- */
-
-/**
- * Get the error object when a JavaScript error has been thrown (e.g. eval failure).
- *
- * \param ctx the context
- * \param index the index
- * \param pop if true, also remove the exception from the stack
- * \return the information
- */
-inline Exception exception(Context *ctx, int index, bool pop = true)
-{
-	Exception ex;
-
-	index = duk_normalize_index(ctx, index);
-
-	duk_get_prop_string(ctx, index, "name");
-	ex.name = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "message");
-	ex.message = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "fileName");
-	ex.fileName = duk_to_string(ctx, -1);
-	duk_get_prop_string(ctx, index, "lineNumber");
-	ex.lineNumber = duk_to_int(ctx, -1);
-	duk_get_prop_string(ctx, index, "stack");
-	ex.stack = duk_to_string(ctx, -1);
-	duk_pop_n(ctx, 5);
-
-	if (pop)
-		duk_remove(ctx, index);
-
-	return ex;
-}
-
-/**
- * Enumerate an object or an array at the specified index.
- *
- * \param ctx the context
- * \param index the object or array index
- * \param flags the optional flags to pass to duk_enum
- * \param getvalue set to true if you want to extract the value
- * \param func the function to call for each properties
- */
-template <typename Func>
-void enumerate(Context *ctx, int index, duk_uint_t flags, duk_bool_t getvalue, Func &&func)
-{
-	duk_enum(ctx, index, flags);
-
-	while (duk_next(ctx, -1, getvalue)) {
-		func(ctx);
-		duk_pop_n(ctx, 1 + (getvalue ? 1 : 0));
-	}
-
-	duk_pop(ctx);
-}
-
-/**
- * Throw an ECMAScript exception.
- *
- * \param ctx the context
- * \param ex the exception
- */
-template <typename Exception>
-void raise(Context *ctx, const Exception &ex)
-{
-	ex.raise(ctx);
-}
-
-/**
- * \}
- */
-
-/**
- * \class Error
- * \brief Base ECMAScript error class.
- * \warning Override the function create for your own exceptions
- */
-class Error {
-private:
-	int m_type{DUK_ERR_ERROR};
-	std::string m_message;
-
-protected:
-	/**
-	 * Constructor with a type of error specified, specially designed for derived errors.
-	 *
-	 * \param type of error (e.g. DUK_ERR_ERROR)
-	 * \param message the message
-	 */
-	inline Error(int type, std::string message) noexcept
-		: m_type(type)
-		, m_message(std::move(message))
-	{
-	}
-
-public:
-	/**
-	 * Constructor with a message.
-	 *
-	 * \param message the message
-	 */
-	inline Error(std::string message) noexcept
-		: m_message(std::move(message))
-	{
-	}
-
-	/**
-	 * Create the exception on the stack.
-	 *
-	 * \note the default implementation search for the global variables
-	 * \param ctx the context
-	 */
-	virtual void raise(Context *ctx) const
-	{
-		duk_error(ctx, m_type, "%s", m_message.c_str());
-	}
-};
-
-/**
- * \class EvalError
- * \brief Error in eval() function.
- */
-class EvalError : public Error {
-public:
-	/**
-	 * Construct an EvalError.
-	 *
-	 * \param message the message
-	 */
-	inline EvalError(std::string message) noexcept
-		: Error(DUK_ERR_EVAL_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class RangeError
- * \brief Value is out of range.
- */
-class RangeError : public Error {
-public:
-	/**
-	 * Construct an RangeError.
-	 *
-	 * \param message the message
-	 */
-	inline RangeError(std::string message) noexcept
-		: Error(DUK_ERR_RANGE_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class ReferenceError
- * \brief Trying to use a variable that does not exist.
- */
-class ReferenceError : public Error {
-public:
-	/**
-	 * Construct an ReferenceError.
-	 *
-	 * \param message the message
-	 */
-	inline ReferenceError(std::string message) noexcept
-		: Error(DUK_ERR_REFERENCE_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class SyntaxError
- * \brief Syntax error in the script.
- */
-class SyntaxError : public Error {
-public:
-	/**
-	 * Construct an SyntaxError.
-	 *
-	 * \param message the message
-	 */
-	inline SyntaxError(std::string message) noexcept
-		: Error(DUK_ERR_SYNTAX_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class TypeError
- * \brief Invalid type given.
- */
-class TypeError : public Error {
-public:
-	/**
-	 * Construct an TypeError.
-	 *
-	 * \param message the message
-	 */
-	inline TypeError(std::string message) noexcept
-		: Error(DUK_ERR_TYPE_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * \class URIError
- * \brief URI manipulation failure.
- */
-class URIError : public Error {
-public:
-	/**
-	 * Construct an URIError.
-	 *
-	 * \param message the message
-	 */
-	inline URIError(std::string message) noexcept
-		: Error(DUK_ERR_URI_ERROR, std::move(message))
-	{
-	}
-};
-
-/**
- * Get an integer, return 0 if not an integer.
- *
- * \param ctx the context
- * \param index the index
- * \return the integer
- */
-inline int getInt(Context *ctx, int index)
-{
-	return duk_get_int(ctx, index);
-}
-
-/**
- * Get a boolean, return 0 if not a boolean.
- *
- * \param ctx the context
- * \param index the index
- * \return the boolean
- */
-inline bool getBool(Context *ctx, int index)
-{
-	return duk_get_boolean(ctx, index) != 0;
-}
-
-/**
- * Get a double, return 0 if not a double.
- *
- * \param ctx the context
- * \param index the index
- * \return the double
- */
-inline double getDouble(Context *ctx, int index)
-{
-	return duk_get_number(ctx, index);
-}
-
-/**
- * Get a string, return 0 if not a string.
- *
- * \param ctx the context
- * \param index the index
- * \return the string
- */
-inline std::string getString(Context *ctx, int index)
-{
-	duk_size_t size;
-	const char *text = duk_get_lstring(ctx, index, &size);
-
-	return std::string(text, size);
-}
-
-/**
- * Get an integer, return 0 if not an integer.
- *
- * \param ctx the context
- * \param index the index
- * \return the integer
- */
-inline unsigned getUnsigned(Context *ctx, int index)
-{
-	return duk_get_uint(ctx, index);
-}
-
-/**
- * Get a pointer, return nullptr if not a pointer.
- *
- * \param ctx the context
- * \param index the index
- * \return the pointer
- */
-inline void *getPointer(Context *ctx, int index)
-{
-	return duk_to_pointer(ctx, index);
-}
-
-/**
- * Check if value is a array.
- *
- * \param ctx the context
- * \param index the index
- * \return true if array
- */
-inline bool isArray(Context *ctx, int index)
-{
-	return duk_is_array(ctx, index) != 0;
-}
-
-/**
- * Check if value is a boolean.
- *
- * \param ctx the context
- * \param index the index
- * \return true if boolean
- */
-inline bool isBool(Context *ctx, int index)
-{
-	return duk_is_boolean(ctx, index) != 0;
-}
-
-/**
- * Check if value is null.
- *
- * \param ctx the context
- * \param index the index
- * \return true if null
- */
-inline bool isNull(Context *ctx, int index)
-{
-	return duk_is_null(ctx, index) != 0;
-}
-
-/**
- * Check if value is an integer.
- *
- * \param ctx the context
- * \param index the index
- * \return true if integer
- */
-inline bool isNumber(Context *ctx, int index)
-{
-	return duk_is_number(ctx, index) != 0;
-}
-
-/**
- * Check if value is an object.
- *
- * \param ctx the context
- * \param index the index
- * \return true if object
- */
-inline bool isObject(Context *ctx, int index)
-{
-	return duk_is_object(ctx, index) != 0;
-}
-
-/**
- * Check if value is a pointer.
- *
- * \param ctx the context
- * \param index the index
- * \return true if pointer
- */
-inline bool isPointer(Context *ctx, int index)
-{
-	return duk_is_pointer(ctx, index) != 0;
-}
-
-/**
- * Check if value is a string.
- *
- * \param ctx the context
- * \param index the index
- * \return true if string
- */
-inline bool isString(Context *ctx, int index)
-{
-	return duk_is_string(ctx, index) != 0;
-}
-
-/**
- * Check if value is undefined.
- *
- * \param ctx the context
- * \param index the index
- * \return true if undefined
- */
-inline bool isUndefined(Context *ctx, int index)
-{
-	return duk_is_undefined(ctx, index) != 0;
-}
-
-/**
- * Get a bool, return defaultValue if the value is not a boolean.
- *
- * \param ctx the context
- * \param index the index
- * \param defaultValue the defaultValue
- * \return the boolean or defaultValue
- */
-inline bool optionalBool(Context *ctx, int index, bool defaultValue)
-{
-	return isBool(ctx, index) ? getBool(ctx, index) : defaultValue;
-}
-
-/**
- * Get a double, return defaultValue if the value is not a double.
- *
- * \param ctx the context
- * \param index the index
- * \param defaultValue the defaultValue
- * \return the double or defaultValue
- */
-inline double optionalDouble(Context *ctx, int index, double defaultValue)
-{
-	return isNumber(ctx, index) ? getDouble(ctx, index) : defaultValue;
-}
-
-/**
- * Get an integer, return defaultValue if the value is not an integer.
- *
- * \param ctx the context
- * \param index the index
- * \param defaultValue the defaultValue
- * \return the integer or defaultValue
- */
-inline int optionalInt(Context *ctx, int index, int defaultValue)
-{
-	return isNumber(ctx, index) ? getInt(ctx, index) : defaultValue;
-}
-
-/**
- * Get a string, return defaultValue if the value is not an string.
- *
- * \param ctx the context
- * \param index the index
- * \param defaultValue the defaultValue
- * \return the string or defaultValue
- */
-inline std::string optionalString(Context *ctx, int index, std::string defaultValue)
-{
-	return isString(ctx, index) ? getString(ctx, index) : defaultValue;
-}
-
-/**
- * Get an integer, return defaultValue if the value is not an integer.
- *
- * \param ctx the context
- * \param index the index
- * \param defaultValue the defaultValue
- * \return the integer or defaultValue
- */
-inline unsigned optionalUnsigned(Context *ctx, int index, unsigned defaultValue)
-{
-	return isNumber(ctx, index) ? getUnsigned(ctx, index) : defaultValue;
-}
-
-/**
- * Get a pointer, return defaultValue if the value is not a pointer.
- *
- * \param ctx the context
- * \param index the index
- * \param defaultValue the defaultValue
- * \return the pointer or defaultValue
- */
-inline void *optionalPointer(Context *ctx, int index, void *defaultValue)
-{
-	return isPointer(ctx, index) ? getPointer(ctx, index) : defaultValue;
-}
-
-/**
- * Create an empty array on the stack.
- *
- * \param ctx the context
- */
-inline void pushArray(Context *ctx)
-{
-	duk_push_array(ctx);
-}
-
-/**
- * Push a boolean.
- *
- * \param ctx the context
- * \param value the value
- */
-inline void pushBool(Context *ctx, bool value)
-{
-	duk_push_boolean(ctx, value);
-}
-
-/**
- * Push a double.
- *
- * \param ctx the context
- * \param value the value
- */
-inline void pushDouble(Context *ctx, double value)
-{
-	duk_push_number(ctx, value);
-}
-
-/**
- * Push the global object into the stack.
- *
- * \param ctx the context
- */
-inline void pushGlobal(Context *ctx)
-{
-	duk_push_global_object(ctx);
-}
-
-/**
- * Push an integer.
- *
- * \param ctx the context
- * \param value the value
- */
-inline void pushInt(Context *ctx, int value)
-{
-	duk_push_int(ctx, value);
-}
-
-/**
- * Push null value on the stack.
- *
- * \param ctx the context
- */
-inline void pushNull(Context *ctx)
-{
-	duk_push_null(ctx);
-}
-
-/**
- * Create an empty object on the stack.
- *
- * \param ctx the context
- */
-inline void pushObject(Context *ctx)
-{
-	duk_push_object(ctx);
-}
-
-/**
- * Push a string.
- *
- * \param ctx the context
- * \param value the value
- */
-inline void pushString(Context *ctx, const std::string &value)
-{
-	duk_push_lstring(ctx, value.c_str(), value.length());
-}
-
-/**
- * Push this function into the stack.
- *
- * \param ctx the context
- */
-inline void pushThis(Context *ctx)
-{
-	duk_push_this(ctx);
-}
-
-/**
- * Push undefined value on the stack.
- *
- * \param ctx the context
- */
-inline void pushUndefined(Context *ctx)
-{
-	duk_push_undefined(ctx);
-}
-
-/**
- * Push an integer.
- *
- * \param ctx the context
- * \param value the value
- */
-inline void pushUnsigned(Context *ctx, unsigned value)
-{
-	duk_push_uint(ctx, value);
-}
-
-/**
- * Push a pointer.
- *
- * \param ctx the context
- * \param value the value
- */
-inline void pushPointer(Context *ctx, void *value)
-{
-	duk_push_pointer(ctx, value);
-}
-
-/**
- * \param ctx the context
- * \param fn the function
- */
-inline void pushFunction(Context *ctx, Function fn)
-{
-	duk_push_c_function(ctx, fn.function, fn.nargs);
-}
-
-/**
- * \param ctx the context
- * \param fn the function
- */
-inline void pushFunction(Context *ctx, duk_c_function function, duk_idx_t nargs = 0)
-{
-	duk_push_c_function(ctx, function, nargs);
-}
-
-/**
- * Push all functions to the object at the top of the stack.
- *
- * \param ctx the context
- * \param map the map of function
- */
-inline void putFunctions(Context *ctx, const FunctionMap &map)
-{
-	StackAssert sa(ctx, 0);
-
-	for (const auto &entry : map) {
-		duk_push_c_function(ctx, entry.second.function, entry.second.nargs);
-		duk_put_prop_string(ctx, -2, entry.first.c_str());
-	}
-}
-
-/**
- * Require a boolean, throws a JavaScript exception if not a boolean.
- *
- * \param ctx the context
- * \param index the index
- * \return the boolean
- */
-inline bool requireBool(Context *ctx, int index)
-{
-	return duk_require_boolean(ctx, index) != 0;
-}
-
-/**
- * Require a double, throws a JavaScript exception if not a double.
- *
- * \param ctx the context
- * \param index the index
- * \return the double
- */
-inline double requireDouble(Context *ctx, int index)
-{
-	return duk_require_number(ctx, index);
-}
-
-/**
- * Require an integer, throws a JavaScript exception if not an integer.
- *
- * \param ctx the context
- * \param index the index
- * \return the integer
- */
-inline int requireInt(Context *ctx, int index)
-{
-	return duk_require_int(ctx, index);
-}
-
-/**
- * Require a string, throws a JavaScript exception if not a string.
- *
- * \param ctx the context
- * \param index the index
- * \return the string
- */
-inline std::string requireString(Context *ctx, int index)
-{
-	duk_size_t size;
-	const char *text = duk_require_lstring(ctx, index, &size);
-
-	return std::string(text, size);
-}
-
-/**
- * Require an integer, throws a JavaScript exception if not an integer.
- *
- * \param ctx the context
- * \param index the index
- * \return the integer
- */
-inline unsigned requireUnsigned(Context *ctx, int index)
-{
-	return duk_require_uint(ctx, index);
-}
-
-/**
- * Require a pointer, throws a JavaScript exception if not a pointer.
- *
- * \param ctx the context
- * \param index the index
- * \return the pointer
- */
-inline void *requirePointer(Context *ctx, int index)
-{
-	return duk_require_pointer(ctx, index);
-}
-
-} // !duk
-
-#endif // !JS_HPP
--- a/modules/js/test/main.cpp	Thu Jun 02 16:56:44 2016 +0200
+++ b/modules/js/test/main.cpp	Fri Jun 03 13:57:20 2016 +0200
@@ -1,7 +1,7 @@
 /*
  * TestJsUnicode.cpp -- test irccd JS functions
  *
- * Copyright (c) 2013-2015 David Demelier <markand@malikania.fr>
+ * Copyright (c) 2016 David Demelier <markand@malikania.fr>
  *
  * Permission to use, copy, modify, and/or distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -18,448 +18,7 @@
 
 #include <gtest/gtest.h>
 
-#include <js.hpp>
-
-/*
- * TODO:
- *
- * - document stack modification in all functions,
- * - check that the stack is correct,
- * - add more C Duktape wrappers.
- */
-
-/*
- * Push & get.
- * ------------------------------------------------------------------
- */
-
-TEST(PushAndGet, boolean)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushBool(context, true);
-	ASSERT_TRUE(duk::getBool(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-	duk::pushBool(context, false);
-	ASSERT_FALSE(duk::getBool(context, -1));
-	ASSERT_EQ(2, duk::top(context));
-}
-
-TEST(PushAndGet, integer)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushInt(context, 123);
-	ASSERT_EQ(123, duk::getInt(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-	duk::pushInt(context, 456);
-	ASSERT_EQ(456, duk::getInt(context, -1));
-	ASSERT_EQ(2, duk::top(context));
-}
-
-TEST(PushAndGet, uinteger)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushUnsigned(context, 123U);
-	ASSERT_EQ(123U, duk::getUnsigned(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-	duk::pushUnsigned(context, 456U);
-	ASSERT_EQ(456U, duk::getUnsigned(context, -1));
-	ASSERT_EQ(2, duk::top(context));
-}
-
-TEST(PushAndGet, number)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushDouble(context, 10.5);
-	ASSERT_EQ(10.5, duk::getDouble(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-	duk::pushDouble(context, 50.1);
-	ASSERT_EQ(50.1, duk::getDouble(context, -1));
-	ASSERT_EQ(2, duk::top(context));
-}
-
-TEST(PushAndGet, string)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushString(context, "hello world!");
-	ASSERT_EQ("hello world!", duk::getString(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(PushAndGet, undefined)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushUndefined(context);
-	ASSERT_EQ(DUK_TYPE_UNDEFINED, duk::type(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(PushAndGet, null)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushNull(context);
-	ASSERT_EQ(DUK_TYPE_NULL, duk::type(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(PushAndGet, pointer)
-{
-	duk::UniqueContext context;
-	int value = 1;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushPointer(context, &value);
-	ASSERT_EQ(1, *static_cast<int *>(duk::getPointer(context, -1)));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-/*
- * Require.
- * ------------------------------------------------------------------
- */
-
-TEST(Require, boolean)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
-			duk::requireBool(ctx, 0);
-
-			return 0;
-		});
-
-		ASSERT_NE(0, duk::peval(context));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Require, integer)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
-			duk::requireInt(ctx, 0);
-
-			return 0;
-		});
-
-		ASSERT_NE(0, duk::peval(context));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Require, uinteger)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
-			duk::requireUnsigned(ctx, 0);
-
-			return 0;
-		});
-
-		ASSERT_NE(0, duk::peval(context));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Require, number)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
-			duk::requireDouble(ctx, 0);
-
-			return 0;
-		});
-
-		ASSERT_NE(0, duk::peval(context));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Require, string)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
-			duk::requireString(ctx, 0);
-
-			return 0;
-		});
-
-		ASSERT_NE(0, duk::peval(context));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Require, pointer)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
-			duk::requirePointer(ctx, 0);
-
-			return 0;
-		});
-
-		ASSERT_NE(0, duk::peval(context));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-/*
- * Is.
- * ------------------------------------------------------------------
- */
-
-TEST(Is, boolean)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushBool(context, true);
-	ASSERT_TRUE(duk::isBool(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, integer)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushInt(context, 123);
-	ASSERT_TRUE(duk::isNumber(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, uinteger)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushUnsigned(context, 123U);
-	ASSERT_TRUE(duk::isNumber(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, number)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushDouble(context, 50.5);
-	ASSERT_TRUE(duk::isNumber(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, string)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushString(context, "hello");
-	ASSERT_TRUE(duk::isString(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, undefined)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushUndefined(context);
-	ASSERT_TRUE(duk::isUndefined(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, null)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushNull(context);
-	ASSERT_TRUE(duk::isNull(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, object)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushObject(context);
-	ASSERT_TRUE(duk::isObject(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, array)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushArray(context);
-	ASSERT_TRUE(duk::isArray(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Is, pointer)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushPointer(context, nullptr);
-	ASSERT_TRUE(duk::isPointer(context, -1));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-/*
- * Optional.
- * ------------------------------------------------------------------
- */
-
-TEST(Optional, boolean)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	ASSERT_TRUE(duk::optionalBool(context, 0, true));
-	ASSERT_FALSE(duk::optionalBool(context, 0, false));
-	ASSERT_EQ(0, duk::top(context));
-}
-
-TEST(Optional, integer)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(123, duk::optionalInt(context, 0, 123));
-	ASSERT_EQ(456, duk::optionalInt(context, 0, 456));
-	ASSERT_EQ(0, duk::top(context));
-}
-
-TEST(Optional, uinteger)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(123U, duk::optionalUnsigned(context, 0, 123U));
-	ASSERT_EQ(456U, duk::optionalUnsigned(context, 0, 456U));
-	ASSERT_EQ(0, duk::top(context));
-}
-
-TEST(Optional, number)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(10.0, duk::optionalDouble(context, 0, 10.0));
-	ASSERT_EQ(20.0, duk::optionalDouble(context, 0, 20.0));
-	ASSERT_EQ(0, duk::top(context));
-}
-
-TEST(Optional, string)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ("no", duk::optionalString(context, 0, "no"));
-	ASSERT_EQ("yes", duk::optionalString(context, 0, "yes"));
-	ASSERT_EQ(0, duk::top(context));
-}
-
-TEST(Optional, pointer)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	ASSERT_EQ(nullptr, duk::optionalPointer(context, 0, nullptr));
-	ASSERT_EQ(0, duk::top(context));
-}
-
-/*
- * Basics.
- * ------------------------------------------------------------------
- */
-
-TEST(Basics, top)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushBool(context, true);
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Basics, pop1)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushBool(context, true);
-	duk::pop(context);
-	ASSERT_EQ(0, duk::top(context));
-}
-
-TEST(Basics, pop2)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushBool(context, true);
-	duk::pushBool(context, true);
-	duk::pop(context, 2);
-	ASSERT_EQ(0, duk::top(context));
-}
+#include <duktape.hpp>
 
 #if 0
 
@@ -484,104 +43,6 @@
 	ASSERT_EQ(1, duk::top(context));
 }
 
-#endif
-
-TEST(Basics, call)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::pushFunction(context, [] (duk::Context *ctx) -> duk::Ret {
-		duk::pushInt(ctx, 123);
-		duk::putGlobal(ctx, "x");
-
-		return 0;
-	});
-	duk::call(context);
-
-	ASSERT_EQ(1, duk::top(context));
-
-	duk::getGlobal(context, "x");
-	ASSERT_EQ(123, duk::getInt(context, -1));
-}
-
-#if 0
-
-/*
- * Eval.
- * ------------------------------------------------------------------
- */
-
-TEST(Eval, simple)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::evalString(context, "x = 123;");
-	ASSERT_EQ(123, duk::getGlobal<int>(context, "x"));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Eval, function)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::evalString(context, "function f() { x = 123; }; f();");
-	ASSERT_EQ(123, duk::getGlobal<int>(context, "x"));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Eval, cfunction)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-	duk::putGlobal(context, "f", duk::Function{[] (duk::Context *ctx) -> duk::Ret {
-		duk::putGlobal(ctx, "x", 123);
-
-		return 0;
-	}});
-	duk::evalString(context, "f()");
-	ASSERT_EQ(123, duk::getGlobal<int>(context, "x"));
-	ASSERT_EQ(1, duk::top(context));
-}
-
-/*
- * Protected eval.
- * ------------------------------------------------------------------
- */
-
-TEST(Peval, success)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		duk::pevalString(context, "x = 1");
-	} catch (const duk::Exception &info) {
-		FAIL() << "error unexpected: " << info.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
-TEST(Peval, failure)
-{
-	duk::UniqueContext context;
-
-	ASSERT_EQ(0, duk::top(context));
-
-	try {
-		ASSERT_NE(0, duk::pevalString(context, "doesnotexists()"));
-	} catch (const std::exception &ex) {
-		FAIL() << ex.what();
-	}
-
-	ASSERT_EQ(1, duk::top(context));
-}
-
 /*
  * Exception handling.
  * ------------------------------------------------------------------