# HG changeset patch # User David Demelier # Date 1470832251 -7200 # Node ID 9af360f34c7db0a246332f03e9b26318b937b0ea # Parent 8e12411560343b23669f3098c4b1aa27509fe0b5 Misc: use raw duktape API diff -r 8e1241156034 -r 9af360f34c7d client/main.cpp --- a/client/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/client/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -37,6 +37,8 @@ #include #include +#if 0 + using namespace malikania; namespace { @@ -208,3 +210,8 @@ return 0; } + +#endif + +int main() {} + diff -r 8e1241156034 -r 9af360f34c7d libclient/CMakeLists.txt --- a/libclient/CMakeLists.txt Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/CMakeLists.txt Wed Aug 10 14:30:51 2016 +0200 @@ -31,6 +31,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-animation.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-animator.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client-resources-loader.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client-target.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-color.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-font.hpp @@ -65,6 +66,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-animation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-animator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client-resources-loader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client-target.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-color.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-font.cpp diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/animation.hpp --- a/libclient/malikania/animation.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/animation.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -29,7 +29,6 @@ #include #include -#include "js.hpp" #include "sprite.hpp" namespace malikania { @@ -87,7 +86,7 @@ * * \see Animator */ -class Animation : public duk::Bindable { +class Animation { private: Sprite m_sprite; AnimationFrames m_frames; diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/animator.hpp --- a/libclient/malikania/animator.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/animator.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -25,7 +25,6 @@ */ #include "elapsed-timer.hpp" -#include "js.hpp" namespace malikania { @@ -39,7 +38,7 @@ * * The animator contains an animation and a state. */ -class Animator : public duk::Bindable { +class Animator { private: Animation &m_animation; ElapsedTimer m_timer; diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/client-target.hpp --- a/libclient/malikania/client-target.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/client-target.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -23,7 +23,7 @@ namespace malikania { -class Client::Target : public duk::Bindable { +class Client::Target { public: Target() = default; diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/font.hpp --- a/libclient/malikania/font.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/font.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -27,7 +27,6 @@ #include #include -#include "js.hpp" #include "size.hpp" namespace malikania { @@ -36,7 +35,7 @@ * \class Font * \brief Font object. */ -class Font : public duk::Bindable { +class Font { private: class Backend; diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/image.hpp --- a/libclient/malikania/image.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/image.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -27,7 +27,6 @@ #include #include -#include "js.hpp" #include "point.hpp" #include "rectangle.hpp" #include "size.hpp" @@ -40,7 +39,7 @@ * \class Image * \brief Image object. */ -class Image : public duk::Bindable { +class Image { private: class Backend; diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-animation.cpp --- a/libclient/malikania/js-animation.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-animation.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,42 +16,89 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "client-resources-loader.hpp" +#include + +#include "js-client-resources-loader.hpp" #include "js-animation.hpp" namespace malikania { namespace { -duk::Ret constructor(duk::ContextPtr ctx) +const std::string Signature("\xff""\xff""malikania-animation-ptr"); + +duk_ret_t constructor(duk_context *ctx) { - duk::StackAssert sa(ctx); - if (!duk_is_constructor_call(ctx)) - duk::raise(ctx, DUK_ERR_ERROR, "animation must be new-constructed"); + duk_error(ctx, DUK_ERR_ERROR, "animation must be new-constructed"); try { - auto loader = duk::getGlobal(ctx, "\xff""\xff""loader"); - auto animation = loader->loadAnimation(duk::require(ctx, 0)); + auto loader = dukx_get_client_loader(ctx); + auto animation = loader->loadAnimation(duk_require_string(ctx, 0)); + + dukx_new_animation(ctx, new Animation(std::move(animation))); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } - duk::construct(ctx, std::make_shared(std::move(animation))); - } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } + return 0; +} + +duk_ret_t destructor(duk_context *ctx) +{ + duk_get_prop_string(ctx, 0, Signature.c_str()); + delete static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, Signature.c_str()); return 0; } } // !namespace -void loadMalikaniaAnimation(duk::ContextPtr ctx) +void dukx_new_animation(duk_context *ctx, Animation *animation) { - duk::StackAssert sa(ctx); + assert(ctx); + assert(animation); + + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_push_pointer(ctx, animation); + duk_put_prop_string(ctx, -2, Signature.c_str()); + duk_pop(ctx); +} + +Animation *dukx_require_animation(duk_context *ctx, duk_idx_t index) +{ + assert(ctx); + + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::push(ctx, duk::Function{constructor, 1}); - duk::putProperty(ctx, -2, "Animation"); - duk::pop(ctx); + duk_get_prop_string(ctx, index, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animation object"); + + return static_cast(ptr); +} + +void dukx_load_animation(duk_context *ctx) +{ + assert(ctx); + + StackAssert sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, 1); + duk_push_object(ctx); + duk_push_c_function(ctx, destructor, 1); + duk_set_finalizer(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Animation"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-animation.hpp --- a/libclient/malikania/js-animation.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-animation.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,12 +19,39 @@ #ifndef MALIKANIA_JS_ANIMATION_HPP #define MALIKANIA_JS_ANIMATION_HPP +#include + #include "animation.hpp" -#include "js.hpp" namespace malikania { -void loadMalikaniaAnimation(duk::ContextPtr ctx); +/** + * Construct an Animation object as this. + * + * \pre ctx != nullptr + * \pre animation != nullptr + * \param ctx the context + * \param animation the animation + */ +void dukx_new_animation(duk_context *ctx, Animation *animation); + +/** + * Get an Animation object at the given index or raise a JavaScript error. + * + * \pre ctx != nullptr + * \param ctx the context + * \param index the value index + * \return the Animation object + */ +Animation *dukx_require_animation(duk_context *ctx, duk_idx_t index); + +/** + * Load the Animation module into the context. + * + * \pre ctx != nullptr + * \param ctx the context + */ +void dukx_load_animation(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-animator.cpp --- a/libclient/malikania/js-animator.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-animator.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,6 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include + #include "js-animation.hpp" #include "js-animator.hpp" #include "js-point.hpp" @@ -25,61 +28,117 @@ namespace { -duk::Ret constructor(duk::ContextPtr ctx) +const std::string Signature("\xff""\xff""malikania-animator-ptr"); + +Animator *self(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animator object"); + + return static_cast(ptr); +} + +duk_ret_t constructor(duk_context *ctx) { if (!duk_is_constructor_call(ctx)) - duk::raise(ctx, DUK_ERR_ERROR, "animator must be new-constructed"); - - duk::construct(ctx, std::make_shared(*duk::require>(ctx, 0))); + duk_error(ctx, DUK_ERR_ERROR, "animator must be new-constructed"); // Be sure animation get not collected before. - duk::push(ctx, duk::This()); - duk::dup(ctx, 0); - duk::putProperty(ctx, -2, "\xff""\xff""animation-ref"); + dukx_new_animator(ctx, new Animator(*dukx_require_animation(ctx, 0))); + duk_push_this(ctx); + duk_dup(ctx, 0); + duk_put_prop_string(ctx, -2, "\xff""\xff""animation-ref"); return 0; } -duk::Ret draw(duk::ContextPtr ctx) +duk_ret_t destructor(duk_context *ctx) +{ + duk_get_prop_string(ctx, 0, Signature.c_str()); + delete static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, Signature.c_str()); + + return 0; +} + +duk_ret_t draw(duk_context *ctx) { try { - auto self = duk::self>(ctx); - auto window = duk::get>(ctx, 0); - auto point = duk::get(ctx, 1); - - self->draw(*window, point); + self(ctx)->draw(*dukx_require_window(ctx, 0), dukx_get_point(ctx, 1)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret update(duk::ContextPtr ctx) +duk_ret_t update(duk_context *ctx) { - duk::self>(ctx)->update(); + self(ctx)->update(); return 0; } -const duk::FunctionMap methods{ - { "draw", { draw, 2 } }, - { "update", { update, 0 } } +const duk_function_list_entry methods[] = { + { "draw", draw, 2 }, + { "update", update, 0 }, + { nullptr, nullptr, 0 } }; } // !namespace -void loadMalikaniaAnimator(duk::ContextPtr ctx) +void dukx_new_animator(duk_context *ctx, Animator *animator) { - duk::StackAssert sa(ctx); + assert(ctx); + assert(animator); + + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_push_pointer(ctx, animator); + duk_put_prop_string(ctx, -2, Signature.c_str()); + duk_pop(ctx); +} + +Animator *dukx_require_animator(duk_context *ctx, duk_idx_t index) +{ + assert(ctx); + + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::push(ctx, duk::Function{constructor, 1}); - duk::push(ctx, duk::Object()); - duk::put(ctx, methods); - duk::putProperty(ctx, -2, "prototype"); - duk::putProperty(ctx, -2, "Animator"); - duk::pop(ctx); + duk_get_prop_string(ctx, index, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animator object"); + + return static_cast(ptr); +} + +void dukx_load_animator(duk_context *ctx) +{ + assert(ctx); + + StackAssert sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, 1); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_push_c_function(ctx, destructor, 1); + duk_set_finalizer(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Animator"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-animator.hpp --- a/libclient/malikania/js-animator.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-animator.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -20,11 +20,31 @@ #define MALIKANIA_JS_ANIMATOR_HPP #include "animator.hpp" -#include "js.hpp" +#include "duktape.hpp" namespace malikania { -void loadMalikaniaAnimator(duk::ContextPtr ctx); +/** + * Construct an Animator object as this. + * + * \pre ctx != nullptr + * \pre animator != nullptr + * \param ctx the context + * \param animator the animator + */ +void dukx_new_animator(duk_context *ctx, Animator *animator); + +/** + * Get the animator at the given index. + * + * \pre ctx != nullptr + * \param ctx the context + * \param index the value index + * \return the animator + */ +Animator *dukx_require_animator(duk_context *ctx, duk_idx_t index); + +void dukx_load_animator(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-client-resources-loader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/js-client-resources-loader.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -0,0 +1,59 @@ +/* + * js-client-resources-loader.cpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * 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. + */ + +#include + +#include "js-client-resources-loader.hpp" +#include "js-resources-loader.hpp" + +namespace malikania { + +namespace { + +const std::string Variable("\xff""\xff""malikania-client-resources-loader"); + +} // !namespace + +void dukx_put_client_loader(duk_context *ctx, ClientResourcesLoader *loader) +{ + assert(ctx); + assert(loader); + + // Also store as parent. + dukx_put_loader(ctx, loader); + + StackAssert sa(ctx); + + duk_push_pointer(ctx, loader); + duk_put_global_string(ctx, Variable.c_str()); +} + +ClientResourcesLoader *dukx_get_client_loader(duk_context *ctx) +{ + assert(ctx); + + StackAssert sa(ctx); + + duk_get_global_string(ctx, Variable.c_str()); + auto ptr = static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return static_cast(ptr); +} + +} // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-client-resources-loader.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/js-client-resources-loader.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -0,0 +1,33 @@ +/* + * js-client-resources-loader.hpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * 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 MALIKANIA_JS_CLIENT_RESOURCES_LOADER_H +#define MALIKANIA_JS_CLIENT_RESOURCES_LOADER_H + +#include "client-resources-loader.hpp" +#include "duktape.hpp" + +namespace malikania { + +void dukx_put_client_loader(duk_context *ctx, ClientResourcesLoader *); + +ClientResourcesLoader *dukx_get_client_loader(duk_context *ctx); + +} // !malikania + +#endif // !MALIKANIA_JS_CLIENT_RESOURCES_LOADER_H diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-client-target.cpp --- a/libclient/malikania/js-client-target.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-client-target.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -1,3 +1,21 @@ +/* + * js-client-target.cpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * 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. + */ + #include "js-client-target.hpp" namespace malikania { @@ -9,32 +27,29 @@ namespace { -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { - - return 0; } -duk::Ret draw(duk::ContextPtr ctx) +duk_ret_t draw(duk_context *ctx) { - //duk::self>(ctx)->draw(); - return 0; } } // !namespace -void loadMalikaniaClientTarget(duk::ContextPtr ctx) +void dukx_load_client_target(duk_context *ctx) { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::getProperty(ctx, -1, "Client"); - duk::push(ctx, duk::Function{constructor}); - duk::putProperty(ctx, -1, "prototype", duk::Object()); - duk::putProperty(ctx, -2, "Target"); - duk::pop(ctx, 2); + duk_get_global_string(ctx, "Malikania"); + duk_get_prop_string(ctx, -1, "Client"); + duk_push_c_function(ctx, constructor, 1); + duk_push_object(ctx); + duk_put_prop_string(ctx, -1, "prototype"); + duk_put_prop_string(ctx, -2, "Target"); + duk_pop_2(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-client-target.hpp --- a/libclient/malikania/js-client-target.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-client-target.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -1,12 +1,30 @@ +/* + * js-client-target.hpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * 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 MALIKANIA_JS_CLIENT_TARGET_HPP #define MALIKANIA_JS_CLIENT_TARGET_HPP #include "client-target.hpp" -#include "js.hpp" +#include "duktape.hpp" namespace malikania { -void loadMalikaniaClientTarget(duk::ContextPtr ctx); +void dukx_load_client_target(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-client.cpp --- a/libclient/malikania/js-client.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-client.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -1,3 +1,23 @@ +/* + * js-client.cpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * 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. + */ + +#include + #include "js-client.hpp" #include "js-client-target.hpp" #include "js-window.hpp" @@ -6,48 +26,56 @@ namespace { -duk::Ret draw(duk::ContextPtr ctx) +duk_ret_t draw(duk_context *) { +#if 0 try { duk::self>(ctx)->draw(); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } +#endif return 0; } -duk::Ret setTarget(duk::ContextPtr ctx) +duk_ret_t setTarget(duk_context *) { - auto self = duk::self>(ctx); +#if 0 + auto self = duk::self(ctx); auto target = duk::get>(ctx, 0); self->setTarget(std::move(target)); +#endif return 0; } -duk::Ret update(duk::ContextPtr ctx) +duk_ret_t update(duk_context *) { +#if 0 try { duk::self>(ctx)->update(); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } +#endif return 0; } -const duk::FunctionMap methods{ - { "draw", { draw, 0 } }, - { "setTarget", { setTarget, 1 } }, - { "update", { update, 0 } } +const duk_function_list_entry methods[] = { + { "draw", draw, 0 }, + { "setTarget", setTarget, 1 }, + { "update", update, 0 }, + { nullptr, nullptr, 0 } }; } // !namespace -void loadMalikaniaClient(duk::ContextPtr ctx) +void dukx_load_client(duk_context *ctx) { +#if 0 duk::StackAssert sa(ctx); duk::getGlobal(ctx, "Malikania"); @@ -59,6 +87,7 @@ duk::putProperty(ctx, -2, "prototype"); duk::putProperty(ctx, -2, "Client"); duk::pop(ctx); +#endif } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-client.hpp --- a/libclient/malikania/js-client.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-client.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -1,31 +1,30 @@ +/* + * js-client.hpp -- client resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 Malikania Authors + * + * 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 MALIKANIA_JS_CLIENT_HPP #define MALIKANIA_JS_CLIENT_HPP #include "client.hpp" -#include "js.hpp" +#include "duktape.hpp" namespace malikania { -namespace duk { - -template <> -class TypeTraits { -public: - static inline void prototype(ContextPtr ctx) - { - StackAssert sa(ctx, 1); - - getGlobal(ctx, "Malikania"); - getProperty(ctx, -1, "Client"); - getProperty(ctx, -1, "prototype"); - remove(ctx, -2); - remove(ctx, -2); - } -}; - -} // !duk - -void loadMalikaniaClient(duk::ContextPtr ctx); +void dukx_load_client(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-color.cpp --- a/libclient/malikania/js-color.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-color.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -25,11 +25,11 @@ namespace { -std::uint8_t clampComponent(duk::ContextPtr ctx, int value, bool required) +std::uint8_t clampComponent(duk_context *ctx, int value, bool required) { if (value < 0 || value > 255) { if (required) - duk::raise(ctx, DUK_ERR_RANGE_ERROR, "%d is out of range (0, 255)", value); + duk_error(ctx, DUK_ERR_RANGE_ERROR, "%d is out of range (0, 255)", value); else value = util::clamp(value, 0, 255); } @@ -37,46 +37,53 @@ return static_cast(value); } -Color parseString(duk::ContextPtr ctx, duk::Index index, bool required) +Color parseString(duk_context *ctx, duk_idx_t index, bool required) { - assert(duk::type(ctx, index) == DUK_TYPE_STRING); + assert(duk_is_string(ctx, index)); Color color; try { - color = Color(duk::get(ctx, index)); + color = Color(duk_get_string(ctx, index)); } catch (const std::exception &ex) { - if (required) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } + if (required) + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return color; } -Color parseObject(duk::ContextPtr ctx, duk::Index index, bool required) +Color parseObject(duk_context *ctx, duk_idx_t index, bool required) { - assert(duk::type(ctx, index) == DUK_TYPE_OBJECT); + assert(duk_is_object(ctx, index)); + + auto require = [&] (const auto prop) -> std::uint8_t { + if (required && !duk_has_prop_string(ctx, index, prop)) + duk_error(ctx, DUK_ERR_ERROR, "missing %s property in color description", prop); - auto require = [&] (const std::string &property) -> std::uint8_t { - if (required && !duk::hasProperty(ctx, index, property)) { - duk::raise(ctx, DUK_ERR_ERROR, "missing %s property in color description", property.c_str()); - } + duk_get_prop_string(ctx, index, prop); + auto comp = duk_get_int(ctx, -1); + duk_pop(ctx); - return clampComponent(ctx, duk::getProperty(ctx, index, property), required); + return clampComponent(ctx, comp, required); }; + // Alpha is optional. + duk_get_prop_string(ctx, index, "alpha"); + auto alpha = duk_is_number(ctx, -1) ? duk_to_int(ctx, -1) : 255; + duk_pop(ctx); + return Color( require("red"), require("green"), require("blue"), - clampComponent(ctx, duk::optionalProperty(ctx, index, "alpha", 255), required) + clampComponent(ctx, alpha, required) ); } -Color parse(duk::ContextPtr ctx, duk::Index index, bool required, Color color = {}) +Color parse(duk_context *ctx, duk_idx_t index, bool required, Color color = {}) { - switch (duk::type(ctx, index)) { + switch (duk_get_type(ctx, index)) { case DUK_TYPE_STRING: color = parseString(ctx, index, required); break; @@ -85,7 +92,7 @@ break; default: if (required) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "color (string, object) expected"); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "color (string, object) expected"); break; } @@ -93,35 +100,37 @@ return color; } -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { Color color; /* - * The constructor allows an additional signature that takes 4 number arguments, otherwise use the literal - * parsing functions. + * The constructor allows an additional signature that takes 4 number + * arguments, otherwise use the literal parsing functions. */ - if (duk::top(ctx) >= 3) { + if (duk_get_top(ctx) >= 3) { + // Alpha is optional. + auto alpha = duk_is_number(ctx, 3) ? duk_to_int(ctx, 3) : 255; + color = Color( - clampComponent(ctx, duk::require(ctx, 0), true), - clampComponent(ctx, duk::require(ctx, 1), true), - clampComponent(ctx, duk::require(ctx, 2), true), - clampComponent(ctx, duk::optional(ctx, 3, 255), true) + clampComponent(ctx, duk_require_int(ctx, 0), true), + clampComponent(ctx, duk_require_int(ctx, 1), true), + clampComponent(ctx, duk_require_int(ctx, 2), true), + clampComponent(ctx, alpha, true) ); - } else if (duk::top(ctx) == 1) + } else if (duk_get_top(ctx) == 1) color = parse(ctx, 0, true); - duk::Ret ret; + duk_ret_t ret; // Allow both constructor and non constructor calls. if (duk_is_constructor_call(ctx)) { - duk::push(ctx, duk::This()); - /* TODO: use duk::put when available */ - duk::TypeTraits::put(ctx, color); - duk::pop(ctx); + duk_push_this(ctx); + dukx_put_color(ctx, color); + duk_pop(ctx); ret = 0; } else { - duk::push(ctx, color); + dukx_push_color(ctx, color); ret = 1; } @@ -130,53 +139,53 @@ } //! namespace -namespace duk { - -Color TypeTraits::get(ContextPtr ctx, Index index) +Color dukx_get_color(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, false); } -Color TypeTraits::require(ContextPtr ctx, Index index) +Color dukx_require_color(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, true); } -Color TypeTraits::optional(ContextPtr ctx, Index index, Color def) +Color dukx_optional_color(duk_context *ctx, duk_idx_t index, Color def) { return parse(ctx, index, false, std::move(def)); } -void TypeTraits::push(ContextPtr ctx, const Color &color) +void dukx_push_color(duk_context *ctx, const Color &color) { - duk::StackAssert sa(ctx, 1); + StackAssert sa(ctx, 1); - duk::push(ctx, Object()); - /* TODO: use duk::put when available */ - duk::TypeTraits::put(ctx, color); + duk_push_object(ctx); + dukx_put_color(ctx, color); } -void TypeTraits::put(ContextPtr ctx, const Color &color) +void dukx_put_color(duk_context *ctx, const Color &color) { - assert(type(ctx, -1) == DUK_TYPE_OBJECT); + assert(duk_is_object(ctx, -1)); StackAssert sa(ctx, 0); - putProperty(ctx, -1, "red", static_cast(color.red())); - putProperty(ctx, -1, "green", static_cast(color.green())); - putProperty(ctx, -1, "blue", static_cast(color.blue())); - putProperty(ctx, -1, "alpha", static_cast(color.alpha())); + duk_push_uint(ctx, color.red()); + duk_put_prop_string(ctx, -2, "red"); + duk_push_uint(ctx, color.green()); + duk_put_prop_string(ctx, -2, "green"); + duk_push_uint(ctx, color.blue()); + duk_put_prop_string(ctx, -2, "blue"); + duk_push_uint(ctx, color.alpha()); + duk_put_prop_string(ctx, -2, "alpha"); } -} // !duk - -void loadMalikaniaColor(duk::ContextPtr ctx) +void dukx_load_color(duk_context *ctx) { - duk::StackAssert sa(ctx, 0); + StackAssert sa(ctx, 0); - duk::getGlobal(ctx, "Malikania"); - duk::putProperty(ctx, -1, "Color", duk::Function{constructor, DUK_VARARGS}); - duk::pop(ctx); + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Color"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-color.hpp --- a/libclient/malikania/js-color.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-color.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,14 +19,8 @@ #ifndef MALIKANIA_JS_COLOR_HPP #define MALIKANIA_JS_COLOR_HPP -#include "color.hpp" -#include "js.hpp" - -namespace malikania { - -namespace duk { - /** + * \file js-color.h * \brief JavaScript binding for Color. * * Colors can be created from plain JavaScript object. @@ -42,61 +36,61 @@ * * It can also takes strings like "#rrggbbaa" and SVG names. */ -template <> -class TypeTraits { -public: - /** - * Get a color. - * - * May return a default value or a color with adjusted components. - * - * \param ctx the context - * \param index the index - */ - static Color get(ContextPtr ctx, Index index); + +#include "color.hpp" +#include "duktape.hpp" + +namespace malikania { - /** - * Require a color. - * - * If the color has any invalid component, raise a JavaScript error. - * - * \param ctx the context - * \param index the index - */ - static Color require(ContextPtr ctx, Index index); +/** + * Get a color. + * + * May return a default value or a color with adjusted components. + * + * @param ctx the context + * @param index the index + */ +Color dukx_get_color(duk_context *ctx, duk_idx_t index); + +/** + * Require a color. + * + * If the color has any invalid component, raise a JavaScript error. + * + * @param ctx the context + * @param index the index + */ +Color dukx_require_color(duk_context *ctx, duk_idx_t index); - /** - * Like get, but return the default value only if the value at the given index is not an object or not a string, - * otherwise, adjust invalid values. - * - * \param ctx the context - * \param index the index - * \param def the default value - */ - static Color optional(ContextPtr ctx, Index index, Color def); +/** + * Like get, but return the default value only if the value at the given + * index is not an object or not a string, otherwise, adjust invalid values. + * + * @param ctx the context + * @param index the index + * @param def the default value + */ +Color dukx_optional_color(duk_context *ctx, duk_idx_t index, Color def); - /** - * Push the color as object. - * - * \param ctx the context - * \param color the color - */ - static void push(ContextPtr ctx, const Color &color); +/** + * Push the color as object. + * + * @param ctx the context + * @param color the color + */ +void dukx_push_color(duk_context *ctx, const Color &color); - /** - * Put the color properties into the object at the top of the stack. - * - * \pre the top value must be an object - * \param ctx the context - * \param color the color - */ - static void put(ContextPtr ctx, const Color &color); -}; +/** + * Put the color properties into the object at the top of the stack. + * + * @pre the top value must be an object + * @param ctx the context + * @param color the color + */ +void dukx_put_color(duk_context *ctx, const Color &color); -} // !duk - -void loadMalikaniaColor(duk::ContextPtr ctx); +void dukx_load_color(duk_context *ctx); } // !malikania -#endif // !MALIKANIA_JS_COLOR_HPP \ No newline at end of file +#endif // !MALIKANIA_JS_COLOR_HPP diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-font.cpp --- a/libclient/malikania/js-font.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-font.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,7 +16,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "client-resources-loader.hpp" +#include + +#include "js-client-resources-loader.hpp" #include "js-font.hpp" #include "js-size.hpp" @@ -24,57 +26,104 @@ namespace { -duk::Ret constructor(duk::ContextPtr ctx) +const std::string Signature("\xff""\xff""malikania-font-ptr"); + +Font *self(duk_context *ctx) { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Font object"); + + return static_cast(ptr); +} + +duk_ret_t constructor(duk_context *ctx) +{ + StackAssert sa(ctx); if (!duk_is_constructor_call(ctx)) - duk::raise(ctx, DUK_ERR_ERROR, "font must be new-constructed"); + duk_error(ctx, DUK_ERR_ERROR, "font must be new-constructed"); try { - auto loader = duk::getGlobal(ctx, "\xff""\xff""loader"); - auto id = duk::require(ctx, 0); - auto size = duk::require(ctx, 1); + auto loader = dukx_get_client_loader(ctx); + auto id = duk_require_string(ctx, 0); + auto size = duk_require_int(ctx, 1); if (size < 0) - duk::raise(ctx, DUK_ERR_RANGE_ERROR, "%d must not be negative", size); + duk_error(ctx, DUK_ERR_RANGE_ERROR, "%d must not be negative", size); - duk::construct(ctx, std::make_shared(loader->loadFont(id, static_cast(size)))); + dukx_new_font(ctx, new Font(loader->loadFont(id, static_cast(size)))); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret clip(duk::ContextPtr ctx) +duk_ret_t clip(duk_context *ctx) { try { - duk::push(ctx, duk::self>(ctx)->clip(duk::require(ctx, 0))); + dukx_push_size(ctx, self(ctx)->clip(duk_require_string(ctx, 0))); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 1; } -const duk::FunctionMap methods{ - { "clip", { clip, 1 } } +const duk_function_list_entry methods[] = { + { "clip", clip, 1 }, + { nullptr, nullptr, 0 } }; } // !namespace -void loadMalikaniaFont(duk::ContextPtr ctx) +void dukx_new_font(duk_context *ctx, Font *font) { - duk::StackAssert sa(ctx); + assert(ctx); + assert(font); + + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_push_pointer(ctx, font); + duk_put_prop_string(ctx, -2, Signature.c_str()); + duk_pop(ctx); +} + +Font *dukx_require_font(duk_context *ctx, duk_idx_t index) +{ + assert(ctx); + + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::push(ctx, duk::Function{constructor, 2}); - duk::push(ctx, duk::Object()); - duk::put(ctx, methods); - duk::putProperty(ctx, -2, "prototype"); - duk::putProperty(ctx, -2, "Font"); - duk::pop(ctx); + duk_get_prop_string(ctx, index, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Font object"); + + return static_cast(ptr); +} + +void dukx_load_font(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, 2); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Font"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-font.hpp --- a/libclient/malikania/js-font.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-font.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,12 +19,16 @@ #ifndef MALIKANIA_JS_FONT_HPP #define MALIKANIA_JS_FONT_HPP +#include "duktape.hpp" #include "font.hpp" -#include "js.hpp" namespace malikania { -void loadMalikaniaFont(duk::ContextPtr ctx); +void dukx_new_font(duk_context *ctx, Font *font); + +Font *dukx_require_font(duk_context *ctx, duk_idx_t index); + +void dukx_load_font(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-image.cpp --- a/libclient/malikania/js-image.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-image.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "client-resources-loader.hpp" +#include "js-client-resources-loader.hpp" #include "js-image.hpp" #include "js-point.hpp" #include "js-rectangle.hpp" @@ -27,76 +27,106 @@ namespace { -duk::Ret size(duk::ContextPtr ctx) +const std::string Signature("\xff""\xff""malikania-image-ptr"); + +Image *self(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Animator object"); + + return static_cast(ptr); +} + +duk_ret_t size(duk_context *ctx) { try { - duk::push(ctx, duk::self>(ctx)->size()); + dukx_push_size(ctx, self(ctx)->size()); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 1; } -duk::Ret draw(duk::ContextPtr ctx) +duk_ret_t draw(duk_context *ctx) { try { - auto self = duk::self>(ctx); - auto window = duk::get>(ctx, 0); + auto image = self(ctx); + auto window = dukx_require_window(ctx, 0); - if (duk::top(ctx) == 2) - self->draw(*window, duk::get(ctx, 1)); - else if (duk::top(ctx) == 3) - self->draw(*window, duk::get(ctx, 1), duk::get(ctx, 2)); + if (duk_get_top(ctx) == 2) + image->draw(*window, dukx_get_point(ctx, 1)); + else if (duk_get_top(ctx) == 3) + image->draw(*window, dukx_get_rect(ctx, 1), dukx_get_rect(ctx, 2)); else - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "invalid number of arguments: #%d", duk::top(ctx)); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "invalid number of arguments: #%d", duk_get_top(ctx)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { - if (!duk_is_constructor_call(ctx)) { - duk::raise(ctx, DUK_ERR_ERROR, "image must be new-constructed"); - } + if (!duk_is_constructor_call(ctx)) + duk_error(ctx, DUK_ERR_ERROR, "image must be new-constructed"); try { - auto loader = duk::getGlobal(ctx, "\xff""\xff""loader"); - auto image = loader->loadImage(duk::require(ctx, 0)); + auto loader = dukx_get_client_loader(ctx); + auto image = new Image(loader->loadImage(duk_require_string(ctx, 0))); - duk::construct(ctx, std::make_shared(std::move(image))); - duk::push(ctx, duk::This()); - duk::push(ctx, "size"); - duk::push(ctx, duk::Function{size, 0}); - duk::defineProperty(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - duk::pop(ctx); + dukx_new_image(ctx, image); + duk_push_this(ctx); + duk_push_string(ctx, "size"); + duk_push_c_function(ctx, size, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_pop(ctx); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -const duk::FunctionMap methods{ - { "draw", { draw, DUK_VARARGS } } +const duk_function_list_entry methods[] = { + { "draw", draw, DUK_VARARGS }, + { nullptr, nullptr, 0 } }; } // !namespace -void loadMalikaniaImage(duk::ContextPtr ctx) +void dukx_new_image(duk_context *ctx, Image *image) { - duk::StackAssert sa(ctx); + assert(ctx); + assert(image); + + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::push(ctx, duk::Function{constructor, 1}); - duk::push(ctx, duk::Object()); - duk::put(ctx, methods); - duk::putProperty(ctx, -2, "prototype"); - duk::putProperty(ctx, -2, "Image"); - duk::pop(ctx); + duk_push_this(ctx); + duk_push_pointer(ctx, image); + duk_put_prop_string(ctx, -2, Signature.c_str()); + duk_pop(ctx); +} + +void dukx_load_image(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, 1); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Image"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-image.hpp --- a/libclient/malikania/js-image.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-image.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,12 +19,14 @@ #ifndef MALIKANIA_JS_IMAGE_HPP #define MALIKANIA_JS_IMAGE_HPP +#include "duktape.hpp" #include "image.hpp" -#include "js.hpp" namespace malikania { -void loadMalikaniaImage(duk::ContextPtr ctx); +void dukx_new_image(duk_context *ctx, Image *image); + +void dukx_load_image(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-line.cpp --- a/libclient/malikania/js-line.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-line.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,37 +16,37 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include "js-line.hpp" namespace malikania { namespace { -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { Line line; - if (duk::top(ctx) == 4) { + if (duk_get_top(ctx) == 4) { line = Line( - duk::get(ctx, 0), - duk::get(ctx, 1), - duk::get(ctx, 2), - duk::get(ctx, 3) + duk_get_int(ctx, 0), + duk_get_int(ctx, 1), + duk_get_int(ctx, 2), + duk_get_int(ctx, 3) ); - } else if (duk::top(ctx) == 1) - line = duk::require(ctx, 0); + } else if (duk_get_top(ctx) == 1) + line = dukx_require_line(ctx, 0); - duk::Ret ret; + duk_ret_t ret; /* Allow both constructor and non constructor calls */ if (duk_is_constructor_call(ctx)) { - duk::push(ctx, duk::This()); - /* TODO: use duk::put when available */ - duk::TypeTraits::put(ctx, line); - duk::pop(ctx); + duk_push_this(ctx); + dukx_put_line(ctx, line); ret = 0; } else { - duk::push(ctx, line); + dukx_push_line(ctx, line); ret = 1; } @@ -55,38 +55,37 @@ } // !namespace -namespace duk { - -Line TypeTraits::get(ContextPtr ctx, Index index) +Line dukx_get_line(duk_context *ctx, duk_idx_t index) { - duk::StackAssert sa(ctx); + auto get = [&] (auto name) { + StackAssert sa(ctx); - return Line( - duk::getProperty(ctx, index, "x1"), - duk::getProperty(ctx, index, "y1"), - duk::getProperty(ctx, index, "x2"), - duk::getProperty(ctx, index, "y2") - ); + duk_get_prop_string(ctx, index, name); + auto v = duk_get_int(ctx, -1); + duk_pop(ctx); + + return v; + }; + + return Line(get("x1"), get("y1"), get("x2"), get("y2")); } -Line TypeTraits::require(ContextPtr ctx, Index index) +Line dukx_require_line(duk_context *ctx, duk_idx_t index) { - duk::StackAssert sa(ctx); + auto get = [&] (auto prop) { + if (!duk_has_prop_string(ctx, index, prop)) + duk_error(ctx, DUK_ERR_ERROR, "missing %s property in line description", prop); - auto get = [&] (const std::string &property) -> int { - if (!duk::hasProperty(ctx, index, property)) - duk::raise(ctx, DUK_ERR_ERROR, "missing %s property in line description", property.c_str()); + duk_get_prop_string(ctx, index, prop); - duk::getProperty(ctx, index, property); - - if (!duk::is(ctx, -1)) { - duk::pop(ctx); - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "property %s is not an int", property.c_str()); + if (!duk_is_number(ctx, -1)) { + duk_pop(ctx); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "property %s is not an int", prop); } - int value = duk::get(ctx, -1); + auto value = duk_to_int(ctx, -1); - duk::pop(ctx); + duk_pop(ctx); return value; }; @@ -94,40 +93,43 @@ return Line(get("x1"), get("y1"), get("x2"), get("y2")); } -Line TypeTraits::optional(ContextPtr ctx, Index index, Line def) +Line dukx_optional_line(duk_context *ctx, duk_idx_t index, Line def) { - return duk::is(ctx, index) ? get(ctx, index) : def; + return duk_is_object(ctx, index) ? dukx_get_line(ctx, index) : def; } -void TypeTraits::push(ContextPtr ctx, const Line &line) +void dukx_push_line(duk_context *ctx, const Line &line) { - duk::StackAssert sa(ctx, 1); + StackAssert sa(ctx, 1); - duk::push(ctx, duk::Object()); - duk::TypeTraits::put(ctx, line); + duk_push_object(ctx); + dukx_put_line(ctx, line); } -void TypeTraits::put(ContextPtr ctx, const Line &line) +void dukx_put_line(duk_context *ctx, const Line &line) { - assert(duk::is(ctx, -1)); + assert(duk_is_object(ctx, -1)); + + StackAssert sa(ctx); - duk::StackAssert sa(ctx); - - duk::putProperty(ctx, -1, "x1", line.x1()); - duk::putProperty(ctx, -1, "y1", line.y1()); - duk::putProperty(ctx, -1, "x2", line.x2()); - duk::putProperty(ctx, -1, "y2", line.y2()); + duk_push_int(ctx, line.x1()); + duk_put_prop_string(ctx, -2, "x1"); + duk_push_int(ctx, line.y1()); + duk_put_prop_string(ctx, -2, "y1"); + duk_push_int(ctx, line.x2()); + duk_put_prop_string(ctx, -2, "x2"); + duk_push_int(ctx, line.y2()); + duk_put_prop_string(ctx, -2, "y2"); } -} // !duk - -void loadMalikaniaLine(duk::ContextPtr ctx) +void dukx_load_line(duk_context *ctx) { - duk::StackAssert sa(ctx, 0); + StackAssert sa(ctx, 0); - duk::getGlobal(ctx, "Malikania"); - duk::putProperty(ctx, -1, "Line", duk::Function{constructor, DUK_VARARGS}); - duk::pop(ctx); + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Line"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-line.hpp --- a/libclient/malikania/js-line.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-line.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,14 +19,8 @@ #ifndef MALIKANIA_JS_LINE_HPP #define MALIKANIA_JS_LINE_HPP -#include "js.hpp" -#include "line.hpp" - -namespace malikania { - -namespace duk { - /** + * \file js-line.h * \brief JavaScript binding for Line. * * Lines are plain objects. @@ -40,59 +34,59 @@ * } * ```` */ -template <> -class TypeTraits { -public: - /** - * Get a line. - * - * \param ctx the context - * \param index the index - * \return the line - */ - static Line get(ContextPtr ctx, Index index); + +#include "duktape.hpp" +#include "line.hpp" + +namespace malikania { - /** - * Require a line. - * - * If value is not an object or any property is invalid, raise a JavaScript error. - * - * \param ctx the context - * \param index the index - * \return the line - */ - static Line require(ContextPtr ctx, Index index); +/** + * Get a line. + * + * @param ctx the context + * @param index the index + * @return the line + */ +Line dukx_get_line(duk_context *ctx, duk_idx_t index); + +/** + * Require a line. + * + * If value is not an object or any property is invalid, raise a JavaScript error. + * + * @param ctx the context + * @param index the index + * @return the line + */ +Line dukx_require_line(duk_context *ctx, duk_idx_t index); - /** - * Like get but return def if the value at the given index is not an object. - * - * \param ctx the context - * \param index the index - * \param def the default value - * \return the line - */ - static Line optional(ContextPtr ctx, Index index, Line def); +/** + * Like get but return def if the value at the given index is not an object. + * + * @param ctx the context + * @param index the index + * @param def the default value + * @return the line + */ +Line dukx_optional_line(duk_context *ctx, duk_idx_t index, Line def); - /** - * Push the line as object. - * - * \param ctx the context - * \param line the line - */ - static void push(ContextPtr ctx, const Line &line); +/** + * Push the line as object. + * + * @param ctx the context + * @param line the line + */ +void dukx_push_line(duk_context *ctx, const Line &line); - /** - * Put the line properties into the object at the top of the stack. - * - * \param ctx the context - * \param line the line - */ - static void put(ContextPtr ctx, const Line &line); -}; +/** + * Put the line properties into the object at the top of the stack. + * + * @param ctx the context + * @param line the line + */ +void dukx_put_line(duk_context *ctx, const Line &line); -} // !duk - -void loadMalikaniaLine(duk::ContextPtr ctx); +void dukx_load_line(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-point.cpp --- a/libclient/malikania/js-point.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-point.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,49 +16,61 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include "js-point.hpp" namespace malikania { namespace { -Point parse(duk::ContextPtr ctx, duk::Index index, bool required, Point point = {}) +Point parse(duk_context *ctx, duk_idx_t index, bool required, Point point = {}) { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); + + if (duk_is_object(ctx, index)) { + if (required && !duk_has_prop_string(ctx, index, "x")) + duk_error(ctx, DUK_ERR_ERROR, "missing x property in point description"); + else if (required && !duk_has_prop_string(ctx, index, "y")) + duk_error(ctx, DUK_ERR_ERROR, "missing y property in point description"); - if (duk::type(ctx, index) == DUK_TYPE_OBJECT){ - if (required && !duk::hasProperty(ctx, index, "x")) - duk::raise(ctx, DUK_ERR_ERROR, "missing x property in point description"); - else if (required && !duk::hasProperty(ctx, index, "y")) - duk::raise(ctx, DUK_ERR_ERROR, "missing y property in point description"); + //point = Point(duk::getProperty(ctx, index, "x"), duk::getProperty(ctx, index, "y")); + int x; + int y; - point = Point(duk::getProperty(ctx, index, "x"), duk::getProperty(ctx, index, "y")); + duk_get_prop_string(ctx, index, "x"); + x = duk_to_int(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "y"); + y = duk_to_int(ctx, -1); + duk_pop(ctx); + + point = Point(x, y); } else if (required) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "point object expected"); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "point object expected"); return point; } -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { Point point; - if (duk::top(ctx) == 2) - point = Point(duk::require(ctx, 0), duk::require(ctx, 1)); - else if (duk::top(ctx) == 1) + if (duk_get_top(ctx) == 2) + point = Point(duk_require_int(ctx, 0), duk_require_int(ctx, 1)); + else if (duk_get_top(ctx) == 1) point = parse(ctx, 0, true); - duk::Ret ret; + duk_ret_t ret; // Allow both constructor and non constructor calls. if (duk_is_constructor_call(ctx)) { - duk::push(ctx, duk::This()); - /* TODO: use duk::put when available */ - duk::TypeTraits::put(ctx, point); - duk::pop(ctx); + duk_push_this(ctx); + dukx_put_point(ctx, point); + duk_pop(ctx); ret = 0; } else { - duk::push(ctx, point); + dukx_push_point(ctx, point); ret = 1; } @@ -67,50 +79,49 @@ } // !namespace -namespace duk { - -Point TypeTraits::get(ContextPtr ctx, Index index) +Point dukx_get_point(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, false); } -Point TypeTraits::require(ContextPtr ctx, Index index) +Point dukx_require_point(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, true); } -Point TypeTraits::optional(ContextPtr ctx, Index index, Point def) +Point dukx_optional_point(duk_context *ctx, duk_idx_t index, Point def) { return parse(ctx, index, false, std::move(def)); } -void TypeTraits::push(ContextPtr ctx, const Point &point) +void dukx_push_point(duk_context *ctx, const Point &point) { - duk::StackAssert sa(ctx, 1); + StackAssert sa(ctx, 1); - duk::push(ctx, duk::Object()); - duk::TypeTraits::put(ctx, point); + duk_push_object(ctx); + dukx_put_point(ctx, point); } -void TypeTraits::put(ContextPtr ctx, const Point &point) +void dukx_put_point(duk_context *ctx, const Point &point) { - assert(duk::type(ctx, -1) == DUK_TYPE_OBJECT); + assert(duk_is_object(ctx, -1)); - duk::StackAssert sa(ctx); + StackAssert sa(ctx); - duk::putProperty(ctx, -1, "x", point.x()); - duk::putProperty(ctx, -1, "y", point.y()); + duk_push_int(ctx, point.x()); + duk_put_prop_string(ctx, -2, "x"); + duk_push_int(ctx, point.y()); + duk_put_prop_string(ctx, -2, "y"); } -} // !duk - -void loadMalikaniaPoint(duk::ContextPtr ctx) +void dukx_load_point(duk_context *ctx) { - duk::StackAssert sa(ctx, 0); + StackAssert sa(ctx, 0); - duk::getGlobal(ctx, "Malikania"); - duk::putProperty(ctx, -1, "Point", duk::Function{constructor, DUK_VARARGS}); - duk::pop(ctx); + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Point"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-point.hpp --- a/libclient/malikania/js-point.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-point.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,30 +19,20 @@ #ifndef MALIKANIA_JS_POINT_HPP #define MALIKANIA_JS_POINT_HPP -#include "js.hpp" +#include "duktape.hpp" #include "point.hpp" namespace malikania { -namespace duk { +Point dukx_require_point(duk_context *ctx, duk_idx_t index); -template <> -class TypeTraits { -public: - static Point get(ContextPtr ctx, Index index); - - static Point require(ContextPtr ctx, Index index); +Point dukx_get_point(duk_context *ctx, duk_idx_t index); - static Point optional(ContextPtr ctx, Index index, Point def); - - static void push(ContextPtr ctx, const Point &point); +void dukx_push_point(duk_context *ctx, const Point &point); - static void put(ContextPtr ctx, const Point &point); -}; +void dukx_put_point(duk_context *ctx, const Point &point); -} // !duk - -void loadMalikaniaPoint(duk::ContextPtr ctx); +void dukx_load_point(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-rectangle.cpp --- a/libclient/malikania/js-rectangle.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-rectangle.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,79 +16,81 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include "js-rectangle.hpp" namespace malikania { namespace { -unsigned clamp(duk::ContextPtr ctx, int value, bool required) +unsigned clamp(duk_context *ctx, int value, bool required) { if (value < 0) { - if (required) { - duk::raise(ctx, DUK_ERR_RANGE_ERROR, "%d can not be negative", value); - } else { + if (required) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "%d can not be negative", value); + else value = 0; - } } return static_cast(value); } -Rectangle parse(duk::ContextPtr ctx, duk::Index index, bool required, Rectangle rect = {}) +Rectangle parse(duk_context *ctx, duk_idx_t index, bool required, Rectangle rect = {}) { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); + + if (duk_is_object(ctx, index)) { + auto get = [&] (auto prop) { + if (required && !duk_has_prop_string(ctx, index, prop)) + duk_error(ctx, DUK_ERR_ERROR, "missing '%s' property", prop); + + duk_get_prop_string(ctx, index, prop); - if (duk::type(ctx, index) == DUK_TYPE_OBJECT) { - if (required && !duk::hasProperty(ctx, index, "x")) { - duk::raise(ctx, DUK_ERR_ERROR, "missing x property in rectangle description"); - } else if (required && !duk::hasProperty(ctx, index, "y")) { - duk::raise(ctx, DUK_ERR_ERROR, "missing y property in rectangle description"); - } else if (required && !duk::hasProperty(ctx, index, "width")) { - duk::raise(ctx, DUK_ERR_ERROR, "missing width property in rectangle description"); - } else if (required && !duk::hasProperty(ctx, index, "height")) { - duk::raise(ctx, DUK_ERR_ERROR, "missing height property in rectangle description"); - } + if (required && !duk_is_number(ctx, -1)) { + duk_pop(ctx); + duk_error(ctx, DUK_ERR_ERROR, "invalid '%s' property (number expected)", prop); + } + + auto value = duk_to_int(ctx, -1); - rect = Rectangle( - duk::getProperty(ctx, index, "x"), - duk::getProperty(ctx, index, "y"), - clamp(ctx, duk::getProperty(ctx, index, "width"), required), - clamp(ctx, duk::getProperty(ctx, index, "height"), required) - ); - } else if (required) { - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "size object expected"); - } + duk_pop(ctx); + + return value; + }; + + rect = Rectangle(get("x"), get("y"), + clamp(ctx, get("width"), required), clamp(ctx, get("height"), required)); + } else if (required) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "rectangle object expected"); return rect; } -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { Rectangle rect; - if (duk::top(ctx) == 4) { + if (duk_get_top(ctx) == 4) { rect = Rectangle( - duk::require(ctx, 0), - duk::require(ctx, 1), - clamp(ctx, duk::require(ctx, 2), true), - clamp(ctx, duk::require(ctx, 3), true) + duk_require_int(ctx, 0), + duk_require_int(ctx, 1), + clamp(ctx, duk_require_int(ctx, 2), true), + clamp(ctx, duk_require_int(ctx, 3), true) ); - } else if (duk::top(ctx) == 1) { + } else if (duk_get_top(ctx) == 1) rect = parse(ctx, 0, true); - } - duk::Ret ret; + duk_ret_t ret; - /* Allow both constructor and non constructor calls */ + // Allow both constructor and non constructor calls. if (duk_is_constructor_call(ctx)) { - duk::push(ctx, duk::This()); - /* TODO: use duk::put when available */ - duk::TypeTraits::put(ctx, rect); - duk::pop(ctx); + duk_push_this(ctx); + dukx_put_rect(ctx, rect); + duk_pop(ctx); ret = 0; } else { - duk::push(ctx, rect); + dukx_push_rect(ctx, rect); ret = 1; } @@ -97,52 +99,53 @@ } // !namespace -namespace duk { - -Rectangle TypeTraits::get(ContextPtr ctx, Index index) +Rectangle dukx_get_rect(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, false); } -Rectangle TypeTraits::require(ContextPtr ctx, Index index) +Rectangle dukx_require_rect(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, true); } -Rectangle TypeTraits::optional(ContextPtr ctx, Index index, Rectangle def) +Rectangle dukx_optional_rect(duk_context *ctx, duk_idx_t index, Rectangle def) { return parse(ctx, index, false, std::move(def)); } -void TypeTraits::push(ContextPtr ctx, const Rectangle &rect) +void dukx_push_rect(duk_context *ctx, const Rectangle &rect) { - duk::StackAssert sa(ctx, 1); + StackAssert sa(ctx, 1); - duk::push(ctx, duk::Object()); - duk::TypeTraits::put(ctx, rect); + duk_push_object(ctx); + dukx_put_rect(ctx, rect); } -void TypeTraits::put(ContextPtr ctx, const Rectangle &rect) +void dukx_put_rect(duk_context *ctx, const Rectangle &rect) { - assert(duk::type(ctx, -1) == DUK_TYPE_OBJECT); + assert(duk_is_object(ctx, -1)); + + StackAssert sa(ctx); - duk::StackAssert sa(ctx); - - duk::putProperty(ctx, -1, "x", rect.x()); - duk::putProperty(ctx, -1, "y", rect.y()); - duk::putProperty(ctx, -1, "width", static_cast(rect.width())); - duk::putProperty(ctx, -1, "height", static_cast(rect.height())); + duk_push_int(ctx, rect.x()); + duk_put_prop_string(ctx, -2, "x"); + duk_push_int(ctx, rect.y()); + duk_put_prop_string(ctx, -2, "y"); + duk_push_uint(ctx, rect.width()); + duk_put_prop_string(ctx, -2, "width"); + duk_push_uint(ctx, rect.height()); + duk_put_prop_string(ctx, -2, "height"); } -} // !dukl - -void loadMalikaniaRectangle(duk::ContextPtr ctx) +void dukx_load_rect(duk_context *ctx) { - duk::StackAssert sa(ctx, 0); + StackAssert sa(ctx, 0); - duk::getGlobal(ctx, "Malikania"); - duk::putProperty(ctx, -1, "Rectangle", duk::Function{constructor, DUK_VARARGS}); - duk::pop(ctx); + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Rectangle"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-rectangle.hpp --- a/libclient/malikania/js-rectangle.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-rectangle.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,14 +19,8 @@ #ifndef MALIKANIA_JS_RECTANGLE_HPP #define MALIKANIA_JS_RECTANGLE_HPP -#include "js.hpp" -#include "rectangle.hpp" - -namespace malikania { - -namespace duk { - /** + * \file js-rectangle.hpp * \brief JavaScript binding for Rectangle. * * Rectangles are plain objects. @@ -40,62 +34,61 @@ * } * ```` */ -template <> -class TypeTraits { -public: - /** - * Get a rectangle. - * - * The rectangle may be adjusted if any values are incorrect. - * - * \param ctx the context - * \param index the value index - * \return the rectangle - */ - static Rectangle get(ContextPtr ctx, Index index); + +#include "duktape.hpp" +#include "rectangle.hpp" + +namespace malikania { - /** - * Require a rectangle. - * - * If the object is not a rectangle or if width, height are invalid, raise a JavaScript error. - * - * \param ctx the context - * \param index the index - * \return the rectangle - */ - static Rectangle require(ContextPtr ctx, Index index); +/** + * Get a rectangle. + * + * The rectangle may be adjusted if any values are incorrect. + * + * @param ctx the context + * @param index the value index + * @return the rectangle + */ +Rectangle dukx_get_rect(duk_context *ctx, duk_idx_t index); +/** + * Require a rectangle. + * + * If the object is not a rectangle or if width, height are invalid, raise a JavaScript error. + * + * @param ctx the context + * @param index the index + * @return the rectangle + */ +Rectangle dukx_require_rect(duk_context *ctx, duk_idx_t index); - /** - * Like get but return the default value if the value at the given index is not an object or invalid - * - * \param ctx the context - * \param index the idnex - * \param def the default value - * \return the rectangle - */ - static Rectangle optional(ContextPtr ctx, Index index, Rectangle def); +/** + * Like get but return the default value if the value at the given index is not an object or invalid + * + * @param ctx the context + * @param index the idnex + * @param def the default value + * @return the rectangle + */ +Rectangle dukx_optional_rect(duk_context *ctx, duk_idx_t index, Rectangle def); - /** - * Push the rectangle as object. - * - * \param ctx the context - * \param rect the rectangle - */ - static void push(ContextPtr ctx, const Rectangle &rect); +/** + * Push the rectangle as object. + * + * @param ctx the context + * @param rect the rectangle + */ +void dukx_push_rect(duk_context *ctx, const Rectangle &rect); - /** - * Put the rectangle properties into the object at the top of the stack. - * - * \param ctx the context - * \param rect the rectangle - */ - static void put(ContextPtr ctx, const Rectangle &rect); -}; +/** + * Put the rectangle properties into the object at the top of the stack. + * + * @param ctx the context + * @param rect the rectangle + */ +void dukx_put_rect(duk_context *ctx, const Rectangle &rect); -} // !duk - -void loadMalikaniaRectangle(duk::ContextPtr ctx); +void dukx_load_rect(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-size.cpp --- a/libclient/malikania/js-size.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-size.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,67 +16,73 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include "js-size.hpp" namespace malikania { namespace { -unsigned clamp(duk::ContextPtr ctx, int value, bool required) -{ - if (value < 0) { - if (required) - duk::raise(ctx, DUK_ERR_RANGE_ERROR, "%d can not be negative", value); - else - value = 0; - } - - return static_cast(value); -} - -Size parse(duk::ContextPtr ctx, duk::Index index, bool required, Size size = {}) +Size parse(duk_context *ctx, duk_idx_t index, bool required, Size size = {}) { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); + + if (duk_is_object(ctx, index)) { + if (required && !duk_has_prop_string(ctx, index, "width")) + duk_error(ctx, DUK_ERR_ERROR, "missing width property in size description"); + else if (required && !duk_has_prop_string(ctx, index, "height")) + duk_error(ctx, DUK_ERR_ERROR, "missing height property in size description"); + + int width; + int height; - if (duk::type(ctx, index) == DUK_TYPE_OBJECT) { - if (required && !duk::hasProperty(ctx, index, "width")) - duk::raise(ctx, DUK_ERR_ERROR, "missing width property in size description"); - else if (required && !duk::hasProperty(ctx, index, "height")) - duk::raise(ctx, DUK_ERR_ERROR, "missing height property in size description"); + duk_get_prop_string(ctx, index, "width"); + width = duk_to_int(ctx, -1); + duk_pop(ctx); + duk_get_prop_string(ctx, index, "height"); + height = duk_to_int(ctx, -1); + duk_pop(ctx); - size = Size( - clamp(ctx, duk::getProperty(ctx, index, "width"), required), - clamp(ctx, duk::getProperty(ctx, index, "height"), required) - ); + if (width < 0) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "width can not be negative"); + if (height < 0) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "height can not be negative"); + + size = Size(width, height); } else if (required) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "size object expected"); + duk_error(ctx, DUK_ERR_TYPE_ERROR, "size object expected"); return size; } -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { - malikania::Size size; + Size size; + + if (duk_get_top(ctx) == 2) { + int width; + int height; - if (duk::top(ctx) == 2) { - size = malikania::Size( - clamp(ctx, duk::require(ctx, 0), true), - clamp(ctx, duk::require(ctx, 1), true) - ); - } else if (duk::top(ctx) == 1) + if ((width = duk_require_int(ctx, 0)) < 0) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "argument #0 can not be negative"); + if ((height = duk_require_int(ctx, 1)) < 0) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "argument #1 can not be negative"); + + size = Size(static_cast(width), static_cast(height)); + } else if (duk_get_top(ctx) == 1) size = parse(ctx, 0, true); - duk::Ret ret; + duk_ret_t ret; // Allow both constructor and non constructor calls. if (duk_is_constructor_call(ctx)) { - duk::push(ctx, duk::This()); - /* TODO: use duk::put when available */ - duk::TypeTraits::put(ctx, size); - duk::pop(ctx); + duk_push_this(ctx); + dukx_put_size(ctx, size); + duk_pop(ctx); ret = 0; } else { - duk::push(ctx, size); + dukx_push_size(ctx, size); ret = 1; } @@ -85,50 +91,49 @@ } // !namespace -namespace duk { - -malikania::Size TypeTraits::get(ContextPtr ctx, Index index) +Size dukx_get_size(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, false); } -malikania::Size TypeTraits::require(ContextPtr ctx, Index index) +Size dukx_require_size(duk_context *ctx, duk_idx_t index) { return parse(ctx, index, true); } -malikania::Size TypeTraits::optional(ContextPtr ctx, Index index, malikania::Size def) +Size dukx_optional_size(duk_context *ctx, duk_idx_t index, Size def) { return parse(ctx, index, false, std::move(def)); } -void TypeTraits::push(ContextPtr ctx, const malikania::Size &size) +void dukx_push_size(duk_context *ctx, const Size &size) { StackAssert sa(ctx, 1); - duk::push(ctx, duk::Object()); - duk::TypeTraits::put(ctx, size); + duk_push_object(ctx); + dukx_put_size(ctx, size); } -void TypeTraits::put(ContextPtr ctx, const malikania::Size &size) +void dukx_put_size(duk_context *ctx, const Size &size) { - assert(type(ctx, -1) == DUK_TYPE_OBJECT); + assert(duk_is_object(ctx, -1)); StackAssert sa(ctx, 0); - duk::putProperty(ctx, -1, "width", static_cast(size.width())); - duk::putProperty(ctx, -1, "height", static_cast(size.height())); + duk_push_uint(ctx, size.width()); + duk_put_prop_string(ctx, -2, "width"); + duk_push_uint(ctx, size.height()); + duk_put_prop_string(ctx, -2, "height"); } -} // !duk - -void loadMalikaniaSize(duk::ContextPtr ctx) +void dukx_load_size(duk_context *ctx) { - duk::StackAssert sa(ctx, 0); + StackAssert sa(ctx, 0); - duk::getGlobal(ctx, "Malikania"); - duk::putProperty(ctx, -1, "Size", duk::Function{constructor, DUK_VARARGS}); - duk::pop(ctx); + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, DUK_VARARGS); + duk_put_prop_string(ctx, -2, "Size"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-size.hpp --- a/libclient/malikania/js-size.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-size.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,14 +19,8 @@ #ifndef MALIKANIA_JS_SIZE_HPP #define MALIKANIA_JS_SIZE_HPP -#include "js.hpp" -#include "size.hpp" - -namespace malikania { - -namespace duk { - /** + * \file js-size.h * \brief JavaScript binding for Size. * * Size are plain objects. @@ -38,61 +32,61 @@ * } * ```` */ -template <> -class TypeTraits { -public: - /** - * Get a size. - * - * The size may be adjusted if any values are incorrect. - * - * \param ctx the context - * \param index the value index - * \return the size - */ - static malikania::Size get(ContextPtr ctx, Index index); + +#include "duktape.hpp" +#include "size.hpp" + +namespace malikania { - /** - * Require a size - * - * If the object is not a size, raise a JavaScript error. - * - * \param ctx the context - * \param index the index - * \return the size - */ - static malikania::Size require(ContextPtr ctx, Index index); +/** + * Get a size. + * + * The size may be adjusted if any values are incorrect. + * + * @param ctx the context + * @param index the value index + * @return the size + */ +Size dukx_get_size(duk_context *ctx, duk_idx_t index); + +/** + * Require a size + * + * If the object is not a size, raise a JavaScript error. + * + * @param ctx the context + * @param index the index + * @return the size + */ +Size dukx_require_size(duk_context *ctx, duk_idx_t index); - /** - * Like get but return the default value if the value at the given index is not an object. - * - * \param ctx the context - * \param index the idnex - * \param def the default value - * \return the size - */ - static malikania::Size optional(ContextPtr ctx, Index index, malikania::Size def); +/** + * Like get but return the default value if the value at the given index is not an object. + * + * @param ctx the context + * @param index the idnex + * @param def the default value + * @return the size + */ +Size dukx_optional_size(duk_context *ctx, duk_idx_t index, Size def); - /** - * Push the size as object. - * - * \param ctx the context - * \param size the size - */ - static void push(ContextPtr ctx, const malikania::Size &size); +/** + * Push the size as object. + * + * @param ctx the context + * @param size the size + */ +void dukx_push_size(duk_context *ctx, const Size &size); - /** - * Put the size properties into the object at the top of the stack. - * - * \param ctx the context - * \param size the size - */ - static void put(ContextPtr ctx, const malikania::Size &size); -}; +/** + * Put the size properties into the object at the top of the stack. + * + * @param ctx the context + * @param size the size + */ +void dukx_put_size(duk_context *ctx, const Size &size); -} // !duk - -void loadMalikaniaSize(duk::ContextPtr ctx); +void dukx_load_size(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-sprite.cpp --- a/libclient/malikania/js-sprite.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-sprite.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,7 +16,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include "client-resources-loader.hpp" +#include "js-client-resources-loader.hpp" #include "js-point.hpp" #include "js-size.hpp" #include "js-sprite.hpp" @@ -26,122 +26,141 @@ namespace { -duk::Ret cell(duk::ContextPtr ctx) +const std::string Signature("\xff""\xff""malikania-sprite-ptr"); + +Sprite *self(duk_context *ctx) { - duk::push(ctx, duk::self>(ctx)->cell()); + StackAssert sa(ctx); - return 1; + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Sprite object"); + + return static_cast(ptr); } -duk::Ret columns(duk::ContextPtr ctx) +duk_ret_t cell(duk_context *ctx) { - duk::push(ctx, static_cast(duk::self>(ctx)->columns())); + dukx_push_size(ctx, self(ctx)->cell()); return 1; } -duk::Ret margins(duk::ContextPtr ctx) +duk_ret_t columns(duk_context *ctx) { - duk::push(ctx, duk::self>(ctx)->margin()); + duk_push_uint(ctx, self(ctx)->columns()); return 1; } -duk::Ret rows(duk::ContextPtr ctx) +duk_ret_t margins(duk_context *ctx) { - duk::push(ctx, static_cast(duk::self>(ctx)->rows())); + dukx_push_size(ctx, self(ctx)->margin()); return 1; } -duk::Ret space(duk::ContextPtr ctx) +duk_ret_t rows(duk_context *ctx) { - duk::push(ctx, duk::self>(ctx)->space()); + duk_push_uint(ctx, self(ctx)->rows()); return 1; } -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t space(duk_context *ctx) +{ + dukx_push_size(ctx, self(ctx)->space()); + + return 1; +} + +duk_ret_t constructor(duk_context *ctx) { if (!duk_is_constructor_call(ctx)) - duk::raise(ctx, DUK_ERR_ERROR, "sprite must be new-constructed"); + duk_error(ctx, DUK_ERR_ERROR, "sprite must be new-constructed"); try { - auto loader = duk::getGlobal(ctx, "\xff""\xff""loader"); - auto sprite = loader->loadSprite(duk::require(ctx, 0)); + auto loader = dukx_get_client_loader(ctx); + auto sprite = loader->loadSprite(duk_require_string(ctx, 0)); - duk::construct(ctx, std::make_shared(std::move(sprite))); - duk::push(ctx, duk::This()); + duk_push_this(ctx); + duk_push_pointer(ctx, new Sprite(std::move(sprite))); + duk_put_prop_string(ctx, -2, Signature.c_str()); // Cell. - duk::push(ctx, "cell"); - duk::push(ctx, duk::Function{cell}); - duk::defineProperty(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_push_string(ctx, "cell"); + duk_push_c_function(ctx, cell, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); // Columns. - duk::push(ctx, "columns"); - duk::push(ctx, duk::Function{columns}); - duk::defineProperty(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_push_string(ctx, "columns"); + duk_push_c_function(ctx, columns, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); // Margins. - duk::push(ctx, "margins"); - duk::push(ctx, duk::Function{margins}); - duk::defineProperty(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_push_string(ctx, "margins"); + duk_push_c_function(ctx, margins, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); // Rows. - duk::push(ctx, "rows"); - duk::push(ctx, duk::Function{rows}); - duk::defineProperty(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_push_string(ctx, "rows"); + duk_push_c_function(ctx, rows, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); // Space. - duk::push(ctx, "space"); - duk::push(ctx, duk::Function{space}); - duk::defineProperty(ctx, -3, DUK_DEFPROP_HAVE_GETTER); + duk_push_string(ctx, "space"); + duk_push_c_function(ctx, space, 0); + duk_def_prop(ctx, -3, DUK_DEFPROP_HAVE_GETTER); - duk::pop(ctx); + duk_pop(ctx); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret draw(duk::ContextPtr ctx) +duk_ret_t draw(duk_context *ctx) { try { - auto self = duk::self>(ctx); - auto window = duk::get>(ctx, 0); - auto cell = duk::require(ctx, 1); - auto point = duk::get(ctx, 2); + auto sprite = self(ctx); + auto window = dukx_require_window(ctx, 0); + auto cell = duk_require_uint(ctx, 1); + auto point = dukx_get_point(ctx, 2); - if (cell < 0 || cell >= static_cast(self->rows() * self->columns())) - duk::raise(ctx, DUK_ERR_RANGE_ERROR, "%d is out of range", cell); + if (cell >= (sprite->rows() * sprite->columns())) + duk_error(ctx, DUK_ERR_RANGE_ERROR, "%d is out of range", cell); - self->draw(*window, static_cast(cell), point); + sprite->draw(*window, cell, point); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -const duk::FunctionMap methods{ - { "draw", { draw, 3 } } +const duk_function_list_entry methods[] = { + { "draw", draw, 3 }, + { nullptr, nullptr, 0 } }; } // !namespace -void loadMalikaniaSprite(duk::ContextPtr ctx) +void dukx_load_sprite(duk_context *ctx) { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::push(ctx, duk::Function{constructor, 1}); - duk::push(ctx, duk::Object()); - duk::put(ctx, methods); - duk::putProperty(ctx, -2, "prototype"); - duk::putProperty(ctx, -2, "Sprite"); - duk::pop(ctx); + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, 1); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Sprite"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-sprite.hpp --- a/libclient/malikania/js-sprite.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-sprite.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,59 +19,12 @@ #ifndef MALIKANIA_JS_SPRITE_HPP #define MALIKANIA_JS_SPRITE_HPP -#include "js.hpp" +#include "duktape.hpp" #include "sprite.hpp" namespace malikania { -namespace duk { - -/** - * \brief JavaScript binding for Sprite. - */ -template <> -class TypeTraits { -public: - /** - * Put the Sprite prototype to the top of the stack. - * - * \param ctx the context - */ - static void prototype(ContextPtr ctx) - { - duk::StackAssert sa(ctx, 1); - - duk::getGlobal(ctx, "Malikania"); - duk::getGlobal(ctx, "Sprite"); - duk::getProperty(ctx, -1, "prototype"); - duk::remove(ctx, -2); - duk::remove(ctx, -2); - } - - /** - * Get the object signature. - * - * \return Sprite signature - */ - static inline std::string name() - { - return "\xff""\xff""Sprite"; - } - - /** - * Get inheritance list. - * - * \return empty - */ - static inline std::vector inherits() - { - return {}; - } -}; - -} // !duk - -void loadMalikaniaSprite(duk::ContextPtr ctx); +void dukx_load_sprite(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-window.cpp --- a/libclient/malikania/js-window.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-window.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include "js-color.hpp" #include "js-font.hpp" #include "js-line.hpp" @@ -27,203 +29,256 @@ namespace { -duk::Ret constructor(duk::ContextPtr ctx) +const std::string Signature("\xff""\xff""malikania-window-ptr"); +const std::string Prototype("\xff""\xff""malikania-window-prototype"); + +Window *self(duk_context *ctx) { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an Window object"); + + return static_cast(ptr); +} + +duk_ret_t constructor(duk_context *ctx) +{ + StackAssert sa(ctx); if (!duk_is_constructor_call(ctx)) - duk::raise(ctx, DUK_ERR_ERROR, "window must be new-constructed"); + duk_error(ctx, DUK_ERR_ERROR, "window must be new-constructed"); - /* TODO: add parameters */ + // TODO: add parameters. try { - duk::construct(ctx, std::make_shared()); + auto win = new Window; + + duk_push_this(ctx); + duk_push_pointer(ctx, win); + duk_put_prop_string(ctx, -2, Signature.c_str()); + duk_pop(ctx); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret clear(duk::ContextPtr ctx) +duk_ret_t clear(duk_context *ctx) { try { - duk::self>(ctx)->clear(); + self(ctx)->clear(); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -duk::Ret present(duk::ContextPtr ctx) -{ - try { - duk::self>(ctx)->present(); - } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret drawingColor(duk::ContextPtr ctx) +duk_ret_t present(duk_context *ctx) { try { - duk::push(ctx, duk::self>(ctx)->drawingColor()); + self(ctx)->present(); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 1; -} - -duk::Ret drawLine(duk::ContextPtr ctx) -{ - try { - duk::self>(ctx)->drawLine(duk::require(ctx, 0)); - } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret drawLines(duk::ContextPtr ctx) +duk_ret_t drawingColor(duk_context *ctx) { try { - duk::self>(ctx)->drawLines(duk::get>(ctx, 0)); + dukx_push_color(ctx, self(ctx)->drawingColor()); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 1; +} + +duk_ret_t drawLine(duk_context *ctx) +{ + try { + self(ctx)->drawLine(dukx_require_line(ctx, 0)); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret drawPoint(duk::ContextPtr ctx) +duk_ret_t drawLines(duk_context *ctx) { try { - duk::self>(ctx)->drawPoint(duk::require(ctx, 0)); + self(ctx)->drawLines(dukx_get_array(ctx, 0, dukx_get_point)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret drawPoints(duk::ContextPtr ctx) +duk_ret_t drawPoint(duk_context *ctx) { try { - duk::self>(ctx)->drawPoints(duk::get>(ctx, 0)); + self(ctx)->drawPoint(dukx_require_point(ctx, 0)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +duk_ret_t drawPoints(duk_context *ctx) +{ + try { + self(ctx)->drawPoints(dukx_get_array(ctx, 0, dukx_get_point)); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret drawRectangle(duk::ContextPtr ctx) +duk_ret_t drawRectangle(duk_context *ctx) { try { - duk::self>(ctx)->drawRectangle(duk::require(ctx, 0)); + self(ctx)->drawRectangle(dukx_require_rect(ctx, 0)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret drawRectangles(duk::ContextPtr ctx) +duk_ret_t drawRectangles(duk_context *ctx) { try { - duk::self>(ctx)->drawRectangles(duk::get>(ctx, 0)); + self(ctx)->drawRectangles(dukx_get_array(ctx, 0, dukx_get_rect)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret drawText(duk::ContextPtr ctx) +duk_ret_t drawText(duk_context *ctx) { try { - auto self = duk::self>(ctx); - auto text = duk::require(ctx, 0); - auto font = duk::get>(ctx, 1); - auto rect = duk::get(ctx, 2); + auto win = self(ctx); + auto text = duk_require_string(ctx, 0); + auto font = dukx_require_font(ctx, 1); + auto rect = dukx_get_rect(ctx, 2); if (!rect.isNull()) - self->drawText(text, *font, rect); + win->drawText(text, *font, rect); else - self->drawText(text, *font, Point(rect.x(), rect.y())); + win->drawText(text, *font, Point(rect.x(), rect.y())); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret fillRectangle(duk::ContextPtr ctx) +duk_ret_t fillRectangle(duk_context *ctx) { try { - duk::self>(ctx)->fillRectangle(duk::require(ctx, 0)); + self(ctx)->fillRectangle(dukx_require_rect(ctx, 0)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +duk_ret_t fillRectangles(duk_context *ctx) +{ + try { + self(ctx)->fillRectangles(dukx_get_array(ctx, 0, dukx_get_rect)); + } catch (const std::exception &ex) { + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -duk::Ret fillRectangles(duk::ContextPtr ctx) +duk_ret_t setDrawingColor(duk_context *ctx) { try { - duk::self>(ctx)->fillRectangles(duk::get>(ctx, 0)); + self(ctx)->setDrawingColor(dukx_require_color(ctx, 0)); } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); - } - - return 0; -} - -duk::Ret setDrawingColor(duk::ContextPtr ctx) -{ - try { - duk::self>(ctx)->setDrawingColor(duk::require(ctx, 0)); - } catch (const std::exception &ex) { - duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + duk_error(ctx, DUK_ERR_ERROR, "%s", ex.what()); } return 0; } -const duk::FunctionMap methods{ - { "clear", { clear, 0 } }, - { "drawingColor", { drawingColor, 0 } }, - { "drawLine", { drawLine, 1 } }, - { "drawLines", { drawLines, 1 } }, - { "drawPoint", { drawPoint, 1 } }, - { "drawPoints", { drawPoints, 1 } }, - { "drawRectangle", { drawRectangle, 1 } }, - { "drawRectangles", { drawRectangles, 1 } }, - { "drawText", { drawText, 3 } }, - { "fillRectangle", { fillRectangle, 1 } }, - { "fillRectangles", { fillRectangles, 1 } }, - { "present", { present, 0 } }, - { "setDrawingColor", { setDrawingColor, 1 } } +const duk_function_list_entry methods[] = { + { "clear", clear, 0 }, + { "drawingColor", drawingColor, 0 }, + { "drawLine", drawLine, 1 }, + { "drawLines", drawLines, 1 }, + { "drawPoint", drawPoint, 1 }, + { "drawPoints", drawPoints, 1 }, + { "drawRectangle", drawRectangle, 1 }, + { "drawRectangles", drawRectangles, 1 }, + { "drawText", drawText, 3 }, + { "fillRectangle", fillRectangle, 1 }, + { "fillRectangles", fillRectangles, 1 }, + { "present", present, 0 }, + { "setDrawingColor", setDrawingColor, 1 }, + { nullptr, nullptr, 0 } }; } // !namespace -void loadMalikaniaWindow(duk::ContextPtr ctx) +void dukx_new_window(duk_context *ctx, Window *window) { - duk::StackAssert sa(ctx); + assert(ctx); + assert(window); + + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_push_pointer(ctx, window); + duk_put_prop_string(ctx, -2, Signature.c_str()); + duk_pop(ctx); +} + +Window *dukx_require_window(duk_context *ctx, duk_idx_t index) +{ + assert(ctx); + + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::push(ctx, duk::Function{constructor}); - duk::push(ctx, duk::Object()); - duk::put(ctx, methods); - duk::putProperty(ctx, -2, "prototype"); - duk::putProperty(ctx, -2, "Window"); - duk::pop(ctx); + duk_get_prop_string(ctx, index, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not a Window object"); + + return static_cast(ptr); +} + +void dukx_load_window(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, 0); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "Window"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/js-window.hpp --- a/libclient/malikania/js-window.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/js-window.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,39 +19,14 @@ #ifndef MALIKANIA_JS_WINDOW_HPP #define MALIKANIA_JS_WINDOW_HPP -#include "js.hpp" +#include "duktape.hpp" #include "window.hpp" namespace malikania { -namespace duk { +Window *dukx_require_window(duk_context *ctx, duk_idx_t index); -/** - * \brief JavaScript binding for Window. - */ -template <> -class TypeTraits { -public: - /** - * Put the Window prototype to the top of the stack. - * - * \param ctx the context - */ - static void prototype(duk::ContextPtr ctx) - { - duk::StackAssert sa(ctx, 1); - - duk::getGlobal(ctx, "Malikania"); - duk::getProperty(ctx, -1, "Window"); - duk::getProperty(ctx, -1, "prototype"); - duk::remove(ctx, -2); - duk::remove(ctx, -2); - } -}; - -} // !duk - -void loadMalikaniaWindow(duk::ContextPtr ctx); +void dukx_load_window(duk_context *ctx); } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/sprite.cpp --- a/libclient/malikania/sprite.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/sprite.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,6 +16,8 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include + #include "sprite.hpp" namespace malikania { diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/sprite.hpp --- a/libclient/malikania/sprite.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/sprite.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -25,7 +25,6 @@ */ #include "image.hpp" -#include "js.hpp" namespace malikania { @@ -36,7 +35,7 @@ * \class Sprite * \brief A Sprite is an image divided into cells. */ -class Sprite : public duk::Bindable { +class Sprite { private: Image m_image; Size m_cell; diff -r 8e1241156034 -r 9af360f34c7d libclient/malikania/window.hpp --- a/libclient/malikania/window.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libclient/malikania/window.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -29,8 +29,6 @@ #include #include -#include "js.hpp" - namespace malikania { class Color; @@ -42,7 +40,7 @@ /** * \brief Main window class and drawing. */ -class Window : public duk::Bindable { +class Window { private: class Backend; diff -r 8e1241156034 -r 9af360f34c7d libcommon/CMakeLists.txt --- a/libcommon/CMakeLists.txt Fri Jul 01 13:32:08 2016 +0200 +++ b/libcommon/CMakeLists.txt Wed Aug 10 14:30:51 2016 +0200 @@ -19,12 +19,12 @@ set( HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/malikania/application.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/game.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/duktape.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/elapsed-timer.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/game.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/id.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-elapsed-timer.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-resources-loader.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-loader.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-locator.hpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/util.hpp @@ -35,6 +35,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/malikania/application.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/elapsed-timer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-elapsed-timer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-resources-loader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-loader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/resources-locator.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/util.cpp diff -r 8e1241156034 -r 9af360f34c7d libcommon/malikania/duktape.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/duktape.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -0,0 +1,505 @@ +/* + * duktape.hpp -- Duktape extras + * + * Copyright (c) 2016 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DUKTAPE_HPP +#define DUKTAPE_HPP + +/** + * \file duktape.hpp + * \brief Bring some extras to Duktape C library. + * \author David Demelier + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/** + * \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(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(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; + + 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 dukx_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; +} + +/** + * Throw an ECMAScript exception. + * + * \param ctx the context + * \param ex the exception + */ +template +void dukx_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 dukx_get_std_string(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 dukx_require_std_string(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 dukx_push_std_string(duk_context *ctx, const std::string &str) +{ + duk_push_lstring(ctx, str.data(), str.length()); +} + +/** + * Get an array. + * + * \param ctx the context + * \param index the array index + * \param get the conversion function (e.g. duk_get_int) + */ +template +auto dukx_get_array(duk_context *ctx, duk_idx_t index, Getter &&get) +{ + using T = decltype(get(ctx, 0)); + + std::vector result; + std::size_t length = duk_get_length(ctx, index); + + for (std::size_t i = 0; i < length; ++i) { + duk_get_prop_index(ctx, -1, i); + result.push_back(get(ctx, -1)); + duk_pop(ctx); + } + + return result; +} + +/** + * Push an array. + * + * \param ctx the context + * \param values the values + * \param push the function to push values + */ +template +void dukx_push_array(duk_context *ctx, const std::vector &values, Pusher &&push) +{ + duk_push_array(ctx); + + int i = 0; + for (auto x : values) { + push(ctx, x); + duk_put_prop_index(ctx, -2, i++); + } +} + +/** + * Get an object. + * + * \param ctx the context + * \param index the object index + * \param get the conversion function (e.g. duk_get_int) + */ +template +auto dukx_get_object(duk_context *ctx, duk_idx_t index, Getter &&get) +{ + using T = decltype(get(ctx, 0)); + + std::unordered_map result; + + duk_enum(ctx, index, 0); + + while (duk_next(ctx, -1, true)) { + result.emplace(dukx_get_std_string(ctx, -2), get(ctx, -1)); + duk_pop_2(ctx); + } + + duk_pop(ctx); + + return result; +} + +/** + * Push an object. + * + * \param ctx the context + * \param values the values + * \param push the function to push values + */ +template +void dukx_push_object(duk_context *ctx, const std::unordered_map &values, Pusher &&push) +{ + duk_push_object(ctx); + + for (const auto &pair : values) { + push(ctx, pair.second); + duk_put_prop_string(ctx, -2, pair.first.c_str()); + } +} + +#endif // !DUKTAPE_HPP diff -r 8e1241156034 -r 9af360f34c7d libcommon/malikania/elapsed-timer.hpp --- a/libcommon/malikania/elapsed-timer.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libcommon/malikania/elapsed-timer.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -26,8 +26,6 @@ #include -#include "js.hpp" - namespace malikania { /** @@ -40,7 +38,7 @@ * It uses std::chrono::high_resolution_clock for more precision and uses * milliseconds only. */ -class ElapsedTimer : public duk::Bindable { +class ElapsedTimer { public: using TimePoint = std::chrono::time_point; diff -r 8e1241156034 -r 9af360f34c7d libcommon/malikania/js-elapsed-timer.cpp --- a/libcommon/malikania/js-elapsed-timer.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libcommon/malikania/js-elapsed-timer.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -16,22 +16,42 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include +#include + #include "elapsed-timer.hpp" -#include "js.hpp" +#include "duktape.hpp" namespace malikania { namespace { +const std::string Signature("\xff" "\xff" "malikania-elapsed-timer-ptr"); + +ElapsedTimer *self(duk_context *ctx) +{ + StackAssert sa(ctx); + + duk_push_this(ctx); + duk_get_prop_string(ctx, -1, Signature.c_str()); + auto ptr = duk_to_pointer(ctx, -1); + duk_pop_2(ctx); + + if (!ptr) + duk_error(ctx, DUK_ERR_TYPE_ERROR, "not an ElapsedTimer object"); + + return static_cast(ptr); +} + /* * Method: ElapsedTimer.pause * ------------------------------------------------------------------ * * Pause the timer, without resetting the current elapsed time stored. */ -duk::Ret pause(duk::ContextPtr ctx) +duk_ret_t pause(duk_context *ctx) { - duk::self>(ctx)->pause(); + self(ctx)->pause(); return 0; } @@ -42,9 +62,9 @@ * * Reset the elapsed time to 0, the status is not modified. */ -duk::Ret reset(duk::ContextPtr ctx) +duk_ret_t reset(duk_context *ctx) { - duk::self>(ctx)->reset(); + self(ctx)->reset(); return 0; } @@ -55,9 +75,9 @@ * * Restart the timer without resetting the current elapsed time. */ -duk::Ret restart(duk::ContextPtr ctx) +duk_ret_t restart(duk_context *ctx) { - duk::self>(ctx)->restart(); + self(ctx)->restart(); return 0; } @@ -71,9 +91,9 @@ * Returns: * The time elapsed. */ -duk::Ret elapsed(duk::ContextPtr ctx) +duk_ret_t elapsed(duk_context *ctx) { - duk::push(ctx, static_cast(duk::self>(ctx)->elapsed())); + duk_push_uint(ctx, self(ctx)->elapsed()); return 1; } @@ -84,33 +104,55 @@ * * Construct a new ElapsedTimer object. */ -duk::Ret constructor(duk::ContextPtr ctx) +duk_ret_t constructor(duk_context *ctx) { - duk::construct(ctx, std::make_shared()); + duk_push_this(ctx); + duk_push_pointer(ctx, new ElapsedTimer); + duk_put_prop_string(ctx, -2, Signature.c_str()); + duk_pop(ctx); + + return 0; +} + +/* + * Function: Malikania.ElapsedTimer() [destructor] + * ------------------------------------------------------------------ + * + * Destroy the timer. + */ +duk_ret_t destructor(duk_context *ctx) +{ + duk_get_prop_string(ctx, 0, Signature.c_str()); + delete static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + duk_del_prop_string(ctx, 0, Signature.c_str()); 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 -void loadJsElapsedTimer(duk::ContextPtr ctx) noexcept +void dukx_load_elapsedtimer(duk_context *ctx) noexcept { - duk::StackAssert sa(ctx); + StackAssert sa(ctx); - duk::getGlobal(ctx, "Malikania"); - duk::push(ctx, duk::Function{constructor, 0}); - duk::push(ctx, duk::Object{}); - duk::put(ctx, methods); - duk::putProperty(ctx, -2, "prototype"); - duk::putProperty(ctx, -2, "ElapsedTimer"); - duk::pop(ctx); + duk_get_global_string(ctx, "Malikania"); + duk_push_c_function(ctx, constructor, 0); + duk_push_object(ctx); + duk_put_function_list(ctx, -1, methods); + duk_push_c_function(ctx, destructor, 1); + duk_set_finalizer(ctx, -2); + duk_put_prop_string(ctx, -2, "prototype"); + duk_put_prop_string(ctx, -2, "ElapsedTimer"); + duk_pop(ctx); } } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libcommon/malikania/js-elapsed-timer.hpp --- a/libcommon/malikania/js-elapsed-timer.hpp Fri Jul 01 13:32:08 2016 +0200 +++ b/libcommon/malikania/js-elapsed-timer.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -19,11 +19,11 @@ #ifndef MALIKANIA_JS_ELAPSED_TIMER_HPP #define MALIKANIA_JS_ELAPSED_TIMER_HPP -#include "js.hpp" +#include "duktape.hpp" namespace malikania { -void loadJsElapsedTimer(duk::ContextPtr ctx) noexcept; +void dukx_load_elapsedtimer(duk_context *ctx) noexcept; } // !malikania diff -r 8e1241156034 -r 9af360f34c7d libcommon/malikania/js-resources-loader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/js-resources-loader.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -0,0 +1,55 @@ +/* + * js-resources-loader.cpp --resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 David Demelier + * + * 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. + */ + +#include + +#include "js-resources-loader.hpp" + +namespace malikania { + +namespace { + +const std::string Variable("\xff""\xff""malikania-resources-loader"); + +} // !namespace + +void dukx_put_loader(duk_context *ctx, ResourcesLoader *loader) +{ + assert(ctx); + assert(loader); + + StackAssert sa(ctx); + + duk_push_pointer(ctx, loader); + duk_put_global_string(ctx, Variable.c_str()); +} + +ResourcesLoader *duk_require_loader(duk_context *ctx) +{ + assert(ctx); + + StackAssert sa(ctx); + + duk_get_global_string(ctx, Variable.c_str()); + auto ptr = static_cast(duk_to_pointer(ctx, -1)); + duk_pop(ctx); + + return static_cast(ptr); +} + +} // !malikania diff -r 8e1241156034 -r 9af360f34c7d libcommon/malikania/js-resources-loader.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcommon/malikania/js-resources-loader.hpp Wed Aug 10 14:30:51 2016 +0200 @@ -0,0 +1,33 @@ +/* + * js-resources-loader.hpp --resources loader (JavaScript binding) + * + * Copyright (c) 2013-2016 David Demelier + * + * 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 MALIKANIA_JS_RESOURCES_LOADER_H +#define MALIKANIA_JS_RESOURCES_LOADER_H + +#include "duktape.hpp" +#include "resources-loader.hpp" + +namespace malikania { + +void dukx_put_loader(duk_context *ctx, ResourcesLoader *); + +ResourcesLoader *dukx_get_loader(duk_context *ctx); + +} // !malikania + +#endif // !MALIKANIA_JS_RESOURCES_LOADER_H diff -r 8e1241156034 -r 9af360f34c7d libcommon/malikania/js.hpp --- a/libcommon/malikania/js.hpp Fri Jul 01 13:32:08 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3103 +0,0 @@ -/* - * js.hpp -- JavaScript C++14 wrapper for Duktape - * - * Copyright (c) 2016 David Demelier - * - * 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 MALIKANIA_JS_HPP -#define MALIKANIA_JS_HPP - -/** - * \file js.hpp - * \brief Bring JavaScript using Duktape. - * - * 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 - * @subpage js-concepts - */ - -/** - * \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::Context ctx; - * - * return 0; - * } - * @endcode - * - * The duk::Context 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 | push, put | push or put properties | - * | std::vector | push, put | push array of values | - * - * ## Special types - * - * These types are used to export C++ object to JavaScript. See @ref js-more-t2 for more explanations and - * @ref js-concept-class. - * - * | Type | Support | Remarks | - * |--------------------|-----------------------------------------|--------------------------------| - * | std::shared_ptr | construct, get, optional, push, require | T must have Class requirements | - */ - -/** - * \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::Context ctx; - * - * duk::pevalString(ctx, "1 + 1"); - * std::cout << duk::get(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::Context ctx; - * - * // Push a function as global "add" - * duk::putGlobal(ctx, "add", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - * int x = duk::require(ctx, 0); - * int y = duk::require(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(ctx, 0) // get an int at index 0 - * duk::get(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(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 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(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(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 - * @subpage js-more-t2 - */ - -/** - * \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, for - * exporting a C++ class, see @ref js-more-t2. - * - * 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 { - * public: - * static void push(ContextPtr 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 { - * public: - * static Point get(ContextPtr ctx, Index index) - * { - * Point point{0, 0}; - * - * if (is(ctx, index)) { - * point.x = getProperty(ctx, index, "x"); - * point.y = getProperty(ctx, index, "y"); - * } - * - * return point; - * } - * }; - * - * } - * @endcode - * - * Now you can invoke `duk::get(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 { - * public: - * static Point require(ContextPtr ctx, Index index) - * { - * Point point; - * - * // Raise an error if not object - * if (!is(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(ctx, index, "x"); - * point.y = duk::getProperty(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 { - * public: - * static bool is(ContextPtr ctx, Index index) - * { - * return is(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 { - * public: - * static Point optional(ContextPtr ctx, Index index, Point def) - * { - * return is(ctx, index) ? get(ctx, index) : def; - * } - * }; - * - * } - * @endcode - */ - -/** - * \page js-more-t2 Advanced 2: exporting C++ class - * \brief How to export a C++ class through Duktape. - * - * This example shows how you can implement a C++ class and export it through C++ through the predefined - * std::shared_ptr duk::TypeTraits specialization. - * - * There are several steps to accomplish this and you must be familiar on how object oriented works in JavaScript. - * - * See this [introduction to OO in JavaScript][oojs]. - * - * \note [RTTI] is required in order to make typesafe binding. - * - * ## Ownership - * - * To facilitate communication between C++ and JavaScript, objects must be instanciated as `std::shared_ptr`. It - * guarantees polymorphic objects and ownership. - * - * ## The C++ class - * - * In that topic, we will implement a basic Car class that has only one drive function, the class must derive from duk::Bindable. - * - * @code - * #include - * - * #include "js.hpp" - * - * class Car : public duk::Binding { - * public: - * void drive() - * { - * std::cout << "Driving the car..." << std::endl; - * } - * }; - * @endcode - * - * ## The JavaScript methods - * - * This is the drive method, put it in a map. The method does not take any argument so pass 0. - * - * @code - * duk::Ret drive(duk::ContextPtr ctx) - * { - * duk::self>(ctx)->drive(); - * - * return 0; - * } - * - * const duk::FunctionMap methods{ - * { "drive", { drive, 0 } } - * }; - * @endcode - * - * ## Construction - * - * There are two ways to export a C++ object to JavaScript. - * - * 1. When constructed from the JavaScript new operator. You must provide a C function and use duk::construct to - * apply your object to it. - * - * 2. When pusing from C++ to JavaScript. You muse use Using duk::push and you will need to implement the `prototype` - * function in duk::TypeTraits (see below). - * - * ## Example 1: provide a constructor for JavaScript ownership - * - * This example provides a function to let the user constructing the object **from** JavaScript. - * - * ### Add a constructor - * - * Add the constructor that will be called from C++. - * - * @code - * duk::Ret constructor(duk::ContextPtr ctx) - * { - * duk::construct(ctx, std::make_shared()); - * - * return 0; - * } - * @endcode - * - * ### Main - * - * We register the constructor, add a prototype and call it from JavaScript. - * - * @code - * int main() - * { - * duk::Context ctx; - * - * // Push the Car constructor function - * duk::push(ctx, duk::Function{constructor}); - * - * // Push the methods as a new object and set it as the .prototype property - * duk::putProperty(ctx, -1, "prototype", methods); - * - * // Now store the Car function - * duk::putGlobal(ctx, "Car"); - * - * // Create a Car from JavaScript - * duk::pevalString(ctx, - * "c = new Car();" - * "c.drive();" - * ); - * - * return 0; - * } - * @endcode - * - * ## Example 2: the object is created from C++ - * - * This example allocates the Car object from C++ and pass it through JavaScript. It requires to implement the - * prototype function from duk::TypeTraits. - * - * ### Prototype function - * - * This function must push into the stack the prototype for the given object. You are free to store it where you want, - * here, we set it as internal global property. - * - * @code - * namespace duk { - * - * template <> - * class TypeTraits { - * public: - * static inline void prototype(ContextPtr ctx) - * { - * getGlobal(ctx, "\xff""\xff""Car-prototype"); - * } - * }; - * - * } - * @endcode - * - * ### Main - * - * Now save this prototype and create the object from C++. - * - * @code - * int main() - * { - * duk::Context ctx; - * - * // Create a prototype directly from the methods table (from example 1) - * duk::putGlobal(ctx, "\xff""\xff""Car-prototype", methods); - * - * // Put a global Car object - * duk::putGlobal(ctx, "car", std::make_shared()); - * - * // Call the JavaScript code - * duk::pevalString(ctx, "car.drive();"); - * } - * @endcode - * - * [oojs]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript - * [RTTI]: https://en.wikipedia.org/wiki/Run-time_type_information - */ - -/** - * \page js-concepts Concepts - * - * @subpage js-concept-class - */ - -/** - * \page js-concept-class Class (Concept) - * \brief This concept is used when exporting C++ class through JavaScript. - * - * When using `std::shared_ptr` with duk::TypeTraits, the user must implement some function by specializing - * duk::TypeTraits. - * - * ## Public static member functions - * - * ### Prototype (optional) - * - * The prototype function is optional, it is only required when exporting the C++ object using duk::push. It must push - * the prototype of your object at the top of the stack. - * - * @code - * static void prototype(duk::ContextPtr ctx); - * @endcode - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace malikania { - -/** - * Duktape C++ namespace wrapper. - */ -namespace duk { - -class Context; - -/** - * \brief Typedef without pointer. - */ -using ContextPtr = 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_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: - ContextPtr 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(ContextPtr ctx, unsigned expected = 0) noexcept -#if !defined(NDEBUG) - : m_context(ctx) - , m_expected(expected) - , m_begin(static_cast(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) - assert((unsigned)duk_get_top(m_context) - m_begin == m_expected); -#endif - } -}; - -/** - * \brief Inherit this class to make type safe C++ objects into JavaScript - */ -class Bindable { -public: - /** - * Default constructor - */ - Bindable() = default; - - /** - * Default destructor. - */ - virtual ~Bindable() = default; -}; - -/** - * \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(ContextPtr 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(ContextPtr ctx, int index); - * @endcode - * - * ## Is - * - * Tells if the value at given index is of the requested type. - * - * @code - * static bool is(ContextPtr ctx, int index); - * @endcode - * - * ## Optional - * - * Get the value at the given index or return the defaultValue. - * - * @code - * static Type optional(ContextPtr ctx, int index, Type defaultValue); - * @endcode - * - * ## Push - * - * Push the value into the stack. - * - * @code - * static void push(ContextPtr ctx, Type value); - * @endcode - * - * ## Put - * - * Apply the value to the object at the top of the stack. - * - * @code - * static void put(ContextPtr ctx, Type value); - * @endcode - * - * ## Require - * - * Require a value at the given index. - * - * @code - * static Type require(ContextPtr ctx, int index); - * @endcode - * - */ -template -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}; -}; - -/** - * \brief Map of functions. - */ -using FunctionMap = std::unordered_map; - -/** - * \brief Map of any type. - */ -template -using Map = std::unordered_map; - -/** - * \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(); - } -}; - -/** - * \class Context - * \brief RAII based Duktape handler. - * - * This class is implicitly convertible to duk_context for convenience. - */ -class Context { -private: - using Deleter = void (*)(duk_context *); - using Handle = std::unique_ptr; - - Handle m_handle; - - Context(const Context &) = delete; - Context &operator=(const Context &) = delete; - -public: - /** - * Create default context. - */ - inline Context() - : m_handle(duk_create_heap_default(), duk_destroy_heap) - { - } - - /** - * Default move constructor. - */ - Context(Context &&) 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. - */ - Context &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_base64_decode](http://duktape.org/api.html#duk_base64_decode). - * - * \param ctx the context - * \param index the index - */ -inline void base64Decode(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr 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 - */ -inline duk_codepoint_t charCodeAt(ContextPtr 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(ContextPtr ctx, Index extra) -{ - return duk_check_stack(ctx, extra); -} - -/** - * 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(ContextPtr ctx, Index top) -{ - return duk_check_stack_top(ctx, top); -} - -/** - * 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(ContextPtr ctx, Index index, int type) -{ - return duk_check_type(ctx, index, type); -} - -/** - * 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(ContextPtr ctx, Index index, unsigned mask) -{ - return duk_check_type_mask(ctx, index, mask); -} - -/** - * Wrapper for [duk_compact](http://duktape.org/api.html#duk_compact). - * - * \param ctx the context - * \param objIndex the object index - */ -inline void compact(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, Index index) -{ - return duk_del_prop(ctx, index); -} - -/** - * 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(ContextPtr ctx, Index index, unsigned position) -{ - return duk_del_prop_index(ctx, index, position); -} - -/** - * 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(ContextPtr ctx, Index index, const std::string &name) -{ - return duk_del_prop_string(ctx, index, name.c_str()); -} - -/** - * Wrapper for [duk_dup](http://duktape.org/api.html#duk_dup). - * - * \param ctx the context - * \param index the value to copy - */ -inline void dup(ContextPtr 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(ContextPtr ctx, Index index1, Index index2) -{ - return duk_equals(ctx, index1, index2); -} - -/** - * Wrapper for [duk_eval](http://duktape.org/api.html#duk_eval). - * - * \param ctx the context - */ -inline void eval(ContextPtr 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(ContextPtr ctx, const std::string &path, bool result = true) -{ - if (result) - duk_eval_file(ctx, path.c_str()); - else - 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(ContextPtr ctx, const std::string &src, bool result = true) -{ - if (result) - duk_eval_string(ctx, src.c_str()); - else - 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(ContextPtr 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(ContextPtr ctx, Index index) -{ - return duk_has_prop(ctx, index); -} - -/** - * 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(ContextPtr ctx, Index index, unsigned position) -{ - return duk_has_prop_index(ctx, index, position); -} - -/** - * Wrapper for [duk_has_prop](http://duktape.org/api.html#duk_has_prop). - * - * \param ctx the context - * \param index the object index - * \param name the property name - * \return true if has - */ -inline bool hasProperty(ContextPtr ctx, int index, const std::string &name) -{ - return duk_has_prop_string(ctx, index, name.c_str()); -} - -/** - * 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(ContextPtr 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(ContextPtr ctx, Index idx1, Index idx2) -{ - return duk_instanceof(ctx, idx1, idx2); -} - -/** - * Wrapper for [duk_join](http://duktape.org/api.html#duk_join). - * - * \param ctx the context - * \param count the number of values - */ -inline void join(ContextPtr 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(ContextPtr 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(ContextPtr 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 - */ -inline Index normalizeIndex(ContextPtr 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 - */ -inline int pcall(ContextPtr 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 - */ -inline int pcallMethod(ContextPtr 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 - */ -inline int pcallProperty(ContextPtr 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 - */ -inline int peval(ContextPtr 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 - */ -inline int pevalFile(ContextPtr 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 - */ -inline int pevalString(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, Index index) -{ - duk_replace(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(ContextPtr 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx) -{ - return duk_get_top(ctx); -} - -/** - * Wrapper for [duk_throw](http://duktape.org/api.html#duk_throw). - * - * \param ctx the context - */ -inline void raise(ContextPtr 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 -inline void raise(ContextPtr ctx, int type, const char *fmt, Args&&... args) -{ - duk_error(ctx, type, fmt, std::forward(args)...); -} - -/** - * Wrapper for [duk_get_type](http://duktape.org/api.html#duk_get_type). - * - * \param ctx the context - * \param index the idnex - * \return the type - */ -inline int type(ContextPtr 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 - * \return the information - */ -inline Exception exception(ContextPtr ctx, int index) -{ - Exception ex; - StackAssert sa(ctx); - - 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); - - return ex; -} - -/** - * Push a value into the stack. Calls TypeTraits::push(ctx, value); - * - * \param ctx the context - * \param value the value to forward - */ -template -inline void push(ContextPtr ctx, Type &&value) -{ - TypeTraits>::push(ctx, std::forward(value)); -} - -/** - * Put the value to the object at the top of the stack. Calls TypeTraits::put(ctx, value); - * - * \param ctx the context - * \param value the value to apply - */ -template -inline void put(ContextPtr ctx, Type &&value) -{ - TypeTraits>::put(ctx, std::forward(value)); -} - -/** - * Generic template function to get a value from the stack. - * - * \param ctx the context - * \param index the index - * \return the value - */ -template -inline auto get(ContextPtr ctx, int index) -> decltype(TypeTraits::get(ctx, 0)) -{ - return TypeTraits::get(ctx, index); -} - -/** - * Require a type at the specified index. - * - * \param ctx the context - * \param index the index - * \return the value - */ -template -inline auto require(ContextPtr ctx, int index) -> decltype(TypeTraits::require(ctx, 0)) -{ - return TypeTraits::require(ctx, index); -} - -/** - * Check if a value is a type of T. - * - * The TypeTraits 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 -inline bool is(ContextPtr ctx, int index) -{ - return TypeTraits::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 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 -inline auto optional(ContextPtr ctx, int index, Type &&defaultValue) -{ - return TypeTraits>::optional(ctx, index, std::forward(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 ::value> * = nullptr> -inline auto getProperty(ContextPtr ctx, int index, const std::string &name) -> decltype(get(ctx, 0)) -{ - duk_get_prop_string(ctx, index, name.c_str()); - decltype(get(ctx, 0)) value = get(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 ::value> * = nullptr> -inline auto getProperty(ContextPtr ctx, int index, int position) -> decltype(get(ctx, 0)) -{ - duk_get_prop_index(ctx, index, position); - decltype(get(ctx, 0)) value = get(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 ::value> * = nullptr> -inline void getProperty(ContextPtr 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 ::value> * = nullptr> -inline void getProperty(ContextPtr 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 -inline auto optionalProperty(ContextPtr ctx, int index, const std::string &name, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward(def))) -{ - duk_get_prop_string(ctx, index, name.c_str()); - decltype(optional(ctx, 0, std::forward(def))) value = optional(ctx, -1, std::forward(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 -inline auto optionalProperty(ContextPtr ctx, int index, int position, DefaultValue &&def) -> decltype(optional(ctx, 0, std::forward(def))) -{ - duk_get_prop_index(ctx, index, position); - decltype(optional(ctx, 0, std::forward(def))) value = optional(ctx, -1, std::forward(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 -void putProperty(ContextPtr ctx, int index, const std::string &name, Type &&value) -{ - index = duk_normalize_index(ctx, index); - - push(ctx, std::forward(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 -void putProperty(ContextPtr ctx, int index, int position, Type &&value) -{ - index = duk_normalize_index(ctx, index); - - push(ctx, std::forward(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 -inline auto getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t::value> * = nullptr) -> decltype(get(ctx, 0)) -{ - duk_get_global_string(ctx, name.c_str()); - decltype(get(ctx, 0)) value = get(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Overload that push the value at the top of the stack instead of returning it. - */ -template -inline void getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t::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 -inline void putGlobal(ContextPtr ctx, const std::string &name, Type&& type) -{ - push(ctx, std::forward(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(ContextPtr 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 -void enumerate(ContextPtr 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 -inline auto self(ContextPtr ctx) -> decltype(TypeTraits::require(ctx, 0)) -{ - duk_push_this(ctx); - decltype(TypeTraits::require(ctx, 0)) value = TypeTraits::require(ctx, -1); - duk_pop(ctx); - - return value; -} - -/** - * Throw an ECMAScript exception. - * - * \param ctx the context - * \param ex the exception - */ -template -void raise(ContextPtr ctx, const Exception &ex) -{ - ex.raise(ctx); -} - -/** - * Construct the object in place, setting value as this binding. - * - * The TypeTraits 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 -inline void construct(ContextPtr ctx, T &&value) -{ - TypeTraits>::construct(ctx, std::forward(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(ContextPtr 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)) - { - } -}; - -/* ------------------------------------------------------------------ - * Standard overloads for TypeTraits - * ------------------------------------------------------------------ */ - -/** - * \class TypeTraits - * \brief Default implementation for int. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits { -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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_is_number(ctx, index); - } - - /** - * 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_require_int(ctx, index); - } -}; - -/** - * \class TypeTraits - * \brief Default implementation for bool. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits { -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(ContextPtr ctx, int index) - { - return duk_get_boolean(ctx, index); - } - - /** - * Check if value is a boolean. - * - * \param ctx the context - * \param index the index - * \return true if boolean - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_boolean(ctx, index); - } - - /** - * 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_require_boolean(ctx, index); - } -}; - -/** - * \class TypeTraits - * \brief Default implementation for double. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits { -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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_is_number(ctx, index); - } - - /** - * 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_require_number(ctx, index); - } -}; - -/** - * \class TypeTraits - * \brief Default implementation for std::string. - * - * Provides: get, is, optional, push, require. - * - * Note: the functions allows embedded '\0'. - */ -template <> -class TypeTraits { -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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_is_string(ctx, index); - } - - /** - * 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, int index) - { - duk_size_t size; - const char *text = duk_require_lstring(ctx, index, &size); - - return std::string{text, size}; - } -}; - -/** - * \class TypeTraits - * \brief Default implementation for const char literals. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits { -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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_is_string(ctx, index); - } - - /** - * 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_require_string(ctx, index); - } -}; - -/** - * \class TypeTraits - * \brief Default implementation for unsigned. - * - * Provides: get, is, optional, push, require. - */ -template <> -class TypeTraits { -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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_is_number(ctx, index); - } - - /** - * 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, int index) - { - return duk_require_uint(ctx, index); - } -}; - -/** - * \brief Implementation for non-managed pointers. - * - * Provides: get, is, optional, push, require. - */ -template -class TypeTraits { -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(ContextPtr ctx, int index) - { - return static_cast(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(ContextPtr ctx, int index) - { - return duk_is_pointer(ctx, index); - } - - /** - * 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(ContextPtr 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(ContextPtr 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(ContextPtr ctx, int index) - { - return static_cast(duk_require_pointer(ctx, index)); - } -}; - -/** - * \class TypeTraits - * \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 { -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(ContextPtr ctx, Index index) - { - return duk_is_callable(ctx, index); - } - - /** - * 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(ContextPtr ctx, Function fn) - { - duk_push_c_function(ctx, fn.function, fn.nargs); - } -}; - -/** - * \class TypeTraits - * \brief Put the functions to the object at the top of the stack. - * - * Provides: put. - */ -template <> -class TypeTraits { -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(ContextPtr 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 - * \brief Push empty object to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits { -public: - /** - * Check if value is an object. - * - * \param ctx the context - * \param index the index - * \return true if object - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_object(ctx, index); - } - - /** - * Create an empty object on the stack. - * - * \param ctx the context - */ - static inline void push(ContextPtr ctx, const Object &) - { - duk_push_object(ctx); - } -}; - -/** - * \class TypeTraits - * \brief Push empty array to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits { -public: - /** - * Check if value is a array. - * - * \param ctx the context - * \param index the index - * \return true if array - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_array(ctx, index); - } - - /** - * Create an empty array on the stack. - * - * \param ctx the context - */ - static inline void push(ContextPtr ctx, const Array &) - { - duk_push_array(ctx); - } -}; - -/** - * \class TypeTraits - * \brief Push undefined value to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits { -public: - /** - * Check if value is undefined. - * - * \param ctx the context - * \param index the index - * \return true if undefined - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_undefined(ctx, index); - } - - /** - * Push undefined value on the stack. - * - * \param ctx the context - */ - static inline void push(ContextPtr ctx, const Undefined &) - { - duk_push_undefined(ctx); - } -}; - -/** - * \class TypeTraits - * \brief Push null value to the stack. - * - * Provides: is, push. - */ -template <> -class TypeTraits { -public: - /** - * Check if value is null. - * - * \param ctx the context - * \param index the index - * \return true if null - */ - static inline bool is(ContextPtr ctx, int index) - { - return duk_is_null(ctx, index); - } - - /** - * Push null value on the stack. - * - * \param ctx the context - */ - static inline void push(ContextPtr ctx, const Null &) - { - duk_push_null(ctx); - } -}; - -/** - * \brief Push this binding into the stack. - * - * Provides: push. - */ -template <> -class TypeTraits { -public: - /** - * Push this function into the stack. - * - * \param ctx the context - */ - static inline void push(ContextPtr ctx, const This &) - { - duk_push_this(ctx); - } -}; - -/** - * \class TypeTraits - * \brief Push the global object to the stack. - * - * Provides: push. - */ -template <> -class TypeTraits { -public: - /** - * Push the global object into the stack. - * - * \param ctx the context - */ - static inline void push(ContextPtr 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 -class TypeTraits> { -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(ContextPtr ctx, const std::unordered_map &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(ContextPtr ctx, const std::unordered_map &map) - { - assert(type(ctx, -1) == DUK_TYPE_OBJECT); - - StackAssert sa(ctx); - - for (const auto &pair : map) { - TypeTraits::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 -class TypeTraits> { -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 get(ContextPtr ctx, int index) - { - StackAssert sa(ctx, 0); - - std::vector result; - - if (!duk_is_array(ctx, -1)) - return result; - - int total = duk_get_length(ctx, index); - - for (int i = 0; i < total; ++i) - result.push_back(getProperty(ctx, index, i)); - - return result; - } - - /** - * Create an array with the specified values. - * - * \param ctx the context - * \param array the values - */ - static void push(ContextPtr ctx, const std::vector &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(ContextPtr ctx, const std::vector &array) - { - assert(type(ctx, -1) == DUK_TYPE_OBJECT); - - StackAssert sa(ctx); - - unsigned i = 0; - for (const auto &v : array) { - TypeTraits::push(ctx, v); - duk_put_prop_index(ctx, -2, i++); - } - } -}; - -/** - * \brief Implementation of managed std::shared_ptr. - * - * This specialization requires T to be @ref js-concept-class. - */ -template -class TypeTraits> { -private: - static void apply(ContextPtr ctx, std::shared_ptr value) - { - StackAssert sa(ctx, 0); - - duk_push_pointer(ctx, new std::shared_ptr(std::move(value))); - duk_put_prop_string(ctx, -2, "\xff""\xff""js-shared-ptr"); - duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret { - duk_get_prop_string(ctx, 0, "\xff""\xff""js-shared-ptr"); - delete static_cast *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_push_null(ctx); - duk_put_prop_string(ctx, 0, "\xff""\xff""js-shared-ptr"); - - return 0; - }, 1); - duk_set_finalizer(ctx, -2); - } - -public: - /** - * Construct the shared_ptr as this. - * - * \param ctx the context - * \param value the value - */ - static void construct(ContextPtr ctx, std::shared_ptr value) - { - static_assert(std::is_base_of::value, "T must be base of Bindable"); - - StackAssert sa(ctx, 0); - - duk_push_this(ctx); - apply(ctx, std::move(value)); - duk_pop(ctx); - } - - /** - * Push a managed shared_ptr as object. - * - * \param ctx the context - * \param value the value - */ - static void push(ContextPtr ctx, std::shared_ptr value) - { - static_assert(std::is_base_of::value, "T must be base of Bindable"); - - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - apply(ctx, std::move(value)); - TypeTraits::prototype(ctx); - duk_set_prototype(ctx, -2); - } - - /** - * Get a managed std::shared_ptr from the stack. - * - * \param ctx the context - * \param index the object index - * \return the pointer or a null if invalid - */ - static std::shared_ptr get(ContextPtr ctx, Index index) - { - static_assert(std::is_base_of::value, "T must be base of Bindable"); - - StackAssert sa(ctx); - - auto ptr = getProperty *>(ctx, index, "\xff""\xff""js-shared-ptr"); - - return (ptr == nullptr) ? nullptr : std::dynamic_pointer_cast(*ptr); - } - - /** - * Require a managed shared_ptr from the stack. - * - * Raise a JavaScript error if the object is not valid. - * - * \param ctx the context - * \param index the index - * \return the pointer - */ - static std::shared_ptr require(ContextPtr ctx, Index index) - { - static_assert(std::is_base_of::value, "T must be base of Bindable"); - - auto ptr = get(ctx, index); - - if (!ptr) - duk::raise(ctx, DUK_ERR_TYPE_ERROR, "invalid this binding"); - - return ptr; - } -}; - -} // !duk - -} // !malikania - -#endif // !JS_HPP diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-animation/main.cpp --- a/tests/libclient/js-animation/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-animation/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -21,8 +21,8 @@ #include -#include #include +#include #include #include #include @@ -36,42 +36,38 @@ protected: ResourcesLocatorDirectory m_locator; ClientResourcesLoader m_loader; - - duk::Context m_ctx; + UniqueContext m_ctx; public: TestAnimation() : m_locator(SOURCE_DIRECTORY "/resources") , m_loader(m_locator) { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaAnimation(m_ctx); - loadMalikaniaAnimator(m_ctx); - loadMalikaniaWindow(m_ctx); - - /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_animation(m_ctx); + dukx_load_animator(m_ctx); + dukx_load_window(m_ctx); + dukx_put_client_loader(m_ctx, &m_loader); } }; TEST_F(TestAnimation, basic) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "w = new Malikania.Window();" "a = new Malikania.Animation('animations/margins.json');" "d = new Malikania.Animator(a);" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); ElapsedTimer timer; while (timer.elapsed() < 8000) { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "w.setDrawingColor('lightskyblue');" "w.clear();" "d.draw(w, { x: 320 - 16, y: 240 - 16 });" @@ -79,9 +75,8 @@ "w.present();" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); } std::this_thread::sleep_for(3s); diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-color/main.cpp --- a/tests/libclient/js-color/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-color/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -24,14 +24,23 @@ class TestColor : public testing::Test { protected: - duk::Context m_ctx; + UniqueContext m_ctx; public: TestColor() { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_color(m_ctx); + } - loadMalikaniaColor(m_ctx); + int component(const char *name) + { + duk_get_global_string(m_ctx, name); + auto value = duk_require_int(m_ctx, -1); + duk_pop(m_ctx); + + return value; } }; @@ -43,7 +52,7 @@ TEST_F(TestColor, ConstructorNoArgs) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = Malikania.Color();" "r = c.red;" "g = c.green;" @@ -51,14 +60,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(0, component("r")); + ASSERT_EQ(0, component("g")); + ASSERT_EQ(0, component("b")); + ASSERT_EQ(255, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -67,7 +75,7 @@ TEST_F(TestColor, ConstructorString) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = Malikania.Color('white');" "r = c.red;" "g = c.green;" @@ -75,14 +83,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(255, component("r")); + ASSERT_EQ(255, component("g")); + ASSERT_EQ(255, component("b")); + ASSERT_EQ(255, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -91,7 +98,7 @@ TEST_F(TestColor, ConstructorStringRgb) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = Malikania.Color('#0000ff');" "r = c.red;" "g = c.green;" @@ -99,14 +106,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(0, component("r")); + ASSERT_EQ(0, component("g")); + ASSERT_EQ(255, component("b")); + ASSERT_EQ(255, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -115,7 +121,7 @@ TEST_F(TestColor, Constructor3Args) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = Malikania.Color(10, 20, 30);" "r = c.red;" "g = c.green;" @@ -123,14 +129,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(10, component("r")); + ASSERT_EQ(20, component("g")); + ASSERT_EQ(30, component("b")); + ASSERT_EQ(255, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -139,7 +144,7 @@ TEST_F(TestColor, Constructor4Args) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = Malikania.Color(10, 20, 30, 40);" "r = c.red;" "g = c.green;" @@ -147,14 +152,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(10, component("r")); + ASSERT_EQ(20, component("g")); + ASSERT_EQ(30, component("b")); + ASSERT_EQ(40, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -163,7 +167,7 @@ TEST_F(TestColor, ConstructorObjectNoAlpha) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = Malikania.Color({ red: 10, green: 20, blue: 30 });" "r = c.red;" "g = c.green;" @@ -171,14 +175,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(10, component("r")); + ASSERT_EQ(20, component("g")); + ASSERT_EQ(30, component("b")); + ASSERT_EQ(255, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -187,7 +190,7 @@ TEST_F(TestColor, ConstructorObjectAlpha) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 40 });" "r = c.red;" "g = c.green;" @@ -195,14 +198,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(10, component("r")); + ASSERT_EQ(20, component("g")); + ASSERT_EQ(30, component("b")); + ASSERT_EQ(40, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -214,7 +216,7 @@ * Just one test, function parse the same way, only 'this' or a new object is returned. */ try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "c = new Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 40 });" "r = c.red;" "g = c.green;" @@ -222,14 +224,13 @@ "a = c.alpha;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "a")); + ASSERT_EQ(10, component("r")); + ASSERT_EQ(20, component("g")); + ASSERT_EQ(30, component("b")); + ASSERT_EQ(40, component("a")); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -243,7 +244,7 @@ TEST_F(TestColor, InvalidConstructorArg1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color(null);" "} catch (e) {" @@ -252,12 +253,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("TypeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("TypeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -266,7 +270,7 @@ TEST_F(TestColor, InvalidConstructorArg2) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color(10, null, 30);" "} catch (e) {" @@ -275,12 +279,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("TypeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("TypeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -289,7 +296,7 @@ TEST_F(TestColor, InvalidConstructorRange1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color(-1, 20, 30);" "} catch (e) {" @@ -298,12 +305,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -312,7 +322,7 @@ TEST_F(TestColor, InvalidConstructorRange2) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color(10, 20, 256);" "} catch (e) {" @@ -321,12 +331,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -335,7 +348,7 @@ TEST_F(TestColor, InvalidConstructorRange3) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color(10, 20, 30, 800);" "} catch (e) {" @@ -344,12 +357,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -358,7 +374,7 @@ TEST_F(TestColor, InvalidConstructorRange4) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color({ red: -1, green: 20, blue: 30 });" "} catch (e) {" @@ -367,12 +383,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -381,7 +400,7 @@ TEST_F(TestColor, InvalidConstructorRange5) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color({ red: 10, green: 20, blue: 30, alpha: 800 });" "} catch (e) {" @@ -390,12 +409,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -404,7 +426,7 @@ TEST_F(TestColor, InvalidConstructorStringUnknown) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color('does not exist');" "} catch (e) {" @@ -413,12 +435,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("Error", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("Error", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -427,7 +452,7 @@ TEST_F(TestColor, InvalidConstructorStringRgb) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Color('#ghijkl');" "} catch (e) {" @@ -436,12 +461,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("Error", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("Error", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -458,27 +486,39 @@ TEST_F(TestColor, requireSuccess) { try { - duk::putGlobal(m_ctx, "draw", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Color color = duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Color color = dukx_require_color(ctx, 0); - duk::putGlobal(ctx, "r", static_cast(color.red())); - duk::putGlobal(ctx, "g", static_cast(color.green())); - duk::putGlobal(ctx, "b", static_cast(color.blue())); - duk::putGlobal(ctx, "a", static_cast(color.alpha())); + duk_push_uint(ctx, color.red()); + duk_put_global_string(ctx, "r"); + duk_push_uint(ctx, color.green()); + duk_put_global_string(ctx, "g"); + duk_push_uint(ctx, color.blue()); + duk_put_global_string(ctx, "b"); + duk_push_uint(ctx, color.alpha()); + duk_put_global_string(ctx, "a"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "draw"); - auto ret = duk::pevalString(m_ctx, "draw('#ff0000');"); + auto ret = duk_peval_string(m_ctx, "draw('#ff0000');"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(255, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + duk_get_global_string(m_ctx, "r"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "g"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "b"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "a"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -487,13 +527,14 @@ TEST_F(TestColor, requireFail) { try { - duk::putGlobal(m_ctx, "draw", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + dukx_require_color(ctx, 0); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "draw"); - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " draw('#ghijkl');" "} catch (e) {" @@ -502,12 +543,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("Error", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("Error", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -516,13 +560,14 @@ TEST_F(TestColor, requireFailAlpha) { try { - duk::putGlobal(m_ctx, "draw", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + dukx_require_color(ctx, 0); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "draw"); - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " draw({ red: 10, green: 20, blue: 30, alpha: 800 });" "} catch (e) {" @@ -531,12 +576,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -552,27 +600,39 @@ TEST_F(TestColor, getNormal) { try { - duk::putGlobal(m_ctx, "draw", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Color color = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Color color = dukx_get_color(ctx, 0); - duk::putGlobal(ctx, "r", static_cast(color.red())); - duk::putGlobal(ctx, "g", static_cast(color.green())); - duk::putGlobal(ctx, "b", static_cast(color.blue())); - duk::putGlobal(ctx, "a", static_cast(color.alpha())); + duk_push_uint(ctx, color.red()); + duk_put_global_string(ctx, "r"); + duk_push_uint(ctx, color.green()); + duk_put_global_string(ctx, "g"); + duk_push_uint(ctx, color.blue()); + duk_put_global_string(ctx, "b"); + duk_push_uint(ctx, color.alpha()); + duk_put_global_string(ctx, "a"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "draw"); - auto ret = duk::pevalString(m_ctx, "draw('#ff0000');"); + auto ret = duk_peval_string(m_ctx, "draw('#ff0000');"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(255, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + duk_get_global_string(m_ctx, "r"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "g"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "b"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "a"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -581,27 +641,39 @@ TEST_F(TestColor, getAdjustRgb) { try { - duk::putGlobal(m_ctx, "draw", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Color color = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Color color = dukx_get_color(ctx, 0); - duk::putGlobal(ctx, "r", static_cast(color.red())); - duk::putGlobal(ctx, "g", static_cast(color.green())); - duk::putGlobal(ctx, "b", static_cast(color.blue())); - duk::putGlobal(ctx, "a", static_cast(color.alpha())); + duk_push_uint(ctx, color.red()); + duk_put_global_string(ctx, "r"); + duk_push_uint(ctx, color.green()); + duk_put_global_string(ctx, "g"); + duk_push_uint(ctx, color.blue()); + duk_put_global_string(ctx, "b"); + duk_push_uint(ctx, color.alpha()); + duk_put_global_string(ctx, "a"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "draw"); - auto ret = duk::pevalString(m_ctx, "draw('#ghijkl');"); + auto ret = duk_peval_string(m_ctx, "draw('#ghijkl');"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(0, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + duk_get_global_string(m_ctx, "r"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "g"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "b"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "a"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -610,27 +682,39 @@ TEST_F(TestColor, getAdjustAll) { try { - duk::putGlobal(m_ctx, "draw", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Color color = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Color color = dukx_get_color(ctx, 0); - duk::putGlobal(ctx, "r", static_cast(color.red())); - duk::putGlobal(ctx, "g", static_cast(color.green())); - duk::putGlobal(ctx, "b", static_cast(color.blue())); - duk::putGlobal(ctx, "a", static_cast(color.alpha())); + duk_push_uint(ctx, color.red()); + duk_put_global_string(ctx, "r"); + duk_push_uint(ctx, color.green()); + duk_put_global_string(ctx, "g"); + duk_push_uint(ctx, color.blue()); + duk_put_global_string(ctx, "b"); + duk_push_uint(ctx, color.alpha()); + duk_put_global_string(ctx, "a"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "draw"); - auto ret = duk::pevalString(m_ctx, "draw({ red: -1, green: 256, blue: 100, alpha: 800 });"); + auto ret = duk_peval_string(m_ctx, "draw({ red: -1, green: 256, blue: 100, alpha: 800 });"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(0, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + duk_get_global_string(m_ctx, "r"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "g"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "b"); + ASSERT_EQ(100U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "a"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -639,27 +723,39 @@ TEST_F(TestColor, getSomethingElse) { try { - duk::putGlobal(m_ctx, "draw", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Color color = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Color color = dukx_get_color(ctx, 0); - duk::putGlobal(ctx, "r", static_cast(color.red())); - duk::putGlobal(ctx, "g", static_cast(color.green())); - duk::putGlobal(ctx, "b", static_cast(color.blue())); - duk::putGlobal(ctx, "a", static_cast(color.alpha())); + duk_push_uint(ctx, color.red()); + duk_put_global_string(ctx, "r"); + duk_push_uint(ctx, color.green()); + duk_put_global_string(ctx, "g"); + duk_push_uint(ctx, color.blue()); + duk_put_global_string(ctx, "b"); + duk_push_uint(ctx, color.alpha()); + duk_put_global_string(ctx, "a"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "draw"); - auto ret = duk::pevalString(m_ctx, "draw(null);"); + auto ret = duk_peval_string(m_ctx, "draw(null);"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(0, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "g")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "b")); - ASSERT_EQ(255, duk::getGlobal(m_ctx, "a")); + duk_get_global_string(m_ctx, "r"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "g"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "b"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "a"); + ASSERT_EQ(255U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-font/main.cpp --- a/tests/libclient/js-font/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-font/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include #include #include @@ -34,28 +34,25 @@ protected: ResourcesLocatorDirectory m_locator; ClientResourcesLoader m_loader; - - duk::Context m_ctx; + UniqueContext m_ctx; public: TestFont() : m_locator(SOURCE_DIRECTORY "/resources") , m_loader(m_locator) { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaFont(m_ctx); - loadMalikaniaWindow(m_ctx); - - /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_put_client_loader(m_ctx, &m_loader); + dukx_load_font(m_ctx); + dukx_load_window(m_ctx); } }; TEST_F(TestFont, basic) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "w = new Malikania.Window();" "f = new Malikania.Font('DejaVuSans.ttf', 10);" "w.setDrawingColor('lightskyblue');" @@ -67,9 +64,8 @@ "w.present();" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); std::this_thread::sleep_for(3s); } catch (const std::exception &ex) { diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-image/main.cpp --- a/tests/libclient/js-image/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-image/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include #include #include @@ -34,39 +34,39 @@ protected: ResourcesLocatorDirectory m_locator; ClientResourcesLoader m_loader; - - duk::Context m_ctx; + UniqueContext m_ctx; public: TestImage() : m_locator(SOURCE_DIRECTORY "/resources") , m_loader(m_locator) { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaImage(m_ctx); - loadMalikaniaWindow(m_ctx); - - /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_image(m_ctx); + dukx_load_window(m_ctx); + dukx_put_client_loader(m_ctx, &m_loader); } }; TEST_F(TestImage, size) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "i = new Malikania.Image('images/smiley.png');" "w = i.size.width;" "h = i.size.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(32, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(32, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(32U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(32U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -75,7 +75,7 @@ TEST_F(TestImage, basic) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "w = new Malikania.Window();" "i = new Malikania.Image('images/smiley.png');" "w.setDrawingColor('lightskyblue');" @@ -84,9 +84,8 @@ "w.present();" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); std::this_thread::sleep_for(3s); } catch (const std::exception &ex) { @@ -97,7 +96,7 @@ TEST_F(TestImage, stretch) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "w = new Malikania.Window();" "i = new Malikania.Image('images/smiley.png');" "w.setDrawingColor('lightskyblue');" @@ -106,9 +105,8 @@ "w.present();" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); std::this_thread::sleep_for(3s); } catch (const std::exception &ex) { diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-line/main.cpp --- a/tests/libclient/js-line/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-line/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -24,14 +24,14 @@ class TestLine : public testing::Test { protected: - duk::Context m_ctx; + UniqueContext m_ctx; public: TestLine() { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaLine(m_ctx); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_line(m_ctx); } }; @@ -43,7 +43,7 @@ TEST_F(TestLine, ConstructorNoArgs) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = Malikania.Line();" "x1 = r.x1;" "y1 = r.y1;" @@ -51,14 +51,21 @@ "y2 = r.y2;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x1")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y1")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x2")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y2")); + duk_get_global_string(m_ctx, "x1"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y1"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "x2"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y2"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -67,7 +74,7 @@ TEST_F(TestLine, Constructor4Args) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = Malikania.Line(10, 20, 30, 40);" "x1 = r.x1;" "y1 = r.y1;" @@ -75,14 +82,21 @@ "y2 = r.y2;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "x1")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "y1")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "x2")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "y2")); + duk_get_global_string(m_ctx, "x1"); + ASSERT_EQ(10, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y1"); + ASSERT_EQ(20, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "x2"); + ASSERT_EQ(30, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y2"); + ASSERT_EQ(40, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -91,7 +105,7 @@ TEST_F(TestLine, ConstructorObject) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = Malikania.Line({ x1: 10, y1: 20, x2: 30, y2: 40 });" "x1 = r.x1;" "y1 = r.y1;" @@ -99,14 +113,21 @@ "y2 = r.y2;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "x1")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "y1")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "x2")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "y2")); + duk_get_global_string(m_ctx, "x1"); + ASSERT_EQ(10, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y1"); + ASSERT_EQ(20, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "x2"); + ASSERT_EQ(30, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y2"); + ASSERT_EQ(40, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -115,7 +136,7 @@ TEST_F(TestLine, ConstructorNew) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = new Malikania.Line({ x1: 10, y1: 20, x2: 30, y2: 40 });" "x1 = r.x1;" "y1 = r.y1;" @@ -123,14 +144,21 @@ "y2 = r.y2;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "x1")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "y1")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "x2")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "y2")); + duk_get_global_string(m_ctx, "x1"); + ASSERT_EQ(10, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y1"); + ASSERT_EQ(20, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "x2"); + ASSERT_EQ(30, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y2"); + ASSERT_EQ(40, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -144,7 +172,7 @@ TEST_F(TestLine, InvalidConstructorArg1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Line(null);" "} catch (e) {" @@ -153,12 +181,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("TypeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("TypeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -172,27 +203,39 @@ TEST_F(TestLine, requireSuccess) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Line line = duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Line line = dukx_require_line(ctx, 0); - duk::putGlobal(ctx, "x1", line.x1()); - duk::putGlobal(ctx, "y1", line.y1()); - duk::putGlobal(ctx, "x2", line.x2()); - duk::putGlobal(ctx, "y2", line.y2()); + duk_push_int(ctx, line.x1()); + duk_put_global_string(ctx, "x1"); + duk_push_int(ctx, line.y1()); + duk_put_global_string(ctx, "y1"); + duk_push_int(ctx, line.x2()); + duk_put_global_string(ctx, "x2"); + duk_push_int(ctx, line.y2()); + duk_put_global_string(ctx, "y2"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });"); + auto ret = duk_peval_string(m_ctx, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(50, duk::getGlobal(m_ctx, "x1")); - ASSERT_EQ(80, duk::getGlobal(m_ctx, "y1")); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "x2")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "y2")); + duk_get_global_string(m_ctx, "x1"); + ASSERT_EQ(50, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y1"); + ASSERT_EQ(80, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "x2"); + ASSERT_EQ(100, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y2"); + ASSERT_EQ(200, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -201,13 +244,14 @@ TEST_F(TestLine, requireFail) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + dukx_require_line(ctx, 0); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " build({});" "} catch (e) {" @@ -216,12 +260,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("Error", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("Error", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -235,27 +282,39 @@ TEST_F(TestLine, getAdjustAll) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Line line = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Line line = dukx_get_line(ctx, 0); - duk::putGlobal(ctx, "x1", line.x1()); - duk::putGlobal(ctx, "y1", line.y1()); - duk::putGlobal(ctx, "x2", line.x2()); - duk::putGlobal(ctx, "y2", line.y2()); + duk_push_int(ctx, line.x1()); + duk_put_global_string(ctx, "x1"); + duk_push_int(ctx, line.y1()); + duk_put_global_string(ctx, "y1"); + duk_push_int(ctx, line.x2()); + duk_put_global_string(ctx, "x2"); + duk_push_int(ctx, line.y2()); + duk_put_global_string(ctx, "y2"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({});"); + auto ret = duk_peval_string(m_ctx, "build({});"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x1")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y1")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x2")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y2")); + duk_get_global_string(m_ctx, "x1"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y1"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "x2"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y2"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-point/main.cpp --- a/tests/libclient/js-point/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-point/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -24,14 +24,14 @@ class TestPoint : public testing::Test { protected: - duk::Context m_ctx; + UniqueContext m_ctx; public: TestPoint() { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaPoint(m_ctx); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_point(m_ctx); } }; @@ -43,18 +43,21 @@ TEST_F(TestPoint, ConstructorNoArgs) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "p = Malikania.Point();" "x = p.x;" "y = p.y;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -63,18 +66,21 @@ TEST_F(TestPoint, Constructor2Args) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "p = Malikania.Point(-10, -20);" "x = p.x;" "y = p.y;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(-10, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(-20, duk::getGlobal(m_ctx, "y")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(-10, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(-20, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -83,18 +89,21 @@ TEST_F(TestPoint, ConstructorObject) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "p = Malikania.Point({ x: 100, y: 200 });" "x = p.x;" "y = p.y;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "y")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(100, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(200, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -103,18 +112,21 @@ TEST_F(TestPoint, ConstructorNew) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "p = new Malikania.Point({ x: 100, y: 200 });" "x = p.x;" "y = p.y;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "y")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(100, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(200, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -128,7 +140,7 @@ TEST_F(TestPoint, InvalidConstructorArg1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Point(null);" "} catch (e) {" @@ -137,12 +149,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("TypeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("TypeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -156,23 +171,29 @@ TEST_F(TestPoint, requireSuccess) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Point point = duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Point point = dukx_require_point(ctx, 0); - duk::putGlobal(ctx, "x", point.x()); - duk::putGlobal(ctx, "y", point.y()); + duk_push_int(ctx, point.x()); + duk_put_global_string(ctx, "x"); + duk_push_int(ctx, point.y()); + duk_put_global_string(ctx, "y"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({ x: 100, y: 200 });"); + auto ret = duk_peval_string(m_ctx, "build({ x: 100, y: 200 });"); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "y")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(100, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(200, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -181,13 +202,14 @@ TEST_F(TestPoint, requireFail) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + dukx_require_point(ctx, 0); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " build({});" "} catch (e) {" @@ -196,12 +218,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("Error", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("Error", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -215,23 +240,29 @@ TEST_F(TestPoint, getAdjustAll) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Point point = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Point point = dukx_get_point(ctx, 0); - duk::putGlobal(ctx, "x", point.x()); - duk::putGlobal(ctx, "y", point.y()); + duk_push_int(ctx, point.x()); + duk_put_global_string(ctx, "x"); + duk_push_int(ctx, point.y()); + duk_put_global_string(ctx, "y"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({});"); + auto ret = duk_peval_string(m_ctx, "build({});"); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-rectangle/main.cpp --- a/tests/libclient/js-rectangle/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-rectangle/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -24,14 +24,14 @@ class TestRectangle : public testing::Test { protected: - duk::Context m_ctx; + UniqueContext m_ctx; public: TestRectangle() { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaRectangle(m_ctx); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_rect(m_ctx); } }; @@ -43,7 +43,7 @@ TEST_F(TestRectangle, ConstructorNoArgs) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = Malikania.Rectangle();" "x = r.x;" "y = r.y;" @@ -51,14 +51,21 @@ "h = r.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -67,7 +74,7 @@ TEST_F(TestRectangle, Constructor4Args) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = Malikania.Rectangle(10, 20, 30, 40);" "x = r.x;" "y = r.y;" @@ -75,14 +82,21 @@ "h = r.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "y")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(10, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(20, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(30U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(40U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -91,7 +105,7 @@ TEST_F(TestRectangle, ConstructorObject) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = Malikania.Rectangle({ x: 10, y: 20, width: 30, height: 40 });" "x = r.x;" "y = r.y;" @@ -99,14 +113,21 @@ "h = r.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "y")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(10, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(20, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(30U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(40U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -115,7 +136,7 @@ TEST_F(TestRectangle, ConstructorNew) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "r = new Malikania.Rectangle({ x: 10, y: 20, width: 30, height: 40 });" "x = r.x;" "y = r.y;" @@ -123,14 +144,21 @@ "h = r.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(10, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(20, duk::getGlobal(m_ctx, "y")); - ASSERT_EQ(30, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(40, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(10, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(20, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(30U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(40U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -144,7 +172,7 @@ TEST_F(TestRectangle, InvalidConstructorArg1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Rectangle(null);" "} catch (e) {" @@ -153,12 +181,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("TypeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("TypeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -167,7 +198,7 @@ TEST_F(TestRectangle, InvalidConstructorRange1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Rectangle(0, 0, -10, -10);" "} catch (e) {" @@ -176,12 +207,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -195,27 +229,39 @@ TEST_F(TestRectangle, requireSuccess) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Rectangle rect = duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Rectangle rect = dukx_require_rect(ctx, 0); - duk::putGlobal(ctx, "x", rect.x()); - duk::putGlobal(ctx, "y", rect.y()); - duk::putGlobal(ctx, "w", static_cast(rect.width())); - duk::putGlobal(ctx, "h", static_cast(rect.height())); + duk_push_int(ctx, rect.x()); + duk_put_global_string(ctx, "x"); + duk_push_int(ctx, rect.y()); + duk_put_global_string(ctx, "y"); + duk_push_uint(ctx, rect.width()); + duk_put_global_string(ctx, "w"); + duk_push_uint(ctx, rect.height()); + duk_put_global_string(ctx, "h"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({ x: 50, y: 80, width: 100, height: 200 });"); + auto ret = duk_peval_string(m_ctx, "build({ x: 50, y: 80, width: 100, height: 200 });"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(50, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(80, duk::getGlobal(m_ctx, "y")); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(50, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(80, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(100U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(200U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -224,13 +270,14 @@ TEST_F(TestRectangle, requireFail) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + dukx_require_rect(ctx, 0); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " build({});" "} catch (e) {" @@ -239,12 +286,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("Error", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("Error", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -258,27 +308,38 @@ TEST_F(TestRectangle, getAdjustAll) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Rectangle rect = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Rectangle rect = dukx_get_rect(ctx, 0); - duk::putGlobal(ctx, "x", rect.x()); - duk::putGlobal(ctx, "y", rect.y()); - duk::putGlobal(ctx, "w", static_cast(rect.width())); - duk::putGlobal(ctx, "h", static_cast(rect.height())); + duk_push_int(ctx, rect.x()); + duk_put_global_string(ctx, "x"); + duk_push_int(ctx, rect.y()); + duk_put_global_string(ctx, "y"); + duk_push_uint(ctx, rect.width()); + duk_put_global_string(ctx, "w"); + duk_push_uint(ctx, rect.height()); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({});"); + auto ret = duk_peval_string(m_ctx, "build({});"); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(0, duk::getGlobal(m_ctx, "x")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "y")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "x"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "y"); + ASSERT_EQ(0, duk_to_int(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-size/main.cpp --- a/tests/libclient/js-size/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-size/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -24,14 +24,14 @@ class TestSize : public testing::Test { protected: - duk::Context m_ctx; + UniqueContext m_ctx; public: TestSize() { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaSize(m_ctx); + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_size(m_ctx); } }; @@ -43,18 +43,21 @@ TEST_F(TestSize, ConstructorNoArgs) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "s = Malikania.Size();" "w = s.width;" "h = s.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -63,18 +66,21 @@ TEST_F(TestSize, Constructor2Args) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "s = Malikania.Size(100, 200);" "w = s.width;" "h = s.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(100U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(200U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -83,18 +89,21 @@ TEST_F(TestSize, ConstructorObject) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "s = Malikania.Size({ width: 100, height: 200 });" "w = s.width;" "h = s.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(100U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(200U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -103,18 +112,21 @@ TEST_F(TestSize, ConstructorNew) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "s = new Malikania.Size({ width: 100, height: 200 });" "w = s.width;" "h = s.height;" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(100U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(200U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -128,7 +140,7 @@ TEST_F(TestSize, InvalidConstructorArg1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Size(null);" "} catch (e) {" @@ -137,12 +149,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("TypeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("TypeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -151,7 +166,7 @@ TEST_F(TestSize, InvalidConstructorRange1) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Size(-1, 200);" "} catch (e) {" @@ -160,12 +175,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -174,7 +192,7 @@ TEST_F(TestSize, InvalidConstructorRange2) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Size(100, -1);" "} catch (e) {" @@ -183,12 +201,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -197,7 +218,7 @@ TEST_F(TestSize, InvalidConstructorRange3) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Size({ width: -1, height: 200 });" "} catch (e) {" @@ -206,12 +227,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -220,7 +244,7 @@ TEST_F(TestSize, InvalidConstructorRange4) { try { - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " Malikania.Size({ width: 100, height: -1 });" "} catch (e) {" @@ -229,12 +253,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("RangeError", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("RangeError", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -248,23 +275,29 @@ TEST_F(TestSize, requireSuccess) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Size size = duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Size size = dukx_require_size(ctx, 0); - duk::putGlobal(ctx, "w", static_cast(size.width())); - duk::putGlobal(ctx, "h", static_cast(size.height())); + duk_push_uint(ctx, size.width()); + duk_put_global_string(ctx, "w"); + duk_push_uint(ctx, size.height()); + duk_put_global_string(ctx, "h"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({ width: 100, height: 200 });"); + auto ret = duk_peval_string(m_ctx, "build({ width: 100, height: 200 });"); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(100, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(200, duk::getGlobal(m_ctx, "h")); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(100U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(200U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -273,13 +306,14 @@ TEST_F(TestSize, requireFail) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - duk::require(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + dukx_require_size(ctx, 0); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, + auto ret = duk_peval_string(m_ctx, "try {" " build({});" "} catch (e) {" @@ -288,12 +322,15 @@ "}" ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ("Error", duk::getGlobal(m_ctx, "name")); - ASSERT_TRUE(duk::getGlobal(m_ctx, "correct")); + duk_get_global_string(m_ctx, "name"); + ASSERT_STREQ("Error", duk_to_string(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "correct"); + ASSERT_TRUE(duk_to_boolean(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } @@ -307,23 +344,29 @@ TEST_F(TestSize, getAdjustAll) { try { - duk::putGlobal(m_ctx, "build", duk::Function{[] (duk::ContextPtr ctx) -> duk::Ret { - Size size = duk::get(ctx, 0); + duk_push_c_function(m_ctx, [] (auto ctx) { + Size size = dukx_get_size(ctx, 0); - duk::putGlobal(ctx, "w", static_cast(size.width())); - duk::putGlobal(ctx, "h", static_cast(size.height())); + duk_push_uint(ctx, size.width()); + duk_put_global_string(ctx, "w"); + duk_push_uint(ctx, size.height()); + duk_put_global_string(ctx, "h"); return 0; - }, 1}); + }, 1); + duk_put_global_string(m_ctx, "build"); - auto ret = duk::pevalString(m_ctx, "build({});"); + auto ret = duk_peval_string(m_ctx, "build({});"); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "r")); - ASSERT_EQ(0, duk::getGlobal(m_ctx, "g")); + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(0U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); } catch (const std::exception &ex) { FAIL() << ex.what(); } diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-sprite/main.cpp --- a/tests/libclient/js-sprite/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-sprite/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -21,7 +21,7 @@ #include -#include +#include #include #include #include @@ -33,153 +33,160 @@ class TestSprite : public testing::Test { protected: - ResourcesLocatorDirectory m_locator; - ClientResourcesLoader m_loader; - - duk::Context m_ctx; + ResourcesLocatorDirectory m_locator; + ClientResourcesLoader m_loader; + UniqueContext m_ctx; public: - TestSprite() - : m_locator(SOURCE_DIRECTORY "/resources") - , m_loader(m_locator) - { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaImage(m_ctx); - loadMalikaniaSprite(m_ctx); - loadMalikaniaWindow(m_ctx); - - /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); - } + TestSprite() + : m_locator(SOURCE_DIRECTORY "/resources") + , m_loader(m_locator) + { + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_image(m_ctx); + dukx_load_sprite(m_ctx); + dukx_load_window(m_ctx); + dukx_put_client_loader(m_ctx, &m_loader); + } }; TEST_F(TestSprite, cell) { - try { - auto ret = duk::pevalString(m_ctx, - "s = new Malikania.Sprite('sprites/margins.json');" - "w = s.cell.width;" - "h = s.cell.height;" - ); + try { + auto ret = duk_peval_string(m_ctx, + "s = new Malikania.Sprite('sprites/margins.json');" + "w = s.cell.width;" + "h = s.cell.height;" + ); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(32, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(32, duk::getGlobal(m_ctx, "h")); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(32U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(32U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestSprite, columns) { - try { - auto ret = duk::pevalString(m_ctx, - "s = new Malikania.Sprite('sprites/margins.json');" - "n = s.columns;" - ); + try { + auto ret = duk_peval_string(m_ctx, + "s = new Malikania.Sprite('sprites/margins.json');" + "n = s.columns;" + ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(4, duk::getGlobal(m_ctx, "n")); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "n"); + ASSERT_EQ(4U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestSprite, margins) { - try { - auto ret = duk::pevalString(m_ctx, - "s = new Malikania.Sprite('sprites/margins.json');" - "w = s.margins.width;" - "h = s.margins.height;" - ); + try { + auto ret = duk_peval_string(m_ctx, + "s = new Malikania.Sprite('sprites/margins.json');" + "w = s.margins.width;" + "h = s.margins.height;" + ); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(4, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(6, duk::getGlobal(m_ctx, "h")); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(4U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(6U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestSprite, rows) { - try { - auto ret = duk::pevalString(m_ctx, - "s = new Malikania.Sprite('sprites/margins.json');" - "n = s.rows;" - ); + try { + auto ret = duk_peval_string(m_ctx, + "s = new Malikania.Sprite('sprites/margins.json');" + "n = s.rows;" + ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - ASSERT_EQ(3, duk::getGlobal(m_ctx, "n")); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "n"); + ASSERT_EQ(3U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestSprite, space) { - try { - auto ret = duk::pevalString(m_ctx, - "s = new Malikania.Sprite('sprites/margins.json');" - "w = s.space.width;" - "h = s.space.height;" - ); + try { + auto ret = duk_peval_string(m_ctx, + "s = new Malikania.Sprite('sprites/margins.json');" + "w = s.space.width;" + "h = s.space.height;" + ); + + if (ret != 0) + throw dukx_exception(m_ctx, -1); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } - - ASSERT_EQ(2, duk::getGlobal(m_ctx, "w")); - ASSERT_EQ(3, duk::getGlobal(m_ctx, "h")); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "w"); + ASSERT_EQ(2U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + duk_get_global_string(m_ctx, "h"); + ASSERT_EQ(3U, duk_to_uint(m_ctx, -1)); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestSprite, basic) { - try { - auto ret = duk::pevalString(m_ctx, - "w = new Malikania.Window();" - "s = new Malikania.Sprite('sprites/margins.json');" - "c = 0;" - ); + try { + auto ret = duk_peval_string(m_ctx, + "w = new Malikania.Window();" + "s = new Malikania.Sprite('sprites/margins.json');" + "c = 0;" + ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - for (unsigned c = 0; c < 12; ++c) { - auto ret = duk::pevalString(m_ctx, - "w.setDrawingColor('lightskyblue');" - "w.clear();" - "s.draw(w, c++, { x: 320 - 16, y: 240 - 16 });" - "w.present();" - ); + for (unsigned c = 0; c < 12; ++c) { + auto ret = duk_peval_string(m_ctx, + "w.setDrawingColor('lightskyblue');" + "w.clear();" + "s.draw(w, c++, { x: 320 - 16, y: 240 - 16 });" + "w.present();" + ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) { + throw dukx_exception(m_ctx, -1); + } - std::this_thread::sleep_for(1s); - } - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + std::this_thread::sleep_for(1s); + } + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } int main(int argc, char **argv) diff -r 8e1241156034 -r 9af360f34c7d tests/libclient/js-window/main.cpp --- a/tests/libclient/js-window/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libclient/js-window/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -29,57 +29,55 @@ class TestWindow : public testing::Test { protected: - duk::Context m_ctx; + UniqueContext m_ctx; public: - TestWindow() - { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); - - loadMalikaniaWindow(m_ctx); - } + TestWindow() + { + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_window(m_ctx); + } }; TEST_F(TestWindow, basic) { - try { - auto ret = duk::pevalString(m_ctx, - "w = new Malikania.Window();" - "w.setDrawingColor('lightskyblue');" - "w.clear();" - "w.present();" - ); + try { + auto ret = duk_peval_string(m_ctx, + "w = new Malikania.Window();" + "w.setDrawingColor('lightskyblue');" + "w.clear();" + "w.present();" + ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - std::this_thread::sleep_for(3s); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + std::this_thread::sleep_for(3s); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestWindow, rect) { - try { - auto ret = duk::pevalString(m_ctx, - "w = new Malikania.Window();" - "w.setDrawingColor('lightskyblue');" - "w.clear();" - "w.setDrawingColor('white');" - "w.drawRectangle({ x: 10, y: 10, width: 10, height: 10 });" - "w.present();" - ); + try { + auto ret = duk_peval_string(m_ctx, + "w = new Malikania.Window();" + "w.setDrawingColor('lightskyblue');" + "w.clear();" + "w.setDrawingColor('white');" + "w.drawRectangle({ x: 10, y: 10, width: 10, height: 10 });" + "w.present();" + ); - if (ret != 0) { - throw duk::exception(m_ctx, -1); - } + if (ret != 0) + throw dukx_exception(m_ctx, -1); - std::this_thread::sleep_for(3s); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + std::this_thread::sleep_for(3s); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } int main(int argc, char **argv) diff -r 8e1241156034 -r 9af360f34c7d tests/libcommon/js-elapsed-timer/main.cpp --- a/tests/libcommon/js-elapsed-timer/main.cpp Fri Jul 01 13:32:08 2016 +0200 +++ b/tests/libcommon/js-elapsed-timer/main.cpp Wed Aug 10 14:30:51 2016 +0200 @@ -33,111 +33,119 @@ class TestElapsedTimer : public testing::Test { protected: - duk::Context m_ctx; - - TestElapsedTimer() - { - duk::putGlobal(m_ctx, "Malikania", duk::Object()); + UniqueContext m_ctx; - loadJsElapsedTimer(m_ctx); - } + TestElapsedTimer() + { + duk_push_object(m_ctx); + duk_put_global_string(m_ctx, "Malikania"); + dukx_load_elapsedtimer(m_ctx); + } - inline void assertRange(int value, int expected) const noexcept - { - if (value < (expected - margin) || value > (expected + margin)) - FAIL() << value << " is bigger than [" << (expected - margin) << ", " << (expected + margin) << "]"; - } + inline void assertRange(int value, int expected) const noexcept + { + if (value < (expected - margin) || value > (expected + margin)) + FAIL() << value << " is bigger than [" << (expected - margin) << ", " << (expected + margin) << "]"; + } }; TEST_F(TestElapsedTimer, standard) { - try { - if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::exception(m_ctx, -1); + try { + if (duk_peval_string(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) + throw dukx_exception(m_ctx, -1); - std::this_thread::sleep_for(300ms); + std::this_thread::sleep_for(300ms); - if (duk::pevalString(m_ctx, "result = timer.elapsed();") != 0) - throw duk::exception(m_ctx, -1); + if (duk_peval_string(m_ctx, "result = timer.elapsed();") != 0) + throw dukx_exception(m_ctx, -1); - assertRange(duk::getGlobal(m_ctx, "result"), 300); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "result"); + assertRange(duk_to_int(m_ctx, -1), 300); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestElapsedTimer, reset) { - try { - if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::exception(m_ctx, -1); + try { + if (duk_peval_string(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) + throw dukx_exception(m_ctx, -1); - std::this_thread::sleep_for(300ms); + std::this_thread::sleep_for(300ms); - if (duk::pevalString(m_ctx, "timer.reset(); result = timer.elapsed();") != 0) - throw duk::exception(m_ctx, -1); + if (duk_peval_string(m_ctx, "timer.reset(); result = timer.elapsed();") != 0) + throw dukx_exception(m_ctx, -1); - assertRange(duk::getGlobal(m_ctx, "result"), 0); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "result"); + assertRange(duk_to_int(m_ctx, -1), 0); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestElapsedTimer, pause) { - try { - if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::exception(m_ctx, -1); + try { + if (duk_peval_string(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) + throw dukx_exception(m_ctx, -1); - /* - * Simulate a pause in the game like this: - * - * start pause restart elapsed - * | 10ms |.5ms.| 6ms | - * - * Since the game was paused, the 5ms must not be totalized. - */ - std::this_thread::sleep_for(10ms); + /* + * Simulate a pause in the game like this: + * + * start pause restart elapsed + * | 10ms |.5ms.| 6ms | + * + * Since the game was paused, the 5ms must not be totalized. + */ + std::this_thread::sleep_for(10ms); + + if (duk_peval_string(m_ctx, "timer.pause();") != 0) + throw dukx_exception(m_ctx, -1); - if (duk::pevalString(m_ctx, "timer.pause();") != 0) - throw duk::exception(m_ctx, -1); + std::this_thread::sleep_for(5ms); - std::this_thread::sleep_for(5ms); + if (duk_peval_string(m_ctx, "timer.restart();") != 0) + throw dukx_exception(m_ctx, -1); - if (duk::pevalString(m_ctx, "timer.restart();") != 0) - throw duk::exception(m_ctx, -1); + std::this_thread::sleep_for(6ms); - std::this_thread::sleep_for(6ms); - - if (duk::pevalString(m_ctx, "result = timer.elapsed()") != 0) - throw duk::exception(m_ctx, -1); + if (duk_peval_string(m_ctx, "result = timer.elapsed()") != 0) + throw dukx_exception(m_ctx, -1); - assertRange(duk::getGlobal(m_ctx, "result"), 16); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "result"); + assertRange(duk_to_int(m_ctx, -1), 16); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } TEST_F(TestElapsedTimer, doublecheck) { - try { - if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::exception(m_ctx, -1); + try { + if (duk_peval_string(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) + throw dukx_exception(m_ctx, -1); - std::this_thread::sleep_for(50ms); + std::this_thread::sleep_for(50ms); - if (duk::pevalString(m_ctx, "result = timer.elapsed()") != 0) - throw duk::exception(m_ctx, -1); + if (duk_peval_string(m_ctx, "result = timer.elapsed()") != 0) + throw dukx_exception(m_ctx, -1); - std::this_thread::sleep_for(50ms); + std::this_thread::sleep_for(50ms); - if (duk::pevalString(m_ctx, "result = timer.elapsed()") != 0) - throw duk::exception(m_ctx, -1); + if (duk_peval_string(m_ctx, "result = timer.elapsed()") != 0) + throw dukx_exception(m_ctx, -1); - assertRange(duk::getGlobal(m_ctx, "result"), 100); - } catch (const std::exception &ex) { - FAIL() << ex.what(); - } + duk_get_global_string(m_ctx, "result"); + assertRange(duk_to_int(m_ctx, -1), 100); + duk_pop(m_ctx); + } catch (const std::exception &ex) { + FAIL() << ex.what(); + } } int main(int argc, char **argv)