[gjs/wip/ptomato/mozjs31prep: 3/3] WIP - First sketch of rooted gjs_parse_call_args()
- From: Philip Chimento <pchimento src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/wip/ptomato/mozjs31prep: 3/3] WIP - First sketch of rooted gjs_parse_call_args()
- Date: Thu, 13 Oct 2016 02:43:22 +0000 (UTC)
commit 2c7fecc6648a63e66fd4a9bd2a9c4a77f3163f26
Author: Philip Chimento <philip endlessm com>
Date: Wed Oct 12 19:40:48 2016 -0700
WIP - First sketch of rooted gjs_parse_call_args()
gjs/jsapi-util.cpp | 340 ++++++++++++++++++++++++++++++++++++----------------
1 files changed, 239 insertions(+), 101 deletions(-)
---
diff --git a/gjs/jsapi-util.cpp b/gjs/jsapi-util.cpp
index 440d5c4..6a92ebc 100644
--- a/gjs/jsapi-util.cpp
+++ b/gjs/jsapi-util.cpp
@@ -832,25 +832,196 @@ gjs_value_to_int64(JSContext *context,
return JS::ToInt64(context, val, (int64_t *) result);
}
+template <typename T>
+static void
+assign(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ T& ref)
+{
+ throw "Wrong type for c, got typeid(T).name";
+}
+
+static void
+assign(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ bool*& ref)
+{
+ if (c != 'b')
+ throw "Wrong type for c, got bool*";
+ if (!value.isBoolean())
+ throw "Not a boolean";
+ *ref = value.toBoolean();
+}
+
+static void
+assign(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ JS::MutableHandleObject& ref)
+{
+ if (c != 'o')
+ throw "Wrong type for c, got JS::MutableHandleObject";
+ if (!value.isObject())
+ throw "Not an object";
+ ref.set(&value.toObject());
+}
+
+// assign('s')
+// assign('F')
+
+static void
+assign(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ int32_t*& ref)
+{
+ if (c != 'i')
+ throw "Wrong type for c, got int32_t*";
+ if (!JS::ToInt32(cx, value, ref)) {
+ /* Our error message is going to be more useful */
+ JS_ClearPendingException(cx);
+ throw "Couldn't convert to integer";
+ }
+}
+
+static void
+assign(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ uint32_t*& ref)
+{
+ double num;
+
+ if (c != 'u')
+ throw "Wrong type for c, got uint32_t*";
+ if (!value.isNumber() || !JS::ToNumber(cx, value, &num)) {
+ /* Our error message is going to be more useful */
+ JS_ClearPendingException(cx);
+ throw "Couldn't convert to unsigned integer";
+ }
+ if (num > G_MAXUINT32 || num < 0)
+ throw "Value is out of range";
+ *ref = num;
+}
+
+static void
+assign(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ int64_t*& ref)
+{
+ if (c != 't')
+ throw "Wrong type for c, got int64_t*";
+ if (!JS::ToInt64(cx, value, ref)) {
+ /* Our error message is going to be more useful */
+ JS_ClearPendingException(cx);
+ throw "Couldn't convert to 64-bit integer";
+ }
+}
+
+static void
+assign(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ double*& ref)
+{
+ if (c != 'f')
+ throw "Wrong type for c, got double*";
+ if (!JS::ToNumber(cx, value, ref)) {
+ /* Our error message is going to be more useful */
+ JS_ClearPendingException(cx);
+ throw "Couldn't convert to double";
+ }
+}
+
+template<typename T>
+static void
+assign_nullable(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ T& ref)
+{
+ throw "Wrong type for ?c, got typeid(T).name";
+}
+
+static void
+assign_nullable(JSContext *cx,
+ const char c,
+ JS::HandleValue& value,
+ JS::MutableHandleObject& ref)
+{
+ if (c != 'o')
+ throw "Wrong type for ?c, got JS::MutableHandleObject";
+ if (value.isNull()) {
+ ref.set(NULL);
+ return;
+ }
+ if (!value.isObject())
+ throw "Not an object";
+ ref.set(&value.toObject());
+}
+
+// assign_nullable('s')
+// assign_nullable('F')
+
+template<typename T, typename... Args>
static bool
-gjs_parse_args_valist (JSContext *context,
- const char *function_name,
- const char *format,
- unsigned argc,
- JS::Value *argv,
- va_list args)
+parse_call_args_helper(JSContext *cx,
+ const char *function_name,
+ JS::CallArgs& args,
+ bool ignore_trailing_args,
+ const char *fmt_required,
+ const char *fmt_optional,
+ unsigned param_ix,
+ const char *param_name,
+ T& param_ref,
+ Args ...params)
{
- guint i;
- const char *fmt_iter;
- guint n_unwind = 0;
-#define MAX_UNWIND_STRINGS 16
- gpointer unwind_strings[MAX_UNWIND_STRINGS];
- bool ignore_trailing_args = false;
- guint n_required = 0;
- guint n_total = 0;
- guint consumed_args;
+ bool nullable = false;
+ const char *fchar = fmt_required;
+ if (*fchar == '\0' && fmt_optional)
+ fchar = fmt_optional;
+ g_assert(((void)"Wrong number of parameters passed to gjs_parse_call_args()",
+ *fchar != '\0'));
+
+ if (*fchar == '?') {
+ nullable = true;
+ fchar++;
+ g_assert(((void)"Invalid format string, parameter required after '?'",
+ *fchar != '\0'));
+ }
- JS_BeginRequest(context);
+ try {
+ if (nullable) {
+ assign_nullable(cx, *fchar, args.get(param_ix), param_ref);
+ } else {
+ assign(cx, *fchar, args.get(param_ix), param_ref);
+ }
+ } catch (const char *message) {
+ gjs_throw(cx, "Error invoking %s, at argument %d (%s): %s",
+ function_name, param_ix, param_name, message);
+ return false;
+ }
+
+ return parse_call_args_helper(cx, function_name, args, ignore_trailing_args,
+ fchar++, param_ix++, params...);
+}
+
+template<typename... Args>
+bool
+gjs_parse_call_args_t(JSContext *cx,
+ const char *function_name,
+ JS::CallArgs& args,
+ const char *format,
+ Args ...params)
+{
+ const char *fmt_iter, *fmt_required, *fmt_optional;
+ unsigned n_required = 0, n_total = 0;
+ bool ignore_trailing_args = false, retval;
+
+ JSAutoRequest ar(cx);
if (*format == '!') {
ignore_trailing_args = true;
@@ -874,17 +1045,54 @@ gjs_parse_args_valist (JSContext *context,
if (n_required == 0)
n_required = n_total;
- if (argc < n_required || (argc > n_total && !ignore_trailing_args)) {
+ g_assert(((void)"Wrong number of parameters passed to gjs_parse_call_args()",
+ sizeof... Args == n_required));
+
+ // COMPAT: In future, use args.requireAtLeast()
+ if (args.length() < n_required ||
+ (args.length() > n_total && !ignore_trailing_args)) {
if (n_required == n_total) {
- gjs_throw(context, "Error invoking %s: Expected %d arguments, got %d", function_name,
- n_required, argc);
+ gjs_throw(cx, "Error invoking %s: Expected %d arguments, got %d",
+ function_name, n_required, args.length());
} else {
- gjs_throw(context, "Error invoking %s: Expected minimum %d arguments (and %d optional), got %d",
function_name,
- n_required, n_total - n_required, argc);
+ gjs_throw(cx,
+ "Error invoking %s: Expected minimum %d arguments (and %d optional), got %d",
+ function_name, n_required, n_total - n_required,
+ args.length());
}
- goto error_unwind;
+ return false;
}
+ char **parts = g_strsplit(format, "|", 2);
+ fmt_required = parts[0];
+ fmt_optional = parts[1]; /* may be NULL */
+
+ retval = parse_call_args_helper(cx, function_name, args, ignore_trailing_args,
+ fmt_required, fmt_optional, 0, params...);
+
+ g_strfreev(parts);
+ return retval;
+}
+
+static bool
+gjs_parse_args_valist (JSContext *context,
+ const char *function_name,
+ const char *format,
+ unsigned argc,
+ JS::Value *argv,
+ va_list args)
+{
+ guint i;
+ const char *fmt_iter;
+ guint n_unwind = 0;
+#define MAX_UNWIND_STRINGS 16
+ gpointer unwind_strings[MAX_UNWIND_STRINGS];
+ guint consumed_args;
+
+ // JS request
+ // check for ignore_trailing_args '!' char
+ // check number of args
+
/* We have 3 iteration variables here.
* @i: The current integer position in fmt_args
* @fmt_iter: A pointer to the character in fmt_args
@@ -913,6 +1121,7 @@ gjs_parse_args_valist (JSContext *context,
js_value = argv[consumed_args];
+ // handled '?o', still need to handle '?s' and '?F'
if (*fmt_iter == '?') {
fmt_iter++;
@@ -924,24 +1133,8 @@ gjs_parse_args_valist (JSContext *context,
}
switch (*fmt_iter) {
- case 'b': {
- if (!js_value.isBoolean()) {
- arg_error_message = "Not a boolean";
- } else {
- bool *arg = (bool *) arg_location;
- *arg = js_value.toBoolean();
- }
- }
- break;
- case 'o': {
- if (!js_value.isObject()) {
- arg_error_message = "Not an object";
- } else {
- JSObject **arg = (JSObject**) arg_location;
- *arg = &js_value.toObject();
- }
- }
- break;
+ // handle 'b'
+ // handle 'o'
case 's': {
char **arg = (char**) arg_location;
@@ -968,57 +1161,16 @@ gjs_parse_args_valist (JSContext *context,
}
}
break;
- case 'i': {
- if (!JS::ToInt32(context, js_value, (int32_t *) arg_location)) {
- /* Our error message is going to be more useful */
- JS_ClearPendingException(context);
- arg_error_message = "Couldn't convert to integer";
- }
- }
- break;
- case 'u': {
- gdouble num;
- if (!js_value.isNumber() || !JS::ToNumber(context, js_value, &num)) {
- /* Our error message is going to be more useful */
- JS_ClearPendingException(context);
- arg_error_message = "Couldn't convert to unsigned integer";
- } else if (num > G_MAXUINT32 || num < 0) {
- arg_error_message = "Value is out of range";
- } else {
- *((guint32*) arg_location) = num;
- }
- }
- break;
- case 't': {
- if (!JS::ToInt64(context, js_value, (int64_t *) arg_location)) {
- /* Our error message is going to be more useful */
- JS_ClearPendingException(context);
- arg_error_message = "Couldn't convert to 64-bit integer";
- }
- }
- break;
- case 'f': {
- double num;
- if (!JS::ToNumber(context, js_value, &num)) {
- /* Our error message is going to be more useful */
- JS_ClearPendingException(context);
- arg_error_message = "Couldn't convert to double";
- } else {
- *((double*) arg_location) = num;
- }
- }
- break;
+ // handle 'i'
+ // handle 'u'
+ // handle 't'
+ // handle 'f'
default:
g_assert_not_reached ();
}
got_value:
- if (arg_error_message != NULL) {
- gjs_throw(context, "Error invoking %s, at argument %d (%s): %s", function_name,
- consumed_args+1, argname, arg_error_message);
- goto error_unwind;
- }
-
+ // throw error if arg_error_message != NULL
consumed_args++;
}
@@ -1068,21 +1220,7 @@ gjs_parse_args_valist (JSContext *context,
* A prefix character '?' means that the next value may be null, in
* which case the C value %NULL is returned.
*/
-bool
-gjs_parse_args (JSContext *context,
- const char *function_name,
- const char *format,
- unsigned argc,
- JS::Value *argv,
- ...)
-{
- va_list args;
- bool ret;
- va_start (args, argv);
- ret = gjs_parse_args_valist (context, function_name, format, argc, argv, args);
- va_end (args);
- return ret;
-}
+
bool
gjs_parse_call_args (JSContext *context,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]