diff --git a/include/ircd/js/del.h b/include/ircd/js/del.h new file mode 100644 index 000000000..285bdb87f --- /dev/null +++ b/include/ircd/js/del.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk + * + * 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_DEL_H + +namespace ircd { +namespace js { + +void del(const JS::HandleObject &obj, const id &id); +void del(const JS::HandleObject &src, const char *const path); + +} // namespace js +} // namespace ircd diff --git a/include/ircd/js/get.h b/include/ircd/js/get.h index 25e89544d..05a24e8a0 100644 --- a/include/ircd/js/get.h +++ b/include/ircd/js/get.h @@ -25,27 +25,8 @@ namespace ircd { namespace js { -inline value -get(const object &obj, - const char *const name) -{ - value ret; - if(!JS_GetProperty(*cx, obj, name, &ret)) - throw reference_error("%s", name); - - return ret; -} - -inline value -get(const object &obj, - const id &id) -{ - value ret; - if(!JS_GetPropertyById(*cx, obj, id, &ret)) - throw reference_error("%s", string(id).c_str()); - - return ret; -} +value get(const JS::HandleObject &obj, const id &id); +value get(const JS::HandleObject &src, const char *const path); } // namespace js } // namespace ircd diff --git a/include/ircd/js/has.h b/include/ircd/js/has.h new file mode 100644 index 000000000..7b9d69b6c --- /dev/null +++ b/include/ircd/js/has.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk + * + * 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_HAS_H + +namespace ircd { +namespace js { + +bool has(const JS::HandleObject &obj, const id &id); +bool has(const JS::HandleObject &src, const char *const path); + +} // namespace js +} // namespace ircd diff --git a/include/ircd/js/js.h b/include/ircd/js/js.h index b1ae91be1..81a438250 100644 --- a/include/ircd/js/js.h +++ b/include/ircd/js/js.h @@ -70,7 +70,10 @@ inline JSVersion version(const char *const &v) { return JS_StringToVersion(v); #include "function_literal.h" #include "vector.h" #include "priv.h" +#include "has.h" #include "get.h" +#include "set.h" +#include "del.h" #include "call.h" #include "for_each.h" #include "trap.h" diff --git a/include/ircd/js/priv.h b/include/ircd/js/priv.h index 7e91658ef..bedbca6bc 100644 --- a/include/ircd/js/priv.h +++ b/include/ircd/js/priv.h @@ -29,7 +29,7 @@ IRCD_EXCEPTION(error, priv_error) template T & -priv(const object &obj, +priv(const JS::HandleObject &obj, const JSClass &jsc) { const auto ret(JS_GetInstancePrivate(*cx, obj, &jsc, nullptr)); @@ -41,7 +41,7 @@ priv(const object &obj, template T & -priv(const object &obj) +priv(const JS::HandleObject &obj) { const auto jsc(JS_GetClass(obj)); if(unlikely(!jsc)) diff --git a/include/ircd/js/set.h b/include/ircd/js/set.h new file mode 100644 index 000000000..8b0192b8c --- /dev/null +++ b/include/ircd/js/set.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2016 Charybdis Development Team + * Copyright (C) 2016 Jason Volk + * + * 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_SET_H + +namespace ircd { +namespace js { + +void set(const JS::HandleObject &obj, const id &id, const value &val); +void set(const JS::HandleObject &src, const char *const path, const value &val); + +} // namespace js +} // namespace ircd diff --git a/ircd/js.cc b/ircd/js.cc index 3704c6f1e..886b8db43 100644 --- a/ircd/js.cc +++ b/ircd/js.cc @@ -574,7 +574,7 @@ bool ircd::js::trap::on_del(const JSObject &obj, const jsid &id) { - return false; + return true; } JS::Value @@ -779,6 +779,182 @@ ircd::js::call(const object &obj, return call(obj, name.c_str(), args); } +/////////////////////////////////////////////////////////////////////////////// +// +// ircd/js/del.h +// + +void +ircd::js::del(const JS::HandleObject &src, + const char *const path) +{ + value val; + object obj(src); + const char *fail(nullptr); + tokens(path, ".", [&path, &val, &obj, &fail] + (char *const &part) + { + if(fail) + throw type_error("cannot recurse through non-object '%s' in `%s'", fail, path); + + if(!JS_GetProperty(*cx, obj, part, &val) || undefined(val)) + throw reference_error("%s", part); + + object tmp(obj.get()); + if(!JS_ValueToObject(*cx, val, &obj) || !obj.get()) + { + fail = part; + obj = std::move(tmp); + } + }); + + del(obj, id(val)); +} + +void +ircd::js::del(const JS::HandleObject &obj, + const id &id) +{ + JS::ObjectOpResult res; + if(!JS_DeletePropertyById(*cx, obj, id, res)) + throw jserror(jserror::pending); + + if(!res.checkStrict(*cx, obj, id)) + throw jserror(jserror::pending); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// ircd/js/set.h +// + +void +ircd::js::set(const JS::HandleObject &src, + const char *const path, + const value &val) +{ + value tmp; + object obj(src); + char buffer[strlen(path) + 1]; + const char *fail(nullptr), *key(nullptr); + tokens(path, ".", buffer, sizeof(buffer), [&path, &tmp, &obj, &fail, &key] + (const char *const &part) + { + if(fail) + throw type_error("cannot recurse through non-object '%s' in `%s'", fail, path); + + if(key) + throw reference_error("%s", part); + + key = part; + if(!JS_GetProperty(*cx, obj, part, &tmp) || undefined(tmp)) + return; + + if(!JS_ValueToObject(*cx, tmp, &obj) || !obj.get()) + fail = part; + }); + + if(!key) + return; + + if(!JS_SetProperty(*cx, obj, key, val)) + throw jserror(jserror::pending); +} + +void +ircd::js::set(const JS::HandleObject &obj, + const id &id, + const value &val) +{ + if(!JS_SetPropertyById(*cx, obj, id, val)) + throw jserror(jserror::pending); +} + +/////////////////////////////////////////////////////////////////////////////// +// +// ircd/js/get.h +// + +ircd::js::value +ircd::js::get(const JS::HandleObject &src, + const char *const path) +{ + value ret; + object obj(src); + const char *fail(nullptr); + tokens(path, ".", [&obj, &path, &ret, &fail] + (const char *const &part) + { + if(fail) + throw type_error("cannot recurse through non-object '%s' in `%s'", fail, path); + + if(!JS_GetProperty(*cx, obj, part, &ret) || undefined(ret)) + throw reference_error("%s", part); + + if(!JS_ValueToObject(*cx, ret, &obj) || !obj.get()) + fail = part; + }); + + return ret; +} + +ircd::js::value +ircd::js::get(const JS::HandleObject &obj, + const id &id) +{ + value ret; + if(!JS_GetPropertyById(*cx, obj, id, &ret) || undefined(ret)) + throw reference_error("%s", string(id).c_str()); + + return ret; +} + +/////////////////////////////////////////////////////////////////////////////// +// +// ircd/js/has.h +// + +bool +ircd::js::has(const JS::HandleObject &src, + const char *const path) +{ + bool ret(true); + object obj(src); + const char *fail(nullptr); + tokens(path, ".", [&obj, &path, &ret, &fail] + (const char *const &part) + { + if(fail) + throw type_error("cannot recurse through non-object '%s' in `%s'", fail, path); + + if(!JS_HasProperty(*cx, obj, part, &ret)) + throw jserror(jserror::pending); + + if(!ret) + return; + + value tmp; + if(!JS_GetProperty(*cx, obj, part, &tmp) || undefined(tmp)) + throw internal_error("%s", part); + + if(!JS_ValueToObject(*cx, tmp, &obj) || !obj.get()) + fail = part; + }); + + return ret; +} + +bool +ircd::js::has(const JS::HandleObject &obj, + const id &id) +{ + bool ret; + if(!JS_HasPropertyById(*cx, obj, id, &ret)) + throw jserror(jserror::pending); + + return ret; +} + /////////////////////////////////////////////////////////////////////////////// // // ircd/js/string.h