[gjs/wip/require: 1/7] bootstrap: Add the skeleton of a new imports system



commit 6aa6e1fe89a9a21d57edcfb639ecbee378021e5b
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Thu Jan 2 15:59:16 2014 -0500

    bootstrap: Add the skeleton of a new imports system
    
    Get the base features implemented, which lets us import a native
    module. We also add a new private module, '_importer', which will
    contain all the native functionality we need for a new imports
    system.

 Makefile-modules.am       |    7 ++-
 gjs/bootstrap.cpp         |   42 ++++++++++++
 gjs/console.cpp           |    2 +-
 gjs/context.cpp           |    6 ++
 gjs/context.h             |    2 +
 gjs/importer.cpp          |    2 +-
 gjs/importer.h            |    2 +
 libgjs-private/gjs-util.h |    4 +-
 modules/bootstrap.js      |   57 ++++++++++++++++-
 modules/importer.cpp      |  153 +++++++++++++++++++++++++++++++++++++++++++++
 modules/importer.h        |   38 +++++++++++
 modules/modules.cpp       |    2 +
 12 files changed, 308 insertions(+), 9 deletions(-)
---
diff --git a/Makefile-modules.am b/Makefile-modules.am
index 4b6e356..4151c5d 100644
--- a/Makefile-modules.am
+++ b/Makefile-modules.am
@@ -1,6 +1,5 @@
 
-NATIVE_MODULES = libconsole.la libsystem.la libmodules_resources.la
-
+NATIVE_MODULES = libconsole.la libsystem.la libmodules_resources.la libimporter.la
 if ENABLE_CAIRO
 NATIVE_MODULES += libcairoNative.la
 endif
@@ -56,3 +55,7 @@ libsystem_la_SOURCES = modules/system.h modules/system.cpp
 libconsole_la_CPPFLAGS = $(JS_NATIVE_MODULE_CFLAGS)
 libconsole_la_LIBADD = $(JS_NATIVE_MODULE_LIBADD) $(READLINE_LIBS)
 libconsole_la_SOURCES = modules/console.h modules/console.cpp
+
+libimporter_la_CPPFLAGS = $(JS_NATIVE_MODULE_CFLAGS)
+libimporter_la_LIBADD = $(JS_NATIVE_MODULE_LIBADD)
+libimporter_la_SOURCES = modules/importer.h modules/importer.cpp
diff --git a/gjs/bootstrap.cpp b/gjs/bootstrap.cpp
index b049ec4..406c26f 100644
--- a/gjs/bootstrap.cpp
+++ b/gjs/bootstrap.cpp
@@ -26,9 +26,48 @@
 #include <gjs/gjs.h>
 
 #include "bootstrap.h"
+#include "native.h"
 
 #include <gio/gio.h>
 
+/* The bootstrap process is the thing that sets up the import system.
+ * As such, we give it a hook to import any native modules it may need.
+ *
+ * The rest of the functionality that the bootstrap code needs should be
+ * in independent native modules which can be imported by this API,
+ * rather than in the bootstrap environment.
+ */
+
+static JSBool
+import_native_module(JSContext *context,
+                     unsigned   argc,
+                     jsval     *vp)
+{
+    JSBool ret = JS_FALSE;
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    char *module_name = NULL;
+    JSObject *module_obj;
+
+    if (!gjs_parse_call_args(context, "importNativeModule", "s", args,
+                             "moduleName", &module_name))
+        goto out;
+
+    if (!gjs_import_native_module(context, module_name, &module_obj))
+        goto out;
+
+    ret = JS_TRUE;
+    args.rval().setObjectOrNull(module_obj);
+
+ out:
+    g_free(module_name);
+    return ret;
+}
+
+static JSFunctionSpec environment_funcs[] = {
+    { "importNativeModule", JSOP_WRAPPER (import_native_module), 1, GJS_MODULE_PROP_FLAGS },
+    { NULL },
+};
+
 static gboolean
 define_bootstrap_environment(JSContext  *context,
                              JSObject  **environment_out)
@@ -38,6 +77,9 @@ define_bootstrap_environment(JSContext  *context,
     if (!environment)
         return FALSE;
 
+    if (!JS_DefineFunctions(context, environment, &environment_funcs[0]))
+        return FALSE;
+
     *environment_out = environment;
     return TRUE;
 }
diff --git a/gjs/console.cpp b/gjs/console.cpp
index 50adca8..2320e55 100644
--- a/gjs/console.cpp
+++ b/gjs/console.cpp
@@ -96,7 +96,7 @@ main(int argc, char **argv)
         filename = "<command line>";
         program_name = argv[0];
     } else if (argc <= 1) {
-        script = g_strdup("const Console = imports.console; Console.interact();");
+        script = g_strdup("const Console = require('console'); Console.interact();");
         len = strlen(script);
         filename = "<stdin>";
         program_name = argv[0];
diff --git a/gjs/context.cpp b/gjs/context.cpp
index 6564440..ed11882 100644
--- a/gjs/context.cpp
+++ b/gjs/context.cpp
@@ -792,3 +792,9 @@ gjs_get_import_global(JSContext *context)
     GjsContext *gjs_context = (GjsContext *) JS_GetContextPrivate(context);
     return gjs_context->global;
 }
+
+const char **
+gjs_context_get_search_path(GjsContext *context)
+{
+    return (const char **) context->search_path;
+}
diff --git a/gjs/context.h b/gjs/context.h
index ccd8bc6..acd07d1 100644
--- a/gjs/context.h
+++ b/gjs/context.h
@@ -77,6 +77,8 @@ void            gjs_context_gc                    (GjsContext  *context);
 
 void            gjs_dumpstack                     (void);
 
+const char **   gjs_context_get_search_path       (GjsContext *context);
+
 G_END_DECLS
 
 #endif  /* __GJS_CONTEXT_H__ */
diff --git a/gjs/importer.cpp b/gjs/importer.cpp
index 3b163e3..e421dda 100644
--- a/gjs/importer.cpp
+++ b/gjs/importer.cpp
@@ -997,7 +997,7 @@ importer_new(JSContext *context,
     return importer;
 }
 
-static G_CONST_RETURN char * G_CONST_RETURN *
+G_CONST_RETURN char * G_CONST_RETURN *
 gjs_get_search_path(void)
 {
     char **search_path;
diff --git a/gjs/importer.h b/gjs/importer.h
index afd4ab1..8f11fb8 100644
--- a/gjs/importer.h
+++ b/gjs/importer.h
@@ -29,6 +29,7 @@
 #endif
 
 #include <glib.h>
+#include <gio/gio.h>
 #include "gjs/jsapi-util.h"
 
 G_BEGIN_DECLS
@@ -44,6 +45,7 @@ JSObject* gjs_define_importer      (JSContext   *context,
                                     const char **initial_search_path,
                                     gboolean     add_standard_search_path);
 
+G_CONST_RETURN char * G_CONST_RETURN * gjs_get_search_path (void);
 
 G_END_DECLS
 
diff --git a/libgjs-private/gjs-util.h b/libgjs-private/gjs-util.h
index 18ca87e..aef6594 100644
--- a/libgjs-private/gjs-util.h
+++ b/libgjs-private/gjs-util.h
@@ -28,10 +28,10 @@
 
 G_BEGIN_DECLS
 
-/* For imports.format */
+/* For 'format' */
 char * gjs_format_int_alternative_output (int n);
 
-/* For imports.gettext */
+/* For 'gettext' */
 void gjs_textdomain     (const char *domain);
 void gjs_bindtextdomain (const char *domain,
                          const char *location);
diff --git a/modules/bootstrap.js b/modules/bootstrap.js
index 45ab533..5f62330 100644
--- a/modules/bootstrap.js
+++ b/modules/bootstrap.js
@@ -1,6 +1,57 @@
-(function(exports) {
+(function(exports, importNativeModule) {
     "use strict";
 
-    // Do early initialization here.
+    const Importer = importNativeModule('_importer');
 
-})(window);
+    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);
+    }
+
+    function runOverridesForGIModule(module, moduleID) {
+        let overridesModuleName = ('overrides/' + moduleID);
+        loadJSModule(overridesModuleName);
+        let overridesModule = _exports[overridesModuleName];
+        if (!overridesModule)
+            return;
+
+        let initFunc = overridesModule._init;
+        if (!initFunc)
+            return;
+
+        initFunc.call(module);
+    }
+
+    function importGIModuleWithOverrides(moduleID, moduleVersion) {
+        let exportedID = 'gi/' + moduleID;
+        if (_exports[exportedID])
+            return _exports[exportedID];
+
+        let module = Importer.importGIModule(moduleID, moduleVersion);
+        _exports[exportedID] = module;
+        _exports[exportedID + '/' + moduleVersion] = module;
+        runOverridesForGIModule(module, moduleID);
+        return module;
+    }
+
+    function loadGIModule(moduleID) {
+        if (!moduleID.startsWith('gi/'))
+            return;
+
+        let giModuleID = moduleID.slice(3);
+
+        let moduleVersion;
+        if (giModuleID.indexOf('/') >= 0)
+            [giModuleID, moduleVersion] = giModuleID.split('/', 2);
+        else
+            moduleVersion = null;
+
+        importGIModuleWithOverrides(giModuleID, moduleVersion);
+    }
+
+})(window, importNativeModule);
diff --git a/modules/importer.cpp b/modules/importer.cpp
new file mode 100644
index 0000000..10b3ed8
--- /dev/null
+++ b/modules/importer.cpp
@@ -0,0 +1,153 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * 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 "importer.h"
+#include <gjs/gjs-module.h>
+#include <gjs/byteArray.h>
+#include "gi/ns.h"
+
+static JSBool
+import_gi_module(JSContext *context,
+                 unsigned   argc,
+                 jsval     *vp)
+{
+    JSBool ret = JS_FALSE;
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    jsval retval = JSVAL_VOID;
+    char *module_name = NULL;
+    char *module_version = NULL;
+    JSObject *module_obj;
+
+    if (!gjs_parse_call_args(context, "importGIModule", "s?s", args,
+                             "moduleName", &module_name,
+                             "moduleVersion", &module_version))
+        goto out;
+
+    if (!gjs_import_gi_module(context, module_name, module_version, &module_obj))
+        goto out;
+
+    ret = JS_TRUE;
+    args.rval().setObject(*module_obj);
+
+ out:
+    g_free(module_name);
+    g_free(module_version);
+    return ret;
+}
+
+static JSBool
+eval_with_scope(JSContext *context,
+                unsigned   argc,
+                jsval     *vp)
+{
+    JSBool ret = JS_FALSE;
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    JSObject *scope;
+    JSObject *script_obj;
+    guint8 *script;
+    gsize script_len;
+    char *filename = NULL;
+    jsval retval;
+
+    if (!gjs_parse_call_args(context, "evalWithScope", "oos", args,
+                             "scope", &scope,
+                             "script", &script_obj,
+                             "filename", &filename))
+        goto out;
+
+    gjs_byte_array_peek_data (context, script_obj, &script, &script_len);
+
+    if (!gjs_eval_with_scope(context, scope, (const char *) script, script_len, filename, &retval))
+        goto out;
+
+    ret = JS_TRUE;
+    args.rval().set(retval);
+
+ out:
+    g_free(filename);
+    return ret;
+}
+
+static JSBool
+get_builtin_search_path(JSContext *context,
+                        unsigned   argc,
+                        jsval     *vp)
+{
+    GjsContext *gjs_context = GJS_CONTEXT(JS_GetContextPrivate(context));
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    const char **context_search_path;
+    int context_search_path_length;
+    const char **global_search_path;
+    int global_search_path_length;
+    GArray *elems;
+    JSObject *search_path_obj;
+    int i;
+
+    context_search_path = gjs_context_get_search_path(gjs_context);
+    context_search_path_length = context_search_path ? g_strv_length((char **) context_search_path) : 0;
+    global_search_path = (const char **) gjs_get_search_path();
+    global_search_path_length = global_search_path ? g_strv_length((char **) global_search_path) : 0;
+
+    elems = g_array_sized_new(FALSE, FALSE, sizeof(jsval),
+                              context_search_path_length + global_search_path_length);
+
+    for (i = 0; i < context_search_path_length; i++) {
+        jsval element = STRING_TO_JSVAL(JS_NewStringCopyZ(context, context_search_path[i]));
+        g_array_append_val(elems, element);
+    }
+
+    for (i = 0; i < global_search_path_length; i++) {
+        jsval element = STRING_TO_JSVAL(JS_NewStringCopyZ(context, global_search_path[i]));
+        g_array_append_val(elems, element);
+    }
+
+    search_path_obj = JS_NewArrayObject(context, elems->len, (jsval *)elems->data);
+    g_array_free(elems, TRUE);
+
+    args.rval().setObject(*search_path_obj);
+    return JS_TRUE;
+}
+
+static JSFunctionSpec module_funcs[] = {
+    { "importGIModule", JSOP_WRAPPER (import_gi_module), 2, GJS_MODULE_PROP_FLAGS },
+    { "evalWithScope", JSOP_WRAPPER (eval_with_scope), 3, GJS_MODULE_PROP_FLAGS },
+    { "getBuiltinSearchPath", JSOP_WRAPPER (get_builtin_search_path), 0, GJS_MODULE_PROP_FLAGS },
+    { NULL },
+};
+
+JSBool
+gjs_js_define_importer_stuff(JSContext  *context,
+                             JSObject  **module_out)
+{
+    JSObject *module;
+
+    module = JS_NewObject(context, NULL, NULL, NULL);
+
+    if (!JS_DefineFunctions(context, module, &module_funcs[0]))
+        return JS_FALSE;
+
+    *module_out = module;
+    return JS_TRUE;
+}
diff --git a/modules/importer.h b/modules/importer.h
new file mode 100644
index 0000000..5fa25b0
--- /dev/null
+++ b/modules/importer.h
@@ -0,0 +1,38 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/*
+ * Copyright 2013 Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef __GJS_MODULE_IMPORTER_H__
+#define __GJS_MODULE_IMPORTER_H__
+
+#include <config.h>
+#include <glib.h>
+#include "gjs/jsapi-util.h"
+
+G_BEGIN_DECLS
+
+JSBool        gjs_js_define_importer_stuff   (JSContext      *context,
+                                              JSObject      **module_out);
+
+G_END_DECLS
+
+#endif  /* __GJS_MODULE_IMPORTER_H__ */
diff --git a/modules/modules.cpp b/modules/modules.cpp
index aae3569..0ccc432 100644
--- a/modules/modules.cpp
+++ b/modules/modules.cpp
@@ -32,6 +32,7 @@
 
 #include "system.h"
 #include "console.h"
+#include "importer.h"
 
 void
 gjs_register_static_modules (void)
@@ -40,5 +41,6 @@ gjs_register_static_modules (void)
     gjs_register_native_module("cairoNative", gjs_js_define_cairo_stuff);
 #endif
     gjs_register_native_module("system", gjs_js_define_system_stuff);
+    gjs_register_native_module("_importer", gjs_js_define_importer_stuff);
     gjs_register_native_module("console", gjs_define_console_stuff);
 }


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