[gjs/wip/ptomato/develop: 7/11] Add marshalling for native JS errors



commit b65f34d7b2e00b2aa7c1b595806802f5acdbfe41
Author: Giovanni Campagna <gcampagna src gnome org>
Date:   Sun Aug 26 00:23:24 2012 +0200

    Add marshalling for native JS errors
    
    Introduce a GError domain for representing native JS errors (such as
    TypeError or ReferenceError) throw by JS code, to be reported to calling
    C code.
    Introduce also a way to retrieve something similar to the original C
    error from this GError, in case it comes through a called C function
    unmodified.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=682701

 gi/gerror.cpp  |   88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gi/gerror.h    |    3 ++
 util/error.cpp |   34 +++++++++++++++++++++
 util/error.h   |   22 +++++++++++++-
 4 files changed, 146 insertions(+), 1 deletions(-)
---
diff --git a/gi/gerror.cpp b/gi/gerror.cpp
index d4d5e28..d0e827b 100644
--- a/gi/gerror.cpp
+++ b/gi/gerror.cpp
@@ -32,6 +32,7 @@
 #include "gjs/mem.h"
 #include "repo.h"
 #include "gerror.h"
+#include "util/error.h"
 
 #include <util/log.h>
 
@@ -428,6 +429,48 @@ define_error_properties(JSContext       *cx,
         exc.restore();
 }
 
+static JSProtoKey
+proto_key_from_error_enum(int val)
+{
+    switch (val) {
+    case GJS_JS_ERROR_EVAL_ERROR:
+        return JSProto_EvalError;
+    case GJS_JS_ERROR_INTERNAL_ERROR:
+        return JSProto_InternalError;
+    case GJS_JS_ERROR_RANGE_ERROR:
+        return JSProto_RangeError;
+    case GJS_JS_ERROR_REFERENCE_ERROR:
+        return JSProto_ReferenceError;
+    case GJS_JS_ERROR_STOP_ITERATION:
+        return JSProto_StopIteration;
+    case GJS_JS_ERROR_SYNTAX_ERROR:
+        return JSProto_SyntaxError;
+    case GJS_JS_ERROR_TYPE_ERROR:
+        return JSProto_TypeError;
+    case GJS_JS_ERROR_URI_ERROR:
+        return JSProto_URIError;
+    case GJS_JS_ERROR_ERROR:
+    default:
+        return JSProto_Error;
+    }
+}
+
+static JSObject *
+gjs_error_from_js_gerror(JSContext *cx,
+                         GError    *gerror)
+{
+    JS::AutoValueArray<1> error_args(cx);
+    if (!gjs_string_from_utf8(cx, gerror->message, -1, error_args[0]))
+        return nullptr;
+
+    JSProtoKey error_kind = proto_key_from_error_enum(gerror->code);
+    JS::RootedObject error_constructor(cx);
+    if (!JS_GetClassObject(cx, error_kind, &error_constructor))
+        return nullptr;
+
+    return JS_New(cx, error_constructor, error_args);
+}
+
 JSObject*
 gjs_error_from_gerror(JSContext             *context,
                       GError                *gerror,
@@ -440,6 +483,9 @@ gjs_error_from_gerror(JSContext             *context,
     if (gerror == NULL)
         return NULL;
 
+    if (gerror->domain == GJS_JS_ERROR)
+        return gjs_error_from_js_gerror(context, gerror);
+
     info = find_error_domain_info(gerror->domain);
 
     if (!info) {
@@ -520,3 +566,45 @@ gjs_typecheck_gerror (JSContext       *context,
 
     return do_base_typecheck(context, obj, throw_error);
 }
+
+GError *
+gjs_gerror_make_from_error(JSContext       *cx,
+                           JS::HandleObject obj)
+{
+    using AutoEnumClass = std::unique_ptr<GEnumClass, decltype(&g_type_class_unref)>;
+
+    if (gjs_typecheck_gerror(cx, obj, false)) {
+        /* This is already a GError, just copy it */
+        GError *inner = gjs_gerror_from_error(cx, obj);
+        return g_error_copy(inner);
+    }
+
+    /* Try to make something useful from the error
+       name and message (in case this is a JS error) */
+    JS::RootedValue v_name(cx);
+    if (!gjs_object_get_property(cx, obj, GJS_STRING_NAME, &v_name))
+        return nullptr;
+
+    GjsAutoJSChar name(cx);
+    if (!gjs_string_to_utf8(cx, v_name, &name))
+        return nullptr;
+
+    JS::RootedValue v_message(cx);
+    if (!gjs_object_get_property(cx, obj, GJS_STRING_MESSAGE, &v_message))
+        return nullptr;
+
+    GjsAutoJSChar message(cx);
+    if (!gjs_string_to_utf8(cx, v_message, &message))
+        return nullptr;
+
+    AutoEnumClass klass(static_cast<GEnumClass *>(g_type_class_ref(GJS_TYPE_JS_ERROR)),
+                        g_type_class_unref);
+    const GEnumValue *value = g_enum_get_value_by_name(klass.get(), name);
+    int code;
+    if (value)
+        code = value->value;
+    else
+        code = GJS_JS_ERROR_ERROR;
+
+    return g_error_new_literal(GJS_JS_ERROR, code, message);
+}
diff --git a/gi/gerror.h b/gi/gerror.h
index 913877c..8f7d549 100644
--- a/gi/gerror.h
+++ b/gi/gerror.h
@@ -44,6 +44,9 @@ bool      gjs_typecheck_gerror         (JSContext             *context,
                                         JS::HandleObject       obj,
                                         bool                   throw_error);
 
+GError *gjs_gerror_make_from_error(JSContext       *cx,
+                                   JS::HandleObject obj);
+
 G_END_DECLS
 
 #endif  /* __GJS_ERROR_H__ */
diff --git a/util/error.cpp b/util/error.cpp
index 8c8b586..b653b08 100644
--- a/util/error.cpp
+++ b/util/error.cpp
@@ -22,6 +22,9 @@
  */
 
 #include <config.h>
+
+#include <glib-object.h>
+
 #include "error.h"
 
 GQuark
@@ -29,3 +32,34 @@ gjs_error_quark (void)
 {
     return g_quark_from_static_string ("gjs-error-quark");
 }
+
+GQuark
+gjs_js_error_quark(void)
+{
+    return g_quark_from_static_string("gjs-js-error-quark");
+}
+
+GType
+gjs_js_error_get_type(void)
+{
+    static volatile GType g_type_id;
+
+    if (g_once_init_enter(&g_type_id)) {
+        static GEnumValue errors[] = {
+            { GJS_JS_ERROR_ERROR, "Error", "error" },
+            { GJS_JS_ERROR_EVAL_ERROR, "EvalError", "eval-error" },
+            { GJS_JS_ERROR_INTERNAL_ERROR, "InternalError", "internal-error" },
+            { GJS_JS_ERROR_RANGE_ERROR, "RangeError", "range-error" },
+            { GJS_JS_ERROR_REFERENCE_ERROR, "ReferenceError", "reference-error" },
+            { GJS_JS_ERROR_STOP_ITERATION, "StopIteration", "stop-iteration" },
+            { GJS_JS_ERROR_SYNTAX_ERROR, "SyntaxError", "syntax-error" },
+            { GJS_JS_ERROR_TYPE_ERROR, "TypeError", "type-error" },
+            { GJS_JS_ERROR_URI_ERROR, "URIError", "uri-error" },
+            { 0, nullptr, nullptr }
+        };
+
+        g_type_id = g_enum_register_static("GjsJSError", errors);
+    }
+
+    return g_type_id;
+}
diff --git a/util/error.h b/util/error.h
index 08a3128..9f97eb5 100644
--- a/util/error.h
+++ b/util/error.h
@@ -24,7 +24,7 @@
 #ifndef __GJS_UTIL_ERROR_H__
 #define __GJS_UTIL_ERROR_H__
 
-#include <glib.h>
+#include <glib-object.h>
 
 #include <gjs/macros.h>
 
@@ -39,6 +39,26 @@ typedef enum {
     GJS_ERROR_SYSTEM_EXIT,
 } GjsError;
 
+GJS_EXPORT
+GQuark gjs_js_error_quark(void);
+#define GJS_JS_ERROR gjs_js_error_quark()
+
+GJS_EXPORT
+GType gjs_js_error_get_type(void);
+#define GJS_TYPE_JS_ERROR gjs_js_error_get_type()
+
+typedef enum {
+    GJS_JS_ERROR_ERROR,
+    GJS_JS_ERROR_EVAL_ERROR,
+    GJS_JS_ERROR_INTERNAL_ERROR,
+    GJS_JS_ERROR_RANGE_ERROR,
+    GJS_JS_ERROR_REFERENCE_ERROR,
+    GJS_JS_ERROR_STOP_ITERATION,
+    GJS_JS_ERROR_SYNTAX_ERROR,
+    GJS_JS_ERROR_TYPE_ERROR,
+    GJS_JS_ERROR_URI_ERROR,
+} GjsJSError;
+
 G_END_DECLS
 
 #endif  /* __GJS_UTIL_ERROR_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]