Mercurial > malikania
changeset 27:0a1adf7dcca0
Common: update libjs and adapt code
line wrap: on
line diff
--- a/client/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/client/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -25,6 +25,8 @@ #include <malikania/js-animation.h> #include <malikania/js-animator.h> +#include <malikania/js-client.h> +#include <malikania/js-client-target.h> #include <malikania/js-color.h> #include <malikania/js-font.h> #include <malikania/js-image.h> @@ -64,16 +66,18 @@ loadMalikaniaSize(ctx); loadMalikaniaSprite(ctx); loadMalikaniaWindow(ctx); + loadMalikaniaClient(ctx); + loadMalikaniaClientTarget(ctx); return ctx; } -void start(duk::Context &ctx) +void start(duk::Context &ctx, std::shared_ptr<Client> client) { duk::getGlobal<void>(ctx, "start"); if (duk::is<duk::Function>(ctx, -1)) { - duk::getGlobal<void>(ctx, "\xff""\xff""window"); + duk::push(ctx, std::move(client)); duk::pcall(ctx, 1); duk::pop(ctx); } else { @@ -81,44 +85,43 @@ } } -void update(duk::Context &ctx) +void update(duk::Context &ctx, std::shared_ptr<Client> client) { duk::getGlobal<void>(ctx, "update"); if (duk::is<duk::Function>(ctx, -1)) { - duk::pcall(ctx, 0); + duk::push(ctx, std::move(client)); + duk::pcall(ctx, 1); duk::pop(ctx); } else { duk::pop(ctx); + client->update(); } } -void draw(duk::Context &ctx) +void draw(duk::Context &ctx, std::shared_ptr<Client> client) { duk::getGlobal<void>(ctx, "draw"); if (duk::is<duk::Function>(ctx, -1)) { - duk::getGlobal<void>(ctx, "\xff""\xff""window"); + duk::push(ctx, std::move(client)); duk::pcall(ctx, 1); duk::pop(ctx); } else { duk::pop(ctx); + client->draw(); } } int run(duk::Context &ctx) { - bool running = true; + auto running = true; + auto client = std::make_shared<Client>(); - /* js-window use duk::Pointer at the moment so store it from there temporarily */ - duk::putGlobal(ctx, "\xff""\xff""window", duk::Pointer<Window>{new Window}); - - Window *window = duk::getGlobal<duk::Pointer<Window>>(ctx, "\xff""\xff""window"); - - window->setOnQuit([&] () { + client->setOnQuit([&] () { running = false; }); - window->setOnKeyDown([&] (unsigned key) { + client->setOnKeyDown([&] (unsigned key) { duk::getGlobal<void>(ctx, "keyDown"); if (duk::is<duk::Function>(ctx, -1)) { @@ -129,7 +132,7 @@ duk::pop(ctx); } }); - window->setOnKeyDown([&] (unsigned key) { + client->setOnKeyDown([&] (unsigned key) { duk::getGlobal<void>(ctx, "keyUp"); if (duk::is<duk::Function>(ctx, -1)) { @@ -141,13 +144,13 @@ } }); - start(ctx); + start(ctx, client); while (running) { - window->poll(); + client->poll(); - update(ctx); - draw(ctx); + update(ctx, client); + draw(ctx, client); // TODO: remove this with an appropriate FPS calculation. std::this_thread::sleep_for(std::chrono::milliseconds(50)); @@ -165,10 +168,10 @@ ResourcesLocatorDirectory locator(directory); ClientResourcesLoader loader(locator); - duk::putGlobal(ctx, "\xff""\xff""loader", duk::RawPointer<ClientResourcesLoader>{&loader}); + duk::putGlobal(ctx, "\xff""\xff""loader", &loader); if (duk::pevalFile(ctx, path) != 0) { - duk::ErrorInfo info = duk::error(ctx, -1); + duk::Exception info = duk::exception(ctx, -1); std::cerr << info.fileName << ":" << info.lineNumber << ": " << info.stack << std::endl;
--- a/examples/01-bouncing/client.js Fri Apr 08 14:16:47 2016 +0200 +++ b/examples/01-bouncing/client.js Tue Apr 12 13:53:11 2016 +0200 @@ -38,4 +38,4 @@ window.setDrawingColor('white'); window.drawText('Malikania', font, { x: x, y: y }); window.present(); -} \ No newline at end of file +}
--- a/libclient/CMakeLists.txt Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/CMakeLists.txt Tue Apr 12 13:53:11 2016 +0200 @@ -20,12 +20,15 @@ HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/malikania/animation.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/animator.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client-resources-loader.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/color.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/font.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/image.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-animation.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-animator.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client.h + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-client-target.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-color.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-font.h ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-image.h @@ -49,12 +52,15 @@ set( SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/malikania/animator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/client-resources-loader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/color.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/font.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/image.cpp ${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-target.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-color.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-font.cpp ${CMAKE_CURRENT_SOURCE_DIR}/malikania/js-image.cpp
--- a/libclient/malikania/animation.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/animation.h Tue Apr 12 13:53:11 2016 +0200 @@ -29,6 +29,7 @@ #include <memory> #include <vector> +#include "js.h" #include "sprite.h" namespace malikania { @@ -86,7 +87,7 @@ * * @see Animator */ -class Animation { +class Animation : public duk::Bindable { private: Sprite m_sprite; AnimationFrames m_frames;
--- a/libclient/malikania/animator.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/animator.h Tue Apr 12 13:53:11 2016 +0200 @@ -24,7 +24,8 @@ * @brief Draw animations. */ -#include <malikania/elapsed-timer.h> +#include "elapsed-timer.h" +#include "js.h" namespace malikania { @@ -38,7 +39,7 @@ * * The animator contains an animation and a state. */ -class Animator { +class Animator : public duk::Bindable { private: Animation &m_animation; ElapsedTimer m_timer;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/client.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -0,0 +1,57 @@ +#include "client.h" +#include "window.h" + +namespace malikania { + +Client::Client() + : m_loading(std::make_shared<Loading>()) + , m_target(m_loading) +{ +} + +void Client::setTarget(std::shared_ptr<Target> target) +{ + m_targetNext = std::move(target); +} + +void Client::update() +{ + if (m_targetNext) { + m_target->unload(*this); + m_target = std::move(m_targetNext); + m_target->load(*this); + } + + m_target->update(*this); +} + +void Client::draw() +{ + m_target->draw(*this); +} + +void Client::Target::load(Client &) +{ +} + +void Client::Target::update(Client &) +{ +} + +void Client::Target::draw(Client &) +{ +} + +void Client::Target::unload(Client &) +{ +} + +void Client::Loading::update(Client &) +{ +} + +void Client::Loading::draw(Client &) +{ +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/client.h Tue Apr 12 13:53:11 2016 +0200 @@ -0,0 +1,54 @@ +#ifndef MALIKANIA_CLIENT_H +#define MALIKANIA_CLIENT_H + +#include <memory> + +#include "window.h" + +namespace malikania { + +class Client : public Window { +public: + class Target; + class Loading; + +private: + std::shared_ptr<Loading> m_loading; + std::shared_ptr<Target> m_target; + std::shared_ptr<Target> m_targetNext; + +public: + Client(); + + void setTarget(std::shared_ptr<Target> target); + + void update(); + + void draw(); +}; + +class Client::Target : public duk::Bindable { +public: + Target() = default; + + virtual ~Target() = default; + + virtual void load(Client &client); + + virtual void update(Client &client); + + virtual void draw(Client &client); + + virtual void unload(Client &client); +}; + +class Client::Loading : public Client::Target { +public: + virtual void update(Client &client); + + virtual void draw(Client &client); +}; + +} // !malikania + +#endif // !MALIKANIA_CLIENT_H
--- a/libclient/malikania/font.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/font.h Tue Apr 12 13:53:11 2016 +0200 @@ -27,6 +27,7 @@ #include <memory> #include <string> +#include "js.h" #include "size.h" namespace malikania { @@ -35,7 +36,7 @@ * @class Font * @brief Font object. */ -class Font { +class Font : public duk::Bindable { private: class Backend;
--- a/libclient/malikania/image.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/image.h Tue Apr 12 13:53:11 2016 +0200 @@ -27,6 +27,7 @@ #include <memory> #include <string> +#include "js.h" #include "point.h" #include "rectangle.h" #include "size.h" @@ -39,7 +40,7 @@ * @class Image * @brief Image object. */ -class Image { +class Image : public duk::Bindable { private: class Backend;
--- a/libclient/malikania/js-animation.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-animation.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -32,10 +32,10 @@ } try { - auto loader = duk::getGlobal<duk::RawPointer<ClientResourcesLoader>>(ctx, "\xff""\xff""loader"); + auto loader = duk::getGlobal<ClientResourcesLoader *>(ctx, "\xff""\xff""loader"); auto animation = loader->loadAnimation(duk::require<std::string>(ctx, 0)); - duk::construct(ctx, duk::Pointer<Animation>{new Animation(std::move(animation))}); + duk::construct(ctx, std::make_shared<Animation>(std::move(animation))); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); }
--- a/libclient/malikania/js-animation.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-animation.h Tue Apr 12 13:53:11 2016 +0200 @@ -24,24 +24,6 @@ namespace malikania { -namespace duk { - -template <> -class TypeTraits<Animation> { -public: - static std::string name() - { - return "\xff""\xff""Animation"; - } - - static std::vector<std::string> inherits() - { - return {}; - } -}; - -} // !duk - void loadMalikaniaAnimation(duk::ContextPtr ctx); } // !malikania
--- a/libclient/malikania/js-animator.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-animator.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -31,7 +31,7 @@ duk::raise(ctx, DUK_ERR_ERROR, "animator must be new-constructed"); } - duk::construct(ctx, duk::Pointer<Animator>{new Animator(*duk::get<duk::Pointer<Animation>>(ctx, 0))}); + duk::construct(ctx, std::make_shared<Animator>(*duk::require<std::shared_ptr<Animation>>(ctx, 0))); /* Be sure animation get not collected before */ duk::push(ctx, duk::This()); @@ -44,8 +44,8 @@ duk::Ret draw(duk::ContextPtr ctx) { try { - auto self = duk::self<duk::Pointer<Animator>>(ctx); - auto window = duk::get<duk::Pointer<Window>>(ctx, 0); + auto self = duk::self<std::shared_ptr<Animator>>(ctx); + auto window = duk::get<std::shared_ptr<Window>>(ctx, 0); auto point = duk::get<Point>(ctx, 1); self->draw(*window, point); @@ -58,7 +58,7 @@ duk::Ret update(duk::ContextPtr ctx) { - duk::self<duk::Pointer<Animator>>(ctx)->update(); + duk::self<std::shared_ptr<Animator>>(ctx)->update(); return 0; } @@ -77,7 +77,7 @@ duk::getGlobal<void>(ctx, "Malikania"); duk::push(ctx, duk::Function{constructor, 1}); duk::push(ctx, duk::Object()); - duk::push(ctx, methods); + duk::put(ctx, methods); duk::putProperty(ctx, -2, "prototype"); duk::putProperty(ctx, -2, "Animator"); duk::pop(ctx);
--- a/libclient/malikania/js-animator.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-animator.h Tue Apr 12 13:53:11 2016 +0200 @@ -24,24 +24,6 @@ namespace malikania { -namespace duk { - -template <> -class TypeTraits<Animator> { -public: - static std::string name() - { - return "\xff""\xff""Animator"; - } - - static std::vector<std::string> inherits() - { - return {}; - } -}; - -} // !duk - void loadMalikaniaAnimator(duk::ContextPtr ctx); } // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/js-client-target.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -0,0 +1,40 @@ +#include "js-client-target.h" + +namespace malikania { + +class JsTarget : public Client::Target { +public: + +}; + +namespace { + +duk::Ret constructor(duk::ContextPtr ctx) +{ + + + return 0; +} + +duk::Ret draw(duk::ContextPtr ctx) +{ + //duk::self<std::shared_ptr<Client::Target>>(ctx)->draw(); + + return 0; +} + +} // !namespace + +void loadMalikaniaClientTarget(duk::ContextPtr ctx) +{ + duk::StackAssert sa(ctx); + + duk::getGlobal<void>(ctx, "Malikania"); + duk::getProperty<void>(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); +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/js-client-target.h Tue Apr 12 13:53:11 2016 +0200 @@ -0,0 +1,13 @@ +#ifndef MALIKANIA_JS_CLIENT_TARGET_H +#define MALIKANIA_JS_CLIENT_TARGET_H + +#include "client.h" +#include "js.h" + +namespace malikania { + +void loadMalikaniaClientTarget(duk::ContextPtr ctx); + +} // !malikania + +#endif // !MALIKANIA_JS_CLIENT_TARGET_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/js-client.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -0,0 +1,64 @@ +#include "js-client.h" +#include "js-client-target.h" +#include "js-window.h" + +namespace malikania { + +namespace { + +duk::Ret draw(duk::ContextPtr ctx) +{ + try { + duk::self<std::shared_ptr<Client>>(ctx)->draw(); + } catch (const std::exception &ex) { + duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +duk::Ret setTarget(duk::ContextPtr ctx) +{ + auto self = duk::self<std::shared_ptr<Client>>(ctx); + auto target = duk::get<std::shared_ptr<Client::Target>>(ctx, 0); + + self->setTarget(std::move(target)); + + return 0; +} + +duk::Ret update(duk::ContextPtr ctx) +{ + try { + duk::self<std::shared_ptr<Client>>(ctx)->update(); + } catch (const std::exception &ex) { + duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); + } + + return 0; +} + +const duk::FunctionMap methods{ + { "draw", { draw, 0 } }, + { "setTarget", { setTarget, 1 } }, + { "update", { update, 0 } } +}; + +} // !namespace + +void loadMalikaniaClient(duk::ContextPtr ctx) +{ + duk::StackAssert sa(ctx); + + duk::getGlobal<void>(ctx, "Malikania"); + duk::push(ctx, duk::Object()); + duk::push(ctx, duk::Object()); + duk::TypeTraits<Window>::prototype(ctx); + duk::setPrototype(ctx, -2); + duk::put(ctx, methods); + duk::putProperty(ctx, -2, "prototype"); + duk::putProperty(ctx, -2, "Client"); + duk::pop(ctx); +} + +} // !malikania
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libclient/malikania/js-client.h Tue Apr 12 13:53:11 2016 +0200 @@ -0,0 +1,32 @@ +#ifndef MALIKANIA_JS_CLIENT_H +#define MALIKANIA_JS_CLIENT_H + +#include "client.h" +#include "js.h" + +namespace malikania { + +namespace duk { + +template <> +class TypeTraits<Client> { +public: + static inline void prototype(ContextPtr ctx) + { + StackAssert sa(ctx, 1); + + getGlobal<void>(ctx, "Malikania"); + getProperty<void>(ctx, -1, "Client"); + getProperty<void>(ctx, -1, "prototype"); + remove(ctx, -2); + remove(ctx, -2); + } +}; + +} // !duk + +void loadMalikaniaClient(duk::ContextPtr ctx); + +} // !malikania + +#endif // !MALIKANIA_JS_CLIENT_H
--- a/libclient/malikania/js-font.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-font.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -33,7 +33,7 @@ } try { - auto loader = duk::getGlobal<duk::RawPointer<ClientResourcesLoader>>(ctx, "\xff""\xff""loader"); + auto loader = duk::getGlobal<ClientResourcesLoader *>(ctx, "\xff""\xff""loader"); auto id = duk::require<std::string>(ctx, 0); auto size = duk::require<int>(ctx, 1); @@ -41,7 +41,7 @@ duk::raise(ctx, DUK_ERR_RANGE_ERROR, "%d must not be negative", size); } - duk::construct(ctx, duk::Pointer<Font>{new Font(loader->loadFont(id, static_cast<unsigned>(size)))}); + duk::construct(ctx, std::make_shared<Font>(loader->loadFont(id, static_cast<unsigned>(size)))); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -52,7 +52,7 @@ duk::Ret clip(duk::ContextPtr ctx) { try { - duk::push(ctx, duk::self<duk::Pointer<Font>>(ctx)->clip(duk::require<std::string>(ctx, 0))); + duk::push(ctx, duk::self<std::shared_ptr<Font>>(ctx)->clip(duk::require<std::string>(ctx, 0))); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -73,7 +73,7 @@ duk::getGlobal<void>(ctx, "Malikania"); duk::push(ctx, duk::Function{constructor, 2}); duk::push(ctx, duk::Object()); - duk::push(ctx, methods); + duk::put(ctx, methods); duk::putProperty(ctx, -2, "prototype"); duk::putProperty(ctx, -2, "Font"); duk::pop(ctx);
--- a/libclient/malikania/js-font.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-font.h Tue Apr 12 13:53:11 2016 +0200 @@ -24,53 +24,6 @@ namespace malikania { -namespace duk { - -/** - * @brief JavaScript binding for Font. - */ -template <> -class TypeTraits<Font> { -public: - /** - * Put the Font prototype to the top of the stack. - * - * @param ctx the context - */ - static void prototype(duk::ContextPtr ctx) - { - duk::StackAssert sa(ctx, 1); - - duk::getGlobal<void>(ctx, "Malikania"); - duk::getGlobal<void>(ctx, "Font"); - duk::getProperty<void>(ctx, -1, "prototype"); - duk::remove(ctx, -2); - duk::remove(ctx, -2); - } - - /** - * Get the object signature. - * - * @return Window signature - */ - static inline std::string name() - { - return "\xff""\xff""Font"; - } - - /** - * Get inheritance list. - * - * @return empty - */ - static std::vector<std::string> inherits() - { - return {}; - } -}; - -} // !duk - void loadMalikaniaFont(duk::ContextPtr ctx); } // !malikania
--- a/libclient/malikania/js-image.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-image.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -30,7 +30,7 @@ duk::Ret size(duk::ContextPtr ctx) { try { - duk::push(ctx, duk::self<duk::Pointer<Image>>(ctx)->size()); + duk::push(ctx, duk::self<std::shared_ptr<Image>>(ctx)->size()); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -41,8 +41,8 @@ duk::Ret draw(duk::ContextPtr ctx) { try { - auto self = duk::self<duk::Pointer<Image>>(ctx); - auto window = duk::get<duk::Pointer<Window>>(ctx, 0); + auto self = duk::self<std::shared_ptr<Image>>(ctx); + auto window = duk::get<std::shared_ptr<Window>>(ctx, 0); if (duk::top(ctx) == 2) { self->draw(*window, duk::get<Point>(ctx, 1)); @@ -65,10 +65,10 @@ } try { - auto loader = duk::getGlobal<duk::RawPointer<ClientResourcesLoader>>(ctx, "\xff""\xff""loader"); + auto loader = duk::getGlobal<ClientResourcesLoader *>(ctx, "\xff""\xff""loader"); auto image = loader->loadImage(duk::require<std::string>(ctx, 0)); - duk::construct(ctx, duk::Pointer<Image>{new Image(std::move(image))}); + duk::construct(ctx, std::make_shared<Image>(std::move(image))); duk::push(ctx, duk::This()); duk::push(ctx, "size"); duk::push(ctx, duk::Function{size, 0}); @@ -94,7 +94,7 @@ duk::getGlobal<void>(ctx, "Malikania"); duk::push(ctx, duk::Function{constructor, 1}); duk::push(ctx, duk::Object()); - duk::push(ctx, methods); + duk::put(ctx, methods); duk::putProperty(ctx, -2, "prototype"); duk::putProperty(ctx, -2, "Image"); duk::pop(ctx);
--- a/libclient/malikania/js-image.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-image.h Tue Apr 12 13:53:11 2016 +0200 @@ -24,24 +24,6 @@ namespace malikania { -namespace duk { - -template <> -class TypeTraits<Image> { -public: - static inline std::string name() - { - return "\xff""\xff""Image"; - } - - static inline std::vector<std::string> inherits() - { - return {}; - } -}; - -} // !duk - void loadMalikaniaImage(duk::ContextPtr ctx); } // !malikania
--- a/libclient/malikania/js-sprite.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-sprite.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -28,35 +28,35 @@ duk::Ret cell(duk::ContextPtr ctx) { - duk::push(ctx, duk::self<duk::Pointer<Sprite>>(ctx)->cell()); + duk::push(ctx, duk::self<std::shared_ptr<Sprite>>(ctx)->cell()); return 1; } duk::Ret columns(duk::ContextPtr ctx) { - duk::push(ctx, static_cast<int>(duk::self<duk::Pointer<Sprite>>(ctx)->columns())); + duk::push(ctx, static_cast<int>(duk::self<std::shared_ptr<Sprite>>(ctx)->columns())); return 1; } duk::Ret margins(duk::ContextPtr ctx) { - duk::push(ctx, duk::self<duk::Pointer<Sprite>>(ctx)->margin()); + duk::push(ctx, duk::self<std::shared_ptr<Sprite>>(ctx)->margin()); return 1; } duk::Ret rows(duk::ContextPtr ctx) { - duk::push(ctx, static_cast<int>(duk::self<duk::Pointer<Sprite>>(ctx)->rows())); + duk::push(ctx, static_cast<int>(duk::self<std::shared_ptr<Sprite>>(ctx)->rows())); return 1; } duk::Ret space(duk::ContextPtr ctx) { - duk::push(ctx, duk::self<duk::Pointer<Sprite>>(ctx)->space()); + duk::push(ctx, duk::self<std::shared_ptr<Sprite>>(ctx)->space()); return 1; } @@ -68,10 +68,10 @@ } try { - auto loader = duk::getGlobal<duk::RawPointer<ClientResourcesLoader>>(ctx, "\xff""\xff""loader"); + auto loader = duk::getGlobal<ClientResourcesLoader *>(ctx, "\xff""\xff""loader"); auto sprite = loader->loadSprite(duk::require<std::string>(ctx, 0)); - duk::construct(ctx, duk::Pointer<Sprite>{new Sprite(std::move(sprite))}); + duk::construct(ctx, std::make_shared<Sprite>(std::move(sprite))); duk::push(ctx, duk::This()); /* Cell */ @@ -110,8 +110,8 @@ duk::Ret draw(duk::ContextPtr ctx) { try { - auto self = duk::self<duk::Pointer<Sprite>>(ctx); - auto window = duk::get<duk::Pointer<Window>>(ctx, 0); + auto self = duk::self<std::shared_ptr<Sprite>>(ctx); + auto window = duk::get<std::shared_ptr<Window>>(ctx, 0); auto cell = duk::require<int>(ctx, 1); auto point = duk::get<Point>(ctx, 2); @@ -140,7 +140,7 @@ duk::getGlobal<void>(ctx, "Malikania"); duk::push(ctx, duk::Function{constructor, 1}); duk::push(ctx, duk::Object()); - duk::push(ctx, methods); + duk::put(ctx, methods); duk::putProperty(ctx, -2, "prototype"); duk::putProperty(ctx, -2, "Sprite"); duk::pop(ctx);
--- a/libclient/malikania/js-window.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-window.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -37,7 +37,7 @@ /* TODO: add parameters */ try { - duk::construct(ctx, duk::Pointer<Window>{new Window()}); + duk::construct(ctx, std::make_shared<Window>()); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -48,7 +48,7 @@ duk::Ret clear(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->clear(); + duk::self<std::shared_ptr<Window>>(ctx)->clear(); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -59,7 +59,7 @@ duk::Ret present(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->present(); + duk::self<std::shared_ptr<Window>>(ctx)->present(); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -70,7 +70,7 @@ duk::Ret drawingColor(duk::ContextPtr ctx) { try { - duk::push(ctx, duk::self<duk::Pointer<Window>>(ctx)->drawingColor()); + duk::push(ctx, duk::self<std::shared_ptr<Window>>(ctx)->drawingColor()); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -81,7 +81,7 @@ duk::Ret drawLine(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->drawLine(duk::require<Line>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->drawLine(duk::require<Line>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -92,7 +92,7 @@ duk::Ret drawLines(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->drawLines(duk::get<std::vector<Point>>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->drawLines(duk::get<std::vector<Point>>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -103,7 +103,7 @@ duk::Ret drawPoint(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->drawPoint(duk::require<Point>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->drawPoint(duk::require<Point>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -114,7 +114,7 @@ duk::Ret drawPoints(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->drawPoints(duk::get<std::vector<Point>>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->drawPoints(duk::get<std::vector<Point>>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -125,7 +125,7 @@ duk::Ret drawRectangle(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->drawRectangle(duk::require<Rectangle>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->drawRectangle(duk::require<Rectangle>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -136,7 +136,7 @@ duk::Ret drawRectangles(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->drawRectangles(duk::get<std::vector<Rectangle>>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->drawRectangles(duk::get<std::vector<Rectangle>>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -147,9 +147,9 @@ duk::Ret drawText(duk::ContextPtr ctx) { try { - auto self = duk::self<duk::Pointer<Window>>(ctx); + auto self = duk::self<std::shared_ptr<Window>>(ctx); auto text = duk::require<std::string>(ctx, 0); - auto font = duk::get<duk::Pointer<Font>>(ctx, 1); + auto font = duk::get<std::shared_ptr<Font>>(ctx, 1); auto rect = duk::get<Rectangle>(ctx, 2); if (!rect.isNull()) { @@ -167,7 +167,7 @@ duk::Ret fillRectangle(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->fillRectangle(duk::require<Rectangle>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->fillRectangle(duk::require<Rectangle>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -178,7 +178,7 @@ duk::Ret fillRectangles(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->fillRectangles(duk::get<std::vector<Rectangle>>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->fillRectangles(duk::get<std::vector<Rectangle>>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -189,7 +189,7 @@ duk::Ret setDrawingColor(duk::ContextPtr ctx) { try { - duk::self<duk::Pointer<Window>>(ctx)->setDrawingColor(duk::require<Color>(ctx, 0)); + duk::self<std::shared_ptr<Window>>(ctx)->setDrawingColor(duk::require<Color>(ctx, 0)); } catch (const std::exception &ex) { duk::raise(ctx, DUK_ERR_ERROR, "%s", ex.what()); } @@ -222,7 +222,7 @@ duk::getGlobal<void>(ctx, "Malikania"); duk::push(ctx, duk::Function{constructor}); duk::push(ctx, duk::Object()); - duk::push(ctx, methods); + duk::put(ctx, methods); duk::putProperty(ctx, -2, "prototype"); duk::putProperty(ctx, -2, "Window"); duk::pop(ctx);
--- a/libclient/malikania/js-window.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/js-window.h Tue Apr 12 13:53:11 2016 +0200 @@ -47,26 +47,6 @@ duk::remove(ctx, -2); duk::remove(ctx, -2); } - - /** - * Get the object signature. - * - * @return Window signature - */ - static inline std::string name() - { - return "\xff""\xff""Window"; - } - - /** - * Get inheritance list. - * - * @return empty - */ - static std::vector<std::string> inherits() - { - return {}; - } }; } // !duk
--- a/libclient/malikania/sprite.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/sprite.h Tue Apr 12 13:53:11 2016 +0200 @@ -27,6 +27,7 @@ #include <malikania/json.h> #include "image.h" +#include "js.h" namespace malikania { @@ -37,7 +38,7 @@ * @class Sprite * @brief A Sprite is an image divided into cells. */ -class Sprite { +class Sprite : public duk::Bindable { private: Image m_image; Size m_cell;
--- a/libclient/malikania/window.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libclient/malikania/window.h Tue Apr 12 13:53:11 2016 +0200 @@ -29,6 +29,8 @@ #include <vector> #include <string> +#include "js.h" + namespace malikania { class Color; @@ -40,7 +42,7 @@ /** * @brief Main window class and drawing. */ -class Window { +class Window : public duk::Bindable { private: class Backend;
--- a/libcommon/malikania/elapsed-timer.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libcommon/malikania/elapsed-timer.h Tue Apr 12 13:53:11 2016 +0200 @@ -26,6 +26,8 @@ #include <chrono> +#include "js.h" + namespace malikania { /** @@ -38,7 +40,7 @@ * It uses std::chrono::high_resolution_clock for more precision and uses * milliseconds only. */ -class ElapsedTimer { +class ElapsedTimer : public duk::Bindable { public: using TimePoint = std::chrono::time_point<std::chrono::high_resolution_clock>;
--- a/libcommon/malikania/js-elapsed-timer.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/libcommon/malikania/js-elapsed-timer.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -21,24 +21,6 @@ namespace malikania { -namespace duk { - -template <> -class TypeTraits<ElapsedTimer> { -public: - static inline std::string name() - { - return "\xff""\xff""ElapsedTimer"; - } - - static inline std::vector<std::string> inherits() - { - return {}; - } -}; - -} // !duk - namespace { /* @@ -49,7 +31,7 @@ */ duk::Ret pause(duk::ContextPtr ctx) { - duk::self<duk::Pointer<ElapsedTimer>>(ctx)->pause(); + duk::self<std::shared_ptr<ElapsedTimer>>(ctx)->pause(); return 0; } @@ -62,7 +44,7 @@ */ duk::Ret reset(duk::ContextPtr ctx) { - duk::self<duk::Pointer<ElapsedTimer>>(ctx)->reset(); + duk::self<std::shared_ptr<ElapsedTimer>>(ctx)->reset(); return 0; } @@ -75,7 +57,7 @@ */ duk::Ret restart(duk::ContextPtr ctx) { - duk::self<duk::Pointer<ElapsedTimer>>(ctx)->restart(); + duk::self<std::shared_ptr<ElapsedTimer>>(ctx)->restart(); return 0; } @@ -91,7 +73,7 @@ */ duk::Ret elapsed(duk::ContextPtr ctx) { - duk::push(ctx, (int)duk::self<duk::Pointer<ElapsedTimer>>(ctx)->elapsed()); + duk::push(ctx, (int)duk::self<std::shared_ptr<ElapsedTimer>>(ctx)->elapsed()); return 1; } @@ -104,7 +86,7 @@ */ duk::Ret constructor(duk::ContextPtr ctx) { - duk::construct(ctx, duk::Pointer<ElapsedTimer>{new ElapsedTimer}); + duk::construct(ctx, std::make_shared<ElapsedTimer>()); return 0; } @@ -125,7 +107,7 @@ duk::getGlobal<void>(ctx, "Malikania"); duk::push(ctx, duk::Function{constructor, 0}); duk::push(ctx, duk::Object{}); - duk::push(ctx, methods); + duk::put(ctx, methods); duk::putProperty(ctx, -2, "prototype"); duk::putProperty(ctx, -2, "ElapsedTimer"); duk::pop(ctx);
--- a/libcommon/malikania/js.h Fri Apr 08 14:16:47 2016 +0200 +++ b/libcommon/malikania/js.h Tue Apr 12 13:53:11 2016 +0200 @@ -29,6 +29,627 @@ * 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.h** 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.h" + * + * 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<std::string, T> | push, put | push or put properties | + * | std::vector<T> | 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<T> | 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.h" + * + * int main() + * { + * duk::Context ctx; + * + * duk::pevalString(ctx, "1 + 1"); + * std::cout << duk::get<int>(ctx -1) << std::endl; + * + * return 0; + * } + * @endcode + */ + +/** + * @page js-basics-t2 Example 2: call C++ code from JavaScript + * @brief Evaluate a function from JavaScript. + * + * In that example, we will add a C++ function to JavaScript and call it from the script. The function just compute the + * two arguments that are passed through the function and return the result. + * + * We take the benefits of C++11 to map the function. The lambda can not have a capture because Duktape use raw C + * function pointers and this module keep them. + * + * @code + * #include "js.h" + * + * 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<int>(ctx, 0); + * int y = duk::require<int>(ctx, 1); + * + * duk::push(ctx, x + y); + * + * return 1; + * }, 2}); + * + * // Evaluate from JavaScript + * duk::pevalString(ctx, "add(1, 2)"); + * + * return 0; + * } + * @endcode + * + * Please note the **2** at end of lambda which indicates that the function takes 2 arguments. If number of arguments + * is variadic, pass DUK_VARARGS there. + */ + +/** + * @page js-basics-t3 Example 3: pushing and getting values + * @brief Manage values between JavaScript and C++. + * + * As you have seen in the previous examples, we were pushing some values to the Duktape context. + * + * With the C Duktape frontend, you usually use duk_push_int, duk_push_string and all other related functions. The libjs + * module provides an uniform and convenient way for sharing values with the same functions. + * + * See the description of duk::TypeTraits to see the supported types. + * + * ## Push + * + * The duk::push function is a template that accept most of the primitives types. It uses the specializations of the + * duk::TypeTraits class (described later). + * + * Example of code + * + * @code + * duk::push(ctx, 123); // an integer + * duk::push(ctx, true); // a boolean + * @endcode + * + * The push function add a new value to the stack for any specialization of TypeTraits provided by libjs. + * + * ## Get + * + * The duk::get function is similar to duk_get_ functions. It usually does not check the value and return a sane default + * value. + * + * This template function does not take the template argument so it can't be deduced and must be specified explicitly. + * + * @code + * duk::get<int>(ctx, 0) // get an int at index 0 + * duk::get<std::string>(ctx, 1) // get a std::string at index 1 + * @endcode + * + * ## Require + * + * The duk::require function is similar to duk_require functions. It requires the exact type at the given index. If the + * value is invalid a JavaScript error is propagated. + * + * @code + * duk::require<int>(ctx, 0) // require an int at index 0 or raise an error + * @endcode + * + * ## Put + * + * This special function is similar to push except that it applies to the existing object at the top of the stack. It + * is usually implemented for map and vector. + * + * @code + * // Fill the object at the top of the stack with this map + * std:unordered_map<std::string, int> map{ + * { "value1", 1 }, + * { "value2", 2 } + * }; + * + * duk::put(ctx, map); + * @endcode + * + * ## Is + * + * This function duk::is checks if the value at the given index is of the given type and return true. + * + * Just like duk::get, this function need the explicit template parameter. + * + * @code + * duk::push(ctx, 1); + * duk::is<int>(ctx, -1); // true + * @endcode + * + * ## Optional + * + * The duk::optional function has no equivalent in Duktape C API. It is a convenient way to get values with a default + * replacement is not available. + * + * The common implementation uses duk::is and then duk::get. + * + * @code + * duk::optional<int>(ctx, -1, 123); // 123 is -1 has no value or is not an int + * @endcode + */ + +/** + * @page js-more Extensions and advanced features. + * @brief Evolved extensions provided by libjs. + * + * The following topics are provided by libjs and have no equivalent in Duktape C API. + * + * @subpage js-more-t1 + * @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<Point> { + * 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<Point> { + * public: + * static Point get(ContextPtr ctx, Index index) + * { + * Point point{0, 0}; + * + * if (is<Object>(ctx, index)) { + * point.x = getProperty<int>(ctx, index, "x"); + * point.y = getProperty<int>(ctx, index, "y"); + * } + * + * return point; + * } + * }; + * + * } + * @endcode + * + * Now you can invoke `duk::get<Point>(ctx, 0)` to convert a JavaScript object to the Point structure. + * + * ## The require function + * + * The require function has the same signature as get. It's up to you to decide which criterias makes the object not + * suitable for conversion. + * + * In that example, we will require that object at the index is a JavaScript object and that **x**, **y** are present. + * + * @code + * namespace duk { + * + * template <> + * class TypeTraits<Point> { + * public: + * static Point require(ContextPtr ctx, Index index) + * { + * Point point; + * + * // Raise an error if not object + * if (!is<Object>(ctx, index)) + * duk::raise(ctx, TypeError("object required")); + * + * // Get x, for simplicity we just check that x and y exist. + * if (!hasProperty(ctx, index, "x")) + * duk::raise(ctx, TypeError("property x missing")); + * + * // Get y + * if (!hasProperty(ctx, index, "y")) + * duk::raise(ctx, TypeError("property y missing")); + * + * // Note: if you need more security, check that types are integers too. + * point.x = duk::getProperty<int>(ctx, index, "x"); + * point.y = duk::getProperty<int>(ctx, index, "y"); + * + * return point; + * } + * }; + * + * } + * @endcode + * + * ## The is function + * + * The is function returns a boolean. Again, you decide when the value is appropriate. + * + * @code + * + * namespace duk { + * + * template <> + * class TypeTraits<Point> { + * public: + * static bool is(ContextPtr ctx, Index index) + * { + * return is<Object>(ctx, index) && hasProperty(ctx, index, "x") && hasProperty(ctx, index, "y"); + * } + * }; + * + * } + * + * @endcode + * + * ## The optional function + * + * The optional function is like get, you should return a value when it is appropriate for conversion. The + * recommandation is to return the default value **only if** there is no value at the given index or it it not + * the correct type. + * + * Usual implementation looks like this: + * + * @code + * namespace duk { + * + * template <> + * class TypeTraits<Point> { + * public: + * static Point optional(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 <iostream> + * + * #include "js.h" + * + * 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<std::shared_ptr<Car>>(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<Car>()); + * + * 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<Car> { + * public: + * static inline void prototype(ContextPtr ctx) + * { + * getGlobal<void>(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<Car>()); + * + * // 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<T>` with duk::TypeTraits, the user must implement some function by specializing + * duk::TypeTraits<T>. + * + * ## 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 <cassert> #include <functional> #include <memory> @@ -49,11 +670,35 @@ class Context; -using CodePoint = duk_codepoint_t; +/** + * @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; -using Size = duk_size_t; + +/** + * @brief Typedef for duk_int_t. + */ +using Int = duk_int_t; + +/** + * @brief Typedef for duk_uint_t; + */ +using Uint = duk_uint_t; /** * @class StackAssert @@ -110,95 +755,131 @@ }; /** + * @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 <typename Type> +class TypeTraits; + +/** * @class Object - * @brief Empty class tag for push() function. + * @brief Special type for duk::TypeTraits. */ class Object { }; /** * @class Array - * @brief Empty class tag for push() function. + * @brief Special type for duk::TypeTraits. */ class Array { }; /** * @class Global - * @brief Empty class tag to push the global object. + * @brief Special type for duk::TypeTraits. */ class Global { }; /** * @class Undefined - * @brief Empty class tag to push undefined to the stack. + * @brief Special type for duk::TypeTraits. */ class Undefined { }; /** * @class Null - * @brief Empty class tag to push null to the stack. + * @brief Special type for duk::TypeTraits. */ class Null { }; /** * @class This - * @brief Empty class tag to push this binding to the stack. + * @brief Special type for duk::TypeTraits. */ class This { }; /** - * @class RawPointer - * @brief Push a non-managed pointer to Duktape, the pointer will never be deleted. - * @note For a managed pointer with prototype, see Pointer - */ -template <typename T> -class RawPointer { -public: - /** - * The pointer to push. - */ - T *object; -}; - -/** - * @brief Manage shared_ptr from C++ and JavaScript - * - * This class allowed you to push and retrieve shared_ptr from C++ and JavaScript without taking care of ownership - * and deletion. - * - */ -template <typename T> -class Shared { -public: - /** - * The shared object. - */ - std::shared_ptr<T> object; -}; - -/** - * @brief Manage pointers from C++ and JavaScript - * - * This class allowed you to push and retrieve C++ pointers from C++ and JavaScript. The object will be deleted when - * the JavaScript garbage collectors collect them so never store a pointer created with this. - * - * The only requirement is to have the function `void prototype(Context &ctx)` in your class T. - */ -template <typename T> -class Pointer { -public: - /** - * The object. - */ - T *object{nullptr}; -}; - -/** * @class Function * @brief Duktape/C function definition. * @@ -218,23 +899,23 @@ }; /** - * Map of functions to set on an object. + * @brief Map of functions. */ using FunctionMap = std::unordered_map<std::string, Function>; /** - * Map of string to type, ideal for setting constants like enums. + * @brief Map of any type. */ -template <typename Type> -using Map = std::unordered_map<std::string, Type>; +template <typename T> +using Map = std::unordered_map<std::string, T>; /** - * @class ErrorInfo + * @class Exception * @brief Error description. * * This class fills the fields got in an Error object. */ -class ErrorInfo : public std::exception { +class Exception : public std::exception { public: std::string name; //!< name of error std::string message; //!< error message @@ -254,42 +935,6 @@ }; /** - * @class TypeTraits - * @brief Type information to implement new types in JavaScript's context. - * - * This class depending on your needs may have the following functions: - * - * - `static void construct(Context &ctx, Type value)` - * - `static Type get(Context &ctx, int index)` - * - `static bool is(Context &ctx, int index)` - * - `static Type optional(Context &ctx, int index, Type defaultValue)` - * - `static void push(Context &ctx, Type value)` - * - `static Type require(Context &ctx, int index)` - * - * The `construct` function is used in Context::construct to build a new value as this (e.g. constructors). - * - * The `get` function is used in Context::get, Context::getProperty, Context::getGlobal to retrieve a value from the - * stack. - * - * The `is` function is used in Context::is to check if the value on the stack is of type `Type`. - * - * The `optional` function is used in Context::optional to get a value or a replacement if not applicable. - * - * The `push` function is used in Context::push to usually create a new value on the stack but some specializations - * may not (e.g. FunctionMap). - * - * The `require` function is used in Context::require to get a value from the stack or raise a JavaScript exception if - * not applicable. - * - * This class is fully specialized for: `bool`, `const char *`, `double`, `int`, `std::string`. - * - * It is also partially specialized for : `Global`, `Object`, `Array`, `Undefined`, `Null`, `std::vector<Type>`. - */ -template <typename Type> -class TypeTraits { -}; - -/** * @class Context * @brief RAII based Duktape handler. * @@ -305,7 +950,6 @@ Context(const Context &) = delete; Context &operator=(const Context &) = delete; - public: /** * Create default context. @@ -315,8 +959,10 @@ { } + /** + * Default move constructor. + */ Context(Context &&) noexcept = default; - Context &operator=(Context &&) noexcept = default; /** * Convert the context to the native Duktape/C type. @@ -337,35 +983,23 @@ { return m_handle.get(); } + + /** + * Default move assignment operator. + */ + Context &operator=(Context &&) noexcept = delete; }; /** - * Get the error object when a JavaScript error has been thrown (e.g. eval failure). + * @name Duktape C functions + * @brief The following functions are wrappers on top of the Duktape C functions. * - * @param ctx the context - * @param index the index - * @return the information + * They are as close as possible to the original functions. */ -inline ErrorInfo error(ContextPtr ctx, int index) -{ - ErrorInfo error; - - index = duk_normalize_index(ctx, index); - duk_get_prop_string(ctx, index, "name"); - error.name = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "message"); - error.message = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "fileName"); - error.fileName = duk_to_string(ctx, -1); - duk_get_prop_string(ctx, index, "lineNumber"); - error.lineNumber = duk_to_int(ctx, -1); - duk_get_prop_string(ctx, index, "stack"); - error.stack = duk_to_string(ctx, -1); - duk_pop_n(ctx, 5); - - return error; -} +/** + * @{ + */ /** * Wrapper for [duk_base64_decode](http://duktape.org/api.html#duk_base64_decode). @@ -383,10 +1017,11 @@ * * @param ctx the context * @param index the index + * @return the base64 string */ -inline void base64Encode(ContextPtr ctx, Index index) +inline std::string base64Encode(ContextPtr ctx, Index index) { - duk_base64_encode(ctx, index); + return duk_base64_encode(ctx, index); } /** @@ -430,7 +1065,7 @@ * @param index the index * @param charOffset the offset */ -inline CodePoint charCodeAt(ContextPtr ctx, Index index, Size charOffset) +inline duk_codepoint_t charCodeAt(ContextPtr ctx, Index index, duk_size_t charOffset) { return duk_char_code_at(ctx, index, charOffset); } @@ -510,6 +1145,7 @@ /** * Wrapper for [duk_copy](http://duktape.org/api.html#duk_copy). * + * @param ctx the context * @param from the from index * @param to the destination */ @@ -519,8 +1155,20 @@ } /** + * 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 */ @@ -532,6 +1180,7 @@ /** * 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 */ @@ -543,6 +1192,7 @@ /** * 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 @@ -555,6 +1205,7 @@ /** * 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 @@ -567,6 +1218,7 @@ /** * 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) @@ -727,10 +1379,11 @@ * * @param ctx the context * @param index the index + * @return the JSON string */ -inline void jsonEncode(ContextPtr ctx, Index index) +inline std::string jsonEncode(ContextPtr ctx, Index index) { - duk_json_encode(ctx, index); + return duk_json_encode(ctx, index); } /** @@ -756,6 +1409,29 @@ } /** + * 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 @@ -801,6 +1477,41 @@ } /** + * 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 @@ -862,34 +1573,95 @@ * @param ctx the context * @return the stack size */ -inline int top(ContextPtr ctx) noexcept +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 <typename... Args> +inline void raise(ContextPtr ctx, int type, const char *fmt, Args&&... args) +{ + duk_error(ctx, type, fmt, std::forward<Args>(args)...); +} + +/** * Wrapper for [duk_get_type](http://duktape.org/api.html#duk_get_type). * * @param ctx the context * @param index the idnex * @return the type */ -inline int type(ContextPtr ctx, Index index) noexcept +inline int type(ContextPtr ctx, Index index) { return duk_get_type(ctx, index); } -/* - * Push / Get / Require / Is / Optional - * ---------------------------------------------------------- +/** + * @} + */ + +/** + * @name Extended functions + * @brief Extended functions for libjs. * - * The following functions are used to push, get or check values from the stack. They use specialization - * of TypeTraits class. + * The following functions are largely modified or extensions to Duktape. + */ + +/** + * @{ */ /** - * Push a value into the stack. Calls TypeTraits<T>::push(*this, value); + * 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<T>::push(ctx, value); + * + * @param ctx the context * @param value the value to forward */ template <typename Type> @@ -899,8 +1671,21 @@ } /** + * Put the value to the object at the top of the stack. Calls TypeTraits<T>::put(ctx, value); + * + * @param ctx the context + * @param value the value to apply + */ +template <typename Type> +inline void put(ContextPtr ctx, Type &&value) +{ + TypeTraits<std::decay_t<Type>>::put(ctx, std::forward<Type>(value)); +} + +/** * Generic template function to get a value from the stack. * + * @param ctx the context * @param index the index * @return the value */ @@ -913,6 +1698,7 @@ /** * Require a type at the specified index. * + * @param ctx the context * @param index the index * @return the value */ @@ -927,6 +1713,7 @@ * * The TypeTraits<T> must have `static bool is(ContextPtr ptr, int index)`. * + * @param ctx the context * @param index the value index * @return true if is the type */ @@ -942,6 +1729,7 @@ * * The TypeTraits<T> must have `static T optional(Context &, int index, T &&defaultValue)`. * + * @param ctx the context * @param index the value index * @param defaultValue the value replacement * @return the value or defaultValue @@ -952,16 +1740,10 @@ return TypeTraits<std::decay_t<Type>>::optional(ctx, index, std::forward<Type>(defaultValue)); } -/* - * Properties management - * ---------------------------------------------------------- - * - * The following functions are used to read or set properties on objects or globals also using TypeTraits. - */ - /** * 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 @@ -980,6 +1762,7 @@ /** * 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 @@ -998,6 +1781,7 @@ /** * 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 @@ -1011,6 +1795,7 @@ /** * 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 @@ -1024,6 +1809,7 @@ /** * 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 @@ -1043,6 +1829,7 @@ /** * 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 @@ -1062,6 +1849,7 @@ /** * 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 @@ -1079,6 +1867,7 @@ /** * 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 @@ -1094,30 +1883,9 @@ } /** - * Put the value that is at the top of the stack as property to the object. - * - * @param index the object index - * @param name the property name - */ -inline void putProperty(ContextPtr ctx, int index, const std::string &name) -{ - duk_put_prop_string(ctx, index, name.c_str()); -} - -/** - * Put the value that is at the top of the stack to the object as index. - * - * @param index the object index - * @param position the position in the object - */ -inline void putProperty(ContextPtr ctx, int index, int position) -{ - 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 */ @@ -1135,7 +1903,7 @@ * Overload that push the value at the top of the stack instead of returning it. */ template <typename Type> -inline void getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) noexcept +inline void getGlobal(ContextPtr ctx, const std::string &name, std::enable_if_t<std::is_void<Type>::value> * = nullptr) { duk_get_global_string(ctx, name.c_str()); } @@ -1143,6 +1911,7 @@ /** * Set a global variable. * + * @param ctx the context * @param name the name of the global variable * @param type the value to set */ @@ -1156,6 +1925,7 @@ /** * 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) @@ -1163,16 +1933,10 @@ duk_put_global_string(ctx, name.c_str()); } -/* - * Extra functions - * ---------------------------------------------------------- - * - * The following functions are implemented for convenience and do not exists in the native Duktape API. - */ - /** * 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 @@ -1194,13 +1958,14 @@ /** * Return the this binding of the current function. * + * @param ctx the context * @return the this binding as the template given */ template <typename T> -inline auto self(ContextPtr ctx) -> decltype(TypeTraits<T>::get(ctx, 0)) +inline auto self(ContextPtr ctx) -> decltype(TypeTraits<T>::require(ctx, 0)) { duk_push_this(ctx); - decltype(TypeTraits<T>::get(ctx, 0)) value = TypeTraits<T>::get(ctx, -1); + decltype(TypeTraits<T>::require(ctx, 0)) value = TypeTraits<T>::require(ctx, -1); duk_pop(ctx); return value; @@ -1209,6 +1974,7 @@ /** * Throw an ECMAScript exception. * + * @param ctx the context * @param ex the exception */ template <typename Exception> @@ -1218,47 +1984,13 @@ } /** - * Wrapper for duk_throw. - * - * @param ctx the context - */ -inline void raise(ContextPtr ctx) -{ - duk_throw(ctx); -} - -/** - * Wrapper for duk_error. - * - * @param ctx the context - * @param type the error type (e.g. DUK_ERR_REFERENCE_ERROR) - * @param fmt the format string - * @param args the arguments - */ -template <typename... Args> -inline void raise(ContextPtr ctx, int type, const char *fmt, Args&&... args) -{ - duk_error(ctx, type, fmt, std::forward<Args>(args)...); -} - -/** - * Wrapper for duk_new. - * - * @param ctx the context - * @param nargs the number of arguments - */ -inline void create(ContextPtr ctx, int nargs = 0) -{ - duk_new(ctx, nargs); -} - -/** * Construct the object in place, setting value as this binding. * * The TypeTraits<T> must have the following requirements: * * - static void construct(Context &, T): must update this with the value and keep the stack unchanged * + * @param ctx the context * @param value the value to forward * @see self */ @@ -1269,63 +2001,8 @@ } /** - * Sign the given object with the name from T. - * - * This is automatically done for when constructing/pushing object with Shared and Pointer helpers, however you need - * to manually add it when using inheritance. + * @} */ -template <typename T> -inline void sign(ContextPtr ctx, Index index) -{ - StackAssert sa(ctx, 0); - - index = duk_normalize_index(ctx, index); - - duk_push_string(ctx, TypeTraits<T>::name().c_str()); - duk_push_boolean(ctx, true); - duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE); - - /* Do for inherited classes */ - for (const std::string &parent : TypeTraits<T>::inherits()) { - duk_push_string(ctx, parent.c_str()); - duk_push_boolean(ctx, true); - duk_def_prop(ctx, index < 0 ? index : index, DUK_DEFPROP_HAVE_VALUE); - } -} - -/** - * Check if the object at the given index is signed by T or raise TypeError if not. - * - * @param ctx the context - * @param index the index - * @see sign - */ -template <typename T> -inline void checkSignature(ContextPtr ctx, Index index) -{ - StackAssert sa(ctx, 0); - - if (!is<Object>(ctx, index) || !getProperty<bool>(ctx, index, TypeTraits<T>::name())) - raise(ctx, DUK_ERR_TYPE_ERROR, "invalid this binding"); -} - -/** - * Tells if the object at the specified index is of type T. - * - * @param ctx the context - * @param index the index - */ -template <typename T> -inline bool isSigned(ContextPtr ctx, Index index) -{ - StackAssert sa(ctx, 0); - - return is<Object>(ctx, index) && getProperty<bool>(ctx, index, TypeTraits<T>::name()); -} - -/* ------------------------------------------------------------------ - * Exception handling - * ------------------------------------------------------------------ */ /** * @class Error @@ -1367,7 +2044,7 @@ * @note the default implementation search for the global variables * @param ctx the context */ - virtual void raise(ContextPtr ctx) const noexcept + virtual void raise(ContextPtr ctx) const { duk_error(ctx, m_type, "%s", m_message.c_str()); } @@ -1838,12 +2515,82 @@ }; /** + * @class TypeTraits<unsigned> + * @brief Default implementation for unsigned. + * + * Provides: get, is, optional, push, require. + */ +template <> +class TypeTraits<unsigned> { +public: + /** + * Get an integer, return 0 if not an integer. + * + * @param ctx the context + * @param index the index + * @return the integer + */ + static inline unsigned get(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 <typename T> -class TypeTraits<RawPointer<T>> { +class TypeTraits<T *> { public: /** * Get a pointer, return nullptr if not a pointer. @@ -1877,9 +2624,9 @@ * @param defaultValue the defaultValue * @return the pointer or defaultValue */ - static inline T *optional(ContextPtr ctx, int index, RawPointer<T> defaultValue) + static inline T *optional(ContextPtr ctx, int index, T *defaultValue) { - return is(ctx, index) ? get(ctx, index) : defaultValue.object; + return is(ctx, index) ? get(ctx, index) : defaultValue; } /** @@ -1888,9 +2635,9 @@ * @param ctx the context * @param value the value */ - static inline void push(ContextPtr ctx, const RawPointer<T> &value) + static inline void push(ContextPtr ctx, T *value) { - duk_push_pointer(ctx, value.object); + duk_push_pointer(ctx, value); } /** @@ -1946,7 +2693,7 @@ * @class TypeTraits<FunctionMap> * @brief Put the functions to the object at the top of the stack. * - * Provides: push. + * Provides: put. */ template <> class TypeTraits<FunctionMap> { @@ -1957,7 +2704,7 @@ * @param ctx the context * @param map the map of function */ - static inline void push(ContextPtr ctx, const FunctionMap &map) + static void put(ContextPtr ctx, const FunctionMap &map) { StackAssert sa(ctx, 0); @@ -2138,7 +2885,7 @@ /** * @brief Push a map of key-value pair as objects. * - * Provides: push. + * Provides: push, put. * * This class is convenient for settings constants such as enums, string and such. */ @@ -2157,6 +2904,21 @@ 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<std::string, T> &map) + { + assert(type(ctx, -1) == DUK_TYPE_OBJECT); + + StackAssert sa(ctx); for (const auto &pair : map) { TypeTraits<T>::push(ctx, pair.second); @@ -2168,7 +2930,7 @@ /** * @brief Push or get vectors as JavaScript arrays. * - * Provides: get, push. + * Provides: get, push, put. */ template <typename T> class TypeTraits<std::vector<T>> { @@ -2208,6 +2970,21 @@ 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<T> &array) + { + assert(type(ctx, -1) == DUK_TYPE_OBJECT); + + StackAssert sa(ctx); unsigned i = 0; for (const auto &v : array) { @@ -2218,23 +2995,22 @@ }; /** - * @brief Implementation of managed shared_ptr - * @see Shared + * @brief Implementation of managed std::shared_ptr<T>. + * + * This specialization requires T to be @ref js-concept-class. */ template <typename T> -class TypeTraits<Shared<T>> { +class TypeTraits<std::shared_ptr<T>> { private: static void apply(ContextPtr ctx, std::shared_ptr<T> value) { StackAssert sa(ctx, 0); - sign<T>(ctx, -1); - - duk_push_pointer(ctx, new std::shared_ptr<T>(std::move(value))); + duk_push_pointer(ctx, new std::shared_ptr<Bindable>(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<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1)); + delete static_cast<std::shared_ptr<Bindable> *>(duk_to_pointer(ctx, -1)); duk_pop(ctx); duk_push_null(ctx); duk_put_prop_string(ctx, 0, "\xff""\xff""js-shared-ptr"); @@ -2251,12 +3027,14 @@ * @param ctx the context * @param value the value */ - static void construct(ContextPtr ctx, Shared<T> value) + static void construct(ContextPtr ctx, std::shared_ptr<T> value) { + static_assert(std::is_base_of<Bindable, T>::value, "T must be base of Bindable"); + StackAssert sa(ctx, 0); duk_push_this(ctx); - apply(ctx, std::move(value.object)); + apply(ctx, std::move(value)); duk_pop(ctx); } @@ -2266,115 +3044,55 @@ * @param ctx the context * @param value the value */ - static void push(ContextPtr ctx, Shared<T> value) + static void push(ContextPtr ctx, std::shared_ptr<T> value) { + static_assert(std::is_base_of<Bindable, T>::value, "T must be base of Bindable"); + StackAssert sa(ctx, 1); duk_push_object(ctx); - apply(ctx, value.object); + apply(ctx, std::move(value)); TypeTraits<T>::prototype(ctx); duk_set_prototype(ctx, -2); } /** - * Get a managed shared_ptr from the stack. + * Get a managed std::shared_ptr from the stack. * * @param ctx the context * @param index the object index - * @return the shared_ptr + * @return the pointer or a null if invalid */ - static std::shared_ptr<T> get(ContextPtr ctx, int index) + static std::shared_ptr<T> get(ContextPtr ctx, Index index) { - StackAssert sa(ctx, 0); - - checkSignature<T>(ctx, index); - - duk_get_prop_string(ctx, index, "\xff""\xff""js-shared-ptr"); - std::shared_ptr<T> value = *static_cast<std::shared_ptr<T> *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return value; - } -}; - -/** - * @brief Implementation of managed pointers - * @see Pointer - */ -template <typename T> -class TypeTraits<Pointer<T>> { -private: - static void apply(ContextPtr ctx, T *value) - { - StackAssert sa(ctx, 0); - - sign<T>(ctx, -1); + static_assert(std::is_base_of<Bindable, T>::value, "T must be base of Bindable"); - duk_push_pointer(ctx, value); - duk_put_prop_string(ctx, -2, "\xff""\xff""js-ptr"); - duk_push_c_function(ctx, [] (duk_context *ctx) -> Ret { - duk_get_prop_string(ctx, 0, "\xff""\xff""js-ptr"); - delete static_cast<T *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - duk_push_null(ctx); - duk_put_prop_string(ctx, 0, "\xff""\xff""js-ptr"); - - return 0; - }, 1); - duk_set_finalizer(ctx, -2); - } + StackAssert sa(ctx); -public: - /** - * Construct the pointer as this. - * - * @param ctx the context - * @param value the value - */ - static void construct(ContextPtr ctx, Pointer<T> value) - { - StackAssert sa(ctx, 0); + auto ptr = getProperty<std::shared_ptr<Bindable> *>(ctx, index, "\xff""\xff""js-shared-ptr"); - duk_push_this(ctx); - apply(ctx, value.object); - duk_pop(ctx); + return (ptr == nullptr) ? nullptr : std::dynamic_pointer_cast<T>(*ptr); } /** - * Push a managed pointer as object. + * Require a managed shared_ptr from the stack. + * + * Raise a JavaScript error if the object is not valid. * * @param ctx the context - * @param value the value + * @param index the index + * @return the pointer */ - static void push(ContextPtr ctx, Pointer<T> value) + static std::shared_ptr<T> require(ContextPtr ctx, Index index) { - StackAssert sa(ctx, 1); - - duk_push_object(ctx); - apply(ctx, value.object); - TypeTraits<T>::prototype(ctx); - duk_set_prototype(ctx, -2); - } + static_assert(std::is_base_of<Bindable, T>::value, "T must be base of Bindable"); - /** - * Get a managed pointer from the stack. - * - * @param ctx the context - * @param index the object index - * @return the pointer - * @warning Do not store the pointer into the C++ side, the object can be deleted at any time - */ - static T *get(ContextPtr ctx, int index) - { - StackAssert sa(ctx, 0); + auto ptr = get(ctx, index); - checkSignature<T>(ctx, index); + if (!ptr) + duk::raise(ctx, DUK_ERR_TYPE_ERROR, "invalid this binding"); - duk_get_prop_string(ctx, index, "\xff""\xff""js-ptr"); - T *value = static_cast<T *>(duk_to_pointer(ctx, -1)); - duk_pop(ctx); - - return value; + return ptr; } }; @@ -2382,4 +3100,4 @@ } // !malikania -#endif // !MALIKANIA_JS_H +#endif // !JS_H
--- a/tests/libclient/js-animation/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-animation/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -51,7 +51,7 @@ loadMalikaniaWindow(m_ctx); /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", duk::RawPointer<ClientResourcesLoader>{&m_loader}); + duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); } }; @@ -65,7 +65,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ElapsedTimer timer; @@ -80,7 +80,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } }
--- a/tests/libclient/js-color/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-color/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -52,7 +52,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "r")); @@ -76,7 +76,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(255, duk::getGlobal<int>(m_ctx, "r")); @@ -100,7 +100,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "r")); @@ -124,7 +124,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "r")); @@ -148,7 +148,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "r")); @@ -172,7 +172,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "r")); @@ -196,7 +196,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "r")); @@ -223,7 +223,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "r")); @@ -253,7 +253,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("TypeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -276,7 +276,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("TypeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -299,7 +299,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -322,7 +322,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -345,7 +345,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -368,7 +368,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -391,7 +391,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -414,7 +414,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("Error", duk::getGlobal<std::string>(m_ctx, "name")); @@ -437,7 +437,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("Error", duk::getGlobal<std::string>(m_ctx, "name")); @@ -472,7 +472,7 @@ auto ret = duk::pevalString(m_ctx, "draw('#ff0000');"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(255, duk::getGlobal<int>(m_ctx, "r")); @@ -503,7 +503,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("Error", duk::getGlobal<std::string>(m_ctx, "name")); @@ -532,7 +532,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -566,7 +566,7 @@ auto ret = duk::pevalString(m_ctx, "draw('#ff0000');"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(255, duk::getGlobal<int>(m_ctx, "r")); @@ -595,7 +595,7 @@ auto ret = duk::pevalString(m_ctx, "draw('#ghijkl');"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "r")); @@ -624,7 +624,7 @@ auto ret = duk::pevalString(m_ctx, "draw({ red: -1, green: 256, blue: 100, alpha: 800 });"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "r")); @@ -653,7 +653,7 @@ auto ret = duk::pevalString(m_ctx, "draw(null);"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "r"));
--- a/tests/libclient/js-font/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-font/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -48,7 +48,7 @@ loadMalikaniaWindow(m_ctx); /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", duk::RawPointer<ClientResourcesLoader>{&m_loader}); + duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); } }; @@ -68,7 +68,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } std::this_thread::sleep_for(3s);
--- a/tests/libclient/js-image/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-image/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -48,7 +48,7 @@ loadMalikaniaWindow(m_ctx); /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", duk::RawPointer<ClientResourcesLoader>{&m_loader}); + duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); } }; @@ -62,7 +62,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(32, duk::getGlobal<int>(m_ctx, "w")); @@ -85,7 +85,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } std::this_thread::sleep_for(3s); @@ -107,7 +107,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } std::this_thread::sleep_for(3s);
--- a/tests/libclient/js-line/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-line/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -52,7 +52,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "x1")); @@ -76,7 +76,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "x1")); @@ -100,7 +100,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "x1")); @@ -124,7 +124,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "x1")); @@ -154,7 +154,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("TypeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -186,7 +186,7 @@ auto ret = duk::pevalString(m_ctx, "build({ x1: 50, y1: 80, x2: 100, y2: 200 });"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(50, duk::getGlobal<int>(m_ctx, "x1")); @@ -217,7 +217,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("Error", duk::getGlobal<std::string>(m_ctx, "name")); @@ -249,7 +249,7 @@ auto ret = duk::pevalString(m_ctx, "build({});"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "x1"));
--- a/tests/libclient/js-point/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-point/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -50,7 +50,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "x")); @@ -70,7 +70,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(-10, duk::getGlobal<int>(m_ctx, "x")); @@ -90,7 +90,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(100, duk::getGlobal<int>(m_ctx, "x")); @@ -110,7 +110,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(100, duk::getGlobal<int>(m_ctx, "x")); @@ -138,7 +138,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("TypeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -168,7 +168,7 @@ auto ret = duk::pevalString(m_ctx, "build({ x: 100, y: 200 });"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(100, duk::getGlobal<int>(m_ctx, "x")); @@ -197,7 +197,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("Error", duk::getGlobal<std::string>(m_ctx, "name")); @@ -227,7 +227,7 @@ auto ret = duk::pevalString(m_ctx, "build({});"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "x"));
--- a/tests/libclient/js-rectangle/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-rectangle/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -52,7 +52,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "x")); @@ -76,7 +76,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "x")); @@ -100,7 +100,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "x")); @@ -124,7 +124,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(10, duk::getGlobal<int>(m_ctx, "x")); @@ -154,7 +154,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("TypeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -177,7 +177,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -209,7 +209,7 @@ auto ret = duk::pevalString(m_ctx, "build({ x: 50, y: 80, width: 100, height: 200 });"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(50, duk::getGlobal<int>(m_ctx, "x")); @@ -240,7 +240,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("Error", duk::getGlobal<std::string>(m_ctx, "name")); @@ -272,7 +272,7 @@ auto ret = duk::pevalString(m_ctx, "build({});"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "x"));
--- a/tests/libclient/js-size/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-size/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -50,7 +50,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "w")); @@ -70,7 +70,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(100, duk::getGlobal<int>(m_ctx, "w")); @@ -90,7 +90,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(100, duk::getGlobal<int>(m_ctx, "w")); @@ -110,7 +110,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(100, duk::getGlobal<int>(m_ctx, "w")); @@ -138,7 +138,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("TypeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -161,7 +161,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -184,7 +184,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -207,7 +207,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -230,7 +230,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("RangeError", duk::getGlobal<std::string>(m_ctx, "name")); @@ -260,7 +260,7 @@ auto ret = duk::pevalString(m_ctx, "build({ width: 100, height: 200 });"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(100, duk::getGlobal<int>(m_ctx, "w")); @@ -289,7 +289,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ("Error", duk::getGlobal<std::string>(m_ctx, "name")); @@ -319,7 +319,7 @@ auto ret = duk::pevalString(m_ctx, "build({});"); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(0, duk::getGlobal<int>(m_ctx, "r"));
--- a/tests/libclient/js-sprite/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-sprite/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -50,7 +50,7 @@ loadMalikaniaWindow(m_ctx); /* Store the loader */ - duk::putGlobal(m_ctx, "\xff""\xff""loader", duk::RawPointer<ClientResourcesLoader>{&m_loader}); + duk::putGlobal(m_ctx, "\xff""\xff""loader", &m_loader); } }; @@ -64,7 +64,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(32, duk::getGlobal<int>(m_ctx, "w")); @@ -83,7 +83,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(4, duk::getGlobal<int>(m_ctx, "n")); @@ -102,7 +102,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(4, duk::getGlobal<int>(m_ctx, "w")); @@ -121,7 +121,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(3, duk::getGlobal<int>(m_ctx, "n")); @@ -140,7 +140,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } ASSERT_EQ(2, duk::getGlobal<int>(m_ctx, "w")); @@ -160,7 +160,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } for (unsigned c = 0; c < 12; ++c) { @@ -172,7 +172,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } std::this_thread::sleep_for(1s);
--- a/tests/libclient/js-window/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libclient/js-window/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -51,7 +51,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } std::this_thread::sleep_for(3s); @@ -73,7 +73,7 @@ ); if (ret != 0) { - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); } std::this_thread::sleep_for(3s);
--- a/tests/libcommon/js-elapsed-timer/main.cpp Fri Apr 08 14:16:47 2016 +0200 +++ b/tests/libcommon/js-elapsed-timer/main.cpp Tue Apr 12 13:53:11 2016 +0200 @@ -53,12 +53,12 @@ { try { if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); std::this_thread::sleep_for(300ms); if (duk::pevalString(m_ctx, "result = timer.elapsed();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); assertRange(duk::getGlobal<int>(m_ctx, "result"), 300); } catch (const std::exception &ex) { @@ -70,12 +70,12 @@ { try { if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); std::this_thread::sleep_for(300ms); if (duk::pevalString(m_ctx, "timer.reset(); result = timer.elapsed();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); assertRange(duk::getGlobal<int>(m_ctx, "result"), 0); } catch (const std::exception &ex) { @@ -87,7 +87,7 @@ { try { if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); /* * Simulate a pause in the game like this: @@ -100,17 +100,17 @@ std::this_thread::sleep_for(10ms); if (duk::pevalString(m_ctx, "timer.pause();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); std::this_thread::sleep_for(5ms); if (duk::pevalString(m_ctx, "timer.restart();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); std::this_thread::sleep_for(6ms); if (duk::pevalString(m_ctx, "result = timer.elapsed()") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); assertRange(duk::getGlobal<int>(m_ctx, "result"), 16); } catch (const std::exception &ex) { @@ -122,17 +122,17 @@ { try { if (duk::pevalString(m_ctx, "timer = new Malikania.ElapsedTimer();") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); std::this_thread::sleep_for(50ms); if (duk::pevalString(m_ctx, "result = timer.elapsed()") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); std::this_thread::sleep_for(50ms); if (duk::pevalString(m_ctx, "result = timer.elapsed()") != 0) - throw duk::error(m_ctx, -1); + throw duk::exception(m_ctx, -1); assertRange(duk::getGlobal<int>(m_ctx, "result"), 100); } catch (const std::exception &ex) {