Mercurial > irccd
changeset 189:bb70bb9e41eb
Irccd: use native Duktape API
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 03 Jun 2016 13:28:10 +0200 |
parents | 0de84b31842b |
children | cb61cc16e2b6 |
files | cmake/internal/sysconfig.hpp.in lib/irccd/duktape.hpp lib/irccd/js.hpp lib/irccd/mod-directory.cpp lib/irccd/mod-elapsed-timer.cpp lib/irccd/mod-file.cpp lib/irccd/mod-file.hpp lib/irccd/mod-irccd.cpp lib/irccd/mod-irccd.hpp lib/irccd/mod-logger.cpp lib/irccd/mod-plugin.cpp lib/irccd/mod-plugin.hpp lib/irccd/mod-server.cpp lib/irccd/mod-server.hpp lib/irccd/mod-system.cpp lib/irccd/mod-timer.cpp lib/irccd/mod-unicode.cpp lib/irccd/mod-util.cpp lib/irccd/net.hpp lib/irccd/plugin-js.cpp lib/irccd/plugin-js.hpp lib/irccd/server-event.cpp |
diffstat | 22 files changed, 1497 insertions(+), 3895 deletions(-) [+] |
line wrap: on
line diff
--- a/cmake/internal/sysconfig.hpp.in Tue May 31 22:33:32 2016 +0200 +++ b/cmake/internal/sysconfig.hpp.in Fri Jun 03 13:28:10 2016 +0200 @@ -104,7 +104,7 @@ # if defined(IRCCD_BUILDING_DLL) # define IRCCD_EXPORT __declspec(dllexport) # else -# define IRCCD_EXPORT __declspec(dllimport) +# define IRCCD_EXPORT # endif #else # define IRCCD_EXPORT
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/irccd/duktape.hpp Fri Jun 03 13:28:10 2016 +0200 @@ -0,0 +1,440 @@ +/* + * 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 IRCCD_DUKTAPE_HPP +#define IRCCD_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> + +namespace irccd { + +/** + * \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 duk_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 duk_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 duk_throw(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); +} + +/** + * Push a C++ string. + * + * \param ctx the context + * \param str the string + */ +inline void duk_push_stdstring(duk_context *ctx, const std::string &str) +{ + duk_push_lstring(ctx, str.data(), str.length()); +} + +} // !irccd + +#endif // !IRCCD_DUKTAPE_HPP
--- a/lib/irccd/js.hpp Tue May 31 22:33:32 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2867 +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 IRCCD_JS_HPP -#define IRCCD_JS_HPP - -/** - * \file js.hpp - * \brief Bring JavaScript using Duktape. - * \author David Demelier <markand@malikania.fr> - * - * This file provides usual Duktape function renamed and placed into `duk` namespace. It also replaces error - * code with exceptions when possible. - * - * For convenience, this file also provides templated functions, overloads and much more. - */ - -/** - * \page js JavaScript binding - * \brief JavaScript binding using Duktape - * - * This page will show you how to setup this module to host JavaScript environment into your C++ application. - * - * ## Duktape - * - * Duktape is a C library designed for performance, small footprint and conformance. This wrapper is built top of it and - * requires it at build and runtime. - * - * It is highly recommended that you read the [Duktape guide](http://duktape.org/guide.html) before continuing because - * a lot of concepts are kept as-is. - * - * ## Installation - * - * You need the Duktape source amalgamation, it is provided with this module. - * - * When compiling, be sure to enable `-DDUK_OPT_CPP_EXCEPTIONS` and that Duktape source file has **cpp** extension. - * - * Just copy the **js.hpp** file and include it into your project. The header depends on **duktape.h** so be sure to - * provide it when compiling. - * - * - \subpage js-init - * - \subpage js-types - * - \subpage js-basics - * - \subpage js-more - */ - -/** - * \page js-init Initialization - * \brief Context initialization. - * - * To host JavaScript, you need a context. Usually one is sufficient but you can create as many as you want but they - * won't share any resource. - * - * \code - * #include "js.hpp" - * - * int main() - * { - * duk::UniqueContext ctx; - * - * return 0; - * } - * \endcode - * - * The duk::UniqueContext class is a RAII based wrapper around the native duk_context structure. It is automatically created and closed - * in the destructor. - * - * Be sure to not keep any pointer to it. - */ - -/** - * \page js-types Predefined types - * \brief Default duk::TypeTraits specializations - * - * The following specializations are provided with libjs. - * - * ## Primitive types - * - * | Type | Support | Remarks | - * |----------------|----------------------------------|---------------------------------------| - * | `int` | get, is, optional, push, require | | - * | `bool` | get, is, optional, push, require | | - * | `double` | get, is, optional, push, require | | - * | `std::string` | get, is, optional, push, require | can contain '\0' and binary data | - * | `const char *` | get, is, optional, push, require | | - * | `unsigned` | get, is, optional, push, require | | - * | T * | get, is, optional, push, require | raw pointer, never deleted by Duktape | - * - * ## Special JavaScript types - * - * The following types are used to create or inspect JavaScript types. - * - * | Type | Support | Remarks | - * |------------------|----------|----------------------------------------| - * | duk::Array | is, push | | - * | duk::Function | is, push | is just check if the value is callable | - * | duk::FunctionMap | put | | - * | duk::Global | push | | - * | duk::Null | is, push | | - * | duk::Object | is, push | | - * | duk::This | push | | - * | duk::Undefined | is, push | | - * - * ## Partial specializations - * - * These partial specializations will use complete specialization for T. - * - * | Type | Support | Remarks | - * |------------------------------------|-----------|------------------------| - * | std::unordered_map<std::string, T> | push, put | push or put properties | - * | std::vector<T> | push, put | push array of values | - */ - -/** - * \page js-basics Basics - * \brief Basics use case. - * - * The following topics are sample use case of the C++ front end. It does not use extended features that this module - * provides. - * - * - \subpage js-basics-t1 - * - \subpage js-basics-t2 - * - \subpage js-basics-t3 - */ - -/** - * \page js-basics-t1 Example 1: call JavaScript code from C++ - * \brief Evaluate JavaScript code from C++. - * - * Let use JavaScript to compute a simple expression. - * - * \code - * #include "js.hpp" - * - * int main() - * { - * duk::UniqueContext ctx; - * - * duk::pevalString(ctx, "1 + 1"); - * std::cout << duk::get<int>(ctx -1) << std::endl; - * - * return 0; - * } - * \endcode - */ - -/** - * \page js-basics-t2 Example 2: call C++ code from JavaScript - * \brief Evaluate a function from JavaScript. - * - * In that example, we will add a C++ function to JavaScript and call it from the script. The function just compute the - * two arguments that are passed through the function and return the result. - * - * We take the benefits of C++11 to map the function. The lambda can not have a capture because Duktape use raw C - * function pointers and this module keep them. - * - * \code - * #include "js.hpp" - * - * int main() - * { - * duk::UniqueContext ctx; - * - * // Push a function as global "add" - * duk::putGlobal(ctx, "add", duk::Function{[] (duk::Context *ctx) -> duk::Ret { - * int x = duk::require<int>(ctx, 0); - * int y = duk::require<int>(ctx, 1); - * - * duk::push(ctx, x + y); - * - * return 1; - * }, 2}); - * - * // Evaluate from JavaScript - * duk::pevalString(ctx, "add(1, 2)"); - * - * return 0; - * } - * \endcode - * - * Please note the **2** at end of lambda which indicates that the function takes 2 arguments. If number of arguments - * is variadic, pass DUK_VARARGS there. - */ - -/** - * \page js-basics-t3 Example 3: pushing and getting values - * \brief Manage values between JavaScript and C++. - * - * As you have seen in the previous examples, we were pushing some values to the Duktape context. - * - * With the C Duktape frontend, you usually use duk_push_int, duk_push_string and all other related functions. The libjs - * module provides an uniform and convenient way for sharing values with the same functions. - * - * See the description of duk::TypeTraits to see the supported types. - * - * ## Push - * - * The duk::push function is a template that accept most of the primitives types. It uses the specializations of the - * duk::TypeTraits class (described later). - * - * Example of code - * - * \code - * duk::push(ctx, 123); // an integer - * duk::push(ctx, true); // a boolean - * \endcode - * - * The push function add a new value to the stack for any specialization of TypeTraits provided by libjs. - * - * ## Get - * - * The duk::get function is similar to duk_get_ functions. It usually does not check the value and return a sane default - * value. - * - * This template function does not take the template argument so it can't be deduced and must be specified explicitly. - * - * \code - * duk::get<int>(ctx, 0) // get an int at index 0 - * duk::get<std::string>(ctx, 1) // get a std::string at index 1 - * \endcode - * - * ## Require - * - * The duk::require function is similar to duk_require functions. It requires the exact type at the given index. If the - * value is invalid a JavaScript error is propagated. - * - * \code - * duk::require<int>(ctx, 0) // require an int at index 0 or raise an error - * \endcode - * - * ## Put - * - * This special function is similar to push except that it applies to the existing object at the top of the stack. It - * is usually implemented for map and vector. - * - * \code - * // Fill the object at the top of the stack with this map - * std:unordered_map<std::string, int> map{ - * { "value1", 1 }, - * { "value2", 2 } - * }; - * - * duk::put(ctx, map); - * \endcode - * - * ## Is - * - * This function duk::is checks if the value at the given index is of the given type and return true. - * - * Just like duk::get, this function need the explicit template parameter. - * - * \code - * duk::push(ctx, 1); - * duk::is<int>(ctx, -1); // true - * \endcode - * - * ## Optional - * - * The duk::optional function has no equivalent in Duktape C API. It is a convenient way to get values with a default - * replacement is not available. - * - * The common implementation uses duk::is and then duk::get. - * - * \code - * duk::optional<int>(ctx, -1, 123); // 123 is -1 has no value or is not an int - * \endcode - */ - -/** - * \page js-more Extensions and advanced features. - * \brief Evolved extensions provided by libjs. - * - * The following topics are provided by libjs and have no equivalent in Duktape C API. - * - * \subpage js-more-t1 - */ - -/** - * \page js-more-t1 Advanced 1: adding your own types to TypeTraits - * \brief How to specialize duk::TypeTraits structure. - * - * This topic shows how you can specialize the duk::TypeTraits structure to add more types. - * - * Specializing the duk::TypeTraits is usually only needed when you want to convert a C++ object into JavaScript. - * - * In this example we will convert a C++ small structure containing two integers to JavaScript. - * - * \note It is not required to implement all functions from duk::TypeTraits. Just provide which one you need. - * - * ## The C++ structure - * - * The point does not have any methods, it just a description of two integers. - * - * \code - * struct Point { - * int x; - * int y; - * }; - * \endcode - * - * ## The push function - * - * Let's add a push function that will create a JavaScript object with **x** and **y** properties. - * - * \code - * namespace duk { - * - * template <> - * class TypeTraits<Point> { - * public: - * static void push(Context *ctx, const Point &point) - * { - * // Create an object - * push(ctx, Object()); - * - * // Set x - * putProperty(ctx, -1, "x", point.x); - * - * // Set y - * putProperty(ctx, -1, "y", point.y); - * } - * }; - * - * } - * \endcode - * - * You can safely use different type of reference as second argument. - * - * That's it, you can now safely invoke `duk::push(ctx, Point{100, 200});`. - * - * ## The get function - * - * The get function usually return a new object. The recommandation is to provide sane defaults except if you have any - * reason to not do so. - * - * \code - * namespace duk { - * - * template <> - * class TypeTraits<Point> { - * public: - * static Point get(Context *ctx, Index index) - * { - * Point point{0, 0}; - * - * if (is<Object>(ctx, index)) { - * point.x = getProperty<int>(ctx, index, "x"); - * point.y = getProperty<int>(ctx, index, "y"); - * } - * - * return point; - * } - * }; - * - * } - * \endcode - * - * Now you can invoke `duk::get<Point>(ctx, 0)` to convert a JavaScript object to the Point structure. - * - * ## The require function - * - * The require function has the same signature as get. It's up to you to decide which criterias makes the object not - * suitable for conversion. - * - * In that example, we will require that object at the index is a JavaScript object and that **x**, **y** are present. - * - * \code - * namespace duk { - * - * template <> - * class TypeTraits<Point> { - * public: - * static Point require(Context *ctx, Index index) - * { - * Point point; - * - * // Raise an error if not object - * if (!is<Object>(ctx, index)) - * duk::raise(ctx, TypeError("object required")); - * - * // Get x, for simplicity we just check that x and y exist. - * if (!hasProperty(ctx, index, "x")) - * duk::raise(ctx, TypeError("property x missing")); - * - * // Get y - * if (!hasProperty(ctx, index, "y")) - * duk::raise(ctx, TypeError("property y missing")); - * - * // Note: if you need more security, check that types are integers too. - * point.x = duk::getProperty<int>(ctx, index, "x"); - * point.y = duk::getProperty<int>(ctx, index, "y"); - * - * return point; - * } - * }; - * - * } - * \endcode - * - * ## The is function - * - * The is function returns a boolean. Again, you decide when the value is appropriate. - * - * \code - * - * namespace duk { - * - * template <> - * class TypeTraits<Point> { - * public: - * static bool is(Context *ctx, Index index) - * { - * return is<Object>(ctx, index) && hasProperty(ctx, index, "x") && hasProperty(ctx, index, "y"); - * } - * }; - * - * } - * - * \endcode - * - * ## The optional function - * - * The optional function is like get, you should return a value when it is appropriate for conversion. The - * recommandation is to return the default value **only if** there is no value at the given index or it it not - * the correct type. - * - * Usual implementation looks like this: - * - * \code - * namespace duk { - * - * template <> - * class TypeTraits<Point> { - * public: - * static Point optional(Context *ctx, Index index, Point def) - * { - * return is(ctx, index) ? get(ctx, index) : def; - * } - * }; - * - * } - * \endcode - */ - -#include <cassert> -#include <cstdio> -#include <functional> -#include <memory> -#include <string> -#include <type_traits> -#include <unordered_map> -#include <utility> -#include <vector> - -#include <duktape.h> - -namespace irccd { - -/** - * 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 TypeTraits - * \brief Type information to implement new types in JavaScript's context. - * - * %This class depending on your needs may have the following functions: - * - * ## Construct - * - * Used by duk::construct, the function must place the value as this binding when the Duktape C function is - * new-constructed. - * - * \code - * static void construct(Context *ctx, Type value); - * \endcode - * - * ## Get - * - * Convert the value at the given index and return it. Should return default object if value is invalid. - * - * \code - * static Type get(Context *ctx, int index); - * \endcode - * - * ## Is - * - * Tells if the value at given index is of the requested type. - * - * \code - * static bool is(Context *ctx, int index); - * \endcode - * - * ## Optional - * - * Get the value at the given index or return the defaultValue. - * - * \code - * static Type optional(Context *ctx, int index, Type defaultValue); - * \endcode - * - * ## Push - * - * Push the value into the stack. - * - * \code - * static void push(Context *ctx, Type value); - * \endcode - * - * ## Put - * - * Apply the value to the object at the top of the stack. - * - * \code - * static void put(Context *ctx, Type value); - * \endcode - * - * ## Require - * - * Require a value at the given index. - * - * \code - * static Type require(Context *ctx, int index); - * \endcode - * - */ -template <typename Type> -class TypeTraits; - -/** - * \class Object - * \brief Special type for duk::TypeTraits. - */ -class Object { -}; - -/** - * \class Array - * \brief Special type for duk::TypeTraits. - */ -class Array { -}; - -/** - * \class Global - * \brief Special type for duk::TypeTraits. - */ -class Global { -}; - -/** - * \class Undefined - * \brief Special type for duk::TypeTraits. - */ -class Undefined { -}; - -/** - * \class Null - * \brief Special type for duk::TypeTraits. - */ -class Null { -}; - -/** - * \class This - * \brief Special type for duk::TypeTraits. - */ -class This { -}; - -/** - * \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>; - -/** - * \brief Map of any type. - */ -template <typename T> -using Map = std::unordered_map<std::string, T>; - -/** - * \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_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_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; -} - -/** - * Push a value into the stack. Calls TypeTraits<T>::push(ctx, value); - * - * \param ctx the context - * \param value the value to forward - */ -template <typename Type> -inline void push(Context *ctx, Type &&value) -{ - TypeTraits<std::decay_t<Type>>::push(ctx, std::forward<Type>(value)); -} - -/** - * Put the value to the object at the top of the stack. Calls TypeTraits<T>::put(ctx, value); - * - * \param ctx the context - * \param value the value to apply - */ -template <typename Type> -inline void put(Context *ctx, Type &&value) -{ - TypeTraits<std::decay_t<Type>>::put(ctx, std::forward<Type>(value)); -} - -/** - * Generic template function to get a value from the stack. - * - * \param ctx the context - * \param index the index - * \return the value - */ -template <typename Type> -inline auto get(Context *ctx, int index) -> decltype(TypeTraits<Type>::get(ctx, 0)) -{ - return TypeTraits<Type>::get(ctx, index); -} - -/** - * Require a type at the specified index. - * - * \param ctx the context - * \param index the index - * \return the value - */ -template <typename Type> -inline auto require(Context *ctx, int index) -> decltype(TypeTraits<Type>::require(ctx, 0)) -{ - return TypeTraits<Type>::require(ctx, index); -} - -/** - * Check if a value is a type of T. - * - * The TypeTraits<T> must have `static bool is(ContextPtr ptr, int index)`. - * - * \param ctx the context - * \param index the value index - * \return true if is the type - */ -template <typename T> -inline bool is(Context *ctx, int index) -{ - return TypeTraits<T>::is(ctx, index); -} - -/** - * Get an optional value from the stack, if the value is not available of not the correct type, - * return defaultValue instead. - * - * The TypeTraits<T> must have `static T optional(Context &, int index, T &&defaultValue)`. - * - * \param ctx the context - * \param index the value index - * \param defaultValue the value replacement - * \return the value or defaultValue - */ -template <typename Type> -inline auto optional(Context *ctx, int index, Type &&defaultValue) -{ - return TypeTraits<std::decay_t<Type>>::optional(ctx, index, std::forward<Type>(defaultValue)); -} - -/** - * Get the property `name' as value from the object at the specified index. - * - * \param ctx the context - * \param index the object index - * \param name the property name - * \return the value - * \note The stack is unchanged - */ -template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> -inline auto getProperty(Context *ctx, int index, const std::string &name) -> decltype(get<Type>(ctx, 0)) -{ - duk_get_prop_string(ctx, index, name.c_str()); - decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Get a property by index, for arrays. - * - * \param ctx the context - * \param index the object index - * \param position the position int the object - * \return the value - * \note The stack is unchanged - */ -template <typename Type, typename std::enable_if_t<!std::is_void<Type>::value> * = nullptr> -inline auto getProperty(Context *ctx, int index, int position) -> decltype(get<Type>(ctx, 0)) -{ - duk_get_prop_index(ctx, index, position); - decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Get the property `name' and push it to the stack from the object at the specified index. - * - * \param ctx the context - * \param index the object index - * \param name the property name - * \note The stack contains the property value - */ -template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> -inline void getProperty(Context *ctx, int index, const std::string &name) -{ - duk_get_prop_string(ctx, index, name.c_str()); -} - -/** - * Get the property by index and push it to the stack from the object at the specified index. - * - * \param ctx the context - * \param index the object index - * \param position the position in the object - * \note The stack contains the property value - */ -template <typename Type, typename std::enable_if_t<std::is_void<Type>::value> * = nullptr> -inline void getProperty(Context *ctx, int index, int position) -{ - duk_get_prop_index(ctx, index, position); -} - -/** - * Get an optional property `name` from the object at the specified index. - * - * \param ctx the context - * \param index the object index - * \param name the property name - * \param def the default value - * \return the value or def - * \note The stack is unchanged - */ -template <typename Type, typename DefaultValue> -inline auto optionalProperty(Context *ctx, int index, const std::string &name, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) -{ - duk_get_prop_string(ctx, index, name.c_str()); - decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def)); - duk_pop(ctx); - - return value; -} - -/** - * Get an optional property by index, for arrays - * - * \param ctx the context - * \param index the object index - * \param position the position int the object - * \param def the default value - * \return the value or def - * \note The stack is unchanged - */ -template <typename Type, typename DefaultValue> -inline auto optionalProperty(Context *ctx, int index, int position, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) -{ - duk_get_prop_index(ctx, index, position); - decltype(optional(ctx, 0, std::forward<DefaultValue>(def))) value = optional(ctx, -1, std::forward<DefaultValue>(def)); - duk_pop(ctx); - - return value; -} - -/** - * Set a property to the object at the specified index. - * - * \param ctx the context - * \param index the object index - * \param name the property name - * \param value the value to forward - * \note The stack is unchanged - */ -template <typename Type> -void putProperty(Context *ctx, int index, const std::string &name, Type &&value) -{ - index = duk_normalize_index(ctx, index); - - push(ctx, std::forward<Type>(value)); - duk_put_prop_string(ctx, index, name.c_str()); -} - -/** - * Set a property by index, for arrays. - * - * \param ctx the context - * \param index the object index - * \param position the position in the object - * \param value the value to forward - * \note The stack is unchanged - */ -template <typename Type> -void putProperty(Context *ctx, int index, int position, Type &&value) -{ - index = duk_normalize_index(ctx, index); - - push(ctx, std::forward<Type>(value)); - duk_put_prop_index(ctx, index, position); -} - -/** - * Get a global value. - * - * \param ctx the context - * \param name the name of the global variable - * \return the value - */ -template <typename Type> -inline auto getGlobal(Context *ctx, const std::string &name, std::enable_if_t<!std::is_void<Type>::value> * = nullptr) -> decltype(get<Type>(ctx, 0)) -{ - duk_get_global_string(ctx, name.c_str()); - decltype(get<Type>(ctx, 0)) value = get<Type>(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Overload that push the value at the top of the stack instead of returning it. - * - * \param ctx the context - * \param name the name of the global variable - */ -template <typename Type> -inline void getGlobal(Context *ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) -{ - duk_get_global_string(ctx, name.c_str()); -} - -/** - * Set a global variable. - * - * \param ctx the context - * \param name the name of the global variable - * \param type the value to set - */ -template <typename Type> -inline void putGlobal(Context *ctx, const std::string &name, Type&& type) -{ - push(ctx, std::forward<Type>(type)); - duk_put_global_string(ctx, name.c_str()); -} - -/** - * Put the value at the top of the stack as global property. - * - * \param ctx the context - * \param name the property name - */ -inline void putGlobal(Context *ctx, const std::string &name) -{ - duk_put_global_string(ctx, name.c_str()); -} - -/** - * 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); -} - -/** - * Return the this binding of the current function. - * - * \param ctx the context - * \return the this binding as the template given - */ -template <typename T> -inline auto self(Context *ctx) -> decltype(TypeTraits<T>::require(ctx, 0)) -{ - duk_push_this(ctx); - decltype(TypeTraits<T>::require(ctx, 0)) value = TypeTraits<T>::require(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * 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); -} - -/** - * Construct the object in place, setting value as this binding. - * - * The TypeTraits<T> must have the following requirements: - * - * - static void construct(Context &, T): must update this with the value and keep the stack unchanged - * - * \param ctx the context - * \param value the value to forward - * \see self - */ -template <typename T> -inline void construct(Context *ctx, T &&value) -{ - TypeTraits<std::decay_t<T>>::construct(ctx, std::forward<T>(value)); -} - -/** - * \} - */ - -/** - * \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)) - { - } -}; - -/** - * \class TypeTraits<int> - * \brief Default implementation for int. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<int> { -public: - /** - * Get an integer, return 0 if not an integer. - * - * \param ctx the context - * \param index the index - * \return the integer - */ - static inline int get(Context *ctx, int index) - { - return duk_get_int(ctx, index); - } - - /** - * Check if value is an integer. - * - * \param ctx the context - * \param index the index - * \return true if integer - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_number(ctx, index) != 0; - } - - /** - * 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 - */ - static inline int optional(Context *ctx, int index, int defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push an integer. - * - * \param ctx the context - * \param value the value - */ - static inline void push(Context *ctx, int value) - { - duk_push_int(ctx, value); - } - - /** - * Require an integer, throws a JavaScript exception if not an integer. - * - * \param ctx the context - * \param index the index - * \return the integer - */ - static inline int require(Context *ctx, int index) - { - return duk_require_int(ctx, index); - } -}; - -/** - * \class TypeTraits<bool> - * \brief Default implementation for bool. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<bool> { -public: - /** - * Get a boolean, return 0 if not a boolean. - * - * \param ctx the context - * \param index the index - * \return the boolean - */ - static inline bool get(Context *ctx, int index) - { - return duk_get_boolean(ctx, index) != 0; - } - - /** - * Check if value is a boolean. - * - * \param ctx the context - * \param index the index - * \return true if boolean - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_boolean(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 - */ - static inline bool optional(Context *ctx, int index, bool defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a boolean. - * - * \param ctx the context - * \param value the value - */ - static inline void push(Context *ctx, bool value) - { - duk_push_boolean(ctx, value); - } - - /** - * Require a boolean, throws a JavaScript exception if not a boolean. - * - * \param ctx the context - * \param index the index - * \return the boolean - */ - static inline bool require(Context *ctx, int index) - { - return duk_require_boolean(ctx, index) != 0; - } -}; - -/** - * \class TypeTraits<double> - * \brief Default implementation for double. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<double> { -public: - /** - * Get a double, return 0 if not a double. - * - * \param ctx the context - * \param index the index - * \return the double - */ - static inline double get(Context *ctx, int index) - { - return duk_get_number(ctx, index); - } - - /** - * Check if value is a double. - * - * \param ctx the context - * \param index the index - * \return true if double - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_number(ctx, index) != 0; - } - - /** - * 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 - */ - static inline double optional(Context *ctx, int index, double defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a double. - * - * \param ctx the context - * \param value the value - */ - static inline void push(Context *ctx, double value) - { - duk_push_number(ctx, value); - } - - /** - * Require a double, throws a JavaScript exception if not a double. - * - * \param ctx the context - * \param index the index - * \return the double - */ - static inline double require(Context *ctx, int index) - { - return duk_require_number(ctx, index); - } -}; - -/** - * \class TypeTraits<std::string> - * \brief Default implementation for std::string. - * - * Provides: get, is, optional, push, require. - * - * Note: the functions allows embedded '\0'. - */ -template <> -class TypeTraits<std::string> { -public: - /** - * Get a string, return 0 if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ - static inline std::string get(Context *ctx, int index) - { - duk_size_t size; - const char *text = duk_get_lstring(ctx, index, &size); - - return std::string{text, size}; - } - - /** - * Check if value is a string. - * - * \param ctx the context - * \param index the index - * \return true if string - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_string(ctx, index) != 0; - } - - /** - * 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 - */ - static inline std::string optional(Context *ctx, int index, std::string defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a string. - * - * \param ctx the context - * \param value the value - */ - static inline void push(Context *ctx, const std::string &value) - { - duk_push_lstring(ctx, value.c_str(), value.length()); - } - - /** - * Require a string, throws a JavaScript exception if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ - static inline std::string require(Context *ctx, int index) - { - duk_size_t size; - const char *text = duk_require_lstring(ctx, index, &size); - - return std::string{text, size}; - } -}; - -/** - * \class TypeTraits<const char *> - * \brief Default implementation for const char literals. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<const char *> { -public: - /** - * Get a string, return 0 if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ - static inline const char *get(Context *ctx, int index) - { - return duk_get_string(ctx, index); - } - - /** - * Check if value is a string. - * - * \param ctx the context - * \param index the index - * \return true if string - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_string(ctx, index) != 0; - } - - /** - * 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 - */ - static inline const char *optional(Context *ctx, int index, const char *defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a string. - * - * \param ctx the context - * \param value the value - */ - static inline void push(Context *ctx, const char *value) - { - duk_push_string(ctx, value); - } - - /** - * Require a string, throws a JavaScript exception if not a string. - * - * \param ctx the context - * \param index the index - * \return the string - */ - static inline const char *require(Context *ctx, int index) - { - return duk_require_string(ctx, index); - } -}; - -/** - * \class TypeTraits<unsigned> - * \brief Default implementation for unsigned. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits<unsigned> { -public: - /** - * Get an integer, return 0 if not an integer. - * - * \param ctx the context - * \param index the index - * \return the integer - */ - static inline unsigned get(Context *ctx, int index) - { - return duk_get_uint(ctx, index); - } - - /** - * Check if value is an integer. - * - * \param ctx the context - * \param index the index - * \return true if integer - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_number(ctx, index) != 0; - } - - /** - * 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 - */ - static inline unsigned optional(Context *ctx, int index, unsigned defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push an integer. - * - * \param ctx the context - * \param value the value - */ - static inline void push(Context *ctx, unsigned value) - { - duk_push_uint(ctx, value); - } - - /** - * Require an integer, throws a JavaScript exception if not an integer. - * - * \param ctx the context - * \param index the index - * \return the integer - */ - static inline unsigned require(Context *ctx, int index) - { - return duk_require_uint(ctx, index); - } -}; - -/** - * \brief Implementation for non-managed pointers. - * - * Provides: get, is, optional, push, require. - */ -template <typename T> -class TypeTraits<T *> { -public: - /** - * Get a pointer, return nullptr if not a pointer. - * - * \param ctx the context - * \param index the index - * \return the pointer - */ - static inline T *get(Context *ctx, int index) - { - return static_cast<T *>(duk_to_pointer(ctx, index)); - } - - /** - * Check if value is a pointer. - * - * \param ctx the context - * \param index the index - * \return true if pointer - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_pointer(ctx, index) != 0; - } - - /** - * 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 - */ - static inline T *optional(Context *ctx, int index, T *defaultValue) - { - return is(ctx, index) ? get(ctx, index) : defaultValue; - } - - /** - * Push a pointer. - * - * \param ctx the context - * \param value the value - */ - static inline void push(Context *ctx, T *value) - { - duk_push_pointer(ctx, value); - } - - /** - * Require a pointer, throws a JavaScript exception if not a pointer. - * - * \param ctx the context - * \param index the index - * \return the pointer - */ - static inline T *require(Context *ctx, int index) - { - return static_cast<T *>(duk_require_pointer(ctx, index)); - } -}; - -/** - * \class TypeTraits<Function> - * \brief Push C++ function to the stack. - * - * Provides: push. - * - * This implementation push a Duktape/C function that is wrapped as C++ for convenience. - */ -template <> -class TypeTraits<Function> { -public: - /** - * Check if the value at the given index is callable. - * - * \param ctx the context - * \param index the value index - * \return true if the value is callable - */ - static bool is(Context *ctx, Index index) - { - return duk_is_callable(ctx, index) != 0; - } - - /** - * Push the C++ function, it is wrapped as Duktape/C function and allocated on the heap by moving the - * std::function. - * - * \param ctx the context - * \param fn the function - */ - static void push(Context *ctx, Function fn) - { - duk_push_c_function(ctx, fn.function, fn.nargs); - } -}; - -/** - * \class TypeTraits<FunctionMap> - * \brief Put the functions to the object at the top of the stack. - * - * Provides: put. - */ -template <> -class TypeTraits<FunctionMap> { -public: - /** - * Push all functions to the object at the top of the stack. - * - * \param ctx the context - * \param map the map of function - */ - static void put(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()); - } - } -}; - -/** - * \class TypeTraits<Object> - * \brief Push empty object to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Object> { -public: - /** - * Check if value is an object. - * - * \param ctx the context - * \param index the index - * \return true if object - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_object(ctx, index) != 0; - } - - /** - * Create an empty object on the stack. - * - * \param ctx the context - */ - static inline void push(Context *ctx, const Object &) - { - duk_push_object(ctx); - } -}; - -/** - * \class TypeTraits<Array> - * \brief Push empty array to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Array> { -public: - /** - * Check if value is a array. - * - * \param ctx the context - * \param index the index - * \return true if array - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_array(ctx, index) != 0; - } - - /** - * Create an empty array on the stack. - * - * \param ctx the context - */ - static inline void push(Context *ctx, const Array &) - { - duk_push_array(ctx); - } -}; - -/** - * \class TypeTraits<Undefined> - * \brief Push undefined value to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Undefined> { -public: - /** - * Check if value is undefined. - * - * \param ctx the context - * \param index the index - * \return true if undefined - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_undefined(ctx, index) != 0; - } - - /** - * Push undefined value on the stack. - * - * \param ctx the context - */ - static inline void push(Context *ctx, const Undefined &) - { - duk_push_undefined(ctx); - } -}; - -/** - * \class TypeTraits<Null> - * \brief Push null value to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits<Null> { -public: - /** - * Check if value is null. - * - * \param ctx the context - * \param index the index - * \return true if null - */ - static inline bool is(Context *ctx, int index) - { - return duk_is_null(ctx, index) != 0; - } - - /** - * Push null value on the stack. - * - * \param ctx the context - */ - static inline void push(Context *ctx, const Null &) - { - duk_push_null(ctx); - } -}; - -/** - * \brief Push this binding into the stack. - * - * Provides: push. - */ -template <> -class TypeTraits<This> { -public: - /** - * Push this function into the stack. - * - * \param ctx the context - */ - static inline void push(Context *ctx, const This &) - { - duk_push_this(ctx); - } -}; - -/** - * \class TypeTraits<Global> - * \brief Push the global object to the stack. - * - * Provides: push. - */ -template <> -class TypeTraits<Global> { -public: - /** - * Push the global object into the stack. - * - * \param ctx the context - */ - static inline void push(Context *ctx, const Global &) - { - duk_push_global_object(ctx); - } -}; - -/** - * \brief Push a map of key-value pair as objects. - * - * Provides: push, put. - * - * This class is convenient for settings constants such as enums, string and such. - */ -template <typename T> -class TypeTraits<std::unordered_map<std::string, T>> { -public: - /** - * Put all values from the map as properties to the object at the top of the stack. - * - * \param ctx the context - * \param map the values - * \note You need an object at the top of the stack before calling this function - */ - static void push(Context *ctx, const std::unordered_map<std::string, T> &map) - { - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - put(ctx, map); - } - - /** - * Apply the map to the object at the top of the stack. - * - * \pre top value must be an object - * \param ctx the context - * \param map the map - */ - static void put(Context *ctx, const std::unordered_map<std::string, T> &map) - { - assert(type(ctx, -1) == DUK_TYPE_OBJECT); - - StackAssert sa(ctx); - - for (const auto &pair : map) { - TypeTraits<T>::push(ctx, pair.second); - duk_put_prop_string(ctx, -2, pair.first.c_str()); - } - } -}; - -/** - * \brief Push or get vectors as JavaScript arrays. - * - * Provides: get, push, put. - */ -template <typename T> -class TypeTraits<std::vector<T>> { -public: - /** - * Get an array from the stack. - * - * \param ctx the context - * \param index the array index - * \return the array or empty array if the value is not an array - */ - static std::vector<T> get(Context *ctx, int index) - { - StackAssert sa(ctx, 0); - - std::vector<T> result; - - if (!duk_is_array(ctx, -1)) - return result; - - size_t total = duk_get_length(ctx, index); - - for (size_t i = 0; i < total; ++i) - result.push_back(getProperty<T>(ctx, index, static_cast<int>(i))); - - return result; - } - - /** - * Create an array with the specified values. - * - * \param ctx the context - * \param array the values - */ - static void push(Context *ctx, const std::vector<T> &array) - { - StackAssert sa(ctx, 1); - - duk_push_array(ctx); - put(ctx, array); - } - - /** - * Apply the array to the object at the top of the stack. - * - * \pre top value must be an object - * \param ctx the context - * \param array the array - */ - static void put(Context *ctx, const std::vector<T> &array) - { - assert(type(ctx, -1) == DUK_TYPE_OBJECT); - - StackAssert sa(ctx); - - unsigned i = 0; - for (const auto &v : array) { - TypeTraits<T>::push(ctx, v); - duk_put_prop_index(ctx, -2, i++); - } - } -}; - -} // !duk - -} // !irccd - -#endif // !IRCCD_JS_HPP
--- a/lib/irccd/mod-directory.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-directory.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -24,8 +24,8 @@ #include <stdexcept> #include <string> +#include "duktape.hpp" #include "fs.hpp" -#include "js.hpp" #include "mod-directory.hpp" #include "mod-irccd.hpp" #include "path.hpp" @@ -36,27 +36,26 @@ namespace { -std::string path(duk::Context *ctx) +std::string path(duk_context *ctx) { - duk::push(ctx, duk::This{}); - duk::getProperty<void>(ctx, -1, "path"); + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, "path"); - if (duk::type(ctx, -1) != DUK_TYPE_STRING) - duk::raise(ctx, duk::TypeError("invalid this binding")); + if (duk_get_type(ctx, -1) != DUK_TYPE_STRING) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Directory object"); - std::string ret = duk::get<std::string>(ctx, -1); + auto ret = duk_get_stdstring(ctx, -1); if (ret.empty()) - duk::raise(ctx, duk::TypeError("invalid directory with empty path")); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "directory object has empty path"); - duk::pop(ctx, 2); + duk_pop_n(ctx, 2); return ret; } /* - * Find an entry recursively (or not) in a directory using a predicate - * which can be used to test for regular expression, equality. + * Find an entry recursively (or not) in a directory using a predicate which can be used to test for regular expression, equality. * * Do not use this function directly, use: * @@ -124,35 +123,37 @@ * * The patternIndex is the argument where to test if the argument is a regex or a string. */ -duk::Ret find(duk::Context *ctx, std::string base, bool recursive, int patternIndex) +duk_ret_t find(duk_context *ctx, std::string base, bool recursive, int patternIndex) { base = path::clean(base); try { std::string path; - if (duk::is<std::string>(ctx, patternIndex)) - path = findName(base, duk::get<std::string>(ctx, patternIndex), recursive); + if (duk_is_string(ctx, patternIndex)) + path = findName(base, duk_get_string(ctx, patternIndex), recursive); else { // Check if it's a valid RegExp object. - duk::getGlobal<void>(ctx, "RegExp"); - - bool isRegex = duk::instanceof(ctx, patternIndex, -1); + duk_get_global_string(ctx, "RegExp"); + auto isRegex = duk_instanceof(ctx, patternIndex, -1); + duk_pop(ctx); - duk::pop(ctx); + if (isRegex) { + duk_get_prop_string(ctx, patternIndex, "source"); + auto pattern = duk_to_string(ctx, -1); + duk_pop(ctx); - if (isRegex) - path = findRegex(base, duk::getProperty<std::string>(ctx, patternIndex, "source"), recursive); - else - duk::raise(ctx, duk::TypeError("pattern must be a string or a regex expression")); + path = findRegex(base, pattern, recursive); + } else + duk_error(ctx, DUK_ERR_TYPE_ERROR, "pattern must be a string or a regex expression"); } if (path.empty()) return 0; - duk::push(ctx, path); + duk_push_stdstring(ctx, path); } catch (const std::exception &ex) { - duk::raise(ctx, duk::Error(ex.what())); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 1; @@ -164,10 +165,10 @@ * - Directory.remove * - Directory.prototype.remove */ -duk::Ret remove(duk::Context *ctx, const std::string &path, bool recursive) +duk_ret_t remove(duk_context *ctx, const std::string &path, bool recursive) { if (!fs::isDirectory(path)) - duk::raise(ctx, SystemError(EINVAL, "not a directory")); + duk_throw(ctx, SystemError(EINVAL, "not a directory")); if (!recursive) { #if defined(_WIN32) @@ -196,9 +197,9 @@ * Throws: * - Any exception on error. */ -duk::Ret methodFind(duk::Context *ctx) +duk_ret_t methodFind(duk_context *ctx) { - return find(ctx, path(ctx), duk::optional<bool>(ctx, 1, false), 0); + return find(ctx, path(ctx), duk_get_boolean(ctx, 1), 0); } /* @@ -213,19 +214,21 @@ * Throws: * - Any exception on error. */ -duk::Ret methodRemove(duk::Context *ctx) +duk_ret_t methodRemove(duk_context *ctx) { - return remove(ctx, path(ctx), duk::optional<bool>(ctx, 0, false)); + return remove(ctx, path(ctx), duk_get_boolean(ctx, 0)); } -const duk::FunctionMap methods{ - { "find", { methodFind, DUK_VARARGS } }, - { "remove", { methodRemove, 1 } } +const duk_function_list_entry methods[] = { + { "find", methodFind, DUK_VARARGS }, + { "remove", methodRemove, 1 }, + { nullptr, nullptr, 0 } }; -/* -------------------------------------------------------- +/* * Directory "static" functions - * -------------------------------------------------------- */ + * ------------------------------------------------------------------ + */ /* * Function: Irccd.Directory(path, flags) [constructor] @@ -239,40 +242,42 @@ * Throws: * - Any exception on error */ -duk::Ret constructor(duk::Context *ctx) +duk_ret_t constructor(duk_context *ctx) { if (!duk_is_constructor_call(ctx)) return 0; try { - std::string path = duk::require<std::string>(ctx, 0); - std::int8_t flags = duk::optional<int>(ctx, 1, 0); + std::string path = duk_require_string(ctx, 0); + std::int8_t flags = duk_get_uint(ctx, 1); if (!fs::isDirectory(path)) - duk::raise(ctx, SystemError(EINVAL, "not a directory")); + duk_throw(ctx, SystemError(EINVAL, "not a directory")); std::vector<fs::Entry> list = fs::readdir(path, flags); - duk::push(ctx, duk::This{}); - duk::push(ctx, "count"); - duk::push(ctx, (int)list.size()); - duk::defineProperty(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); - duk::push(ctx, "path"); - duk::push(ctx, path); - duk::defineProperty(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); - duk::push(ctx, "entries"); - duk::push(ctx, duk::Array{}); + duk_push_this(ctx); + duk_push_string(ctx, "count"); + duk_push_int(ctx, list.size()); + duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); + duk_push_string(ctx, "path"); + duk_push_stdstring(ctx, path); + duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); + duk_push_string(ctx, "entries"); + duk_push_array(ctx); for (unsigned i = 0; i < list.size(); ++i) { - duk::push(ctx, duk::Object{}); - duk::putProperty(ctx, -1, "name", list[i].name); - duk::putProperty(ctx, -1, "type", static_cast<int>(list[i].type)); - duk::putProperty(ctx, -2, (int)i); + duk_push_object(ctx); + duk_push_stdstring(ctx, list[i].name); + duk_put_prop_string(ctx, -2, "name"); + duk_push_int(ctx, list[i].type); + duk_put_prop_string(ctx, -2, "type"); + duk_put_prop_index(ctx, -2, i); } - duk::defineProperty(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); + duk_def_prop(ctx, -3, DUK_DEFPROP_ENUMERABLE | DUK_DEFPROP_HAVE_VALUE); } catch (const std::exception &ex) { - duk::raise(ctx, SystemError(errno, ex.what())); + duk_throw(ctx, SystemError(errno, ex.what())); } return 0; @@ -291,9 +296,9 @@ * Returns: * The path to the file or undefined on errors or not found. */ -duk::Ret funcFind(duk::Context *ctx) +duk_ret_t funcFind(duk_context *ctx) { - return find(ctx, duk::require<std::string>(ctx, 0), duk::optional<bool>(ctx, 2, false), 1); + return find(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 2), 1); } /* @@ -308,9 +313,9 @@ * Throws: * - Any exception on error. */ -duk::Ret funcRemove(duk::Context *ctx) +duk_ret_t funcRemove(duk_context *ctx) { - return remove(ctx, duk::require<std::string>(ctx, 0), duk::optional<bool>(ctx, 1, false)); + return remove(ctx, duk_require_string(ctx, 0), duk_get_boolean(ctx, 1)); } /* @@ -326,30 +331,35 @@ * Throws: * - Any exception on error. */ -duk::Ret funcMkdir(duk::Context *ctx) +duk_ret_t funcMkdir(duk_context *ctx) { try { - fs::mkdir(duk::require<std::string>(ctx, 0), duk::optional<int>(ctx, 1, 0700)); + fs::mkdir( + duk_require_string(ctx, 0), + duk_is_number(ctx, 1) ? duk_get_int(ctx, 1) : 0700 + ); } catch (const std::exception &ex) { - duk::raise(ctx, SystemError(errno, ex.what())); + duk_throw(ctx, SystemError(errno, ex.what())); } return 0; } -const duk::FunctionMap functions{ - { "find", { funcFind, DUK_VARARGS } }, - { "mkdir", { funcMkdir, DUK_VARARGS } }, - { "remove", { funcRemove, DUK_VARARGS } } +const duk_function_list_entry functions[] = { + { "find", funcFind, DUK_VARARGS }, + { "mkdir", funcMkdir, DUK_VARARGS }, + { "remove", funcRemove, DUK_VARARGS }, + { nullptr, nullptr, 0 } }; -const duk::Map<int> constants{ +const duk_number_list_entry constants[] = { { "Dot", static_cast<int>(fs::Dot) }, { "DotDot", static_cast<int>(fs::DotDot) }, { "TypeUnknown", static_cast<int>(fs::Entry::Unknown) }, { "TypeDir", static_cast<int>(fs::Entry::Dir) }, { "TypeFile", static_cast<int>(fs::Entry::File) }, - { "TypeLink", static_cast<int>(fs::Entry::Link) } + { "TypeLink", static_cast<int>(fs::Entry::Link) }, + { nullptr, 0 } }; } // !namespace @@ -361,18 +371,19 @@ void DirectoryModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Function{constructor, 2}); - duk::put(plugin.context(), constants); - duk::put(plugin.context(), functions); - duk::putProperty(plugin.context(), -1, "separator", std::string{fs::separator()}); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), methods); - duk::putProperty(plugin.context(), -2, "prototype"); - duk::putProperty(plugin.context(), -2, "Directory"); - duk::pop(plugin.context()); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_c_function(plugin.context(), constructor, 2); + duk_put_number_list(plugin.context(), -1, constants); + duk_put_function_list(plugin.context(), -1, functions); + duk_push_stdstring(plugin.context(), std::string{fs::separator()}); + duk_put_prop_string(plugin.context(), -2, "separator"); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, methods); + duk_put_prop_string(plugin.context(), -2, "prototype"); + duk_put_prop_string(plugin.context(), -2, "Directory"); + duk_pop(plugin.context()); } } // !irccd
--- a/lib/irccd/mod-elapsed-timer.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-elapsed-timer.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -24,38 +24,22 @@ namespace { -const std::string Signature{"\xff""\xff""irccd-elapsed-timer-ptr"}; - -} // !namespace - -namespace duk { +const char *Signature("\xff""\xff""irccd-elapsed-timer-ptr"); -template <> -class TypeTraits<ElapsedTimer *> { -public: - static inline void construct(duk::Context *ctx, ElapsedTimer *timer) - { - duk::StackAssert sa(ctx); +ElapsedTimer *self(duk_context *ctx) +{ + StackAssert sa(ctx); - duk::push(ctx, duk::This()); - duk::putProperty(ctx, -1, Signature, static_cast<void *>(timer)); - duk::pop(ctx); - } - - static inline ElapsedTimer *require(duk::Context *ctx, Index index) - { - auto ptr = static_cast<ElapsedTimer *>(duk::getProperty<void *>(ctx, index, Signature)); + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature); + auto ptr = static_cast<ElapsedTimer *>(duk_to_pointer(ctx, -1)); + duk_pop_2(ctx); - if (!ptr) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object"); + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object"); - return ptr; - } -}; - -} // !duk - -namespace { + return ptr; +} /* * Method: ElapsedTimer.pause @@ -63,9 +47,9 @@ * * Pause the timer, without resetting the current elapsed time stored. */ -duk::Ret pause(duk::Context *ctx) +duk_ret_t pause(duk_context *ctx) { - duk::self<ElapsedTimer *>(ctx)->pause(); + self(ctx)->pause(); return 0; } @@ -76,9 +60,9 @@ * * Reset the elapsed time to 0, the status is not modified. */ -duk::Ret reset(duk::Context *ctx) +duk_ret_t reset(duk_context *ctx) { - duk::self<ElapsedTimer *>(ctx)->reset(); + self(ctx)->reset(); return 0; } @@ -89,9 +73,9 @@ * * Restart the timer without resetting the current elapsed time. */ -duk::Ret restart(duk::Context *ctx) +duk_ret_t restart(duk_context *ctx) { - duk::self<ElapsedTimer *>(ctx)->restart(); + self(ctx)->restart(); return 0; } @@ -105,9 +89,9 @@ * Returns: * The time elapsed. */ -duk::Ret elapsed(duk::Context *ctx) +duk_ret_t elapsed(duk_context *ctx) { - duk::push(ctx, static_cast<int>(duk::self<ElapsedTimer *>(ctx)->elapsed())); + duk_push_uint(ctx, self(ctx)->elapsed()); return 1; } @@ -118,9 +102,12 @@ * * Construct a new ElapsedTimer object. */ -duk::Ret constructor(duk::Context *ctx) +duk_ret_t constructor(duk_context *ctx) { - duk::construct(ctx, new ElapsedTimer); + duk_push_this(ctx); + duk_push_pointer(ctx, new ElapsedTimer); + duk_put_prop_string(ctx, -2, Signature); + duk_pop_2(ctx); return 0; } @@ -131,20 +118,22 @@ * * Delete the property. */ -duk::Ret destructor(duk::Context *ctx) +duk_ret_t destructor(duk_context *ctx) { - delete static_cast<ElapsedTimer *>(duk::getProperty<void *>(ctx, 0, Signature)); - - duk::deleteProperty(ctx, 0, Signature); + duk_get_prop_string(ctx, 0, Signature); + delete static_cast<ElapsedTimer *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, Signature); return 0; } -const duk::FunctionMap methods{ - { "elapsed", { elapsed, 0 } }, - { "pause", { pause, 0 } }, - { "reset", { reset, 0 } }, - { "restart", { restart, 0 } } +const duk_function_list_entry methods[] = { + { "elapsed", elapsed, 0 }, + { "pause", pause, 0 }, + { "reset", reset, 0 }, + { "restart", restart, 0 }, + { nullptr, nullptr, 0 } }; } // !namespace @@ -156,17 +145,17 @@ void ElapsedTimerModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Function{constructor, 0}); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), methods); - duk::push(plugin.context(), duk::Function(destructor, 1)); - duk::setFinalizer(plugin.context(), -2); - duk::putProperty(plugin.context(), -2, "prototype"); - duk::putProperty(plugin.context(), -2, "ElapsedTimer"); - duk::pop(plugin.context()); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_c_function(plugin.context(), constructor, 0); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, methods); + duk_push_c_function(plugin.context(), destructor, 1); + duk_set_finalizer(plugin.context(), -2); + duk_put_prop_string(plugin.context(), -2, "prototype"); + duk_put_prop_string(plugin.context(), -2, "ElapsedTimer"); + duk_pop(plugin.context()); } } // !irccd
--- a/lib/irccd/mod-file.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-file.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -38,80 +38,78 @@ namespace { -const std::string Signature("\xff""\xff""irccd-file-ptr"); -const std::string Prototype("\xff""\xff""irccd-file-prototype"); - -} // !namespace +const char *Signature("\xff""\xff""irccd-file-ptr"); +const char *Prototype("\xff""\xff""irccd-file-prototype"); #if defined(HAVE_STAT) /* - * duk::TypeInfo specialization for struct stat + * pushStat * ------------------------------------------------------------------ */ -namespace duk { +void pushStat(duk_context *ctx, const struct stat &st) +{ + StackAssert sa(ctx, 1); -template <> -class TypeTraits<struct stat> { -public: - static void push(Context *ctx, const struct stat &st) - { - duk::push(ctx, Object{}); + duk_push_object(ctx); #if defined(HAVE_STAT_ST_ATIME) - duk::putProperty(ctx, -2, "atime", static_cast<int>(st.st_atime)); + duk_push_int(ctx, st.st_atime); + duk_put_prop_string(ctx, -2, "atime"); #endif #if defined(HAVE_STAT_ST_BLKSIZE) - duk::putProperty(ctx, -2, "blksize", static_cast<int>(st.st_blksize)); + duk_push_int(ctx, st.st_blksize); + duk_put_prop_string(ctx, -2, "blksize"); #endif #if defined(HAVE_STAT_ST_BLOCKS) - duk::putProperty(ctx, -2, "blocks", static_cast<int>(st.st_blocks)); + duk_push_int(ctx, st.st_blocks); + duk_put_prop_string(ctx, -2, "blocks"); #endif #if defined(HAVE_STAT_ST_CTIME) - duk::putProperty(ctx, -2, "ctime", static_cast<int>(st.st_ctime)); + duk_push_int(ctx, st.st_ctime); + duk_put_prop_string(ctx, -2, "ctime"); #endif #if defined(HAVE_STAT_ST_DEV) - duk::putProperty(ctx, -2, "dev", static_cast<int>(st.st_dev)); + duk_push_int(ctx, st.st_dev); + duk_put_prop_string(ctx, -2, "dev"); #endif #if defined(HAVE_STAT_ST_GID) - duk::putProperty(ctx, -2, "gid", static_cast<int>(st.st_gid)); + duk_push_int(ctx, st.st_gid); + duk_put_prop_string(ctx, -2, "gid"); #endif #if defined(HAVE_STAT_ST_INO) - duk::putProperty(ctx, -2, "ino", static_cast<int>(st.st_ino)); + duk_push_int(ctx, st.st_ino); + duk_put_prop_string(ctx, -2, "ino"); #endif #if defined(HAVE_STAT_ST_MODE) - duk::putProperty(ctx, -2, "mode", static_cast<int>(st.st_mode)); + duk_push_int(ctx, st.st_mode); + duk_put_prop_string(ctx, -2, "mode"); #endif #if defined(HAVE_STAT_ST_MTIME) - duk::putProperty(ctx, -2, "mtime", static_cast<int>(st.st_mtime)); + duk_push_int(ctx, st.st_mtime); + duk_put_prop_string(ctx, -2, "mtime"); #endif #if defined(HAVE_STAT_ST_NLINK) - duk::putProperty(ctx, -2, "nlink", static_cast<int>(st.st_nlink)); + duk_push_int(ctx, st.st_nlink); + duk_put_prop_string(ctx, -2, "nlink"); #endif #if defined(HAVE_STAT_ST_RDEV) - duk::putProperty(ctx, -2, "rdev", static_cast<int>(st.st_rdev)); + duk_push_int(ctx, st.st_rdev); + duk_put_prop_string(ctx, -2, "rdev"); #endif #if defined(HAVE_STAT_ST_SIZE) - duk::putProperty(ctx, -2, "size", static_cast<int>(st.st_size)); + duk_push_int(ctx, st.st_size); + duk_put_prop_string(ctx, -2, "size"); #endif #if defined(HAVE_STAT_ST_UID) - duk::putProperty(ctx, -2, "uid", static_cast<int>(st.st_uid)); + duk_push_int(ctx, st.st_uid); + duk_put_prop_string(ctx, -2, "uid"); #endif - } -}; - -} // !duk +} #endif // !HAVE_STAT -namespace { - -/* - * Anonymous helpers. - * ------------------------------------------------------------------ - */ - // Remove trailing \r for CRLF line style. inline std::string clearCr(std::string input) { @@ -121,6 +119,18 @@ return input; } +inline File *self(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature); + File *file = static_cast<File *>(duk_to_pointer(ctx, -1)); + duk_pop_2(ctx); + + return file; +} + /* * File methods. * ------------------------------------------------------------------ @@ -132,12 +142,12 @@ * * Synonym of `Irccd.File.basename(path)` but with the path from the file. * - * Returns: + * duk_ret_turns: * The base name. */ -duk::Ret methodBasename(duk::Context *ctx) +duk_ret_t methodBasename(duk_context *ctx) { - duk::push(ctx, fs::baseName(duk::self<File *>(ctx)->path())); + duk_push_stdstring(ctx, fs::baseName(self(ctx)->path())); return 1; } @@ -148,9 +158,9 @@ * * Force close of the file, automatically called when object is collected. */ -duk::Ret methodClose(duk::Context *ctx) +duk_ret_t methodClose(duk_context *ctx) { - duk::self<File *>(ctx)->close(); + self(ctx)->close(); return 0; } @@ -161,12 +171,12 @@ * * Synonym of `Irccd.File.dirname(path)` but with the path from the file. * - * Returns: + * duk_ret_turns: * The directory name. */ -duk::Ret methodDirname(duk::Context *ctx) +duk_ret_t methodDirname(duk_context *ctx) { - duk::push(ctx, fs::dirName(duk::self<File *>(ctx)->path())); + duk_push_stdstring(ctx, fs::dirName(self(ctx)->path())); return 1; } @@ -177,16 +187,16 @@ * * Read all lines and return an array. * - * Returns: + * duk_ret_turns: * An array with all lines. * Throws * - Any exception on error. */ -duk::Ret methodLines(duk::Context *ctx) +duk_ret_t methodLines(duk_context *ctx) { - duk::push(ctx, duk::Array{}); + duk_push_array(ctx); - std::FILE *fp = duk::self<File *>(ctx)->handle(); + std::FILE *fp = self(ctx)->handle(); std::string buffer; std::array<char, 128> data; std::int32_t i = 0; @@ -197,18 +207,22 @@ auto pos = buffer.find('\n'); if (pos != std::string::npos) { - duk::putProperty(ctx, -1, i++, clearCr(buffer.substr(0, pos))); + duk_push_stdstring(ctx, clearCr(buffer.substr(0, pos))); + duk_put_prop_index(ctx, -2, i++); + buffer.erase(0, pos + 1); } } // Maybe an error in the stream. if (std::ferror(fp)) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); // Missing '\n' in end of file. - if (!buffer.empty()) - duk::putProperty(ctx, -1, i++, clearCr(buffer)); + if (!buffer.empty()) { + duk_push_stdstring(ctx, clearCr(buffer)); + duk_put_prop_index(ctx, -2, i++); + } return 1; } @@ -221,15 +235,15 @@ * * Arguments: * - amount, the amount of characters or -1 to read all (Optional, default: -1). - * Returns: + * duk_ret_turns: * The string. * Throws: * - Any exception on error. */ -duk::Ret methodRead(duk::Context *ctx) +duk_ret_t methodRead(duk_context *ctx) { - auto amount = duk::optional<int>(ctx, 0, -1); - auto file = duk::self<File *>(ctx); + auto file = self(ctx); + auto amount = duk_is_number(ctx, 0) ? duk_get_int(ctx, 0) : 0; if (amount == 0 || file->handle() == nullptr) return 0; @@ -246,7 +260,7 @@ nread = std::fread(&buffer[0], sizeof (buffer[0]), buffer.size(), file->handle()); if (std::ferror(file->handle())) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); std::copy(buffer.begin(), buffer.begin() + nread, std::back_inserter(data)); total += nread; @@ -256,14 +270,14 @@ total = std::fread(&data[0], sizeof (data[0]), (std::size_t)amount, file->handle()); if (std::ferror(file->handle())) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); data.resize(total); } - duk::push(ctx, data); + duk_push_stdstring(ctx, data); } catch (const std::exception &) { - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); } return 1; @@ -275,14 +289,14 @@ * * Read the next line available. * - * Returns: + * duk_ret_turns: * The next line or undefined if eof. * Throws: * - Any exception on error. */ -duk::Ret methodReadline(duk::Context *ctx) +duk_ret_t methodReadline(duk_context *ctx) { - std::FILE *fp = duk::self<File *>(ctx)->handle(); + std::FILE *fp = self(ctx)->handle(); std::string result; if (fp == nullptr || std::feof(fp)) @@ -290,9 +304,9 @@ for (int ch; (ch = std::fgetc(fp)) != EOF && ch != '\n'; ) result += (char)ch; if (std::ferror(fp)) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); - duk::push(ctx, clearCr(result)); + duk_push_stdstring(ctx, clearCr(result)); return 1; } @@ -306,10 +320,10 @@ * Throws: * - Any exception on error. */ -duk::Ret methodRemove(duk::Context *ctx) +duk_ret_t methodRemove(duk_context *ctx) { - if (::remove(duk::self<File *>(ctx)->path().c_str()) < 0) - duk::raise(ctx, SystemError()); + if (::remove(self(ctx)->path().c_str()) < 0) + duk_throw(ctx, SystemError()); return 0; } @@ -326,14 +340,14 @@ * Throws: * - Any exception on error. */ -duk::Ret methodSeek(duk::Context *ctx) +duk_ret_t methodSeek(duk_context *ctx) { - auto type = duk::require<int>(ctx, 0); - auto amount = duk::require<int>(ctx, 1); - auto fp = duk::self<File *>(ctx)->handle(); + auto fp = self(ctx)->handle(); + auto type = duk_require_int(ctx, 0); + auto amount = duk_require_int(ctx, 1); if (fp != nullptr && std::fseek(fp, amount, type) != 0) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); return 0; } @@ -346,20 +360,20 @@ * * Synonym of File.stat(path) but with the path from the file. * - * Returns: + * duk_ret_turns: * The stat information. * Throws: * - Any exception on error. */ -duk::Ret methodStat(duk::Context *ctx) +duk_ret_t methodStat(duk_context *ctx) { + auto file = self(ctx); struct stat st; - auto file = duk::self<File *>(ctx); if (file->handle() == nullptr && ::stat(file->path().c_str(), &st) < 0) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); else - duk::push(ctx, st); + pushStat(ctx, st); return 1; } @@ -372,23 +386,23 @@ * * Get the actual position in the file. * - * Returns: + * duk_ret_turns: * The position. * Throws: * - Any exception on error. */ -duk::Ret methodTell(duk::Context *ctx) +duk_ret_t methodTell(duk_context *ctx) { - auto fp = duk::self<File *>(ctx)->handle(); + auto fp = self(ctx)->handle(); long pos; if (fp == nullptr) return 0; if ((pos = std::ftell(fp)) == -1L) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); else - duk::push(ctx, (int)pos); + duk_push_int(ctx, pos); return 1; } @@ -401,15 +415,15 @@ * * Arguments: * - data, the character to write. - * Returns: + * duk_ret_turns: * The number of bytes written. * Throws: * - Any exception on error. */ -duk::Ret methodWrite(duk::Context *ctx) +duk_ret_t methodWrite(duk_context *ctx) { - std::FILE *fp = duk::self<File *>(ctx)->handle(); - std::string data = duk::require<std::string>(ctx, 0); + std::FILE *fp = self(ctx)->handle(); + std::string data = duk_require_string(ctx, 0); if (fp == nullptr) return 0; @@ -417,27 +431,28 @@ std::size_t nwritten = std::fwrite(data.c_str(), 1, data.length(), fp); if (std::ferror(fp)) - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); - duk::push(ctx, (int)nwritten); + duk_push_uint(ctx, nwritten); return 1; } -const duk::FunctionMap methods{ - { "basename", { methodBasename, 0 } }, - { "close", { methodClose, 0 } }, - { "dirname", { methodDirname, 0 } }, - { "lines", { methodLines, 0 } }, - { "read", { methodRead, 1 } }, - { "readline", { methodReadline, 0 } }, - { "remove", { methodRemove, 0 } }, - { "seek", { methodSeek, 2 } }, +const duk_function_list_entry methods[] = { + { "basename", methodBasename, 0 }, + { "close", methodClose, 0 }, + { "dirname", methodDirname, 0 }, + { "lines", methodLines, 0 }, + { "read", methodRead, 1 }, + { "readline", methodReadline, 0 }, + { "remove", methodRemove, 0 }, + { "seek", methodSeek, 2 }, #if defined(HAVE_STAT) - { "stat", { methodStat, 0 } }, + { "stat", methodStat, 0 }, #endif - { "tell", { methodTell, 0 } }, - { "write", { methodWrite, 1 } }, + { "tell", methodTell, 0 }, + { "write", methodWrite, 1 }, + { nullptr, nullptr, 0 } }; /* @@ -457,15 +472,15 @@ * Throws: * - Any exception on error. */ -duk::Ret constructor(duk::Context *ctx) +duk_ret_t constructor(duk_context *ctx) { - if (!duk::isConstructorCall(ctx)) + if (!duk_is_constructor_call(ctx)) return 0; try { - duk::construct(ctx, new File(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1))); + duk_new_file(ctx, new File(duk_require_string(ctx, 0), duk_require_string(ctx, 1))); } catch (const std::exception &) { - duk::raise(ctx, SystemError()); + duk_throw(ctx, SystemError()); } return 0; @@ -477,11 +492,12 @@ * * Delete the property. */ -duk::Ret destructor(duk::Context *ctx) +duk_ret_t destructor(duk_context *ctx) { - delete static_cast<File *>(duk::getProperty<void *>(ctx, 0, Signature)); - - duk::deleteProperty(ctx, 0, Signature); + duk_get_prop_string(ctx, 0, Signature); + delete static_cast<File *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, Signature); return 0; } @@ -490,16 +506,16 @@ * Function: Irccd.File.basename(path) * -------------------------------------------------------- * - * Return the file basename as specified in `basename(3)` C function. + * duk_ret_turn the file basename as specified in `basename(3)` C function. * * Arguments: * - path, the path to the file. - * Returns: + * duk_ret_turns: * The base name. */ -duk::Ret functionBasename(duk::Context *ctx) +duk_ret_t functionBasename(duk_context *ctx) { - duk::push(ctx, fs::baseName(duk::require<std::string>(ctx, 0))); + duk_push_stdstring(ctx, fs::baseName(duk_require_string(ctx, 0))); return 1; } @@ -508,16 +524,16 @@ * Function: Irccd.File.dirname(path) * -------------------------------------------------------- * - * Return the file directory name as specified in `dirname(3)` C function. + * duk_ret_turn the file directory name as specified in `dirname(3)` C function. * * Arguments: * - path, the path to the file. - * Returns: + * duk_ret_turns: * The directory name. */ -duk::Ret functionDirname(duk::Context *ctx) +duk_ret_t functionDirname(duk_context *ctx) { - duk::push(ctx, fs::dirName( duk::require<std::string>(ctx, 0))); + duk_push_stdstring(ctx, fs::dirName(duk_require_string(ctx, 0))); return 1; } @@ -530,14 +546,14 @@ * * Arguments: * - path, the path to the file. - * Returns: + * duk_ret_turns: * True if exists. * Throws: * - Any exception if we don't have access. */ -duk::Ret functionExists(duk::Context *ctx) +duk_ret_t functionExists(duk_context *ctx) { - duk::push(ctx, fs::exists(duk::require<std::string>(ctx, 0))); + duk_push_boolean(ctx, fs::exists(duk_require_string(ctx, 0))); return 1; } @@ -553,10 +569,10 @@ * Throws: * - Any exception on error. */ -duk::Ret functionRemove(duk::Context *ctx) +duk_ret_t functionRemove(duk_context *ctx) { - if (::remove(duk::require<std::string>(ctx, 0).c_str()) < 0) - duk::raise(ctx, SystemError()); + if (::remove(duk_require_string(ctx, 0)) < 0) + duk_throw(ctx, SystemError()); return 0; } @@ -571,36 +587,37 @@ * * Arguments: * - path, the path to the file. - * Returns: + * duk_ret_turns: * The stat information. * Throws: * - Any exception on error. */ -duk::Ret functionStat(duk::Context *ctx) +duk_ret_t functionStat(duk_context *ctx) { struct stat st; - if (::stat(duk::require<std::string>(ctx, 0).c_str(), &st) < 0) - duk::raise(ctx, SystemError()); + if (::stat(duk_require_string(ctx, 0), &st) < 0) + duk_throw(ctx, SystemError()); - duk::push(ctx, st); + pushStat(ctx, st); return 1; } #endif // !HAVE_STAT -const duk::FunctionMap functions{ - { "basename", { functionBasename, 1 } }, - { "dirname", { functionDirname, 1 } }, - { "exists", { functionExists, 1 } }, - { "remove", { functionRemove, 1 } }, +const duk_function_list_entry functions[] = { + { "basename", functionBasename, 1 }, + { "dirname", functionDirname, 1 }, + { "exists", functionExists, 1 }, + { "remove", functionRemove, 1 }, #if defined(HAVE_STAT) - { "stat", { functionStat, 1 } }, + { "stat", functionStat, 1 }, #endif + { nullptr, nullptr, 0 } }; -const duk::Map<int> constants{ +const duk_number_list_entry constants[] = { { "SeekCur", SEEK_CUR }, { "SeekEnd", SEEK_END }, { "SeekSet", SEEK_SET }, @@ -608,41 +625,6 @@ } // !namespace -namespace duk { - -void TypeTraits<File *>::construct(duk::Context *ctx, File *fp) -{ - assert(fp); - - duk::StackAssert sa(ctx); - - duk::push(ctx, duk::This()); - duk::putProperty(ctx, -1, Signature, static_cast<void *>(fp)); - duk::pop(ctx); -} - -void TypeTraits<File *>::push(duk::Context *ctx, File *fp) -{ - duk::StackAssert sa(ctx, 1); - - duk::push(ctx, duk::Object()); - duk::putProperty(ctx, -1, Signature, static_cast<void *>(fp)); - duk::getGlobal<void>(ctx, Prototype); - duk::setPrototype(ctx, -2); -} - -File *TypeTraits<File *>::require(duk::Context *ctx, Index index) -{ - auto ptr = static_cast<File *>(duk::getProperty<void *>(ctx, index, Signature)); - - if (!ptr) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); - - return ptr; -} - -} // !duk - FileModule::FileModule() noexcept : Module("Irccd.File") { @@ -650,21 +632,60 @@ void FileModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); + + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_c_function(plugin.context(), constructor, 2); + duk_put_number_list(plugin.context(), -1, constants); + duk_put_function_list(plugin.context(), -1, functions); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, methods); + duk_push_c_function(plugin.context(), destructor, 1); + duk_set_finalizer(plugin.context(), -2); + duk_dup(plugin.context(), -1); + duk_get_global_string(plugin.context(), Prototype); + duk_put_prop_string(plugin.context(), -2, "prototype"); + duk_put_prop_string(plugin.context(), -2, "File"); + duk_pop(plugin.context()); +} + +void duk_new_file(duk_context *ctx, File *fp) +{ + assert(ctx); + assert(fp); + + StackAssert sa(ctx); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Function(constructor, 2)); - duk::put(plugin.context(), constants); - duk::put(plugin.context(), functions); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), methods); - duk::push(plugin.context(), duk::Function(destructor, 1)); - duk::setFinalizer(plugin.context(), -2); - duk::dup(plugin.context(), -1); - duk::putGlobal(plugin.context(), Prototype); - duk::putProperty(plugin.context(), -2, "prototype"); - duk::putProperty(plugin.context(), -2, "File"); - duk::pop(plugin.context()); + duk_push_this(ctx); + duk_push_pointer(ctx, fp); + duk_put_prop_string(ctx, -2, Signature); + duk_pop(ctx); +} + +void duk_push_file(duk_context *ctx, File *fp) +{ + assert(ctx); + assert(fp); + + StackAssert sa(ctx, 1); + + duk_push_object(ctx); + duk_push_pointer(ctx, fp); + duk_put_prop_string(ctx, -2, Signature); + duk_get_global_string(ctx, Prototype); + duk_set_prototype(ctx, -2); +} + +File *duk_require_file(duk_context *ctx, duk_idx_t index) +{ + if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a File object"); + + duk_get_prop_string(ctx, index, Signature); + File *file = static_cast<File *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return file; } } // !irccd
--- a/lib/irccd/mod-file.hpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-file.hpp Fri Jun 03 13:28:10 2016 +0200 @@ -32,7 +32,7 @@ #include <stdexcept> #include <string> -#include "js.hpp" +#include "duktape.hpp" #include "module.hpp" namespace irccd { @@ -136,43 +136,6 @@ } }; -namespace duk { - -/** - * \brief JavaScript binding for File. - */ -template <> -class TypeTraits<File *> { -public: - /** - * Construct the file. - * - * \pre fp != nullptr - * \param ctx the the context - * \param fp the file - */ - IRCCD_EXPORT static void construct(duk::Context *ctx, File *fp); - - /** - * Push a file. - * - * \pre fp != nullptr - * \param ctx the the context - * \param fp the file - */ - IRCCD_EXPORT static void push(duk::Context *ctx, File *fp); - - /** - * Require a file. Raises a JavaScript error if not a File. - * - * \param ctx the context - * \param index the index - */ - IRCCD_EXPORT static File *require(duk::Context *ctx, Index index); -}; - -} // !duk - /** * \brief Irccd.File JavaScript API. * \ingroup modules @@ -190,6 +153,34 @@ IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override; }; +/** + * Construct the file as this. + * + * The object prototype takes ownership of fp and will be deleted once collected. + * + * \pre fp != nullptr + * \param ctx the the context + * \param fp the file + */ +IRCCD_EXPORT void duk_new_file(duk_context *ctx, File *fp); + +/** + * Push a file. + * + * \pre fp != nullptr + * \param ctx the the context + * \param fp the file + */ +IRCCD_EXPORT void duk_push_file(duk_context *ctx, File *fp); + +/** + * Require a file. Raises a JavaScript error if not a File. + * + * \param ctx the context + * \param index the index + */ +IRCCD_EXPORT File *duk_require_file(duk_context *ctx, duk_idx_t index); + } // !irccd #endif // !IRCCD_MOD_FILE_HPP
--- a/lib/irccd/mod-irccd.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-irccd.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -22,6 +22,24 @@ namespace irccd { +namespace { + +duk_ret_t constructor(duk_context *ctx) +{ + duk_push_this(ctx); + duk_push_int(ctx, duk_require_int(ctx, 0)); + duk_put_prop_string(ctx, -2, "errno"); + duk_push_string(ctx, duk_require_string(ctx, 1)); + duk_put_prop_string(ctx, -2, "message"); + duk_push_string(ctx, "SystemError"); + duk_put_prop_string(ctx, -2, "name"); + duk_pop(ctx); + + return 0; +} + +} // !namespace + SystemError::SystemError() : m_errno(errno) , m_message(std::strerror(m_errno)) @@ -34,28 +52,17 @@ { } -void SystemError::raise(duk::Context *ctx) const +void SystemError::raise(duk_context *ctx) const { - duk::StackAssert sa(ctx, 0); + StackAssert sa(ctx, 0); - duk::getGlobal<void>(ctx, "Irccd"); - duk::getProperty<void>(ctx, -1, "SystemError"); - duk::remove(ctx, -2); - duk::push(ctx, m_errno); - duk::push(ctx, m_message); - duk::create(ctx, 2); - duk::raise(ctx); -} - -duk::Ret constructor(duk::Context *ctx) -{ - duk::push(ctx, duk::This{}); - duk::putProperty(ctx, -1, "errno", duk::require<int>(ctx, 0)); - duk::putProperty(ctx, -1, "message", duk::require<std::string>(ctx, 1)); - duk::putProperty(ctx, -1, "name", "SystemError"); - duk::pop(ctx); - - return 0; + duk_get_global_string(ctx, "Irccd"); + duk_get_prop_string(ctx, -1, "SystemError"); + duk_remove(ctx, -2); + duk_push_int(ctx, m_errno); + duk_push_stdstring(ctx, m_message); + duk_new(ctx, 2); + duk_throw(ctx); } IrccdModule::IrccdModule() noexcept @@ -65,33 +72,48 @@ void IrccdModule::load(Irccd &irccd, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); // Irccd. - duk::push(plugin.context(), duk::Object{}); + duk_push_object(plugin.context()); // Version. - duk::push(plugin.context(), duk::Object{}); - duk::putProperty(plugin.context(), -1, "major", IRCCD_VERSION_MAJOR); - duk::putProperty(plugin.context(), -1, "minor", IRCCD_VERSION_MINOR); - duk::putProperty(plugin.context(), -1, "patch", IRCCD_VERSION_PATCH); - duk::putProperty(plugin.context(), -2, "version"); + duk_push_object(plugin.context()); + duk_push_int(plugin.context(), IRCCD_VERSION_MAJOR); + duk_put_prop_string(plugin.context(), -2, "major"); + duk_push_int(plugin.context(), IRCCD_VERSION_MINOR); + duk_put_prop_string(plugin.context(), -2, "minor"); + duk_push_int(plugin.context(), IRCCD_VERSION_PATCH); + duk_put_prop_string(plugin.context(), -2, "patch"); + duk_put_prop_string(plugin.context(), -2, "version"); // Create the SystemError that inherits from Error. - duk::push(plugin.context(), duk::Function{constructor, 2}); - duk::push(plugin.context(), duk::Object{}); - duk::getGlobal<void>(plugin.context(), "Error"); - duk::getProperty<void>(plugin.context(), -1, "prototype"); - duk::remove(plugin.context(), -2); - duk::setPrototype(plugin.context(), -2); - duk::putProperty(plugin.context(), -2, "prototype"); - duk::putProperty(plugin.context(), -2, "SystemError"); + duk_push_c_function(plugin.context(), constructor, 2); + duk_push_object(plugin.context()); + duk_get_global_string(plugin.context(), "Error"); + duk_put_prop_string(plugin.context(), -1, "prototype"); + duk_remove(plugin.context(), -2); + duk_set_prototype(plugin.context(), -2); + duk_put_prop_string(plugin.context(), -2, "prototype"); + duk_put_prop_string(plugin.context(), -2, "SystemError"); // Set Irccd as global. - duk::putGlobal(plugin.context(), "Irccd"); + duk_put_global_string(plugin.context(), "Irccd"); // Store global instance. - duk::putGlobal(plugin.context(), "\xff""\xff""irccd",&irccd); + duk_push_pointer(plugin.context(), &irccd); + duk_put_global_string(plugin.context(), "\xff""\xff""irccd-ref"); +} + +Irccd &duk_get_irccd(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_get_global_string(ctx, "\xff""\xff""irccd-ref"); + Irccd *irccd = static_cast<Irccd *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return *irccd; } } // !irccd
--- a/lib/irccd/mod-irccd.hpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-irccd.hpp Fri Jun 03 13:28:10 2016 +0200 @@ -28,7 +28,7 @@ #include <cstring> #include <string> -#include "js.hpp" +#include "duktape.hpp" #include "module.hpp" namespace irccd { @@ -62,7 +62,7 @@ * * \param ctx the context */ - IRCCD_EXPORT void raise(duk::Context *ctx) const; + IRCCD_EXPORT void raise(duk_context *ctx) const; }; /** @@ -82,6 +82,14 @@ IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override; }; +/** + * Get irccd instance stored in this context. + * + * \param ctx the context + * \return the irccd reference + */ +Irccd &duk_get_irccd(duk_context *ctx); + } // !irccd #endif // !IRCCD_MOD_IRCCD_HPP
--- a/lib/irccd/mod-logger.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-logger.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -17,6 +17,7 @@ */ #include "mod-logger.hpp" +#include "mod-plugin.hpp" #include "logger.hpp" #include "plugin-js.hpp" @@ -24,14 +25,9 @@ namespace { -duk::Ret print(duk::Context *ctx, std::ostream &out) +duk_ret_t print(duk_context *ctx, std::ostream &out) { - /* - * Get the message before we start printing stuff to avoid - * empty lines. - */ - out << "plugin " << duk::getGlobal<std::string>(ctx, "\xff""\xff""name"); - out << ": " << duk::require<std::string>(ctx, 0) << std::endl; + out << "plugin " << duk_get_plugin(ctx)->name() << ": " << duk_require_string(ctx, 0) << std::endl; return 0; } @@ -45,7 +41,7 @@ * Arguments: * - message, the message. */ -duk::Ret info(duk::Context *ctx) +duk_ret_t info(duk_context *ctx) { return print(ctx, log::info()); } @@ -59,7 +55,7 @@ * Arguments: * - message, the warning. */ -duk::Ret warning(duk::Context *ctx) +duk_ret_t warning(duk_context *ctx) { return print(ctx, log::warning()); } @@ -73,15 +69,16 @@ * Arguments: * - message, the message. */ -duk::Ret debug(duk::Context *ctx) +duk_ret_t debug(duk_context *ctx) { return print(ctx, log::debug()); } -const duk::FunctionMap functions{ - { "info", { info, 1 } }, - { "warning", { warning, 1 } }, - { "debug", { debug, 1 } } +const duk_function_list_entry functions[] = { + { "info", info, 1 }, + { "warning", warning, 1 }, + { "debug", debug, 1 }, + { nullptr, nullptr, 0 } }; } // !namespace @@ -93,13 +90,13 @@ void LoggerModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), functions); - duk::putProperty(plugin.context(), -2, "Logger"); - duk::pop(plugin.context()); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, functions); + duk_put_prop_string(plugin.context(), -2, "Logger"); + duk_pop(plugin.context()); } } // !irccd
--- a/lib/irccd/mod-plugin.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-plugin.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -19,13 +19,14 @@ #include "irccd.hpp" #include "plugin-js.hpp" #include "service-plugin.hpp" +#include "mod-irccd.hpp" #include "mod-plugin.hpp" namespace irccd { namespace { -const std::string PluginGlobal{"\xff""\xff""irccd-plugin-ptr"}; +const char *PluginGlobal("\xff""\xff""irccd-plugin-ptr"); /* * Wrap function for these functions because they all takes the same arguments. @@ -35,16 +36,16 @@ * - unload. */ template <typename Func> -duk::Ret wrap(duk::Context *ctx, int nret, Func &&func) +duk_idx_t wrap(duk_context *ctx, int nret, Func &&func) { - std::string name = duk::require<std::string>(ctx, 0); + std::string name = duk_require_string(ctx, 0); try { - func(*duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd"), name); + func(duk_get_irccd(ctx), name); } catch (const std::out_of_range &ex) { - duk::raise(ctx, duk::ReferenceError(ex.what())); + duk_throw(ctx, ReferenceError(ex.what())); } catch (const std::exception &ex) { - duk::raise(ctx, duk::Error(ex.what())); + duk_throw(ctx, Error(ex.what())); } return nret; @@ -66,27 +67,32 @@ * * Arguments: * - name, the plugin identifier, if not specified the current plugin is selected. - * Returns: + * duk_idx_turns: * The plugin information or undefined if the plugin was not found. */ -duk::Ret info(duk::Context *ctx) +duk_idx_t info(duk_context *ctx) { - Plugin *plugin = nullptr; + std::shared_ptr<Plugin> plugin; - if (duk::top(ctx) >= 1) - plugin = duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->pluginService().get(duk::require<std::string>(ctx, 0)).get(); + if (duk_get_top(ctx) >= 1) + plugin = duk_get_irccd(ctx).pluginService().get(duk_require_string(ctx, 0)); else - plugin = duk::getGlobal<Plugin *>(ctx, "\xff""\xff""plugin"); + plugin = duk_get_plugin(ctx); if (!plugin) return 0; - duk::push(ctx, duk::Object{}); - duk::putProperty(ctx, -1, "name", plugin->name()); - duk::putProperty(ctx, -1, "author", plugin->author()); - duk::putProperty(ctx, -1, "license", plugin->license()); - duk::putProperty(ctx, -1, "summary", plugin->summary()); - duk::putProperty(ctx, -1, "version", plugin->version()); + duk_push_object(ctx); + duk_push_stdstring(ctx, plugin->name()); + duk_put_prop_string(ctx, -2, "name"); + duk_push_stdstring(ctx, plugin->author()); + duk_put_prop_string(ctx, -2, "author"); + duk_push_stdstring(ctx, plugin->license()); + duk_put_prop_string(ctx, -2, "license"); + duk_push_stdstring(ctx, plugin->summary()); + duk_put_prop_string(ctx, -2, "summary"); + duk_push_stdstring(ctx, plugin->version()); + duk_put_prop_string(ctx, -2, "version"); return 1; } @@ -97,16 +103,18 @@ * * Get the list of plugins, the array returned contains all plugin names. * - * Returns: + * duk_idx_turns: * The list of all plugin names. */ -duk::Ret list(duk::Context *ctx) +duk_idx_t list(duk_context *ctx) { - duk::push(ctx, duk::Array{}); + duk_push_array(ctx); int i = 0; - for (const auto &plugin : duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->pluginService().plugins()) - duk::putProperty(ctx, -1, i++, plugin->name()); + for (const auto &plugin : duk_get_irccd(ctx).pluginService().plugins()) { + duk_push_stdstring(ctx, plugin->name()); + duk_put_prop_index(ctx, -1, i++); + } return 1; } @@ -123,7 +131,7 @@ * - Error on errors, * - ReferenceError if the plugin was not found. */ -duk::Ret load(duk::Context *ctx) +duk_idx_t load(duk_context *ctx) { return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) { irccd.pluginService().load(name); @@ -142,7 +150,7 @@ * - Error on errors, * - ReferenceError if the plugin was not found. */ -duk::Ret reload(duk::Context *ctx) +duk_idx_t reload(duk_context *ctx) { return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) { irccd.pluginService().reload(name); @@ -161,32 +169,24 @@ * - Error on errors, * - ReferenceError if the plugin was not found. */ -duk::Ret unload(duk::Context *ctx) +duk_idx_t unload(duk_context *ctx) { return wrap(ctx, 0, [&] (Irccd &irccd, const std::string &name) { irccd.pluginService().unload(name); }); } -const duk::FunctionMap functions{ - { "info", { info, DUK_VARARGS } }, - { "list", { list, 0 } }, - { "load", { load, 1 } }, - { "reload", { reload, 1 } }, - { "unload", { unload, 1 } } +const duk_function_list_entry functions[] = { + { "info", info, DUK_VARARGS }, + { "list", list, 0 }, + { "load", load, 1 }, + { "reload", reload, 1 }, + { "unload", unload, 1 }, + { nullptr, nullptr, 0 } }; } // !namespace -namespace duk { - -std::shared_ptr<JsPlugin> TypeTraits<std::shared_ptr<JsPlugin>>::get(duk::Context *ctx) -{ - return std::static_pointer_cast<JsPlugin>(static_cast<Plugin *>(duk::getGlobal<void *>(ctx, PluginGlobal))->shared_from_this()); -} - -} // !duk - PluginModule::PluginModule() noexcept : Module("Irccd.Plugin") { @@ -194,18 +194,30 @@ void PluginModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::putGlobal<void *>(plugin.context(), PluginGlobal, &plugin); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), functions); - duk::push(plugin.context(), duk::Object{}); - duk::putProperty(plugin.context(), -2, "config"); - duk::push(plugin.context(), duk::Object{}); - duk::putProperty(plugin.context(), -2, "format"); - duk::putProperty(plugin.context(), -2, "Plugin"); - duk::pop(plugin.context()); + duk_push_pointer(plugin.context(), &plugin); + duk_put_global_string(plugin.context(), PluginGlobal); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, functions); + duk_push_object(plugin.context()); + duk_put_prop_string(plugin.context(), -2, "config"); + duk_push_object(plugin.context()); + duk_put_prop_string(plugin.context(), -2, "format"); + duk_put_prop_string(plugin.context(), -2, "Plugin"); + duk_pop(plugin.context()); +} + +std::shared_ptr<JsPlugin> duk_get_plugin(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_get_global_string(ctx, PluginGlobal); + auto plugin = std::static_pointer_cast<JsPlugin>(static_cast<JsPlugin *>(duk_to_pointer(ctx, -1))->shared_from_this()); + duk_pop(ctx); + + return plugin; } } // !irccd
--- a/lib/irccd/mod-plugin.hpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-plugin.hpp Fri Jun 03 13:28:10 2016 +0200 @@ -24,31 +24,11 @@ * \brief Irccd.Plugin JavaScript API. */ -#include "js.hpp" +#include "duktape.hpp" #include "module.hpp" namespace irccd { -namespace duk { - -/** - * \brief Custom specialization for JsPlugin. - * \note Use the dedicated get function to get the underlying JsPlugin. - */ -template <> -class TypeTraits<std::shared_ptr<JsPlugin>> { -public: - /** - * Get the plugin. - * - * \param ctx the context - * \return the plugin - */ - IRCCD_EXPORT static std::shared_ptr<JsPlugin> get(duk::Context *ctx); -}; - -} // !duk - /** * \brief Irccd.Plugin JavaScript API. * \ingroup modules @@ -66,6 +46,14 @@ IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override; }; +/** + * Access the plugin stored in this context. + * + * \param ctx the context + * \return the plugin + */ +std::shared_ptr<JsPlugin> duk_get_plugin(duk_context *ctx); + } // !irccd #endif // !IRCCD_MOD_PLUGIN_HPP
--- a/lib/irccd/mod-server.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-server.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -21,6 +21,7 @@ #include <unordered_map> #include "irccd.hpp" +#include "mod-irccd.hpp" #include "mod-server.hpp" #include "plugin-js.hpp" #include "server.hpp" @@ -30,8 +31,23 @@ namespace { -const std::string Signature("\xff""\xff""irccd-server-ptr"); -const std::string Prototype("\xff""\xff""irccd-server-prototype"); +const char *Signature("\xff""\xff""irccd-server-ptr"); +const char *Prototype("\xff""\xff""irccd-server-prototype"); + +std::shared_ptr<Server> self(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); + + return *static_cast<std::shared_ptr<Server> *>(ptr); +} /* * Method: Server.cmode(channel, mode) @@ -43,9 +59,9 @@ * - channel, the channel, * - mode, the mode. */ -duk::Ret cmode(duk::Context *ctx) +duk_ret_t cmode(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->cmode(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)); + self(ctx)->cmode(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); return 0; } @@ -60,9 +76,9 @@ * - channel, the channel, * - message, the message. */ -duk::Ret cnotice(duk::Context *ctx) +duk_ret_t cnotice(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->cnotice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)); + self(ctx)->cnotice(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); return 0; } @@ -80,29 +96,40 @@ * sslVerify: true if ssl was verified * channels: an array of all channels */ -duk::Ret info(duk::Context *ctx) +duk_ret_t info(duk_context *ctx) { - auto server = duk::self<std::shared_ptr<Server>>(ctx); + auto server = self(ctx); - duk::push(ctx, duk::Object{}); - duk::putProperty(ctx, -1, "name", server->name()); - duk::putProperty(ctx, -1, "host", server->info().host); - duk::putProperty(ctx, -1, "port", static_cast<int>(server->info().port)); - duk::putProperty<bool>(ctx, -1, "ssl", server->info().flags & ServerInfo::Ssl); - duk::putProperty<bool>(ctx, -1, "sslVerify", server->info().flags & ServerInfo::SslVerify); - duk::putProperty(ctx, -1, "commandChar", server->settings().command); - duk::putProperty(ctx, -1, "realname", server->identity().realname); - duk::putProperty(ctx, -1, "nickname", server->identity().nickname); - duk::putProperty(ctx, -1, "username", server->identity().username); + duk_push_object(ctx); + duk_push_stdstring(ctx, server->name()); + duk_put_prop_string(ctx, -2, "name"); + duk_push_stdstring(ctx, server->info().host); + duk_put_prop_string(ctx, -2, "host"); + duk_push_int(ctx, server->info().port); + duk_put_prop_string(ctx, -2, "port"); + duk_push_boolean(ctx, server->info().flags & ServerInfo::Ssl); + duk_put_prop_string(ctx, -2, "ssl"); + duk_push_boolean(ctx, server->info().flags & ServerInfo::SslVerify); + duk_put_prop_string(ctx, -2, "sslVerify"); + duk_push_stdstring(ctx, server->settings().command); + duk_put_prop_string(ctx, -2, "commandChar"); + duk_push_stdstring(ctx, server->identity().realname); + duk_put_prop_string(ctx, -2, "realname"); + duk_push_stdstring(ctx, server->identity().nickname); + duk_put_prop_string(ctx, -2, "nickname"); + duk_push_stdstring(ctx, server->identity().username); + duk_put_prop_string(ctx, -2, "username"); // Channels. - duk::push(ctx, duk::Array{}); + duk_push_array(ctx); int i = 0; - for (const auto &channel : server->settings().channels) - duk::putProperty(ctx, -1, i++, channel.name); + for (const auto &channel : server->settings().channels) { + duk_push_stdstring(ctx, channel.name); + duk_put_prop_index(ctx, -1, i++); + } - duk::putProperty(ctx, -2, "channels"); + duk_put_prop_string(ctx, -2, "channels"); return 1; } @@ -117,9 +144,9 @@ * - target, the target to invite, * - channel, the channel. */ -duk::Ret invite(duk::Context *ctx) +duk_ret_t invite(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->invite(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)); + self(ctx)->invite(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); return 0; } @@ -134,9 +161,9 @@ * - channel, the channel to join, * - password, the password or undefined to not use. */ -duk::Ret join(duk::Context *ctx) +duk_ret_t join(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->join(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, "")); + self(ctx)->join(duk_require_string(ctx, 0), duk_get_string(ctx, 1)); return 0; } @@ -152,13 +179,9 @@ * - channel, the channel, * - reason, the optional reason or undefined to not set. */ -duk::Ret kick(duk::Context *ctx) +duk_ret_t kick(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->kick( - duk::require<std::string>(ctx, 0), - duk::require<std::string>(ctx, 1), - duk::optional<std::string>(ctx, 2, "") - ); + self(ctx)->kick(duk_require_string(ctx, 0), duk_require_string(ctx, 1), duk_get_string(ctx, 2)); return 0; } @@ -173,9 +196,9 @@ * - target, the target or a channel, * - message, the message. */ -duk::Ret me(duk::Context *ctx) +duk_ret_t me(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->me(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)); + self(ctx)->me(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); return 0; } @@ -190,9 +213,9 @@ * - target, the target or a channel, * - message, the message. */ -duk::Ret message(duk::Context *ctx) +duk_ret_t message(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->message(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)); + self(ctx)->message(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); return 0; } @@ -206,9 +229,9 @@ * Arguments: * - mode, the new mode. */ -duk::Ret mode(duk::Context *ctx) +duk_ret_t mode(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->mode(duk::require<std::string>(ctx, 0)); + self(ctx)->mode(duk_require_string(ctx, 0)); return 0; } @@ -222,9 +245,9 @@ * Arguments: * - channel, the channel. */ -duk::Ret names(duk::Context *ctx) +duk_ret_t names(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->names(duk::require<std::string>(ctx, 0)); + self(ctx)->names(duk_require_string(ctx, 0)); return 0; } @@ -238,9 +261,9 @@ * Arguments: * - nickname, the nickname. */ -duk::Ret nick(duk::Context *ctx) +duk_ret_t nick(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->nick(duk::require<std::string>(ctx, 0)); + self(ctx)->nick(duk_require_string(ctx, 0)); return 0; } @@ -255,9 +278,9 @@ * - target, the target, * - message, the notice message. */ -duk::Ret notice(duk::Context *ctx) +duk_ret_t notice(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->notice(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)); + self(ctx)->notice(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); return 0; } @@ -272,9 +295,9 @@ * - channel, the channel to leave, * - reason, the optional reason, keep undefined for portability. */ -duk::Ret part(duk::Context *ctx) +duk_ret_t part(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->part(duk::require<std::string>(ctx, 0), duk::optional<std::string>(ctx, 1, "")); + self(ctx)->part(duk_require_string(ctx, 0), duk_get_string(ctx, 1)); return 0; } @@ -288,9 +311,9 @@ * Arguments: * - raw, the raw message (without terminators). */ -duk::Ret send(duk::Context *ctx) +duk_ret_t send(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->send(duk::require<std::string>(ctx, 0)); + self(ctx)->send(duk_require_string(ctx, 0)); return 0; } @@ -305,9 +328,9 @@ * - channel, the channel, * - topic, the new topic. */ -duk::Ret topic(duk::Context *ctx) +duk_ret_t topic(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->topic(duk::require<std::string>(ctx, 0), duk::require<std::string>(ctx, 1)); + self(ctx)->topic(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); return 0; } @@ -321,9 +344,9 @@ * Arguments: * - target, the target. */ -duk::Ret whois(duk::Context *ctx) +duk_ret_t whois(duk_context *ctx) { - duk::self<std::shared_ptr<Server>>(ctx)->whois(duk::require<std::string>(ctx, 0)); + self(ctx)->whois(duk_require_string(ctx, 0)); return 0; } @@ -335,12 +358,12 @@ * Convert the object to std::string, convenience for adding the object * as property key. * - * Returns: + * duk_ret_turns: * The server name (unique). */ -duk::Ret toString(duk::Context *ctx) +duk_ret_t toString(duk_context *ctx) { - duk::push(ctx, duk::self<std::shared_ptr<Server>>(ctx)->name()); + duk_push_stdstring(ctx, self(ctx)->name()); return 1; } @@ -366,9 +389,10 @@ * realname: "real name", (Optional, default: IRC Client Daemon) * commandChar: "!", (Optional, the command char, default: "!") */ -duk::Ret constructor(duk::Context *ctx) +duk_ret_t constructor(duk_context *ctx) { - if (!duk::isConstructorCall(ctx)) +#if 0 + if (!isConstructorCall(ctx)) return 0; std::string name; @@ -377,37 +401,41 @@ ServerSettings settings; // Information part. - name = duk::getProperty<std::string>(ctx, 0, "name"); - info.host = duk::getProperty<std::string>(ctx, 0, "host"); - info.port = duk::optionalProperty<int>(ctx, 0, "port", static_cast<int>(info.port)); - info.password = duk::optionalProperty<std::string>(ctx, 0, "password", ""); + name = getProperty<std::string>(ctx, 0, "name"); + info.host = getProperty<std::string>(ctx, 0, "host"); + info.port = optionalProperty<int>(ctx, 0, "port", static_cast<int>(info.port)); + info.password = optionalProperty<std::string>(ctx, 0, "password", ""); - if (duk::optionalProperty<bool>(ctx, 0, "ipv6", false)) + if (optionalProperty<bool>(ctx, 0, "ipv6", false)) info.flags |= ServerInfo::Ipv6; // Identity part. - identity.nickname = duk::optionalProperty<std::string>(ctx, 0, "nickname", identity.nickname); - identity.username = duk::optionalProperty<std::string>(ctx, 0, "username", identity.username); - identity.realname = duk::optionalProperty<std::string>(ctx, 0, "realname", identity.realname); - identity.ctcpversion = duk::optionalProperty<std::string>(ctx, 0, "version", identity.ctcpversion); + identity.nickname = optionalProperty<std::string>(ctx, 0, "nickname", identity.nickname); + identity.username = optionalProperty<std::string>(ctx, 0, "username", identity.username); + identity.realname = optionalProperty<std::string>(ctx, 0, "realname", identity.realname); + identity.ctcpversion = optionalProperty<std::string>(ctx, 0, "version", identity.ctcpversion); // Settings part. - for (const auto &chan: duk::getProperty<std::vector<std::string>>(ctx, 0, "channels")) + for (const auto &chan: getProperty<std::vector<std::string>>(ctx, 0, "channels")) settings.channels.push_back(Server::splitChannel(chan)); - settings.reconnectTries = duk::optionalProperty<int>(ctx, 0, "recoTries", (int)settings.reconnectTries); - settings.reconnectDelay = duk::optionalProperty<int>(ctx, 0, "recoTimeout", (int)settings.reconnectDelay); + settings.reconnectTries = optionalProperty<int>(ctx, 0, "recoTries", (int)settings.reconnectTries); + settings.reconnectDelay = optionalProperty<int>(ctx, 0, "recoTimeout", (int)settings.reconnectDelay); - if (duk::optionalProperty<bool>(ctx, 0, "joinInvite", false)) + if (optionalProperty<bool>(ctx, 0, "joinInvite", false)) settings.flags |= ServerSettings::JoinInvite; - if (duk::optionalProperty<bool>(ctx, 0, "autoRejoin", false)) + if (optionalProperty<bool>(ctx, 0, "autoRejoin", false)) settings.flags |= ServerSettings::AutoRejoin; try { - duk::construct(ctx, std::make_shared<Server>(std::move(name), std::move(info), std::move(identity), std::move(settings))); + push(ctx, This()); + pushPointer(ctx, new std::shared_ptr<Server>(std::move(name), std::move(info), std::move(identity), std::move(settings))); + putProperty(ctx, -2, Signature); + pop(ctx); } catch (const std::exception &ex) { - duk::raise(ctx, duk::Error(ex.what())); + raise(ctx, Error(ex.what())); } +#endif return 0; } @@ -418,11 +446,12 @@ * * Delete the property. */ -duk::Ret destructor(duk::Context *ctx) +duk_ret_t destructor(duk_context *ctx) { - delete static_cast<std::shared_ptr<Server> *>(duk::getProperty<void *>(ctx, 0, Signature)); - - duk::deleteProperty(ctx, 0, Signature); + duk_get_prop_string(ctx, 0, Signature); + delete static_cast<std::shared_ptr<Server> *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, Signature); return 0; } @@ -436,9 +465,9 @@ * Arguments: * - s, the server to add. */ -duk::Ret add(duk::Context *ctx) +duk_ret_t add(duk_context *ctx) { - duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().add(duk::require<std::shared_ptr<Server>>(ctx, 0)); + duk_get_irccd(ctx).serverService().add(duk_require_server(ctx, 0)); return 0; } @@ -451,19 +480,17 @@ * * Arguments: * - name, the server name - * Returns: + * duk_ret_turns: * The server object or undefined if not found. */ -duk::Ret find(duk::Context *ctx) +duk_ret_t find(duk_context *ctx) { - const auto name = duk::require<std::string>(ctx, 0); - const auto irccd = duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd"); + auto server = duk_get_irccd(ctx).serverService().get(duk_require_string(ctx, 0)); - try { - duk::push(ctx, irccd->serverService().require(name)); - } catch (...) { + if (!server) return 0; - } + + duk_push_server(ctx, server); return 1; } @@ -474,15 +501,17 @@ * * Get the map of all loaded servers. * - * Returns: + * duk_ret_turns: * An object with string-to-servers pairs. */ -duk::Ret list(duk::Context *ctx) +duk_ret_t list(duk_context *ctx) { - duk::push(ctx, duk::Object{}); + duk_push_object(ctx); - for (const auto &server : duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().servers()) - duk::putProperty(ctx, -1, server->name(), server); + for (const auto &server : duk_get_irccd(ctx).serverService().servers()) { + duk_push_server(ctx, server); + duk_put_prop_string(ctx, -2, server->name().c_str()); + } return 1; } @@ -496,79 +525,44 @@ * Arguments: * - name the server name. */ -duk::Ret remove(duk::Context *ctx) +duk_ret_t remove(duk_context *ctx) { - duk::getGlobal<Irccd *>(ctx, "\xff""\xff""irccd")->serverService().remove(duk::require<std::string>(ctx, 0)); + duk_get_irccd(ctx).serverService().remove(duk_require_string(ctx, 0)); return 0; } -const duk::FunctionMap methods{ - { "cmode", { cmode, 2 } }, - { "cnotice", { cnotice, 2 } }, - { "info", { info, 0 } }, - { "invite", { invite, 2 } }, - { "join", { join, DUK_VARARGS } }, - { "kick", { kick, DUK_VARARGS } }, - { "me", { me, 2 } }, - { "message", { message, 2 } }, - { "mode", { mode, 1 } }, - { "names", { names, 1 } }, - { "nick", { nick, 1 } }, - { "notice", { notice, 2 } }, - { "part", { part, DUK_VARARGS } }, - { "send", { send, 1 } }, - { "topic", { topic, 2 } }, - { "whois", { whois, 1 } }, - { "toString", { toString, 0 } } +const duk_function_list_entry methods[] = { + { "cmode", cmode, 2 }, + { "cnotice", cnotice, 2 }, + { "info", info, 0 }, + { "invite", invite, 2 }, + { "join", join, DUK_VARARGS }, + { "kick", kick, DUK_VARARGS }, + { "me", me, 2 }, + { "message", message, 2 }, + { "mode", mode, 1 }, + { "names", names, 1 }, + { "nick", nick, 1 }, + { "notice", notice, 2 }, + { "part", part, DUK_VARARGS }, + { "send", send, 1 }, + { "topic", topic, 2 }, + { "whois", whois, 1 }, + { "toString", toString, 0 }, + { nullptr, nullptr, 0 } }; -const duk::FunctionMap functions{ - { "add", { add, 1 } }, - { "find", { find, 1 } }, - { "list", { list, 0 } }, - { "remove", { remove, 1 } } +const duk_function_list_entry functions[] = { + { "add", add, 1 }, + { "find", find, 1 }, + { "list", list, 0 }, + { "remove", remove, 1 }, + { nullptr, nullptr, 0 } }; } // !namespace -namespace duk { - -void TypeTraits<std::shared_ptr<Server>>::construct(Context *ctx, std::shared_ptr<Server> server) -{ - assert(server); - - duk::StackAssert sa(ctx); - - duk::push(ctx, This()); - duk::putProperty(ctx, -1, Signature, new std::shared_ptr<Server>(std::move(server))); - duk::pop(ctx); -} - -void TypeTraits<std::shared_ptr<Server>>::push(Context *ctx, std::shared_ptr<Server> server) -{ - assert(server); - - duk::StackAssert sa(ctx, 1); - - duk::push(ctx, Object()); - duk::putProperty(ctx, -1, Signature, new std::shared_ptr<Server>(std::move(server))); - duk::getGlobal<void>(ctx, Prototype); - duk::setPrototype(ctx, -2); -} - -std::shared_ptr<Server> TypeTraits<std::shared_ptr<Server>>::require(Context *ctx, Index index) -{ - auto ptr = getProperty<std::shared_ptr<Server> *>(ctx, index, Signature); - - if (!ptr) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); - - return *ptr; -} - -} // !duk - ServerModule::ServerModule() noexcept : Module("Irccd.Server") { @@ -576,20 +570,46 @@ void ServerModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); + + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_c_function(plugin.context(), constructor, 1); + duk_put_function_list(plugin.context(), -1, functions); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, methods); + duk_push_c_function(plugin.context(), destructor, 1); + duk_set_finalizer(plugin.context(), -2); + duk_dup_top(plugin.context()); + duk_get_global_string(plugin.context(), Prototype); + duk_put_prop_string(plugin.context(), -2, "prototype"); + duk_put_prop_string(plugin.context(), -2, "Server"); + duk_pop(plugin.context()); +} - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Function(constructor, 1)); - duk::put(plugin.context(), functions); - duk::push(plugin.context(), duk::Object()); - duk::put(plugin.context(), methods); - duk::push(plugin.context(), duk::Function(destructor, 1)); - duk::setFinalizer(plugin.context(), -2); - duk::dup(plugin.context()); - duk::putGlobal(plugin.context(), Prototype); - duk::putProperty(plugin.context(), -2, "prototype"); - duk::putProperty(plugin.context(), -2, "Server"); - duk::pop(plugin.context()); +void duk_push_server(duk_context *ctx, std::shared_ptr<Server> server) +{ + assert(ctx); + assert(server); + + StackAssert sa(ctx, 1); + + duk_push_object(ctx); + duk_push_pointer(ctx, new std::shared_ptr<Server>(std::move(server))); + duk_put_prop_string(ctx, -2, Signature); + duk_get_global_string(ctx, Prototype); + duk_set_finalizer(ctx, -2); +} + +std::shared_ptr<Server> require(duk_context *ctx, duk_idx_t index) +{ + if (!duk_is_object(ctx, index) || !duk_has_prop_string(ctx, index, Signature)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Server object"); + + duk_get_prop_string(ctx, index, Signature); + auto file = *static_cast<std::shared_ptr<Server> *>(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return file; } } // !irccd
--- a/lib/irccd/mod-server.hpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-server.hpp Fri Jun 03 13:28:10 2016 +0200 @@ -24,50 +24,12 @@ * \brief Irccd.Server JavaScript API. */ -#include "js.hpp" +#include "duktape.hpp" #include "module.hpp" #include "server.hpp" namespace irccd { -namespace duk { - -/** - * \brief JavaScript binding for Server. - */ -template <> -class TypeTraits<std::shared_ptr<Server>> { -public: - /** - * Construct a server. - * - * \pre server != nullptr - * \param ctx the context - * \param server the server - */ - IRCCD_EXPORT static void construct(Context *ctx, std::shared_ptr<Server> server); - - /** - * Push a server. - * - * \pre server != nullptr - * \param ctx the context - * \param server the server - */ - IRCCD_EXPORT static void push(Context *ctx, std::shared_ptr<Server> server); - - /** - * Require a server. Raise a JavaScript error if not a Server. - * - * \param ctx the context - * \param index the index - * \return the server - */ - IRCCD_EXPORT static std::shared_ptr<Server> require(Context *ctx, Index index); -}; - -} // !duk - /** * \brief Irccd.Server JavaScript API. * \ingroup modules @@ -85,6 +47,24 @@ IRCCD_EXPORT void load(Irccd &irccd, JsPlugin &plugin) override; }; +/** + * Push a server. + * + * \pre server != nullptr + * \param ctx the context + * \param server the server + */ +IRCCD_EXPORT void duk_push_server(duk_context *ctx, std::shared_ptr<Server> server); + +/** + * Require a server. Raise a JavaScript error if not a Server. + * + * \param ctx the context + * \param index the index + * \return the server + */ +IRCCD_EXPORT std::shared_ptr<Server> duk_require_server(duk_context *ctx, duk_idx_t index); + } // !irccd #endif // !IRCCD_JS_SERVER_HPP
--- a/lib/irccd/mod-system.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-system.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -47,9 +47,9 @@ * Returns: * The value. */ -int env(duk::Context *ctx) +duk_ret_t env(duk_context *ctx) { - duk::push(ctx, sys::env(duk::get<std::string>(ctx, 0))); + duk_push_stdstring(ctx, sys::env(duk_get_string(ctx, 0))); return 1; } @@ -63,9 +63,9 @@ * Arguments: * - cmd, the command to execute. */ -int exec(duk::Context *ctx) +duk_ret_t exec(duk_context *ctx) { - std::system(duk::get<const char *>(ctx, 0)); + std::system(duk_get_string(ctx, 0)); return 0; } @@ -79,9 +79,9 @@ * Returns: * The user home directory. */ -int home(duk::Context *ctx) +duk_ret_t home(duk_context *ctx) { - duk::push(ctx, sys::home()); + duk_push_stdstring(ctx, sys::home()); return 1; } @@ -95,9 +95,9 @@ * Returns: * The system name. */ -int name(duk::Context *ctx) +duk_ret_t name(duk_context *ctx) { - duk::push(ctx, sys::name()); + duk_push_stdstring(ctx, sys::name()); return 1; } @@ -118,14 +118,14 @@ * Throws * - Irccd.SystemError on failures. */ -int popen(duk::Context *ctx) +duk_ret_t popen(duk_context *ctx) { - auto fp = ::popen(duk::require<const char *>(ctx, 0), duk::require<const char *>(ctx, 1)); + auto fp = ::popen(duk_require_string(ctx, 0), duk_require_string(ctx, 1)); if (fp == nullptr) - duk::raise(ctx, SystemError{}); + duk_throw(ctx, SystemError()); - duk::push(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); })); + duk_push_file(ctx, new File(fp, [] (std::FILE *fp) { ::pclose(fp); })); return 1; } @@ -138,9 +138,9 @@ * * Sleep the main loop for the specific delay in seconds. */ -int sleep(duk::Context *ctx) +duk_ret_t sleep(duk_context *ctx) { - std::this_thread::sleep_for(std::chrono::seconds(duk::get<int>(ctx, 0))); + std::this_thread::sleep_for(std::chrono::seconds(duk_get_int(ctx, 0))); return 0; } @@ -154,9 +154,9 @@ * Returns: * The number of milliseconds. */ -int ticks(duk::Context *ctx) +duk_ret_t ticks(duk_context *ctx) { - duk::push(ctx, static_cast<int>(sys::ticks())); + duk_push_int(ctx, sys::ticks()); return 1; } @@ -167,9 +167,9 @@ * * Sleep the main loop for the specific delay in microseconds. */ -int usleep(duk::Context *ctx) +duk_ret_t usleep(duk_context *ctx) { - std::this_thread::sleep_for(std::chrono::microseconds(duk::get<int>(ctx, 0))); + std::this_thread::sleep_for(std::chrono::microseconds(duk_get_int(ctx, 0))); return 0; } @@ -183,9 +183,9 @@ * Returns: * The system uptime. */ -int uptime(duk::Context *ctx) +duk_ret_t uptime(duk_context *ctx) { - duk::push<int>(ctx, sys::uptime()); + duk_push_int(ctx, sys::uptime()); return 0; } @@ -199,26 +199,26 @@ * Returns: * The system version. */ -int version(duk::Context *ctx) +duk_ret_t version(duk_context *ctx) { - duk::push(ctx, sys::version()); + duk_push_stdstring(ctx, sys::version()); return 1; } -const duk::FunctionMap functions{ - { "env", { env, 1 } }, - { "exec", { exec, 1 } }, - { "home", { home, 0 } }, - { "name", { name, 0 } }, +const duk_function_list_entry functions[] = { + { "env", env, 1 }, + { "exec", exec, 1 }, + { "home", home, 0 }, + { "name", name, 0 }, #if defined(HAVE_POPEN) - { "popen", { popen, 2 } }, + { "popen", popen, 2 }, #endif - { "sleep", { sleep, 1 } }, - { "ticks", { ticks, 0 } }, - { "uptime", { uptime, 0 } }, - { "usleep", { usleep, 1 } }, - { "version", { version, 0 } } + { "sleep", sleep, 1 }, + { "ticks", ticks, 0 }, + { "uptime", uptime, 0 }, + { "usleep", usleep, 1 }, + { "version", version, 0 } }; } // !namespace @@ -230,13 +230,13 @@ void SystemModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), functions); - duk::putProperty(plugin.context(), -2, "System"); - duk::pop(plugin.context()); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, functions); + duk_put_prop_string(plugin.context(), -2, "System"); + duk_pop(plugin.context()); } } // !irccd
--- a/lib/irccd/mod-timer.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-timer.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -20,6 +20,7 @@ #include "irccd.hpp" #include "logger.hpp" +#include "mod-irccd.hpp" #include "mod-timer.hpp" #include "mod-plugin.hpp" #include "plugin-js.hpp" @@ -31,39 +32,8 @@ namespace { -const std::string Signature{"\xff""\xff""irccd-timer-ptr"}; -const std::string CallbackTable{"\xff""\xff""irccd-timer-callbacks"}; - -} // !namespace - -namespace duk { - -template <> -class TypeTraits<std::shared_ptr<Timer>> { -public: - static inline void construct(duk::Context *ctx, std::shared_ptr<Timer> timer) - { - duk::StackAssert sa(ctx); - - duk::push(ctx, duk::This()); - duk::putProperty<void *>(ctx, -1, Signature, new std::shared_ptr<Timer>(std::move(timer))); - duk::pop(ctx); - } - - static inline std::shared_ptr<Timer> require(duk::Context *ctx, duk::Index index) - { - auto ptr = static_cast<std::shared_ptr<Timer> *>(duk::getProperty<void *>(ctx, index, Signature)); - - if (!ptr) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "not a Timer object"); - - return *ptr; - } -}; - -} // !duk - -namespace { +const char *Signature("\xff""\xff""irccd-timer-ptr"); +const char *CallbackTable("\xff""\xff""irccd-timer-callbacks"); void handleSignal(std::weak_ptr<JsPlugin> ptr, std::string key) { @@ -72,34 +42,39 @@ if (!plugin) return; - auto irccd = duk::getGlobal<Irccd *>(plugin->context(), "\xff""\xff""irccd"); + auto &irccd = duk_get_irccd(plugin->context()); - irccd->post([plugin, key] (Irccd &) { - duk::StackAssert sa(plugin->context()); + irccd.post([plugin, key] (Irccd &) { + StackAssert sa(plugin->context()); - duk::getGlobal<void>(plugin->context(), CallbackTable); - duk::getProperty<void>(plugin->context(), -1, key); - duk::remove(plugin->context(), -2); + duk_get_global_string(plugin->context(), CallbackTable); + duk_get_prop_string(plugin->context(), -1, key.c_str()); + duk_remove(plugin->context(), -2); - if (duk::is<duk::Function>(plugin->context(), -1)) { - if (duk::pcall(plugin->context()) != 0) - log::warning("plugin {}: {}"_format(plugin->name(), duk::exception(plugin->context(), -1).stack)); + if (duk_is_callable(plugin->context(), -1)) { + if (duk_pcall(plugin->context(), 0) != 0) + log::warning("plugin {}: {}"_format(plugin->name(), duk_exception(plugin->context(), -1).stack)); else - duk::pop(plugin->context()); + duk_pop(plugin->context()); } else - duk::pop(plugin->context()); + duk_pop(plugin->context()); }); } +std::shared_ptr<Timer> self(duk_context *ctx) +{ + return nullptr; +} + /* * Method: Timer.start() * -------------------------------------------------------- * * Start the timer. If the timer is already started the method is a no-op. */ -duk::Ret start(duk::Context *ctx) +duk_ret_t start(duk_context *ctx) { - auto timer = duk::self<std::shared_ptr<Timer>>(ctx); + auto timer = self(ctx); if (!timer->isRunning()) timer->start(); @@ -113,9 +88,9 @@ * * Stop the timer. */ -duk::Ret stop(duk::Context *ctx) +duk_ret_t stop(duk_context *ctx) { - auto timer = duk::self<std::shared_ptr<Timer>>(ctx); + auto timer = self(ctx); if (timer->isRunning()) timer->stop(); @@ -123,9 +98,10 @@ return 0; } -const duk::FunctionMap methods{ - { "start", { start, 0 } }, - { "stop", { stop, 0 } } +const duk_function_list_entry methods[] = { + { "start", start, 0 }, + { "stop", stop, 0 }, + { nullptr, nullptr, 0 } }; /* @@ -139,56 +115,60 @@ * - delay, the interval in milliseconds, * - callback, the function to call. */ -duk::Ret constructor(duk::Context *ctx) +duk_ret_t constructor(duk_context *ctx) { // Check parameters. - auto type = duk::require<int>(ctx, 0); - auto delay = duk::require<int>(ctx, 1); + auto type = duk_require_int(ctx, 0); + auto delay = duk_require_int(ctx, 1); if (type < static_cast<int>(TimerType::Single) || type > static_cast<int>(TimerType::Repeat)) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type"); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid timer type"); if (delay < 0) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "negative delay given"); - if (!duk::is<duk::Function>(ctx, 2)) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "missing callback function"); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "negative delay given"); + if (!duk_is_callable(ctx, 2)) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "missing callback function"); // Construct the timer in 'this'. auto timer = std::make_shared<Timer>(static_cast<TimerType>(type), delay); - auto plugin = duk::TypeTraits<std::shared_ptr<JsPlugin>>::get(ctx); auto hash = std::to_string(reinterpret_cast<std::uintptr_t>(timer.get())); - timer->onSignal.connect(std::bind(handleSignal, std::weak_ptr<JsPlugin>(plugin), hash)); + timer->onSignal.connect(std::bind(handleSignal, std::weak_ptr<JsPlugin>(duk_get_plugin(ctx)), hash)); + + duk_push_this(ctx); + duk_push_pointer(ctx, new std::shared_ptr<Timer>(std::move(timer))); + duk_put_prop_string(ctx, -2, Signature); + duk_push_string(ctx, hash.c_str()); + duk_put_prop_string(ctx, -2, "\xff""\xff""timer-key"); - // Set a finalizer that closes the timer. - duk::construct(ctx, std::shared_ptr<Timer>(std::move(timer))); - duk::push(ctx, duk::This()); - duk::putProperty(ctx, -1, "\xff""\xff""timer-key", hash); - duk::push(ctx, duk::Function{[] (duk::Context *ctx) -> duk::Ret { - duk::StackAssert sa(ctx); +#if 0 + push(ctx, Function{[] (duk_context *ctx) -> duk_ret_t { + StackAssert sa(ctx); - duk::require<std::shared_ptr<Timer>>(ctx, 0)->stop(); - delete static_cast<std::shared_ptr<Timer> *>(duk::getProperty<void *>(ctx, 0, Signature)); - duk::getGlobal<void>(ctx, CallbackTable); - duk::deleteProperty(ctx, -1, duk::getProperty<std::string>(ctx, 0, "\xff""\xff""timer-key")); - duk::pop(ctx); + require<std::shared_ptr<Timer>>(ctx, 0)->stop(); + delete static_cast<std::shared_ptr<Timer> *>(getProperty<void *>(ctx, 0, Signature)); + getGlobal<void>(ctx, CallbackTable); + deleteProperty(ctx, -1, getProperty<std::string>(ctx, 0, "\xff""\xff""timer-key")); + pop(ctx); log::debug("plugin: timer destroyed"); return 0; }, 1}); - duk::setFinalizer(ctx, -2); + setFinalizer(ctx, -2); +#endif // Save a callback function into the callback table. - duk::getGlobal<void>(ctx, CallbackTable); - duk::dup(ctx, 2); - duk::putProperty(ctx, -2, hash); - duk::pop(ctx); + duk_get_global_string(ctx, CallbackTable); + duk_dup(ctx, 2); + duk_put_prop_string(ctx, -2, hash.c_str()); + duk_pop(ctx); return 0; } -const duk::Map<int> constants{ - { "Single", static_cast<int>(TimerType::Single) }, - { "Repeat", static_cast<int>(TimerType::Repeat) }, +const duk_number_list_entry constants[] = { + { "Single", static_cast<int>(TimerType::Single) }, + { "Repeat", static_cast<int>(TimerType::Repeat) }, + { nullptr, 0 } }; } // !namespace @@ -200,17 +180,18 @@ void TimerModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Function{constructor, 3}); - duk::put(plugin.context(), constants); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), methods); - duk::putProperty(plugin.context(), -2, "prototype"); - duk::putProperty(plugin.context(), -2, "Timer"); - duk::pop(plugin.context()); - duk::putGlobal(plugin.context(), CallbackTable, duk::Object{}); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_c_function(plugin.context(), constructor, 3); + duk_put_number_list(plugin.context(), -1, constants); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, methods); + duk_put_prop_string(plugin.context(), -2, "prototype"); + duk_put_prop_string(plugin.context(), -2, "Timer"); + duk_pop(plugin.context()); + duk_push_object(plugin.context()); + duk_put_global_string(plugin.context(), CallbackTable); } } // !irccd
--- a/lib/irccd/mod-unicode.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-unicode.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "js.hpp" +#include "duktape.hpp" #include "mod-unicode.hpp" #include "plugin-js.hpp" #include "unicode.hpp" @@ -34,9 +34,9 @@ * Returns: * True if the code is in the digit category. */ -duk::Ret isDigit(duk::Context *ctx) +duk_ret_t isDigit(duk_context *ctx) { - duk::push(ctx, unicode::isdigit(duk::get<int>(ctx, 0))); + duk_push_boolean(ctx, unicode::isdigit(duk_get_int(ctx, 0))); return 1; } @@ -50,9 +50,9 @@ * Returns: * True if the code is in the letter category. */ -duk::Ret isLetter(duk::Context *ctx) +duk_ret_t isLetter(duk_context *ctx) { - duk::push(ctx, unicode::isalpha(duk::get<int>(ctx, 0))); + duk_push_boolean(ctx, unicode::isalpha(duk_get_int(ctx, 0))); return 1; } @@ -66,9 +66,9 @@ * Returns: * True if the code is lower case. */ -duk::Ret isLower(duk::Context *ctx) +duk_ret_t isLower(duk_context *ctx) { - duk::push(ctx, unicode::islower(duk::get<int>(ctx, 0))); + duk_push_boolean(ctx, unicode::islower(duk_get_int(ctx, 0))); return 1; } @@ -82,9 +82,9 @@ * Returns: * True if the code is in the space category. */ -duk::Ret isSpace(duk::Context *ctx) +duk_ret_t isSpace(duk_context *ctx) { - duk::push(ctx, unicode::isspace(duk::get<int>(ctx, 0))); + duk_push_boolean(ctx, unicode::isspace(duk_get_int(ctx, 0))); return 1; } @@ -98,9 +98,9 @@ * Returns: * True if the code is title case. */ -duk::Ret isTitle(duk::Context *ctx) +duk_ret_t isTitle(duk_context *ctx) { - duk::push(ctx, unicode::istitle(duk::get<int>(ctx, 0))); + duk_push_boolean(ctx, unicode::istitle(duk_get_int(ctx, 0))); return 1; } @@ -114,20 +114,21 @@ * Returns: * True if the code is upper case. */ -duk::Ret isUpper(duk::Context *ctx) +duk_ret_t isUpper(duk_context *ctx) { - duk::push(ctx, unicode::isupper(duk::get<int>(ctx, 0))); + duk_push_boolean(ctx, unicode::isupper(duk_get_int(ctx, 0))); return 1; } -const duk::FunctionMap functions{ - { "isDigit", { isDigit, 1 } }, - { "isLetter", { isLetter, 1 } }, - { "isLower", { isLower, 1 } }, - { "isSpace", { isSpace, 1 } }, - { "isTitle", { isTitle, 1 } }, - { "isUpper", { isUpper, 1 } }, +const duk_function_list_entry functions[] = { + { "isDigit", isDigit, 1 }, + { "isLetter", isLetter, 1 }, + { "isLower", isLower, 1 }, + { "isSpace", isSpace, 1 }, + { "isTitle", isTitle, 1 }, + { "isUpper", isUpper, 1 }, + { nullptr, nullptr, 0 } }; } // !namespace @@ -139,13 +140,13 @@ void UnicodeModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), functions); - duk::putProperty(plugin.context(), -2, "Unicode"); - duk::pop(plugin.context()); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, functions); + duk_put_prop_string(plugin.context(), -2, "Unicode"); + duk_pop(plugin.context()); } } // !irccd
--- a/lib/irccd/mod-util.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/mod-util.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -24,7 +24,7 @@ namespace irccd { -namespace duk { +namespace { /** * Read parameters for Irccd.Util.format function, the object is defined as follow: @@ -37,30 +37,22 @@ * fieldn: ... * } */ -template <> -class TypeTraits<util::Substitution> { -public: - static util::Substitution get(duk::Context *ctx, int index) - { - util::Substitution params; +util::Substitution getSubstitution(duk_context *ctx, int index) +{ + util::Substitution params; - if (!duk::is<Object>(ctx, index)) - return params; + if (!duk_is_object(ctx, index)) + return params; - duk::enumerate(ctx, index, 0, true, [&] (duk::Context *) { - if (duk::get<std::string>(ctx, -2) == "date") - params.time = static_cast<time_t>(duk::get<double>(ctx, -1) / 1000); - else - params.keywords.insert({duk::get<std::string>(ctx, -2), duk::get<std::string>(ctx, -1)}); - }); + duk_enumerate(ctx, index, 0, true, [&] (duk_context *) { + if (duk_get_stdstring(ctx, -2) == "date") + params.time = static_cast<time_t>(duk_get_number(ctx, -1) / 1000); + else + params.keywords.insert({duk_get_string(ctx, -2), duk_get_string(ctx, -1)}); + }); - return params; - } -}; - -} // !duk - -namespace { + return params; +} /* * Function: Irccd.Util.format(text, parameters) @@ -74,12 +66,12 @@ * Returns: * The converted text. */ -duk::Ret format(duk::Context *ctx) +duk_ret_t format(duk_context *ctx) { try { - duk::push(ctx, util::format(duk::get<std::string>(ctx, 0), duk::get<util::Substitution>(ctx, 1))); + duk_push_stdstring(ctx, util::format(duk_get_stdstring(ctx, 0), getSubstitution(ctx, 1))); } catch (const std::exception &ex) { - duk::raise(ctx, duk::SyntaxError(ex.what())); + duk_throw(ctx, SyntaxError(ex.what())); } return 1; @@ -96,13 +88,13 @@ * Returns: * The nickname. */ -duk::Ret splituser(duk::Context *ctx) +duk_ret_t splituser(duk_context *ctx) { - const char *target = duk::require<const char *>(ctx, 0); + auto target = duk_require_string(ctx, 0); char nick[32] = {0}; irc_target_get_nick(target, nick, sizeof (nick) -1); - duk::push(ctx, std::string(nick)); + duk_push_string(ctx, nick); return 1; } @@ -118,21 +110,22 @@ * Returns: * The hostname. */ -duk::Ret splithost(duk::Context *ctx) +duk_ret_t splithost(duk_context *ctx) { - const char *target = duk::require<const char *>(ctx, 0); + auto target = duk_require_string(ctx, 0); char host[32] = {0}; irc_target_get_host(target, host, sizeof (host) -1); - duk::push(ctx, std::string(host)); + duk_push_string(ctx, host); return 1; } -const duk::FunctionMap functions{ - { "format", { format, DUK_VARARGS } }, - { "splituser", { splituser, 1 } }, - { "splithost", { splithost, 1 } } +const duk_function_list_entry functions[] = { + { "format", format, DUK_VARARGS }, + { "splituser", splituser, 1 }, + { "splithost", splithost, 1 }, + { nullptr, nullptr, 0 } }; } // !namespace @@ -144,13 +137,13 @@ void UtilModule::load(Irccd &, JsPlugin &plugin) { - duk::StackAssert sa(plugin.context()); + StackAssert sa(plugin.context()); - duk::getGlobal<void>(plugin.context(), "Irccd"); - duk::push(plugin.context(), duk::Object{}); - duk::put(plugin.context(), functions); - duk::putProperty(plugin.context(), -2, "Util"); - duk::pop(plugin.context()); + duk_get_global_string(plugin.context(), "Irccd"); + duk_push_object(plugin.context()); + duk_put_function_list(plugin.context(), -1, functions); + duk_put_prop_string(plugin.context(), -2, "Util"); + duk_pop(plugin.context()); } } // !irccd
--- a/lib/irccd/net.hpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/net.hpp Fri Jun 03 13:28:10 2016 +0200 @@ -2802,7 +2802,7 @@ : m_length(length) { assert(address); - assert(length <= sizeof (sockaddr_storage)); + assert(static_cast<unsigned>(length) <= sizeof (sockaddr_storage)); std::memset(&m_address, 0, sizeof (sockaddr_storage)); std::memcpy(&m_address, address, length);
--- a/lib/irccd/plugin-js.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/plugin-js.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -36,19 +36,19 @@ void JsPlugin::call(const std::string &name, unsigned nargs) { - duk::getGlobal<void>(m_context, name); + duk_get_global_string(m_context, name.c_str()); - if (duk::type(m_context, -1) == DUK_TYPE_UNDEFINED) + if (duk_get_type(m_context, -1) == DUK_TYPE_UNDEFINED) // Function not defined, remove the undefined value and all arguments. - duk::pop(m_context, nargs + 1); + duk_pop_n(m_context, nargs + 1); else { // Call the function and discard the result. - duk::insert(m_context, -nargs - 1); + duk_insert(m_context, -nargs - 1); - if (duk::pcall(m_context, nargs) != 0) - throw duk::exception(m_context, -1, true); + if (duk_pcall(m_context, nargs) != 0) + throw duk_exception(m_context, -1, true); - duk::pop(m_context); + duk_pop(m_context); } } @@ -60,16 +60,19 @@ void JsPlugin::putVars() { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::putGlobal<void *>(m_context, "\xff""\xff""plugin", this); - duk::putGlobal(m_context, "\xff""\xff""name", name()); - duk::putGlobal(m_context, "\xff""\xff""path", path()); + duk_push_pointer(m_context, this); + duk_get_global_string(m_context, "\xff""\xff""plugin"); + duk_push_stdstring(m_context, name()); + duk_put_global_string(m_context, "\xff""\xff""name"); + duk_push_stdstring(m_context, path()); + duk_put_global_string(m_context, "\xff""\xff""path"); } void JsPlugin::putPath(const std::string &varname, const std::string &append, path::Path type) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); bool found = true; std::string foundpath; @@ -88,43 +91,48 @@ if (!found) foundpath = path::clean(path::get(type, path::OwnerSystem) + append); - duk::getGlobal<void>(m_context, "Irccd"); - duk::getProperty<void>(m_context, -1, "Plugin"); - duk::putProperty(m_context, -1, varname, foundpath); - duk::pop(m_context, 2); + duk_get_global_string(m_context, "Irccd"); + duk_get_prop_string(m_context, -2, "Plugin"); + duk_push_stdstring(m_context, foundpath); + duk_put_prop_string(m_context, -2, varname.c_str()); + duk_pop_n(m_context, 2); } void JsPlugin::putConfig(const PluginConfig &config) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); // TODO: override dataPath, configPath, cachePath. // TODO: verify more that these values still exist. // Store plugin configuration into Irccd.Plugin.config. - duk::getGlobal<void>(m_context, "Irccd"); - duk::getProperty<void>(m_context, -1, "Plugin"); - duk::getProperty<void>(m_context, -1, "config"); + duk_get_global_string(m_context, "Irccd"); + duk_get_prop_string(m_context, -1, "Plugin"); + duk_get_prop_string(m_context, -1, "config"); - for (const auto &pair : config) - duk::putProperty(m_context, -1, pair.first, pair.second); + for (const auto &pair : config) { + duk_push_stdstring(m_context, pair.second); + duk_put_prop_string(m_context, -2, pair.first.c_str()); + } - duk::putProperty(m_context, -2, "config"); - duk::pop(m_context, 2); + duk_put_prop_string(m_context, -2, "config"); + duk_pop_n(m_context, 2); } void JsPlugin::putFormats() { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); + + duk_get_global_string(m_context, "Irccd"); + duk_get_prop_string(m_context, -1, "Plugin"); + duk_get_prop_string(m_context, -1, "format"); - duk::getGlobal<void>(m_context, "Irccd"); - duk::getProperty<void>(m_context, -1, "Plugin"); - duk::getProperty<void>(m_context, -1, "format"); + for (const auto &pair : formats()) { + duk_push_stdstring(m_context, pair.second); + duk_put_prop_string(m_context, -1, pair.first.c_str()); + } - for (const auto &pair : formats()) - duk::putProperty(m_context, -1, pair.first, pair.second); - - duk::pop(m_context, 3); + duk_pop_n(m_context, 3); } JsPlugin::JsPlugin(std::string name, std::string path, const PluginConfig &config) @@ -139,13 +147,13 @@ const std::string &mode, const std::string &arg) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, mode); - duk::push(m_context, arg); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, mode); + duk_push_stdstring(m_context, arg); call("onChannelMode", 5); } @@ -155,12 +163,12 @@ const std::string &channel, const std::string ¬ice) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, notice); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, notice); call("onChannelNotice", 4); } @@ -170,40 +178,40 @@ const std::string &channel, const std::string &message) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, message); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, message); call("onCommand", 4); } void JsPlugin::onConnect(Irccd &, const std::shared_ptr<Server> &server) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); + duk_push_server(m_context, server); call("onConnect", 1); } void JsPlugin::onInvite(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); call("onInvite", 3); } void JsPlugin::onJoin(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &channel) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); call("onJoin", 3); } @@ -214,19 +222,19 @@ const std::string &target, const std::string &reason) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, target); - duk::push(m_context, reason); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, target); + duk_push_stdstring(m_context, reason); call("onKick", 5); } void JsPlugin::onLoad(Irccd &irccd) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); /* * Duktape currently emit useless warnings when a file do @@ -235,9 +243,8 @@ #if defined(HAVE_STAT) struct stat st; - if (::stat(path().c_str(), &st) < 0) { + if (::stat(path().c_str(), &st) < 0) throw std::runtime_error(std::strerror(errno)); - } #endif /* @@ -251,26 +258,28 @@ putPath("cachePath", "plugin/" + name(), path::PathCache); // Try to load the file (does not call onLoad yet). - if (duk::pevalFile(m_context, path()) != 0) - throw duk::exception(m_context, -1, true); + if (duk_peval_file(m_context, path().c_str()) != 0) + throw duk_exception(m_context, -1, true); - duk::pop(m_context); + duk_pop(m_context); putConfig(config()); putFormats(); // Read metadata . - duk::getGlobal<void>(m_context, "info"); + duk_get_global_string(m_context, "info"); - if (duk::type(m_context, -1) == DUK_TYPE_OBJECT) { - setAuthor(duk::optionalProperty<std::string>(m_context, -1, "author", author())); - setLicense(duk::optionalProperty<std::string>(m_context, -1, "license", license())); - setSummary(duk::optionalProperty<std::string>(m_context, -1, "summary", summary())); - setVersion(duk::optionalProperty<std::string>(m_context, -1, "version", version())); + if (duk_get_type(m_context, -1) == DUK_TYPE_OBJECT) { + // TODO: bring back +#if 0 + setAuthor(optionalProperty<std::string>(m_context, -1, "author", author())); + setLicense(optionalProperty<std::string>(m_context, -1, "license", license())); + setSummary(optionalProperty<std::string>(m_context, -1, "summary", summary())); + setVersion(optionalProperty<std::string>(m_context, -1, "version", version())); +#endif } - duk::pop(m_context); - + duk_pop(m_context); call("onLoad", 0); } @@ -280,12 +289,12 @@ const std::string &channel, const std::string &message) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, message); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, message); call("onMessage", 4); } @@ -295,52 +304,53 @@ const std::string &channel, const std::string &message) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, message); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, message); call("onMe", 4); } void JsPlugin::onMode(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string &mode) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, mode); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, mode); call("onMode", 3); } void JsPlugin::onNames(Irccd &, const std::shared_ptr<Server> &server, const std::string &channel, const std::vector<std::string> &names) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, channel); - duk::push(m_context, names); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, channel); + // TODO + // duk_push_stdstring(m_context, names); call("onNames", 3); } void JsPlugin::onNick(Irccd &, const std::shared_ptr<Server> &server, const std::string &oldnick, const std::string &newnick) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, oldnick); - duk::push(m_context, newnick); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, oldnick); + duk_push_stdstring(m_context, newnick); call("onNick", 3); } void JsPlugin::onNotice(Irccd &, const std::shared_ptr<Server> &server, const std::string &origin, const std::string ¬ice) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, notice); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, notice); call("onNotice", 3); } @@ -350,12 +360,12 @@ const std::string &channel, const std::string &reason) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, reason); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, reason); call("onPart", 4); } @@ -364,11 +374,11 @@ const std::string &origin, const std::string &message) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, message); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, message); call("onQuery", 3); } @@ -377,17 +387,17 @@ const std::string &origin, const std::string &message) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, message); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, message); call("onQueryCommand", 3); } void JsPlugin::onReload(Irccd &) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); call("onReload"); } @@ -398,18 +408,18 @@ const std::string &channel, const std::string &topic) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, origin); - duk::push(m_context, channel); - duk::push(m_context, topic); + duk_push_server(m_context, server); + duk_push_stdstring(m_context, origin); + duk_push_stdstring(m_context, channel); + duk_push_stdstring(m_context, topic); call("onTopic", 4); } void JsPlugin::onUnload(Irccd &irccd) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); call("onUnload"); @@ -419,15 +429,20 @@ void JsPlugin::onWhois(Irccd &, const std::shared_ptr<Server> &server, const ServerWhois &whois) { - duk::StackAssert sa(m_context); + StackAssert sa(m_context); - duk::push(m_context, server); - duk::push(m_context, duk::Object{}); - duk::putProperty(m_context, -1, "nickname", whois.nick); - duk::putProperty(m_context, -1, "username", whois.user); - duk::putProperty(m_context, -1, "realname", whois.realname); - duk::putProperty(m_context, -1, "host", whois.host); - duk::putProperty(m_context, 1, "channels", whois.channels); + duk_push_server(m_context, server); + duk_push_object(m_context); + duk_push_stdstring(m_context, whois.nick); + duk_put_prop_string(m_context, -2, "nickname"); + duk_push_stdstring(m_context, whois.user); + duk_put_prop_string(m_context, -2, "username"); + duk_push_stdstring(m_context, whois.realname); + duk_put_prop_string(m_context, -2, "realname"); + duk_push_stdstring(m_context, whois.host); + duk_put_prop_string(m_context, -2, "host"); + // TODO + // duk_put_prop_string(m_context, -2, "channels", whois.channels); call("onWhois", 2); }
--- a/lib/irccd/plugin-js.hpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/plugin-js.hpp Fri Jun 03 13:28:10 2016 +0200 @@ -24,7 +24,7 @@ * \brief JavaScript plugins for irccd. */ -#include "js.hpp" +#include "duktape.hpp" #include "path.hpp" #include "plugin.hpp" #include "signals.hpp" @@ -40,7 +40,7 @@ class JsPlugin : public Plugin { private: // JavaScript context - duk::UniqueContext m_context; + UniqueContext m_context; // Store loaded modules. std::vector<std::shared_ptr<Module>> m_modules; @@ -68,7 +68,7 @@ * * \return the context */ - inline duk::UniqueContext &context() noexcept + inline UniqueContext &context() noexcept { return m_context; }
--- a/lib/irccd/server-event.cpp Tue May 31 22:33:32 2016 +0200 +++ b/lib/irccd/server-event.cpp Fri Jun 03 13:28:10 2016 +0200 @@ -54,7 +54,7 @@ // TODO: get generic error. try { m_exec(*plugin); - } catch (const duk::Exception &info) { + } catch (const Exception &info) { log::warning() << "plugin " << plugin->name() << ": error: " << info.what() << std::endl; if (!info.fileName.empty())