[gjs/wip/require: 11/11] import compat



commit 2177544c823e87881962e91b07a794ec9735f1ee
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Wed Jan 15 11:17:38 2014 -0500

    import compat

 Makefile.am           |    7 +-
 gi/boxed.cpp          |    2 +-
 gi/enumeration.cpp    |    2 +-
 gi/foreign.cpp        |   15 +-
 gi/gerror.cpp         |    2 +-
 gi/ns.cpp             |    2 +-
 gi/object.cpp         |    2 +-
 gi/param.cpp          |    2 +-
 gi/repo.cpp           |  760 --------------------------------
 gi/union.cpp          |    3 +-
 gi/util.cpp           |  401 +++++++++++++++++
 gi/{repo.h => util.h} |    3 -
 gjs/byteArray.cpp     |    2 +-
 gjs/context.cpp       |   67 ++-
 gjs/context.h         |    2 +
 gjs/gi.cpp            |   39 --
 gjs/gi.h              |    2 -
 gjs/gjs-module.h      |    1 -
 gjs/importer.cpp      | 1172 -------------------------------------------------
 gjs/importer.h        |   52 ---
 gjs/jsapi-util.h      |    2 -
 modules/bootstrap.js  |  132 ++++++
 22 files changed, 597 insertions(+), 2075 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index dfd72df..8c8dc94 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -31,7 +31,6 @@ nobase_gjs_module_include_HEADERS =   \
        gjs/gjs-module.h        \
        gjs/compat.h            \
        gjs/byteArray.h         \
-       gjs/importer.h          \
        gjs/jsapi-util.h        \
        gjs/runtime.h           \
        gjs/type-module.h       \
@@ -41,7 +40,7 @@ nobase_gjs_module_include_HEADERS =   \
        gi/object.h     \
        gi/foreign.h    \
        gi/param.h      \
-       gi/repo.h       \
+       gi/util.h       \
        gi/union.h      \
        gi/value.h      \
        gi/arg.h        \
@@ -105,9 +104,7 @@ libgjs_la_SOURCES =         \
        gjs/byteArray.cpp               \
        gjs/context.cpp         \
        gjs/bootstrap.cpp       \
-       gjs/importer.cpp                \
        gjs/gi.h                \
-       gjs/gi.cpp              \
        gjs/jsapi-private.cpp   \
        gjs/jsapi-util.cpp      \
        gjs/jsapi-dynamic-class.cpp \
@@ -142,7 +139,7 @@ libgjs_la_SOURCES += \
        gi/foreign.cpp  \
        gi/param.cpp    \
        gi/proxyutils.cpp       \
-        gi/repo.cpp    \
+        gi/util.cpp    \
        gi/union.cpp    \
         gi/value.cpp   \
        gi/interface.cpp        \
diff --git a/gi/boxed.cpp b/gi/boxed.cpp
index 4fcda3b..fce45e1 100644
--- a/gi/boxed.cpp
+++ b/gi/boxed.cpp
@@ -30,7 +30,7 @@
 #include "object.h"
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
-#include "repo.h"
+#include "util.h"
 #include "proxyutils.h"
 #include "function.h"
 #include "gtype.h"
diff --git a/gi/enumeration.cpp b/gi/enumeration.cpp
index 0fb0132..c907d92 100644
--- a/gi/enumeration.cpp
+++ b/gi/enumeration.cpp
@@ -27,7 +27,7 @@
 
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
-#include "repo.h"
+#include "util.h"
 #include "gtype.h"
 
 #include <util/log.h>
diff --git a/gi/foreign.cpp b/gi/foreign.cpp
index efbadfd..bb47ff1 100644
--- a/gi/foreign.cpp
+++ b/gi/foreign.cpp
@@ -69,26 +69,23 @@ gjs_foreign_load_foreign_module(JSContext *context,
         if (strcmp(gi_namespace, foreign_modules[i].gi_namespace) != 0)
             continue;
 
-        if (foreign_modules[i].loaded) {
+        if (foreign_modules[i].loaded)
             return JS_TRUE;
-        }
 
         // FIXME: Find a way to check if a module is imported
         //        and only execute this statement if isn't
-        script = g_strdup_printf("imports.%s;", gi_namespace);
-        if (!gjs_context_eval((GjsContext*) JS_GetContextPrivate(context), script, strlen(script),
-                              "<internal>", &code,
-                              &error)) {
-            g_printerr("ERROR: %s\n", error->message);
+        script = g_strdup_printf("require('%s');", gi_namespace);
+        if (!gjs_eval_with_scope(context, NULL, script, -1, "<internal>", NULL)) {
             g_free(script);
-            g_error_free(error);
             return JS_FALSE;
         }
+
         g_free(script);
         foreign_modules[i].loaded = TRUE;
+        return JS_TRUE;
     }
 
-    return JS_TRUE;
+    return JS_FALSE;
 }
 
 JSBool
diff --git a/gi/gerror.cpp b/gi/gerror.cpp
index 0856955..917bfd4 100644
--- a/gi/gerror.cpp
+++ b/gi/gerror.cpp
@@ -29,7 +29,7 @@
 #include <gjs/compat.h>
 #include "boxed.h"
 #include "enumeration.h"
-#include "repo.h"
+#include "util.h"
 #include "gerror.h"
 
 #include <util/log.h>
diff --git a/gi/ns.cpp b/gi/ns.cpp
index 1a55849..2488794 100644
--- a/gi/ns.cpp
+++ b/gi/ns.cpp
@@ -24,7 +24,7 @@
 #include <config.h>
 
 #include "ns.h"
-#include "repo.h"
+#include "util.h"
 #include "param.h"
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
diff --git a/gi/object.cpp b/gi/object.cpp
index c92b169..f8c1d3b 100644
--- a/gi/object.cpp
+++ b/gi/object.cpp
@@ -29,7 +29,7 @@
 #include "object.h"
 #include "gtype.h"
 #include "arg.h"
-#include "repo.h"
+#include "util.h"
 #include "gtype.h"
 #include "function.h"
 #include "proxyutils.h"
diff --git a/gi/param.cpp b/gi/param.cpp
index 3286238..0457615 100644
--- a/gi/param.cpp
+++ b/gi/param.cpp
@@ -28,7 +28,7 @@
 #include "param.h"
 #include "arg.h"
 #include "object.h"
-#include "repo.h"
+#include "util.h"
 #include "gtype.h"
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
diff --git a/gi/union.cpp b/gi/union.cpp
index 8364473..d3ad5af 100644
--- a/gi/union.cpp
+++ b/gi/union.cpp
@@ -25,7 +25,6 @@
 
 #include <string.h>
 
-/* include first for logging related #define used in repo.h */
 #include <util/log.h>
 
 #include "union.h"
@@ -33,7 +32,7 @@
 #include "object.h"
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
-#include "repo.h"
+#include "util.h"
 #include "proxyutils.h"
 #include "function.h"
 #include "gtype.h"
diff --git a/gi/util.cpp b/gi/util.cpp
new file mode 100644
index 0000000..599b5dc
--- /dev/null
+++ b/gi/util.cpp
@@ -0,0 +1,401 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright (c) 2008  litl, LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <config.h>
+
+#include "util.h"
+#include "ns.h"
+#include "function.h"
+#include "object.h"
+#include "param.h"
+#include "boxed.h"
+#include "union.h"
+#include "enumeration.h"
+#include "arg.h"
+#include "foreign.h"
+#include "interface.h"
+#include "gerror.h"
+
+#include <gjs/compat.h>
+#include <gjs/runtime.h>
+
+#include <util/log.h>
+#include <util/misc.h>
+
+#include <girepository.h>
+#include <string.h>
+
+static JSBool
+gjs_define_constant(JSContext      *context,
+                    JSObject       *in_object,
+                    GIConstantInfo *info)
+{
+    jsval value;
+    GArgument garg = { 0, };
+    GITypeInfo *type_info;
+    const char *name;
+    JSBool ret = JS_FALSE;
+
+    type_info = g_constant_info_get_type(info);
+    g_constant_info_get_value(info, &garg);
+
+    if (!gjs_value_from_g_argument(context, &value, type_info, &garg, TRUE))
+        goto out;
+
+    name = g_base_info_get_name((GIBaseInfo*) info);
+
+    if (JS_DefineProperty(context, in_object,
+                          name, value,
+                          NULL, NULL,
+                          GJS_MODULE_PROP_FLAGS))
+        ret = JS_TRUE;
+
+ out:
+    g_constant_info_free_value (info, &garg);
+    g_base_info_unref((GIBaseInfo*) type_info);
+    return ret;
+}
+
+#if GJS_VERBOSE_ENABLE_GI_USAGE
+void
+_gjs_log_info_usage(GIBaseInfo *info)
+{
+#define DIRECTION_STRING(d) ( ((d) == GI_DIRECTION_IN) ? "IN" : ((d) == GI_DIRECTION_OUT) ? "OUT" : "INOUT" )
+#define TRANSFER_STRING(t) ( ((t) == GI_TRANSFER_NOTHING) ? "NOTHING" : ((t) == GI_TRANSFER_CONTAINER) ? 
"CONTAINER" : "EVERYTHING" )
+
+    {
+        char *details;
+        GIInfoType info_type;
+        GIBaseInfo *container;
+
+        info_type = g_base_info_get_type(info);
+
+        if (info_type == GI_INFO_TYPE_FUNCTION) {
+            GString *args;
+            int n_args;
+            int i;
+            GITransfer retval_transfer;
+
+            args = g_string_new("{ ");
+
+            n_args = g_callable_info_get_n_args((GICallableInfo*) info);
+            for (i = 0; i < n_args; ++i) {
+                GIArgInfo *arg;
+                GIDirection direction;
+                GITransfer transfer;
+
+                arg = g_callable_info_get_arg((GICallableInfo*)info, i);
+                direction = g_arg_info_get_direction(arg);
+                transfer = g_arg_info_get_ownership_transfer(arg);
+
+                g_string_append_printf(args,
+                                       "{ GI_DIRECTION_%s, GI_TRANSFER_%s }, ",
+                                       DIRECTION_STRING(direction),
+                                       TRANSFER_STRING(transfer));
+
+                g_base_info_unref((GIBaseInfo*) arg);
+            }
+            if (args->len > 2)
+                g_string_truncate(args, args->len - 2); /* chop comma */
+
+            g_string_append(args, " }");
+
+            retval_transfer = g_callable_info_get_caller_owns((GICallableInfo*) info);
+
+            details = g_strdup_printf(".details = { .func = { .retval_transfer = GI_TRANSFER_%s, .n_args = 
%d, .args = %s } }",
+                                      TRANSFER_STRING(retval_transfer), n_args, args->str);
+            g_string_free(args, TRUE);
+        } else {
+            details = g_strdup_printf(".details = { .nothing = {} }");
+        }
+
+        container = g_base_info_get_container(info);
+
+        gjs_debug_gi_usage("{ GI_INFO_TYPE_%s, \"%s\", \"%s\", \"%s\", %s },",
+                           gjs_info_type_name(info_type),
+                           g_base_info_get_namespace(info),
+                           container ? g_base_info_get_name(container) : "",
+                           g_base_info_get_name(info),
+                           details);
+        g_free(details);
+    }
+}
+#endif /* GJS_VERBOSE_ENABLE_GI_USAGE */
+
+JSBool
+gjs_define_info(JSContext  *context,
+                JSObject   *in_object,
+                GIBaseInfo *info)
+{
+#if GJS_VERBOSE_ENABLE_GI_USAGE
+    _gjs_log_info_usage(info);
+#endif
+    switch (g_base_info_get_type(info)) {
+    case GI_INFO_TYPE_FUNCTION:
+        {
+            JSObject *f;
+            f = gjs_define_function(context, in_object, 0, (GICallableInfo*) info);
+            if (f == NULL)
+                return JS_FALSE;
+        }
+        break;
+    case GI_INFO_TYPE_OBJECT:
+        {
+            GType gtype;
+            gtype = g_registered_type_info_get_g_type((GIRegisteredTypeInfo*)info);
+
+            if (g_type_is_a (gtype, G_TYPE_PARAM)) {
+                gjs_define_param_class(context, in_object);
+            } else if (g_type_is_a (gtype, G_TYPE_OBJECT)) {
+                gjs_define_object_class(context, in_object, (GIObjectInfo*) info, gtype, NULL);
+            } else {
+                gjs_throw (context,
+                           "Unsupported type %s, deriving from fundamental %s",
+                           g_type_name(gtype), g_type_name(g_type_fundamental(gtype)));
+                return JS_FALSE;
+            }
+        }
+        break;
+    case GI_INFO_TYPE_STRUCT:
+    case GI_INFO_TYPE_BOXED:
+        gjs_define_boxed_class(context, in_object, (GIBoxedInfo*) info);
+        break;
+    case GI_INFO_TYPE_UNION:
+        if (!gjs_define_union_class(context, in_object, (GIUnionInfo*) info))
+            return JS_FALSE;
+        break;
+    case GI_INFO_TYPE_ENUM:
+        if (g_enum_info_get_error_domain((GIEnumInfo*) info)) {
+            /* define as GError subclass */
+            gjs_define_error_class(context, in_object, (GIEnumInfo*) info);
+            break;
+        }
+        /* fall through */
+
+    case GI_INFO_TYPE_FLAGS:
+        if (!gjs_define_enumeration(context, in_object, (GIEnumInfo*) info))
+            return JS_FALSE;
+        break;
+    case GI_INFO_TYPE_CONSTANT:
+        if (!gjs_define_constant(context, in_object, (GIConstantInfo*) info))
+            return JS_FALSE;
+        break;
+    case GI_INFO_TYPE_INTERFACE:
+        gjs_define_interface_class(context, in_object, (GIInterfaceInfo*) info);
+        break;
+    default:
+        gjs_throw(context, "API of type %s not implemented, cannot define %s.%s",
+                  gjs_info_type_name(g_base_info_get_type(info)),
+                  g_base_info_get_namespace(info),
+                  g_base_info_get_name(info));
+        return JS_FALSE;
+    }
+
+    return JS_TRUE;
+}
+
+/* Get the "unknown namespace", which should be used for unnamespaced types */
+JSObject*
+gjs_lookup_private_namespace(JSContext *context)
+{
+    jsid ns_name;
+    ns_name = gjs_context_get_const_string(context, GJS_STRING_PRIVATE_NS_MARKER);
+    return gjs_lookup_namespace_object_by_name(context, ns_name);
+}
+
+/* Get the namespace object that the GIBaseInfo should be inside */
+JSObject*
+gjs_lookup_namespace_object(JSContext  *context,
+                            GIBaseInfo *info)
+{
+    const char *ns;
+    jsid ns_name;
+
+    ns = g_base_info_get_namespace(info);
+    if (ns == NULL) {
+        gjs_throw(context, "%s '%s' does not have a namespace",
+                     gjs_info_type_name(g_base_info_get_type(info)),
+                     g_base_info_get_name(info));
+
+        return NULL;
+    }
+
+    ns_name = gjs_intern_string_to_id(context, ns);
+    return gjs_lookup_namespace_object_by_name(context, ns_name);
+}
+
+JSObject*
+gjs_lookup_namespace_object_by_name(JSContext      *context,
+                                    jsid            ns_name)
+{
+    char *name;
+    char *script;
+    jsval ns_val;
+    JSObject *ns_obj = NULL;
+
+    JS_BeginRequest(context);
+
+    if (!gjs_get_string_id(context, ns_name, &name))
+        goto out;
+
+    script = g_strdup_printf("require('gi/%s');", name);
+    if (!gjs_eval_with_scope(context, NULL, script, -1, "<internal>", &ns_val))
+        goto out;
+
+    ns_obj = JSVAL_TO_OBJECT(ns_val);
+
+ out:
+    JS_EndRequest(context);
+    return ns_obj;
+}
+
+const char*
+gjs_info_type_name(GIInfoType type)
+{
+    switch (type) {
+    case GI_INFO_TYPE_INVALID:
+        return "INVALID";
+    case GI_INFO_TYPE_FUNCTION:
+        return "FUNCTION";
+    case GI_INFO_TYPE_CALLBACK:
+        return "CALLBACK";
+    case GI_INFO_TYPE_STRUCT:
+        return "STRUCT";
+    case GI_INFO_TYPE_BOXED:
+        return "BOXED";
+    case GI_INFO_TYPE_ENUM:
+        return "ENUM";
+    case GI_INFO_TYPE_FLAGS:
+        return "FLAGS";
+    case GI_INFO_TYPE_OBJECT:
+        return "OBJECT";
+    case GI_INFO_TYPE_INTERFACE:
+        return "INTERFACE";
+    case GI_INFO_TYPE_CONSTANT:
+        return "CONSTANT";
+    case GI_INFO_TYPE_UNION:
+        return "UNION";
+    case GI_INFO_TYPE_VALUE:
+        return "VALUE";
+    case GI_INFO_TYPE_SIGNAL:
+        return "SIGNAL";
+    case GI_INFO_TYPE_VFUNC:
+        return "VFUNC";
+    case GI_INFO_TYPE_PROPERTY:
+        return "PROPERTY";
+    case GI_INFO_TYPE_FIELD:
+        return "FIELD";
+    case GI_INFO_TYPE_ARG:
+        return "ARG";
+    case GI_INFO_TYPE_TYPE:
+        return "TYPE";
+    case GI_INFO_TYPE_UNRESOLVED:
+        return "UNRESOLVED";
+    case GI_INFO_TYPE_INVALID_0:
+        g_assert_not_reached();
+        break;
+    }
+
+    return "???";
+}
+
+char*
+gjs_camel_from_hyphen(const char *hyphen_name)
+{
+    GString *s;
+    const char *p;
+    gboolean next_upper;
+
+    s = g_string_sized_new(strlen(hyphen_name) + 1);
+
+    next_upper = FALSE;
+    for (p = hyphen_name; *p; ++p) {
+        if (*p == '-' || *p == '_') {
+            next_upper = TRUE;
+        } else {
+            if (next_upper) {
+                g_string_append_c(s, g_ascii_toupper(*p));
+                next_upper = FALSE;
+            } else {
+                g_string_append_c(s, *p);
+            }
+        }
+    }
+
+    return g_string_free(s, FALSE);
+}
+
+char*
+gjs_hyphen_from_camel(const char *camel_name)
+{
+    GString *s;
+    const char *p;
+
+    /* four hyphens should be reasonable guess */
+    s = g_string_sized_new(strlen(camel_name) + 4 + 1);
+
+    for (p = camel_name; *p; ++p) {
+        if (g_ascii_isupper(*p)) {
+            g_string_append_c(s, '-');
+            g_string_append_c(s, g_ascii_tolower(*p));
+        } else {
+            g_string_append_c(s, *p);
+        }
+    }
+
+    return g_string_free(s, FALSE);
+}
+
+JSObject *
+gjs_lookup_generic_prototype(JSContext  *context,
+                             GIBaseInfo *info)
+{
+    JSObject *in_object;
+    JSObject *constructor;
+    const char *constructor_name;
+    jsval value;
+
+    in_object = gjs_lookup_namespace_object(context, (GIBaseInfo*) info);
+    constructor_name = g_base_info_get_name((GIBaseInfo*) info);
+
+    if (G_UNLIKELY (!in_object))
+        return NULL;
+
+    if (!JS_GetProperty(context, in_object, constructor_name, &value))
+        return NULL;
+
+    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value) || JSVAL_IS_NULL(value)))
+        return NULL;
+
+    constructor = JSVAL_TO_OBJECT(value);
+    g_assert(constructor != NULL);
+
+    if (!gjs_object_get_property_const(context, constructor,
+                                       GJS_STRING_PROTOTYPE, &value))
+        return NULL;
+
+    if (G_UNLIKELY (!JSVAL_IS_OBJECT(value)))
+        return NULL;
+
+    return JSVAL_TO_OBJECT(value);
+}
diff --git a/gi/repo.h b/gi/util.h
similarity index 91%
rename from gi/repo.h
rename to gi/util.h
index 60d5be4..c737b08 100644
--- a/gi/repo.h
+++ b/gi/util.h
@@ -32,9 +32,6 @@
 
 G_BEGIN_DECLS
 
-JSBool      gjs_define_repo                     (JSContext      *context,
-                                                 JSObject      **module_out,
-                                                 const char     *name);
 const char* gjs_info_type_name                  (GIInfoType      type);
 JSObject*   gjs_lookup_private_namespace        (JSContext      *context);
 JSObject*   gjs_lookup_namespace_object         (JSContext      *context,
diff --git a/gjs/byteArray.cpp b/gjs/byteArray.cpp
index 42d7dc1..e60b303 100644
--- a/gjs/byteArray.cpp
+++ b/gjs/byteArray.cpp
@@ -544,7 +544,7 @@ byte_array_get_prototype(JSContext *context)
     JSObject *prototype;
 
     if (!gjs_eval_with_scope(context, NULL,
-                             "imports.byteArray.ByteArray.prototype;", -1,
+                            "require('byteArray').ByteArray.prototype;", -1,
                              "<internal>", &retval))
         g_error ("Could not import byte array prototype\n");
 
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 46f3302..58b829c 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -27,7 +27,6 @@
 
 #include "context.h"
 #include "bootstrap.h"
-#include "importer.h"
 #include "jsapi-util.h"
 #include "native.h"
 #include "byteArray.h"
@@ -73,7 +72,7 @@ struct _GjsContext {
 /* Keep this consistent with GjsConstString */
 static const char *const_strings[] = {
     "constructor", "prototype", "length",
-    "imports", "__parentModule__", "__init__", "searchPath",
+    "__parentModule__", "__init__", "searchPath",
     "__gjsKeepAlive", "__gjsPrivateNS",
     "gi", "versions", "overrides",
     "_init", "_new_internal", "new",
@@ -316,7 +315,6 @@ gjs_context_class_init(GjsContextClass *klass)
 
     gjs_register_native_module("byteArray", gjs_define_byte_array_stuff);
     gjs_register_native_module("_gi", gjs_define_private_gi_stuff);
-    gjs_register_native_module("gi", gjs_define_gi_stuff);
 
     gjs_register_static_modules();
 }
@@ -461,24 +459,6 @@ gjs_context_constructed(GObject *object)
                            4, GJS_MODULE_PROP_FLAGS))
         g_error("Failed to define printerr function");
 
-    /* We create the global-to-runtime root importer with the
-     * passed-in search path. If someone else already created
-     * the root importer, this is a no-op.
-     */
-    if (!gjs_create_root_importer(js_context->context,
-                                  js_context->search_path ?
-                                  (const char**) js_context->search_path :
-                                  NULL,
-                                  TRUE))
-        g_error("Failed to create root importer");
-
-    /* Now copy the global root importer (which we just created,
-     * if it didn't exist) to our global object
-     */
-    if (!gjs_define_root_importer(js_context->context,
-                                  js_context->global))
-        g_error("Failed to point 'imports' property at root importer");
-
     if (!gjs_run_bootstrap(js_context->context))
         g_error("Failed to bootstrap GJS context");
 
@@ -765,3 +745,48 @@ gjs_context_get_search_path(GjsContext *context)
 {
     return (const char **) context->search_path;
 }
+
+char ** gjs_search_path;
+
+G_CONST_RETURN char * G_CONST_RETURN *
+gjs_get_search_path(void)
+{
+    char **search_path;
+
+    /* not thread safe */
+
+    if (!gjs_search_path) {
+        G_CONST_RETURN gchar* G_CONST_RETURN * system_data_dirs;
+        const char *envstr;
+        GPtrArray *path;
+        gsize i;
+
+        path = g_ptr_array_new();
+
+        /* in order of priority */
+
+        /* $GJS_PATH */
+        envstr = g_getenv("GJS_PATH");
+        if (envstr) {
+            char **dirs, **d;
+            dirs = g_strsplit(envstr, G_SEARCHPATH_SEPARATOR_S, 0);
+            for (d = dirs; *d != NULL; d++)
+                g_ptr_array_add(path, *d);
+            /* we assume the array and strings are allocated separately */
+            g_free(dirs);
+        }
+
+        /* ${datadir}/share/gjs-1.0 */
+        g_ptr_array_add(path, g_strdup("resource:///org/gnome/gjs/modules/"));
+
+        g_ptr_array_add(path, NULL);
+
+        search_path = (char**)g_ptr_array_free(path, FALSE);
+
+        gjs_search_path = search_path;
+    } else {
+        search_path = gjs_search_path;
+    }
+
+    return (G_CONST_RETURN char * G_CONST_RETURN *)search_path;
+}
diff --git a/gjs/context.h b/gjs/context.h
index acd07d1..54969a0 100644
--- a/gjs/context.h
+++ b/gjs/context.h
@@ -79,6 +79,8 @@ void            gjs_dumpstack                     (void);
 
 const char **   gjs_context_get_search_path       (GjsContext *context);
 
+G_CONST_RETURN char * G_CONST_RETURN * gjs_get_search_path (void);
+
 G_END_DECLS
 
 #endif  /* __GJS_CONTEXT_H__ */
diff --git a/gjs/gi.h b/gjs/gi.h
index 837d03d..786fc61 100644
--- a/gjs/gi.h
+++ b/gjs/gi.h
@@ -30,8 +30,6 @@
 
 G_BEGIN_DECLS
 
-JSBool        gjs_define_gi_stuff     (JSContext      *context,
-                                       JSObject      **module_out);
 JSBool        gjs_define_private_gi_stuff   (JSContext     *context,
                                              JSObject     **module_out);
 
diff --git a/gjs/gjs-module.h b/gjs/gjs-module.h
index f85f89b..f644139 100644
--- a/gjs/gjs-module.h
+++ b/gjs/gjs-module.h
@@ -27,7 +27,6 @@
 #include <gjs/gjs.h>
 #include <gjs/native.h>
 #include <gjs/mem.h>
-#include <gjs/importer.h>
 #include <gjs/runtime.h>
 #include <gjs/jsapi-util.h>
 
diff --git a/gjs/jsapi-util.h b/gjs/jsapi-util.h
index 32b2d4c..d5a7c3e 100644
--- a/gjs/jsapi-util.h
+++ b/gjs/jsapi-util.h
@@ -46,7 +46,6 @@ enum {
 };
 
 typedef enum {
-    GJS_GLOBAL_SLOT_IMPORTS,
     GJS_GLOBAL_SLOT_KEEP_ALIVE,
     GJS_GLOBAL_SLOT_LAST,
 } GjsGlobalSlot;
@@ -408,7 +407,6 @@ typedef enum {
   GJS_STRING_CONSTRUCTOR,
   GJS_STRING_PROTOTYPE,
   GJS_STRING_LENGTH,
-  GJS_STRING_IMPORTS,
   GJS_STRING_PARENT_MODULE,
   GJS_STRING_MODULE_INIT,
   GJS_STRING_SEARCH_PATH,
diff --git a/modules/bootstrap.js b/modules/bootstrap.js
index 31a988d..ef52a15 100644
--- a/modules/bootstrap.js
+++ b/modules/bootstrap.js
@@ -6,6 +6,10 @@
 
     let _exports = {};
 
+    // This is where "unknown namespace" classes live, where we don't
+    // have info for them. One common example is GLocalFile.
+    _exports['gi/__gjsPrivateNS'] = {};
+
     function loadNativeModule(moduleID) {
         _exports[moduleID] = importNativeModule(moduleID);
     }
@@ -134,4 +138,132 @@
     }
     require.paths = Importer.getBuiltinSearchPath();
 
+    function installCompatImports() {
+        // imports.gi
+        let gi = new Proxy({
+            versions: {},
+        }, {
+            get: function(target, name) {
+                if (target[name])
+                    return target[name];
+
+                let version = target.versions[name] || null;
+                return importGIModuleWithOverrides(name, version);
+            },
+        });
+
+        function importModule(module, file) {
+            let success, script;
+            try {
+                [success, script] = file.load_contents(null);
+            } catch(e) {
+                return null;
+            }
+
+            // Don't catch errors for the eval, as those should propagate
+            // back up to the user...
+            Importer.evalWithScope(module, script, file.get_parse_name());
+            return module;
+        }
+
+        function importFile(parent, name, file) {
+            let module = {};
+            module.__file__ = file.get_parse_name();
+            module.__moduleName__ = name;
+            module.__parentModule__ = parent;
+            importModule(module, file);
+            return module;
+        }
+
+        function importDirectory(parent, name) {
+            let searchPath = parent.searchPath.map(function(path) {
+                return path + '/' + name;
+            }).filter(function(path) {
+                let file = Gio.File.new_for_commandline_arg(path);
+                let type = file.query_file_type(Gio.FileQueryInfoFlags.NONE, null);
+                return (type == Gio.FileType.DIRECTORY);
+            });
+
+            let module = createSearchPathImporter();
+            module.searchPath = searchPath;
+            module.__moduleName__ = name;
+            module.__parentModule__ = parent;
+
+            function runInit() {
+                for (let path of searchPath) {
+                    let initFile = Gio.File.new_for_commandline_arg(path + '/__init__.js');
+                    if (initFile.query_exists(null)) {
+                        importModule(module, initFile);
+                        return;
+                    }
+                }
+            }
+
+            runInit();
+
+            return module;
+        }
+
+        function tryImport(proxy, name) {
+            function tryPath(path) {
+                let file, type;
+                file = Gio.File.new_for_commandline_arg(path);
+                type = file.query_file_type(Gio.FileQueryInfoFlags.NONE, null);
+                if (type == Gio.FileType.DIRECTORY)
+                    return importDirectory(proxy, name);
+
+                file = Gio.File.new_for_commandline_arg(path + '.js');
+                if (file.query_exists(null))
+                    return importFile(proxy, name, file);
+
+                return null;
+            }
+
+            for (let path of proxy.searchPath) {
+                let modulePath = path + '/' + name;
+                let obj = tryPath(modulePath);
+                if (obj)
+                    return obj;
+            }
+            return null;
+        }
+
+        function createSearchPathImporter() {
+            let proxy = new Proxy({}, {
+                get: function(target, name) {
+                    if (target[name])
+                        return target[name];
+
+                    let obj = tryImport(proxy, name);
+                    target[obj] = obj;
+                    return obj;
+                },
+            });
+            return proxy;
+        }
+
+        let rootDirectoryImporter = createSearchPathImporter();
+        rootDirectoryImporter.searchPath = Importer.getBuiltinSearchPath();
+
+        // root importer, checks for native modules
+        let rootImporter = new Proxy(rootDirectoryImporter, {
+            get: function(target, name) {
+                if (target[name])
+                    return target[name];
+
+                let nativeModule = importNativeModule(name);
+                if (nativeModule) {
+                    target[name] = nativeModule;
+                    return nativeModule;
+                }
+
+                return rootDirectoryImporter[name];
+            },
+        });
+        rootImporter.gi = gi;
+
+        exports.imports = rootImporter;
+    }
+    installCompatImports();
+
 })(window, importNativeModule);


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