Mercurial > code
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. * ------------------------------------------------------------------