mirror of
https://github.com/matrix-construct/construct
synced 2025-01-13 16:33:53 +01:00
ircd::js: Add trap::property; Improve trap construction interface.
This commit is contained in:
parent
8d92c8a9c4
commit
01d814ea1a
6 changed files with 465 additions and 72 deletions
|
@ -36,8 +36,7 @@ inline object
|
||||||
ctor(trap &trap,
|
ctor(trap &trap,
|
||||||
const vector<value>::handle &args = {})
|
const vector<value>::handle &args = {})
|
||||||
{
|
{
|
||||||
object proto(trap());
|
return trap.construct(args);
|
||||||
return JS_New(*cx, proto, args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
|
|
|
@ -91,6 +91,7 @@ inline JSVersion version(const char *const &v) { return JS_StringToVersion(v);
|
||||||
#include "args.h"
|
#include "args.h"
|
||||||
#include "trap.h"
|
#include "trap.h"
|
||||||
#include "trap_function.h"
|
#include "trap_function.h"
|
||||||
|
#include "trap_property.h"
|
||||||
#include "ctor.h"
|
#include "ctor.h"
|
||||||
#include "generator.h"
|
#include "generator.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
|
@ -27,23 +27,26 @@ namespace js {
|
||||||
|
|
||||||
struct trap
|
struct trap
|
||||||
{
|
{
|
||||||
|
struct property;
|
||||||
struct function;
|
struct function;
|
||||||
|
|
||||||
protected:
|
trap *parent;
|
||||||
const std::string parent;
|
|
||||||
const std::string _name; // don't touch
|
const std::string _name; // don't touch
|
||||||
std::array<JSPropertySpec, 32> sps; // static property spec
|
std::map<std::string, property *> member;
|
||||||
std::array<JSPropertySpec, 32> ps; // property spec
|
std::map<std::string, function *> memfun;
|
||||||
std::array<JSFunctionSpec, 32> sfs; // static function spec
|
|
||||||
std::array<JSFunctionSpec, 32> fs; // function spec
|
|
||||||
std::unique_ptr<JSClass> _class;
|
|
||||||
std::map<std::string, trap *> children;
|
std::map<std::string, trap *> children;
|
||||||
std::set<function *> memfun;
|
|
||||||
trap *parent_prototype;
|
std::array<JSConstIntegerSpec, 32> cis; // static const integer spec
|
||||||
trap *prototype;
|
std::array<JSConstDoubleSpec, 32> cds; // static const double spec
|
||||||
|
std::array<JSPropertySpec, 32> sps; // static property spec
|
||||||
|
std::array<JSFunctionSpec, 32> sfs; // static function spec
|
||||||
|
std::array<JSPropertySpec, 32> ps; // property spec
|
||||||
|
std::array<JSFunctionSpec, 32> fs; // function spec
|
||||||
|
std::unique_ptr<JSClass> _class; // class spec
|
||||||
|
trap *prototrap; // pointer to __proto__ trap
|
||||||
|
|
||||||
static trap &from(const JSObject &);
|
static trap &from(const JSObject &);
|
||||||
static trap &from(const JS::HandleObject &);
|
static trap &from(const JSObject *const &);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void debug(const void *const &that, const char *fmt, ...) const AFP(3, 4);
|
void debug(const void *const &that, const char *fmt, ...) const AFP(3, 4);
|
||||||
|
@ -74,6 +77,8 @@ struct trap
|
||||||
static bool handle_del(JSContext *, JS::HandleObject, JS::HandleId, JS::ObjectOpResult &) noexcept;
|
static bool handle_del(JSContext *, JS::HandleObject, JS::HandleId, JS::ObjectOpResult &) noexcept;
|
||||||
static bool handle_has(JSContext *, JS::HandleObject, JS::HandleId, bool *resolved) noexcept;
|
static bool handle_has(JSContext *, JS::HandleObject, JS::HandleId, bool *resolved) noexcept;
|
||||||
static bool handle_enu(JSContext *, JS::HandleObject) noexcept;
|
static bool handle_enu(JSContext *, JS::HandleObject) noexcept;
|
||||||
|
static bool handle_setter(JSContext *, unsigned argc, JS::Value *argv) noexcept;
|
||||||
|
static bool handle_getter(JSContext *, unsigned argc, JS::Value *argv) noexcept;
|
||||||
static bool handle_call(JSContext *, unsigned argc, JS::Value *argv) noexcept;
|
static bool handle_call(JSContext *, unsigned argc, JS::Value *argv) noexcept;
|
||||||
static bool handle_ctor(JSContext *, unsigned argc, JS::Value *argv) noexcept;
|
static bool handle_ctor(JSContext *, unsigned argc, JS::Value *argv) noexcept;
|
||||||
static void handle_dtor(JSFreeOp *, JSObject *) noexcept;
|
static void handle_dtor(JSFreeOp *, JSObject *) noexcept;
|
||||||
|
@ -81,6 +86,7 @@ struct trap
|
||||||
public:
|
public:
|
||||||
auto &name() const { return _name; }
|
auto &name() const { return _name; }
|
||||||
auto &jsclass() const { return *_class; }
|
auto &jsclass() const { return *_class; }
|
||||||
|
auto &jsclass() { return *_class; }
|
||||||
|
|
||||||
// Get child by name (NOT PATH)
|
// Get child by name (NOT PATH)
|
||||||
const trap &child(const std::string &name) const;
|
const trap &child(const std::string &name) const;
|
||||||
|
@ -93,10 +99,13 @@ struct trap
|
||||||
operator const JSClass &() const { return jsclass(); }
|
operator const JSClass &() const { return jsclass(); }
|
||||||
operator const JSClass *() const { return &jsclass(); }
|
operator const JSClass *() const { return &jsclass(); }
|
||||||
|
|
||||||
// Produces prototype. Call ctor(trap) for full construction
|
object prototype(const object::handle &globals);
|
||||||
object operator()();
|
object construct(const object::handle &globals, const vector<value>::handle &argv = {});
|
||||||
|
object construct(const vector<value>::handle &argv = {});
|
||||||
|
template<class... args> object operator()(args&&...);
|
||||||
|
|
||||||
trap(const std::string &path, const uint &flags = 0, const uint &prop_flags = 0);
|
trap(trap &parent, const std::string &name, const uint &flags = 0, const uint &prop_flags = 0);
|
||||||
|
trap(const std::string &name, const uint &flags = 0, const uint &prop_flags = 0);
|
||||||
trap(trap &&) = delete;
|
trap(trap &&) = delete;
|
||||||
trap(const trap &) = delete;
|
trap(const trap &) = delete;
|
||||||
virtual ~trap() noexcept;
|
virtual ~trap() noexcept;
|
||||||
|
@ -106,3 +115,11 @@ extern __thread trap *tree;
|
||||||
|
|
||||||
} // namespace js
|
} // namespace js
|
||||||
} // namespace ircd
|
} // namespace ircd
|
||||||
|
|
||||||
|
template<class... args>
|
||||||
|
ircd::js::object
|
||||||
|
ircd::js::trap::operator()(args&&... a)
|
||||||
|
{
|
||||||
|
vector<value> argv{{std::forward<args>(a)...}};
|
||||||
|
return construct(argv);
|
||||||
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ struct trap::function
|
||||||
static bool handle_call(JSContext *, unsigned, JS::Value *) noexcept;
|
static bool handle_call(JSContext *, unsigned, JS::Value *) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
js::function operator()(const object::handle &);
|
js::function operator()(const object::handle &) const;
|
||||||
|
|
||||||
function(trap &,
|
function(trap &,
|
||||||
std::string name,
|
std::string name,
|
||||||
|
|
50
include/ircd/js/trap_property.h
Normal file
50
include/ircd/js/trap_property.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016 Charybdis Development Team
|
||||||
|
* Copyright (C) 2016 Jason Volk <jason@zemos.net>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice is present in all copies.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||||
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||||
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#define HAVE_IRCD_JS_TRAP_PROPERTY
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
struct trap::property
|
||||||
|
{
|
||||||
|
using function = js::function;
|
||||||
|
|
||||||
|
struct trap *trap;
|
||||||
|
const std::string name;
|
||||||
|
|
||||||
|
virtual value on_set(function::handle, object::handle, value::handle);
|
||||||
|
virtual value on_get(function::handle, object::handle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool handle_set(JSContext *c, unsigned argc, JS::Value *argv) noexcept;
|
||||||
|
static bool handle_get(JSContext *c, unsigned argc, JS::Value *argv) noexcept;
|
||||||
|
|
||||||
|
public:
|
||||||
|
property(struct trap &, std::string name);
|
||||||
|
property(property &&) = delete;
|
||||||
|
property(const property &) = delete;
|
||||||
|
virtual ~property() noexcept;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace js
|
||||||
|
} // namespace ircd
|
436
ircd/js.cc
436
ircd/js.cc
|
@ -436,7 +436,14 @@ ircd::js::global::global(trap &trap,
|
||||||
if(!JS_InitStandardClasses(*cx, *this))
|
if(!JS_InitStandardClasses(*cx, *this))
|
||||||
throw error("Failed to init standard classes for global object");
|
throw error("Failed to init standard classes for global object");
|
||||||
|
|
||||||
|
for(auto it(begin(trap.memfun)); it != end(trap.memfun); ++it)
|
||||||
|
{
|
||||||
|
trap::function &deffun(*it->second);
|
||||||
|
deffun(*this);
|
||||||
|
}
|
||||||
|
|
||||||
JS_InitReflectParse(*cx, *this);
|
JS_InitReflectParse(*cx, *this);
|
||||||
|
|
||||||
JS_FireOnNewGlobalObject(*cx, *this);
|
JS_FireOnNewGlobalObject(*cx, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,6 +470,169 @@ noexcept
|
||||||
// ircd/js/generator.h
|
// ircd/js/generator.h
|
||||||
//
|
//
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// ircd/js/trap_property.h
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::js::trap::property::property(struct trap &trap,
|
||||||
|
std::string name)
|
||||||
|
try
|
||||||
|
:trap{&trap}
|
||||||
|
,name{std::move(name)}
|
||||||
|
{
|
||||||
|
const auto it(std::find_if(begin(trap.ps), end(trap.ps), []
|
||||||
|
(const JSPropertySpec &ps)
|
||||||
|
{
|
||||||
|
return !ps.name;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if(it == end(trap.ps))
|
||||||
|
throw error("out of slots");
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto it(trap.member.emplace(this->name, this));
|
||||||
|
if(!it.second)
|
||||||
|
throw error("already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
JSPropertySpec &spec(*it);
|
||||||
|
spec.name = this->name.c_str();
|
||||||
|
spec.flags = JSPROP_SHARED;
|
||||||
|
spec.getter.native.op = handle_get;
|
||||||
|
spec.setter.native.op = handle_set;
|
||||||
|
|
||||||
|
log.debug("Registered property '%s' on trap '%s'",
|
||||||
|
this->name.c_str(),
|
||||||
|
trap.name().c_str());
|
||||||
|
}
|
||||||
|
catch(const error &e)
|
||||||
|
{
|
||||||
|
throw error("Failed to register property '%s': out slots on trap '%s': %s",
|
||||||
|
this->name.c_str(),
|
||||||
|
trap.name().c_str(),
|
||||||
|
e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::js::trap::property::~property()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
assert(trap);
|
||||||
|
const auto it(std::find_if(begin(trap->ps), end(trap->ps), [this]
|
||||||
|
(const JSPropertySpec &spec)
|
||||||
|
{
|
||||||
|
return name == spec.name;
|
||||||
|
}));
|
||||||
|
|
||||||
|
if(it != end(trap->ps))
|
||||||
|
{
|
||||||
|
JSPropertySpec &spec(*it);
|
||||||
|
memset(&spec, 0x0, sizeof(spec));
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t erased(trap->member.erase(name));
|
||||||
|
assert(erased);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ircd::js::trap::property::handle_get(JSContext *const c,
|
||||||
|
const unsigned argc,
|
||||||
|
JS::Value *const argv)
|
||||||
|
noexcept try
|
||||||
|
{
|
||||||
|
using js::function;
|
||||||
|
|
||||||
|
const struct args args(argc, argv);
|
||||||
|
object that(args.computeThis(c));
|
||||||
|
function func(args.callee());
|
||||||
|
const string name(js::name(func));
|
||||||
|
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.debug(that.get(), "get '%s' (property)",
|
||||||
|
name.c_str());
|
||||||
|
|
||||||
|
property &prop(*trap.member.at(name));
|
||||||
|
args.rval().set(prop.on_get(func, that));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(const jserror &e)
|
||||||
|
{
|
||||||
|
e.set_pending();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch(const std::exception &e)
|
||||||
|
{
|
||||||
|
auto ca(JS::CallArgsFromVp(argc, argv));
|
||||||
|
object that(ca.computeThis(c));
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.host_exception(that.get(), "property get: %s", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
struct foodata
|
||||||
|
:priv_data
|
||||||
|
{
|
||||||
|
trap::property *ptr;
|
||||||
|
|
||||||
|
foodata(trap::property *const &ptr = nullptr): ptr{ptr} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace js
|
||||||
|
} // namespace ircd
|
||||||
|
|
||||||
|
bool
|
||||||
|
ircd::js::trap::property::handle_set(JSContext *const c,
|
||||||
|
const unsigned argc,
|
||||||
|
JS::Value *const argv)
|
||||||
|
noexcept try
|
||||||
|
{
|
||||||
|
using js::function;
|
||||||
|
|
||||||
|
const struct args args(argc, argv);
|
||||||
|
object that(args.computeThis(c));
|
||||||
|
function func(args.callee());
|
||||||
|
const string name(js::name(func));
|
||||||
|
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.debug(that.get(), "set '%s' (property)",
|
||||||
|
name.c_str());
|
||||||
|
|
||||||
|
property &prop(*trap.member.at(name));
|
||||||
|
args.rval().set(prop.on_get(func, that));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(const jserror &e)
|
||||||
|
{
|
||||||
|
e.set_pending();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch(const std::exception &e)
|
||||||
|
{
|
||||||
|
auto ca(JS::CallArgsFromVp(argc, argv));
|
||||||
|
object that(ca.computeThis(c));
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.host_exception(that.get(), "property set: %s", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::js::value
|
||||||
|
ircd::js::trap::property::on_get(function::handle,
|
||||||
|
object::handle that)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::js::value
|
||||||
|
ircd::js::trap::property::on_set(function::handle,
|
||||||
|
object::handle that,
|
||||||
|
value::handle val)
|
||||||
|
{
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// ircd/js/trap_function.h
|
// ircd/js/trap_function.h
|
||||||
|
@ -479,17 +649,18 @@ ircd::js::trap::function::function(trap &member,
|
||||||
,flags{flags}
|
,flags{flags}
|
||||||
,lambda{lambda}
|
,lambda{lambda}
|
||||||
{
|
{
|
||||||
member.memfun.emplace(this);
|
member.memfun.emplace(this->name, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::js::trap::function::~function()
|
ircd::js::trap::function::~function()
|
||||||
noexcept
|
noexcept
|
||||||
{
|
{
|
||||||
member->memfun.erase(this);
|
member->memfun.erase(this->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::js::function
|
ircd::js::function
|
||||||
ircd::js::trap::function::operator()(const object::handle &obj)
|
ircd::js::trap::function::operator()(const object::handle &obj)
|
||||||
|
const
|
||||||
{
|
{
|
||||||
const auto jsf(::js::DefineFunctionWithReserved(*cx,
|
const auto jsf(::js::DefineFunctionWithReserved(*cx,
|
||||||
obj,
|
obj,
|
||||||
|
@ -514,8 +685,8 @@ noexcept try
|
||||||
assert(&our(c) == cx);
|
assert(&our(c) == cx);
|
||||||
|
|
||||||
const struct args args(argc, argv);
|
const struct args args(argc, argv);
|
||||||
const value that(args.computeThis(c));
|
|
||||||
const object func(args.callee());
|
const object func(args.callee());
|
||||||
|
const value that(args.computeThis(c));
|
||||||
auto &trap(from(func));
|
auto &trap(from(func));
|
||||||
log.debug("trap(%p) this(%p) %s() call argv[%u]",
|
log.debug("trap(%p) this(%p) %s() call argv[%u]",
|
||||||
(const void *)&trap,
|
(const void *)&trap,
|
||||||
|
@ -574,21 +745,24 @@ ircd::js::trap::function::on_call(object::handle obj,
|
||||||
// ircd/js/trap.h
|
// ircd/js/trap.h
|
||||||
//
|
//
|
||||||
|
|
||||||
ircd::js::trap::trap(const std::string &path,
|
ircd::js::trap::trap(const std::string &name,
|
||||||
const uint &flags,
|
const uint &flags,
|
||||||
const uint &prop_flags)
|
const uint &prop_flags)
|
||||||
:parent{[&path]
|
:trap{*tree, name, flags, prop_flags}
|
||||||
{
|
{
|
||||||
const auto ret(rsplit(path, ".").first);
|
|
||||||
return ret == path? std::string{} : ret;
|
|
||||||
}()}
|
|
||||||
,_name
|
|
||||||
{
|
|
||||||
path.empty()? std::string{""} : token_last(path, ".")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ircd::js::trap::trap(trap &parent,
|
||||||
|
const std::string &name,
|
||||||
|
const uint &flags,
|
||||||
|
const uint &prop_flags)
|
||||||
|
:parent{&parent != this? &parent : nullptr}
|
||||||
|
,_name{name}
|
||||||
|
,cis{0}
|
||||||
|
,cds{0}
|
||||||
,sps{0}
|
,sps{0}
|
||||||
,ps{0}
|
|
||||||
,sfs{0}
|
,sfs{0}
|
||||||
|
,ps{0}
|
||||||
,fs{0}
|
,fs{0}
|
||||||
,_class{std::make_unique<JSClass>(JSClass
|
,_class{std::make_unique<JSClass>(JSClass
|
||||||
{
|
{
|
||||||
|
@ -608,13 +782,14 @@ ircd::js::trap::trap(const std::string &path,
|
||||||
flags & JSCLASS_GLOBAL_FLAGS? JS_GlobalObjectTraceHook : handle_trace,
|
flags & JSCLASS_GLOBAL_FLAGS? JS_GlobalObjectTraceHook : handle_trace,
|
||||||
{ this } // reserved[0] TODO: ?????????
|
{ this } // reserved[0] TODO: ?????????
|
||||||
})}
|
})}
|
||||||
,parent_prototype{nullptr}
|
,prototrap{nullptr}
|
||||||
,prototype{nullptr}
|
|
||||||
{
|
{
|
||||||
std::fill(begin(sfs), end(sfs), (JSFunctionSpec)JS_FS_END);
|
std::fill(begin(sfs), end(sfs), (JSFunctionSpec)JS_FS_END);
|
||||||
std::fill(begin(fs), end(fs), (JSFunctionSpec)JS_FS_END);
|
std::fill(begin(fs), end(fs), (JSFunctionSpec)JS_FS_END);
|
||||||
|
|
||||||
ps[0].flags |= prop_flags;
|
//ps[0].name = "";
|
||||||
|
//ps[0].flags |= prop_flags;
|
||||||
|
//ps[0].flags |= JSPROP_ENUMERATE;
|
||||||
add_this();
|
add_this();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,27 +808,51 @@ noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::js::object
|
ircd::js::object
|
||||||
ircd::js::trap::operator()()
|
ircd::js::trap::construct(const vector<value>::handle &argv)
|
||||||
{
|
{
|
||||||
object p(prototype? ctor(*prototype) : object{});
|
const object globals;
|
||||||
object pp(parent_prototype? ctor(*parent_prototype) : object{});
|
return construct(globals, argv);
|
||||||
object proto(JS_InitClass(*cx,
|
}
|
||||||
p,
|
|
||||||
pp,
|
ircd::js::object
|
||||||
_class.get(),
|
ircd::js::trap::construct(const object::handle &globals,
|
||||||
nullptr,
|
const vector<value>::handle &argv)
|
||||||
0,
|
{
|
||||||
ps.data(),
|
const object prototype(this->prototype(globals));
|
||||||
fs.data(),
|
return JS_New(*cx, prototype, argv);
|
||||||
sps.data(),
|
}
|
||||||
sfs.data()));
|
|
||||||
|
ircd::js::object
|
||||||
|
ircd::js::trap::prototype(const object::handle &globals)
|
||||||
|
{
|
||||||
|
const object super
|
||||||
|
{
|
||||||
|
prototrap? prototrap->construct() : object{object::uninitialized}
|
||||||
|
};
|
||||||
|
|
||||||
|
const object proto
|
||||||
|
{
|
||||||
|
JS_InitClass(*cx,
|
||||||
|
globals,
|
||||||
|
super,
|
||||||
|
_class.get(),
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
ps.data(),
|
||||||
|
fs.data(),
|
||||||
|
sps.data(),
|
||||||
|
sfs.data())
|
||||||
|
};
|
||||||
|
|
||||||
for(auto it(begin(memfun)); it != end(memfun); ++it)
|
for(auto it(begin(memfun)); it != end(memfun); ++it)
|
||||||
{
|
{
|
||||||
trap::function &deffun(**it);
|
const function &deffun(*it->second);
|
||||||
deffun(proto);
|
const js::function func(deffun(proto));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JS_DefineConstIntegers(*cx, proto, cis.data());
|
||||||
|
JS_DefineConstDoubles(*cx, proto, cds.data());
|
||||||
|
|
||||||
return proto;
|
return proto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,25 +860,28 @@ void
|
||||||
ircd::js::trap::del_this()
|
ircd::js::trap::del_this()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(name().empty())
|
// It is a special condition when the parent is self (this) and the trap has no name.
|
||||||
|
if(!parent && name().empty())
|
||||||
{
|
{
|
||||||
tree = nullptr;
|
tree = nullptr; // thread_local
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &parent(find(this->parent));
|
if(!parent)
|
||||||
if(!parent.children.erase(name()))
|
return;
|
||||||
|
|
||||||
|
if(!parent->children.erase(name()))
|
||||||
throw std::out_of_range("child not in parent's map");
|
throw std::out_of_range("child not in parent's map");
|
||||||
|
|
||||||
log.debug("Unregistered trap '%s' in `%s'",
|
log.debug("Unregistered trap '%s' in `%s'",
|
||||||
name().c_str(),
|
name().c_str(),
|
||||||
this->parent.c_str());
|
parent->name().c_str());
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
log.error("Failed to unregister object trap '%s' in `%s': %s",
|
log.error("Failed to unregister object trap '%s' in `%s': %s",
|
||||||
name().c_str(),
|
name().c_str(),
|
||||||
parent.c_str(),
|
parent->name().c_str(),
|
||||||
e.what());
|
e.what());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -688,36 +890,29 @@ void
|
||||||
ircd::js::trap::add_this()
|
ircd::js::trap::add_this()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if(name().empty())
|
// It is a special condition when the parent is self (this) and the trap has no name.
|
||||||
|
if(!parent && name().empty())
|
||||||
{
|
{
|
||||||
if(tree)
|
tree = this; // thread_local
|
||||||
throw error("ircd::js::tree is already active. Won't overwrite.");
|
|
||||||
|
|
||||||
tree = this;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &parent(find(this->parent));
|
if(!parent)
|
||||||
const auto iit(parent.children.emplace(name(), this));
|
return;
|
||||||
|
|
||||||
|
const auto iit(parent->children.emplace(name(), this));
|
||||||
if(!iit.second)
|
if(!iit.second)
|
||||||
throw error("Failed to overwrite existing");
|
throw error("Failed to overwrite existing");
|
||||||
|
|
||||||
log.debug("Registered trap '%s' in `%s'",
|
log.debug("Registered trap '%s' in `%s'",
|
||||||
name().c_str(),
|
name().c_str(),
|
||||||
this->parent.c_str());
|
parent->name().c_str());
|
||||||
}
|
|
||||||
catch(const std::out_of_range &e)
|
|
||||||
{
|
|
||||||
log.error("Failed to register object trap '%s' in `%s': missing parent.",
|
|
||||||
name().c_str(),
|
|
||||||
parent.c_str());
|
|
||||||
throw;
|
|
||||||
}
|
}
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
log.error("Failed to register object trap '%s' in `%s': %s",
|
log.error("Failed to register object trap '%s' in `%s': %s",
|
||||||
name().c_str(),
|
name().c_str(),
|
||||||
parent.c_str(),
|
parent->name().c_str(),
|
||||||
e.what());
|
e.what());
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -953,12 +1148,118 @@ catch(const jserror &e)
|
||||||
catch(const std::exception &e)
|
catch(const std::exception &e)
|
||||||
{
|
{
|
||||||
auto &trap(from(obj));
|
auto &trap(from(obj));
|
||||||
trap.host_exception("del '%s': %s",
|
trap.host_exception(obj.get(), "del '%s': %s",
|
||||||
string(id).c_str(),
|
string(id).c_str(),
|
||||||
e.what());
|
e.what());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace ircd {
|
||||||
|
namespace js {
|
||||||
|
|
||||||
|
std::map<std::string, heap_value> tempo;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ircd::js::trap::handle_getter(JSContext *const c,
|
||||||
|
unsigned argc,
|
||||||
|
JS::Value *const argv)
|
||||||
|
noexcept try
|
||||||
|
{
|
||||||
|
using js::function;
|
||||||
|
|
||||||
|
const struct args args(argc, argv);
|
||||||
|
object that(args.computeThis(c));
|
||||||
|
function func(args.callee());
|
||||||
|
const string name(js::name(func));
|
||||||
|
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.debug(that.get(), "get '%s' (getter)",
|
||||||
|
name.c_str());
|
||||||
|
|
||||||
|
const auto it(tempo.find(name));
|
||||||
|
if(it == end(tempo))
|
||||||
|
{
|
||||||
|
//throw reference_error("%s", name.c_str());
|
||||||
|
args.rval().set(value{});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
heap_value &val(it->second);
|
||||||
|
args.rval().set(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(const jserror &e)
|
||||||
|
{
|
||||||
|
e.set_pending();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch(const std::exception &e)
|
||||||
|
{
|
||||||
|
auto ca(JS::CallArgsFromVp(argc, argv));
|
||||||
|
object that(ca.computeThis(c));
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.host_exception(that.get(), "getter: %s", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ircd::js::trap::handle_setter(JSContext *const c,
|
||||||
|
unsigned argc,
|
||||||
|
JS::Value *const argv)
|
||||||
|
noexcept try
|
||||||
|
{
|
||||||
|
using js::function;
|
||||||
|
|
||||||
|
const struct args args(argc, argv);
|
||||||
|
object that(args.computeThis(c));
|
||||||
|
function func(args.callee());
|
||||||
|
|
||||||
|
value val(args[0]);
|
||||||
|
const auto type(basic::type(val));
|
||||||
|
const string name(js::name(func));
|
||||||
|
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.debug(that.get(), "set '%s' (%s) (setter)",
|
||||||
|
name.c_str(),
|
||||||
|
reflect(type));
|
||||||
|
|
||||||
|
auto it(tempo.lower_bound(name));
|
||||||
|
assert(it != end(tempo));
|
||||||
|
heap_value &hval(it->second);
|
||||||
|
switch(js::type(type))
|
||||||
|
{
|
||||||
|
case jstype::OBJECT:
|
||||||
|
{
|
||||||
|
//const auto flags(JSPROP_SHARED);
|
||||||
|
//object ret(JS_DefineObject(*cx, object(val), "", &trap.jsclass(), flags));
|
||||||
|
//tempo.emplace(name, heap_value(ret));
|
||||||
|
//args.rval().set(ret);
|
||||||
|
//return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
hval = val;
|
||||||
|
args.rval().set(val);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const jserror &e)
|
||||||
|
{
|
||||||
|
e.set_pending();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
catch(const std::exception &e)
|
||||||
|
{
|
||||||
|
auto ca(JS::CallArgsFromVp(argc, argv));
|
||||||
|
object that(ca.computeThis(c));
|
||||||
|
auto &trap(from(that));
|
||||||
|
trap.host_exception(that.get(), "setter: %s", e.what());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ircd::js::trap::handle_get(JSContext *const c,
|
ircd::js::trap::handle_get(JSContext *const c,
|
||||||
JS::HandleObject obj,
|
JS::HandleObject obj,
|
||||||
|
@ -1108,9 +1409,9 @@ catch(const std::exception &e)
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::js::trap &
|
ircd::js::trap &
|
||||||
ircd::js::trap::from(const JS::HandleObject &o)
|
ircd::js::trap::from(const JSObject *const &o)
|
||||||
{
|
{
|
||||||
return from(*o.get());
|
return from(*o);
|
||||||
}
|
}
|
||||||
|
|
||||||
ircd::js::trap &
|
ircd::js::trap &
|
||||||
|
@ -1206,6 +1507,31 @@ bool
|
||||||
ircd::js::trap::on_has(object::handle,
|
ircd::js::trap::on_has(object::handle,
|
||||||
id::handle id)
|
id::handle id)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
const string sid(id);
|
||||||
|
if(children.count(sid))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(std::any_of(begin(memfun), end(memfun), [&sid]
|
||||||
|
(const auto &it)
|
||||||
|
{
|
||||||
|
const auto &memfun(*it.second);
|
||||||
|
return sid == memfun.name;
|
||||||
|
}))
|
||||||
|
return false;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
value val;
|
||||||
|
const auto flags(JSPROP_SHARED | JSPROP_ENUMERATE);
|
||||||
|
if(!JS_DefinePropertyById(*cx, obj, id, val, flags, handle_getter, handle_setter))
|
||||||
|
throw jserror("Failed to define property '%s'", sid.c_str());
|
||||||
|
|
||||||
|
*/
|
||||||
|
// const auto flags(0);
|
||||||
|
// if(!JS_DefineObject(*cx, obj, sid.c_str(), &jsclass(), flags))
|
||||||
|
// throw jserror("Failed to define property '%s'", sid.c_str());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue