[gjs/wip/require: 6/7] bootstrap: Add a JS implementation of the imports system



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

    bootstrap: Add a JS implementation of the imports system
    
    Re-implement the old importer with a Proxy in bootstrap.js, reducing the
    footprint and making the code significantly easier to understand.

 Makefile.am           |    9 +-
 gi/boxed.cpp          |    2 +-
 gi/enumeration.cpp    |    2 +-
 gi/fundamental.cpp    |   14 +-
 gi/gerror.cpp         |    2 +-
 gi/interface.cpp      |    2 +-
 gi/ns.cpp             |    2 +-
 gi/object.cpp         |    2 +-
 gi/param.cpp          |    2 +-
 gi/repo.cpp           |  796 -----------------------------------
 gi/union.cpp          |    3 +-
 gi/util.cpp           |  438 +++++++++++++++++++
 gi/{repo.h => util.h} |    3 -
 gjs/context.cpp       |   22 +-
 gjs/gi.cpp            |   39 --
 gjs/gi.h              |    2 -
 gjs/gjs-module.h      |    1 -
 gjs/importer.cpp      | 1118 -------------------------------------------------
 gjs/importer.h        |   50 ---
 gjs/jsapi-util.h      |    2 -
 modules/bootstrap.js  |  134 ++++++-
 21 files changed, 578 insertions(+), 2067 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 835bb86..09eeed9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -35,7 +35,6 @@ nobase_gjs_module_include_HEADERS =   \
        gjs/compat.h            \
        gjs/coverage.h \
        gjs/byteArray.h         \
-       gjs/importer.h          \
        gjs/jsapi-util.h        \
        gjs/runtime.h           \
        gjs/type-module.h       \
@@ -46,7 +45,7 @@ nobase_gjs_module_include_HEADERS =   \
        gi/foreign.h    \
        gi/fundamental.h        \
        gi/param.h      \
-       gi/repo.h       \
+       gi/util.h       \
        gi/union.h      \
        gi/value.h      \
        gi/arg.h        \
@@ -112,10 +111,8 @@ libgjs_la_SOURCES =                \
        gjs/byteArray.cpp               \
        gjs/context.cpp         \
        gjs/bootstrap.cpp       \
-       gjs/importer.cpp                \
        gjs/gi.h                \
-       gjs/gi.cpp              \
-       gjs/coverage.cpp \
+       gjs/coverage.cpp        \
        gjs/jsapi-private.cpp   \
        gjs/jsapi-util.cpp      \
        gjs/jsapi-dynamic-class.cpp \
@@ -151,7 +148,7 @@ libgjs_la_SOURCES += \
        gi/fundamental.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 7584525..658f578 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 598a11a..8593bea 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 "function.h"
 
diff --git a/gi/fundamental.cpp b/gi/fundamental.cpp
index 0e1908f..f1b0d23 100644
--- a/gi/fundamental.cpp
+++ b/gi/fundamental.cpp
@@ -24,25 +24,19 @@
 
 #include <config.h>
 
-#include <string.h>
-
-#include <gjs/gi.h>
-
 #include "fundamental.h"
+
 #include "arg.h"
 #include "object.h"
 #include "boxed.h"
-#include "repo.h"
 #include "function.h"
 #include "gtype.h"
 #include "proxyutils.h"
+#include "util.h"
 
-#include <gjs/gjs.h>
-
+#include <gjs/gjs-module.h>
+#include <gjs/compat.h>
 #include <util/log.h>
-
-#include <jsapi.h>
-
 #include <girepository.h>
 
 /*
diff --git a/gi/gerror.cpp b/gi/gerror.cpp
index f183ca3..af84bbe 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/interface.cpp b/gi/interface.cpp
index 96c7230..767184d 100644
--- a/gi/interface.cpp
+++ b/gi/interface.cpp
@@ -27,7 +27,7 @@
 #include "function.h"
 #include "gtype.h"
 #include "interface.h"
-#include "repo.h"
+#include "util.h"
 
 #include <gjs/gjs-module.h>
 #include <gjs/compat.h>
diff --git a/gi/ns.cpp b/gi/ns.cpp
index ef73826..229a9f8 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 376dd85..44b10bf 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 27918b2..596268e 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 "function.h"
 #include <gjs/gjs-module.h>
diff --git a/gi/union.cpp b/gi/union.cpp
index 23ca458..5533af5 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..055d6a6
--- /dev/null
+++ b/gi/util.cpp
@@ -0,0 +1,438 @@
+/* -*- 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 "fundamental.h"
+#include "interface.h"
+#include "gerror.h"
+
+#include <gjs/compat.h>
+#include <gjs/jsapi-private.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,
+                gboolean   *defined)
+{
+#if GJS_VERBOSE_ENABLE_GI_USAGE
+    _gjs_log_info_usage(info);
+#endif
+
+    *defined = TRUE;
+
+    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 if (G_TYPE_IS_INSTANTIATABLE(gtype)) {
+                if (!gjs_define_fundamental_class(context, in_object, (GIObjectInfo*)info, NULL, NULL)) {
+                    gjs_throw (context,
+                               "Unsupported fundamental class creation for type %s",
+                               g_type_name(gtype));
+                    return JS_FALSE;
+                }
+            } 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:
+        /* We don't want GType structures in the namespace,
+           we expose their fields as vfuncs and their methods
+           as static methods
+        */
+        if (g_struct_info_is_gtype_struct((GIStructInfo*) info)) {
+            *defined = FALSE;
+            break;
+        }
+        /* Fall through */
+
+    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("imports.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_constructor(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);
+
+    return constructor;
+}
+
+JSObject *
+gjs_lookup_generic_prototype(JSContext  *context,
+                             GIBaseInfo *info)
+{
+    JSObject *constructor;
+    jsval value;
+
+    constructor = gjs_lookup_generic_constructor(context, info);
+    if (G_UNLIKELY (constructor == NULL))
+        return 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 92%
rename from gi/repo.h
rename to gi/util.h
index ba1fd90..c2b277e 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/context.cpp b/gjs/context.cpp
index aaedb6f..3f0be36 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -27,7 +27,6 @@
 
 #include "context-private.h"
 #include "bootstrap.h"
-#include "importer.h"
 #include "jsapi-private.h"
 #include "jsapi-util.h"
 #include "native.h"
@@ -78,7 +77,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", "_instance_init", "_new_internal", "new",
@@ -321,7 +320,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();
 }
@@ -443,24 +441,6 @@ gjs_context_constructed(GObject *object)
     if (!JS_DefineFunctions(js_context->context, js_context->global, &global_funcs[0]))
         g_error("Failed to define properties on the global object");
 
-    /* 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");
 
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 6e98713..49770d4 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_BYTE_ARRAY_PROTOTYPE,
     GJS_GLOBAL_SLOT_LAST,
@@ -407,7 +406,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 3f1ee3d..2292ef5 100644
--- a/modules/bootstrap.js
+++ b/modules/bootstrap.js
@@ -15,18 +15,10 @@
     }
 
     const Importer = importNativeModule('_importer');
+    const Gio = Importer.importGIModule('Gio', '2.0');
 
     function loadNativeModule(moduleID) {
-        // _exports[moduleID] = importNativeModule(moduleID);
-
-        // XXX: In order to not double-register modules, we need
-        // to do this. As soon as we implement the importer on
-        // top of the new system, revert this.
-
-        try {
-            _exports[moduleID] = imports[moduleID];
-        } catch(e) {
-        }
+        _exports[moduleID] = importNativeModule(moduleID);
     }
 
     function runOverridesForGIModule(module, moduleID) {
@@ -70,4 +62,126 @@
         importGIModuleWithOverrides(giModuleID, moduleVersion);
     }
 
+
+    function installImports() {
+        // Implement the global "imports" object.
+
+        // 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 = {};
+            parent[name] = module;
+            module.__file__ = file.get_parse_name();
+            module.__moduleName__ = name;
+            module.__parentModule__ = parent;
+            importModule(module, file);
+        }
+
+        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();
+            parent[name] = module;
+            module.searchPath = searchPath;
+            module.__moduleName__ = name;
+            module.__parentModule__ = parent;
+
+            tryImport(module, '__init__');
+        }
+
+        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) {
+                    importDirectory(proxy, name);
+                    return true;
+                } else {
+                    file = Gio.File.new_for_commandline_arg(path + '.js');
+                    if (file.query_exists(null)) {
+                        importFile(proxy, name, file);
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            for (let path of proxy.searchPath) {
+                let modulePath = path + '/' + name;
+                if (tryPath(modulePath))
+                    return;
+            }
+        }
+
+        function createSearchPathImporter() {
+            let proxy = new Proxy({ __init__: {} }, {
+                get: function(target, name) {
+                    if (target.__init__[name])
+                        return target.__init__[name];
+
+                    if (!target[name])
+                        tryImport(proxy, name);
+
+                    return target[name];
+                },
+            });
+            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;
+    }
+    installImports();
+
 })(window, importNativeModule);


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