[gjs/wip/imports-rewrite: 5/5] bootstrap: Add a JS implementation of the imports system
- From: Jasper St. Pierre <jstpierre src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gjs/wip/imports-rewrite: 5/5] bootstrap: Add a JS implementation of the imports system
- Date: Wed, 17 Jun 2015 23:56:22 +0000 (UTC)
commit 75b676e8164eb09e3da1a9bd4ceae15c9c1073a1
Author: Jasper St. Pierre <jstpierre mecheye net>
Date: Thu Jan 2 15:59:16 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-modules.am | 7 +-
Makefile.am | 5 +-
gi/repo.cpp | 384 +-------------
gi/repo.h | 3 -
gi/union.cpp | 1 -
gjs/bootstrap.cpp | 42 ++
gjs/context.cpp | 30 +-
gjs/context.h | 2 +
gjs/gi.h | 2 -
gjs/gjs-module.h | 1 -
gjs/importer.cpp | 1118 --------------------------------------
gjs/importer.h | 50 --
gjs/jsapi-util.h | 7 -
modules/bootstrap.js | 143 +++++-
modules/importer.cpp | 153 ++++++
gjs/gi.cpp => modules/importer.h | 25 +-
modules/modules.cpp | 2 +
17 files changed, 377 insertions(+), 1598 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/Makefile.am b/Makefile.am
index 835bb86..5774462 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 \
@@ -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 \
diff --git a/gi/repo.cpp b/gi/repo.cpp
index fd665ed..2b56e75 100644
--- a/gi/repo.cpp
+++ b/gi/repo.cpp
@@ -39,6 +39,7 @@
#include <gjs/compat.h>
#include <gjs/jsapi-private.h>
+#include <gjs/runtime.h>
#include <util/log.h>
#include <util/misc.h>
@@ -46,298 +47,6 @@
#include <girepository.h>
#include <string.h>
-typedef struct {
- void *dummy;
-
-} Repo;
-
-extern struct JSClass gjs_repo_class;
-
-GJS_DEFINE_PRIV_FROM_JS(Repo, gjs_repo_class)
-
-static JSObject * lookup_override_function(JSContext *, jsid);
-
-static JSBool
-get_version_for_ns (JSContext *context,
- JSObject *repo_obj,
- jsid ns_id,
- char **version)
-{
- jsid versions_name;
- jsval versions_val;
- JSObject *versions;
- jsval version_val;
-
- versions_name = gjs_context_get_const_string(context, GJS_STRING_GI_VERSIONS);
- if (!gjs_object_require_property(context, repo_obj, "GI repository object", versions_name,
&versions_val) ||
- !JSVAL_IS_OBJECT(versions_val)) {
- gjs_throw(context, "No 'versions' property in GI repository object");
- return JS_FALSE;
- }
-
- versions = JSVAL_TO_OBJECT(versions_val);
-
- *version = NULL;
- if (JS_GetPropertyById(context, versions, ns_id, &version_val) &&
- JSVAL_IS_STRING(version_val)) {
- gjs_string_to_utf8(context, version_val, version);
- }
-
- return JS_TRUE;
-}
-
-static JSBool
-resolve_namespace_object(JSContext *context,
- JSObject *repo_obj,
- jsid ns_id,
- const char *ns_name)
-{
- char *version = NULL;
- JSObject *override;
- jsval result;
- JSObject *gi_namespace = NULL;
- JSBool ret = JS_FALSE;
-
- JS_BeginRequest(context);
-
- if (!get_version_for_ns(context, repo_obj, ns_id, &version))
- goto out;
-
- /* Defines a property on "obj" (the javascript repo object)
- * with the given namespace name, pointing to that namespace
- * in the repo.
- */
- if (!gjs_import_gi_module(context, ns_name, version, &gi_namespace))
- goto out;
-
- JS_AddObjectRoot(context, &gi_namespace);
-
- /* Define the property early, to avoid reentrancy issues if
- the override module looks for namespaces that import this */
- if (!JS_DefineProperty(context, repo_obj,
- ns_name, OBJECT_TO_JSVAL(gi_namespace),
- NULL, NULL,
- GJS_MODULE_PROP_FLAGS))
- g_error("no memory to define ns property");
-
- override = lookup_override_function(context, ns_id);
- if (override && !JS_CallFunctionValue (context,
- gi_namespace, /* thisp */
- OBJECT_TO_JSVAL(override), /* callee */
- 0, /* argc */
- NULL, /* argv */
- &result))
- goto out;
-
- gjs_debug(GJS_DEBUG_GNAMESPACE,
- "Defined namespace '%s' %p in GIRepository %p", ns_name, gi_namespace, repo_obj);
-
- ret = JS_TRUE;
- gjs_schedule_gc_if_needed(context);
-
- out:
- g_free(version);
- if (gi_namespace)
- JS_RemoveObjectRoot(context, &gi_namespace);
- JS_EndRequest(context);
- return ret;
-}
-
-/*
- * Like JSResolveOp, but flags provide contextual information as follows:
- *
- * JSRESOLVE_QUALIFIED a qualified property id: obj.id or obj[id], not id
- * JSRESOLVE_ASSIGNING obj[id] is on the left-hand side of an assignment
- * JSRESOLVE_DETECTING 'if (o.p)...' or similar detection opcode sequence
- * JSRESOLVE_DECLARING var, const, or function prolog declaration opcode
- * JSRESOLVE_CLASSNAME class name used when constructing
- *
- * The *objp out parameter, on success, should be null to indicate that id
- * was not resolved; and non-null, referring to obj or one of its prototypes,
- * if id was resolved.
- */
-static JSBool
-repo_new_resolve(JSContext *context,
- JS::HandleObject obj,
- JS::HandleId id,
- unsigned flags,
- JS::MutableHandleObject objp)
-{
- Repo *priv;
- char *name;
- JSBool ret = JS_TRUE;
-
- if (!gjs_get_string_id(context, id, &name))
- return JS_TRUE; /* not resolved, but no error */
-
- /* let Object.prototype resolve these */
- if (strcmp(name, "valueOf") == 0 ||
- strcmp(name, "toString") == 0)
- goto out;
-
- priv = priv_from_js(context, obj);
- gjs_debug_jsprop(GJS_DEBUG_GREPO, "Resolve prop '%s' hook obj %p priv %p", name, *obj, priv);
-
- if (priv == NULL) /* we are the prototype, or have the wrong class */
- goto out;
-
- if (!resolve_namespace_object(context, obj, id, name)) {
- ret = JS_FALSE;
- } else {
- objp.set(obj); /* store the object we defined the prop in */
- }
-
- out:
- g_free(name);
- return ret;
-}
-
-GJS_NATIVE_CONSTRUCTOR_DEFINE_ABSTRACT(repo)
-
-static void
-repo_finalize(JSFreeOp *fop,
- JSObject *obj)
-{
- Repo *priv;
-
- priv = (Repo*) JS_GetPrivate(obj);
- gjs_debug_lifecycle(GJS_DEBUG_GREPO,
- "finalize, obj %p priv %p", obj, priv);
- if (priv == NULL)
- return; /* we are the prototype, not a real instance */
-
- GJS_DEC_COUNTER(repo);
- g_slice_free(Repo, priv);
-}
-
-/* The bizarre thing about this vtable is that it applies to both
- * instances of the object, and to the prototype that instances of the
- * class have.
- */
-struct JSClass gjs_repo_class = {
- "GIRepository", /* means "new GIRepository()" works */
- JSCLASS_HAS_PRIVATE |
- JSCLASS_NEW_RESOLVE,
- JS_PropertyStub,
- JS_DeletePropertyStub,
- JS_PropertyStub,
- JS_StrictPropertyStub,
- JS_EnumerateStub,
- (JSResolveOp) repo_new_resolve, /* needs cast since it's the new resolve signature */
- JS_ConvertStub,
- repo_finalize,
- JSCLASS_NO_OPTIONAL_MEMBERS
-};
-
-JSPropertySpec gjs_repo_proto_props[] = {
- { NULL }
-};
-
-JSFunctionSpec gjs_repo_proto_funcs[] = {
- { NULL }
-};
-
-static JSObject*
-repo_new(JSContext *context)
-{
- Repo *priv;
- JSObject *repo;
- JSObject *global;
- JSObject *versions;
- JSObject *private_ns;
- JSBool found;
- jsid versions_name, private_ns_name;
-
- global = gjs_get_import_global(context);
-
- if (!JS_HasProperty(context, global, gjs_repo_class.name, &found))
- return NULL;
- if (!found) {
- JSObject *prototype;
- prototype = JS_InitClass(context, global,
- /* parent prototype JSObject* for
- * prototype; NULL for
- * Object.prototype
- */
- NULL,
- &gjs_repo_class,
- /* constructor for instances (NULL for
- * none - just name the prototype like
- * Math - rarely correct)
- */
- gjs_repo_constructor,
- /* number of constructor args */
- 0,
- /* props of prototype */
- &gjs_repo_proto_props[0],
- /* funcs of prototype */
- &gjs_repo_proto_funcs[0],
- /* props of constructor, MyConstructor.myprop */
- NULL,
- /* funcs of constructor, MyConstructor.myfunc() */
- NULL);
- if (prototype == NULL)
- g_error("Can't init class %s", gjs_repo_class.name);
-
- gjs_debug(GJS_DEBUG_GREPO, "Initialized class %s prototype %p",
- gjs_repo_class.name, prototype);
- }
-
- repo = JS_NewObject(context, &gjs_repo_class, NULL, global);
- if (repo == NULL) {
- gjs_throw(context, "No memory to create repo object");
- return NULL;
- }
-
- priv = g_slice_new0(Repo);
-
- GJS_INC_COUNTER(repo);
-
- g_assert(priv_from_js(context, repo) == NULL);
- JS_SetPrivate(repo, priv);
-
- gjs_debug_lifecycle(GJS_DEBUG_GREPO,
- "repo constructor, obj %p priv %p", repo, priv);
-
- versions = JS_NewObject(context, NULL, NULL, global);
- versions_name = gjs_context_get_const_string(context, GJS_STRING_GI_VERSIONS);
- JS_DefinePropertyById(context, repo,
- versions_name,
- OBJECT_TO_JSVAL(versions),
- NULL, NULL,
- JSPROP_PERMANENT);
-
- private_ns = JS_NewObject(context, NULL, NULL, global);
- private_ns_name = gjs_context_get_const_string(context, GJS_STRING_PRIVATE_NS_MARKER);
- JS_DefinePropertyById(context, repo,
- private_ns_name,
- OBJECT_TO_JSVAL(private_ns),
- NULL, NULL, JSPROP_PERMANENT);
-
- /* FIXME - hack to make namespaces load, since
- * gobject-introspection does not yet search a path properly.
- */
- {
- jsval value;
- JS_GetProperty(context, repo, "GLib", &value);
- }
-
- return repo;
-}
-
-JSBool
-gjs_define_repo(JSContext *context,
- JSObject **module_out,
- const char *name)
-{
- JSObject *repo;
-
- repo = repo_new(context);
- *module_out = repo;
-
- return JS_TRUE;
-}
-
static JSBool
gjs_define_constant(JSContext *context,
JSObject *in_object,
@@ -533,7 +242,6 @@ 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);
}
@@ -559,95 +267,29 @@ gjs_lookup_namespace_object(JSContext *context,
return gjs_lookup_namespace_object_by_name(context, ns_name);
}
-static JSObject*
-lookup_override_function(JSContext *context,
- jsid ns_name)
-{
- jsval importer;
- jsval overridespkg;
- jsval module;
- jsval function;
- jsid overrides_name, object_init_name;
-
- JS_BeginRequest(context);
-
- importer = gjs_get_global_slot(context, GJS_GLOBAL_SLOT_IMPORTS);
- g_assert(JSVAL_IS_OBJECT(importer));
-
- overridespkg = JSVAL_VOID;
- overrides_name = gjs_context_get_const_string(context, GJS_STRING_GI_OVERRIDES);
- if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(importer), "importer",
- overrides_name, &overridespkg) ||
- !JSVAL_IS_OBJECT(overridespkg))
- goto fail;
-
- module = JSVAL_VOID;
- if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(overridespkg), "GI repository object",
ns_name, &module)
- || !JSVAL_IS_OBJECT(module))
- goto fail;
-
- object_init_name = gjs_context_get_const_string(context, GJS_STRING_GOBJECT_INIT);
- if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(module), "override module",
- object_init_name, &function) ||
- !JSVAL_IS_OBJECT(function))
- goto fail;
-
- JS_EndRequest(context);
- return JSVAL_TO_OBJECT(function);
-
- fail:
- JS_ClearPendingException(context);
- JS_EndRequest(context);
- return NULL;
-}
-
JSObject*
gjs_lookup_namespace_object_by_name(JSContext *context,
jsid ns_name)
{
- JSObject *repo_obj;
- jsval importer;
- jsval girepository;
- jsval ns_obj;
- jsid gi_name;
+ char *name;
+ char *script;
+ jsval ns_val;
+ JSObject *ns_obj = NULL;
JS_BeginRequest(context);
- importer = gjs_get_global_slot(context, GJS_GLOBAL_SLOT_IMPORTS);
- g_assert(JSVAL_IS_OBJECT(importer));
-
- girepository = JSVAL_VOID;
- gi_name = gjs_context_get_const_string(context, GJS_STRING_GI_MODULE);
- if (!gjs_object_require_property(context, JSVAL_TO_OBJECT(importer), "importer",
- gi_name, &girepository) ||
- !JSVAL_IS_OBJECT(girepository)) {
- gjs_log_exception(context);
- gjs_throw(context, "No gi property in importer");
- goto fail;
- }
-
- repo_obj = JSVAL_TO_OBJECT(girepository);
-
- if (!gjs_object_require_property(context, repo_obj, "GI repository object", ns_name, &ns_obj)) {
- goto fail;
- }
-
- if (!JSVAL_IS_OBJECT(ns_obj)) {
- char *name;
-
- gjs_get_string_id(context, ns_name, &name);
- gjs_throw(context, "Namespace '%s' is not an object?", name);
+ if (!gjs_get_string_id(context, ns_name, &name))
+ goto out;
- g_free(name);
- goto fail;
- }
+ script = g_strdup_printf("imports.gi.%s;", name);
+ if (!gjs_eval_with_scope(context, NULL, script, -1, "<internal>", &ns_val))
+ goto out;
- JS_EndRequest(context);
- return JSVAL_TO_OBJECT(ns_obj);
+ ns_obj = JSVAL_TO_OBJECT(ns_val);
- fail:
+ out:
JS_EndRequest(context);
- return NULL;
+ return ns_obj;
}
const char*
diff --git a/gi/repo.h b/gi/repo.h
index ba1fd90..c2b277e 100644
--- a/gi/repo.h
+++ b/gi/repo.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/gi/union.cpp b/gi/union.cpp
index 23ca458..1a28bff 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"
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/context.cpp b/gjs/context.cpp
index d1bd77c..20d12df 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,10 +77,8 @@ struct _GjsContext {
/* Keep this consistent with GjsConstString */
static const char *const_strings[] = {
"constructor", "prototype", "length",
- "imports", "__parentModule__", "__init__", "searchPath",
"__gjsKeepAlive", "__gjsPrivateNS",
- "gi", "versions", "overrides",
- "_init", "_instance_init", "_new_internal", "new",
+ "gi", "_init", "_instance_init", "_new_internal", "new",
"message", "code", "stack", "fileName", "lineNumber", "name",
"x", "y", "width", "height",
};
@@ -321,7 +318,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 +439,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");
@@ -793,6 +771,12 @@ gjs_get_import_global(JSContext *context)
return gjs_context->global;
}
+const char **
+gjs_context_get_search_path(GjsContext *context)
+{
+ return (const char **) context->search_path;
+}
+
G_CONST_RETURN char * G_CONST_RETURN *
gjs_get_search_path(void)
{
diff --git a/gjs/context.h b/gjs/context.h
index 175ccca..54969a0 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_CONST_RETURN char * G_CONST_RETURN * gjs_get_search_path (void);
G_END_DECLS
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..35ba939 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,15 +406,9 @@ 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,
GJS_STRING_KEEP_ALIVE_MARKER,
GJS_STRING_PRIVATE_NS_MARKER,
GJS_STRING_GI_MODULE,
- GJS_STRING_GI_VERSIONS,
- GJS_STRING_GI_OVERRIDES,
GJS_STRING_GOBJECT_INIT,
GJS_STRING_INSTANCE_INIT,
GJS_STRING_NEW_INTERNAL,
diff --git a/modules/bootstrap.js b/modules/bootstrap.js
index 45ab533..7e27a5f 100644
--- a/modules/bootstrap.js
+++ b/modules/bootstrap.js
@@ -1,6 +1,143 @@
-(function(exports) {
+(function(exports, importNativeModule) {
"use strict";
- // Do early initialization here.
+ const Importer = importNativeModule('_importer');
+ const Gio = Importer.importGIModule('Gio', '2.0');
-})(window);
+ function runOverridesForGIModule(module, moduleID) {
+ let overridesModule = imports.overrides[moduleID];
+ if (!overridesModule)
+ return;
+
+ let initFunc = overridesModule._init;
+ if (!initFunc)
+ return;
+
+ initFunc.call(module);
+ }
+
+ function importGIModuleWithOverrides(parent, moduleID, moduleVersion) {
+ let module = Importer.importGIModule(moduleID, moduleVersion);
+ parent[moduleID] = module;
+ runOverridesForGIModule(module, moduleID);
+ }
+
+ function installImports() {
+ // Implement the global "imports" object.
+
+ // imports.gi
+ let gi = new Proxy({
+ versions: {},
+ __gjsPrivateNS: {},
+ }, {
+ get: function(target, name) {
+ if (!target[name]) {
+ let version = target.versions[name] || null;
+ importGIModuleWithOverrides(target, name, version);
+ }
+
+ return target[name];
+ },
+ });
+
+ 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])
+ target[name] = importNativeModule(name);
+ if (!target[name])
+ target[name] = rootDirectoryImporter[name];
+ return target[name];
+ },
+ });
+ rootImporter.gi = gi;
+
+ exports.imports = rootImporter;
+ }
+ installImports();
+
+})(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/gjs/gi.cpp b/modules/importer.h
similarity index 75%
rename from gjs/gi.cpp
rename to modules/importer.h
index 6ff4847..5fa25b0 100644
--- a/gjs/gi.cpp
+++ b/modules/importer.h
@@ -1,6 +1,6 @@
/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
- * Copyright (c) 2008 litl, LLC
+ * 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
@@ -21,19 +21,18 @@
* IN THE SOFTWARE.
*/
-#include "gi.h"
+#ifndef __GJS_MODULE_IMPORTER_H__
+#define __GJS_MODULE_IMPORTER_H__
-#include <util/misc.h>
+#include <config.h>
+#include <glib.h>
+#include "gjs/jsapi-util.h"
-#include <string.h>
+G_BEGIN_DECLS
-#include "gjs/native.h"
-#include "gjs/compat.h"
-#include "gi/repo.h"
+JSBool gjs_js_define_importer_stuff (JSContext *context,
+ JSObject **module_out);
-JSBool
-gjs_define_gi_stuff(JSContext *context,
- JSObject **module_out)
-{
- return gjs_define_repo(context, module_out, "gi");
-}
+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]