diff options
author | Garrett Regier <garrettregier@gmail.com> | 2015-01-19 00:33:05 -0800 |
---|---|---|
committer | Garrett Regier <garrettregier@gmail.com> | 2015-02-14 12:23:40 -0800 |
commit | d2bed913817ef7bd9e018b3f63a36369aac74b9f (patch) | |
tree | 847af268760ad9ec412758f38c9d9bbc71c0b279 /loaders | |
parent | 2be61ccc64ed40c4bca3208de43d4c13d5c5e36d (diff) | |
download | libpeas-d2bed913817ef7bd9e018b3f63a36369aac74b9f.tar.gz |
Use Lua to implement the plugin loader's logic
This allows us to avoid using Lua's C API and have a
more understandable implementation.
https://bugzilla.gnome.org/show_bug.cgi?id=742410
Diffstat (limited to 'loaders')
-rw-r--r-- | loaders/lua5.1/Makefile.am | 21 | ||||
-rw-r--r-- | loaders/lua5.1/peas-lua-compile.lua | 60 | ||||
-rw-r--r-- | loaders/lua5.1/peas-lua-internal.c | 202 | ||||
-rw-r--r-- | loaders/lua5.1/peas-lua-internal.h | 40 | ||||
-rw-r--r-- | loaders/lua5.1/peas-lua-internal.lua | 162 | ||||
-rw-r--r-- | loaders/lua5.1/peas-lua-utils.c | 57 | ||||
-rw-r--r-- | loaders/lua5.1/peas-lua-utils.h | 6 | ||||
-rw-r--r-- | loaders/lua5.1/peas-lua.gresource.xml | 6 | ||||
-rw-r--r-- | loaders/lua5.1/peas-plugin-loader-lua.c | 297 |
9 files changed, 607 insertions, 244 deletions
diff --git a/loaders/lua5.1/Makefile.am b/loaders/lua5.1/Makefile.am index 6a71650..6be90ea 100644 --- a/loaders/lua5.1/Makefile.am +++ b/loaders/lua5.1/Makefile.am @@ -13,6 +13,9 @@ AM_CPPFLAGS = \ loader_LTLIBRARIES = liblua51loader.la liblua51loader_la_SOURCES = \ + peas-lua-internal.c \ + peas-lua-internal.h \ + peas-lua-resources.c \ peas-plugin-loader-lua.c \ peas-plugin-loader-lua.h \ peas-lua-utils.c \ @@ -27,5 +30,23 @@ liblua51loader_la_LIBADD = \ $(PEAS_LIBS) \ $(LUA51_LIBS) +%.luac: %.lua + $(AM_V_GEN) $(LUA51_BIN) $(srcdir)/peas-lua-compile.lua $< $@ + +all-local: peas-lua-internal.luac + +loader_resources_deps = $(shell $(GLIB_COMPILE_RESOURCES) --sourcedir=$(srcdir) --generate-dependencies $(srcdir)/peas-lua.gresource.xml) +peas-lua-resources.c: $(srcdir)/peas-lua.gresource.xml $(loader_resources_deps) + $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --internal --target=$@ --sourcedir=$(srcdir) --generate-source $(srcdir)/peas-lua.gresource.xml + +EXTRA_DIST = \ + peas-lua-compile.lua \ + peas-lua.gresource.xml \ + $(loader_resources_deps) + +CLEANFILES = \ + peas-lua-internal.luac \ + peas-lua-resources.c + gcov_sources = $(liblua51loader_la_SOURCES) include $(top_srcdir)/Makefile.gcov diff --git a/loaders/lua5.1/peas-lua-compile.lua b/loaders/lua5.1/peas-lua-compile.lua new file mode 100644 index 0000000..bdad8cb --- /dev/null +++ b/loaders/lua5.1/peas-lua-compile.lua @@ -0,0 +1,60 @@ +-- +-- Copyright (C) 2015 - Garrett Regier +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU Library General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Library General Public License for more details. +-- +-- You should have received a copy of the GNU Library General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, +-- Boston, MA 02110-1301, USA. + +local io = require 'io' +local os = require 'os' + + +local function check(err, format, ...) + if err == nil then + return + end + + io.stderr:write(('Error: %s:\n%s\n'):format(format:format(...), err)) + os.exit(1) +end + + +local function main(arg) + for i = 1, #arg, 2 do + local filename = arg[i] + local output = arg[i + 1] + + local input_file, err = io.open(filename, 'rb') + check(err, 'Failed to open file "%s"', filename) + + -- Error includes the filename + local compiled, err = loadstring(input_file:read('*a'), + '@' .. filename) + check(err, 'Invalid Lua file') + + local f, err = io.open(output, 'wb') + check(err, 'Failed to open file "%s"', output) + + local success, err = f:write(string.dump(compiled)) + check(err, 'Failed to write to "%s"', output) + + local success, err = f:close() + check(err, 'Failed to save "%s"', output) + end +end + + +os.exit(main(arg) or 0) + +-- ex:ts=4:et: diff --git a/loaders/lua5.1/peas-lua-internal.c b/loaders/lua5.1/peas-lua-internal.c new file mode 100644 index 0000000..23d2d6b --- /dev/null +++ b/loaders/lua5.1/peas-lua-internal.c @@ -0,0 +1,202 @@ +/* + * peas-lua-internal.c + * This file is part of libpeas + * + * Copyright (C) 2015 - Garrett Regier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "peas-lua-internal.h" + +#include <gio/gio.h> + +#include <lauxlib.h> +#include <lualib.h> + +#include "peas-lua-utils.h" + + +static gpointer hooks_key = NULL; +static gpointer failed_err_key = NULL; + + +static int +failed_fn (lua_State *L) +{ + gchar *msg; + + /* The first parameter is the Hooks table instance */ + luaL_checktype (L, 1, LUA_TTABLE); + + /* The tracebacks have a trailing newline */ + msg = g_strchomp (g_strdup (luaL_checkstring (L, 2))); + + g_warning ("%s", msg); + + /* peas_lua_internal_call() knows to check for this value */ + lua_pushlightuserdata (L, &failed_err_key); + + g_free (msg); + return lua_error (L); +} + +gboolean +peas_lua_internal_setup (lua_State *L) +{ + GBytes *internal_lua; + const gchar *code; + gsize code_len; + + /* We don't use the byte-compiled Lua source + * because glib-compile-resources cannot output + * depends for generated files. + * + * There are also concerns that the bytecode is + * not stable enough between different Lua versions. + * + * https://bugzilla.gnome.org/show_bug.cgi?id=673101 + */ + internal_lua = g_resources_lookup_data ("/org/gnome/libpeas/loaders/" + "lua5.1/internal.lua", + G_RESOURCE_LOOKUP_FLAGS_NONE, + NULL); + g_return_val_if_fail (internal_lua != NULL, FALSE); + + code = g_bytes_get_data (internal_lua, &code_len); + + /* Filenames are prefixed with '@' */ + if (luaL_loadbuffer (L, code, code_len, "@peas-lua-internal.lua") != 0) + { + g_warning ("Failed to load internal Lua code: %s", + lua_tostring (L, -1)); + + /* Pop error */ + lua_pop (L, 1); + g_bytes_unref (internal_lua); + return FALSE; + } + + g_bytes_unref (internal_lua); + + if (!peas_lua_utils_call (L, 0, 1)) + { + g_warning ("Failed to run internal Lua code: %s", + lua_tostring (L, -1)); + + /* Pop error */ + lua_pop (L, 1); + return FALSE; + } + + if (!lua_istable (L, -1)) + { + g_warning ("Invalid result from internal Lua code: %s", + lua_tostring (L, -1)); + + /* Pop result */ + lua_pop (L, 1); + return FALSE; + } + + /* Set Hooks.failed to failed_fn */ + lua_pushcfunction (L, failed_fn); + lua_setfield (L, -2, "failed"); + + /* Set registry[&hooks_key] = hooks */ + lua_pushlightuserdata (L, &hooks_key); + lua_pushvalue (L, -2); + lua_rawset (L, LUA_REGISTRYINDEX); + + /* Pop hooks */ + lua_pop (L, -1); + return TRUE; +} + +void +peas_lua_internal_shutdown (lua_State *L) +{ + lua_pushlightuserdata (L, &hooks_key); + lua_pushnil (L); + lua_rawset (L, LUA_REGISTRYINDEX); +} + +gboolean +peas_lua_internal_call (lua_State *L, + const gchar *name, + guint n_args, + gint return_type) +{ + /* Get the Hooks table */ + lua_pushlightuserdata (L, &hooks_key); + lua_rawget (L, LUA_REGISTRYINDEX); + + /* Get the method */ + lua_getfield (L, -1, name); + + /* Swap the method and the table */ + lua_insert (L, -2); + + if (n_args > 0) + { + /* Before: [args..., method, table] + * After: [method, table, args...] + */ + lua_insert (L, -n_args - 2); + lua_insert (L, -n_args - 2); + } + + if (!peas_lua_utils_call (L, 1 + n_args, 1)) + { + /* Raised by failed_fn() to prevent printing the error */ + if (!lua_isuserdata (L, -1) || + lua_touserdata (L, -1) != &failed_err_key) + { + g_warning ("Failed to run internal Lua hook '%s':\n%s", + name, lua_tostring (L, -1)); + } + + /* Pop the error */ + lua_pop (L, 1); + return FALSE; + } + + if (lua_type (L, -1) != return_type) + { + /* Don't warn for a nil result */ + if (lua_type (L, -1) != LUA_TNIL) + { + g_warning ("Invalid return value for internal Lua hook '%s': " + "expected %s, got: %s (%s)", name, + lua_typename (L, return_type), + lua_typename (L, lua_type (L, -1)), + lua_tostring (L, -1)); + } + + /* Pop result */ + lua_pop (L, 1); + return FALSE; + } + + /* Pop the result if nil */ + if (return_type == LUA_TNIL) + lua_pop (L, 1); + + return TRUE; +} diff --git a/loaders/lua5.1/peas-lua-internal.h b/loaders/lua5.1/peas-lua-internal.h new file mode 100644 index 0000000..d605856 --- /dev/null +++ b/loaders/lua5.1/peas-lua-internal.h @@ -0,0 +1,40 @@ +/* + * peas-lua-internal.h + * This file is part of libpeas + * + * Copyright (C) 2015 - Garrett Regier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __PEAS_LUA_INTERNAL_H__ +#define __PEAS_LUA_INTERNAL_H__ + +#include <glib.h> +#include <lua.h> + +G_BEGIN_DECLS + +gboolean peas_lua_internal_setup (lua_State *L); +void peas_lua_internal_shutdown (lua_State *L); + +gboolean peas_lua_internal_call (lua_State *L, + const gchar *name, + guint n_args, + gint return_type); + +G_END_DECLS + +#endif /* __PEAS_LUA_INTERNAL_H__ */ diff --git a/loaders/lua5.1/peas-lua-internal.lua b/loaders/lua5.1/peas-lua-internal.lua new file mode 100644 index 0000000..8f4e60d --- /dev/null +++ b/loaders/lua5.1/peas-lua-internal.lua @@ -0,0 +1,162 @@ +-- +-- Copyright (C) 2015 - Garrett Regier +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU Library General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU Library General Public License for more details. +-- +-- You should have received a copy of the GNU Library General Public License +-- along with this program; if not, write to the Free Software +-- Foundation, Inc., 51 Franklin Street, Fifth Floor, +-- Boston, MA 02110-1301, USA. + +local debug = require 'debug' +local package = require 'package' + +local lgi = require 'lgi' +local GObject = lgi.GObject +local Peas = lgi.Peas + + +local Hooks = {} +Hooks.__index = Hooks + +function Hooks.new() + local self = { priv = {} } + setmetatable(self, Hooks) + + self.priv.module_cache = {} + self.priv.extension_cache = {} + return self +end + +function Hooks:failed(msg) + -- This is implemented by the plugin loader + error('Hooks:failed() was not implemented!') +end + +local function add_package_path(package_path) + local paths = (';%s/?.lua;%s/?/init.lua'):format(package_path, + package_path) + + if not package.path:find(paths, 1, true) then + package.path = package.path .. paths + end +end + +local function format_plugin_exception(err) + -- Format the error even if given a userdata + local formatted = debug.traceback(tostring(err), 2) + + if type(formatted) ~= 'string' then + return formatted + end + + -- Remove all mentions of this file + local lines = {} + for line in formatted:gmatch('([^\n]+\n?)') do + if line:find('peas-lua-internal.lua', 1, true) then + break + end + + table.insert(lines, line) + end + + return table.concat(lines, '') +end + +function Hooks:load(filename, module_dir, module_name) + local module = self.priv.module_cache[filename] + + if module ~= nil then + return module ~= false + end + + if package.loaded[module_name] ~= nil then + local msg = ("Error loading plugin '%s': " .. + "module name '%s' has already been used") + self:failed(msg:format(filename, module_name)) + end + + add_package_path(module_dir) + + local success, result = xpcall(function() + return require(module_name) + end, format_plugin_exception) + + if not success then + local msg = "Error loading plugin '%s':\n%s" + self:failed(msg:format(module_name, tostring(result))) + end + + if type(result) ~= 'table' then + self.priv.module_cache[filename] = false + + local msg = "Error loading plugin '%s': expected table, got: %s (%s)" + self:failed(msg:format(module_name, type(result), tostring(result))) + end + + self.priv.module_cache[filename] = result + self.priv.extension_cache[filename] = {} + return true +end + +function Hooks:find_extension_type(filename, gtype) + local module_gtypes = self.priv.extension_cache[filename] + local extension_type = module_gtypes[gtype] + + if extension_type ~= nil then + if extension_type == false then + return nil + end + + return extension_type + end + + for _, value in pairs(self.priv.module_cache[filename]) do + local value_gtype = value._gtype + + if value_gtype ~= nil then + if GObject.type_is_a(value_gtype, gtype) then + module_gtypes[gtype] = value_gtype + return value_gtype + end + end + end + + module_gtypes[gtype] = false + return nil +end + +local function check_native(native, wrapped, typename) + local msg = ('Invalid wrapper for %s: %s'):format(typename, + tostring(wrapped)) + + -- Cannot compare userdata directly! + assert(wrapped ~= nil, msg) + assert(tostring(native) == tostring(wrapped._native), msg) +end + +function Hooks:setup_extension(exten, info) + local wrapped_exten = GObject.Object(exten, false) + check_native(exten, wrapped_exten, 'extension') + + local wrapped_info = Peas.PluginInfo(info, false) + check_native(info, wrapped_info, 'PeasPluginInfo') + + wrapped_exten.priv.plugin_info = wrapped_info +end + +function Hooks:garbage_collect() + collectgarbage() +end + +return Hooks.new() + +-- ex:set ts=4 et sw=4 ai: diff --git a/loaders/lua5.1/peas-lua-utils.c b/loaders/lua5.1/peas-lua-utils.c index 4fc6ce9..76f7a9c 100644 --- a/loaders/lua5.1/peas-lua-utils.c +++ b/loaders/lua5.1/peas-lua-utils.c @@ -2,7 +2,7 @@ * peas-lua-utils.c * This file is part of libpeas * - * Copyright (C) 2014 - Garrett Regier + * Copyright (C) 2014-2015 - Garrett Regier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published by @@ -120,3 +120,58 @@ error: g_strfreev (version_str_parts); return success; } + +static gint +traceback (lua_State *L) +{ + /* Always ignore an error that isn't a string */ + if (!lua_isstring (L, 1)) + return 1; + + lua_getglobal (L, "debug"); + if (!lua_istable (L, -1)) + { + lua_pop (L, 1); + return 1; + } + + lua_getfield (L, -1, "traceback"); + if (!lua_isfunction (L, -1)) + { + lua_pop (L, 2); + return 1; + } + + /* Replace debug with traceback */ + lua_replace (L, -2); + + /* Push the error */ + lua_pushvalue (L, 1); + + /* Skip this function when generating the traceback */ + lua_pushinteger (L, 2); + + /* If we fail we have a new error object... */ + lua_pcall (L, 2, 1, 0); + return 1; +} + +gboolean +peas_lua_utils_call (lua_State *L, + guint n_args, + guint n_results) +{ + gboolean success; + + /* Push the error function */ + lua_pushcfunction (L, traceback); + + /* Move traceback to before the arguments */ + lua_insert (L, -2 - n_args); + + success = lua_pcall (L, n_args, n_results, -2 - n_args) == 0; + + /* Remove traceback */ + lua_remove (L, -1 - (success ? n_results : 1)); + return success; +} diff --git a/loaders/lua5.1/peas-lua-utils.h b/loaders/lua5.1/peas-lua-utils.h index 03fb792..29069be 100644 --- a/loaders/lua5.1/peas-lua-utils.h +++ b/loaders/lua5.1/peas-lua-utils.h @@ -2,7 +2,7 @@ * peas-lua-utils.h * This file is part of libpeas * - * Copyright (C) 2014 - Garrett Regier + * Copyright (C) 2014-2015 - Garrett Regier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published by @@ -36,6 +36,10 @@ gboolean peas_lua_utils_check_version (lua_State *L, guint req_minor, guint req_micro); +gboolean peas_lua_utils_call (lua_State *L, + guint n_args, + guint n_results); + G_END_DECLS #endif /* __PEAS_LUA_UTILS_H__ */ diff --git a/loaders/lua5.1/peas-lua.gresource.xml b/loaders/lua5.1/peas-lua.gresource.xml new file mode 100644 index 0000000..2eaf9cb --- /dev/null +++ b/loaders/lua5.1/peas-lua.gresource.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/gnome/libpeas/loaders/lua5.1"> + <file alias="internal.lua">peas-lua-internal.lua</file> + </gresource> +</gresources> diff --git a/loaders/lua5.1/peas-plugin-loader-lua.c b/loaders/lua5.1/peas-plugin-loader-lua.c index d477ecb..32c6418 100644 --- a/loaders/lua5.1/peas-plugin-loader-lua.c +++ b/loaders/lua5.1/peas-plugin-loader-lua.c @@ -2,7 +2,7 @@ * peas-plugin-loader-lua.c * This file is part of libpeas * - * Copyright (C) 2014 - Garrett Regier + * Copyright (C) 2014-2015 - Garrett Regier * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published by @@ -32,6 +32,7 @@ #include <lauxlib.h> #include <lualib.h> +#include "peas-lua-internal.h" #include "peas-lua-utils.h" @@ -64,173 +65,6 @@ peas_register_types (PeasObjectModule *module) PEAS_TYPE_PLUGIN_LOADER_LUA); } -static gboolean -_lua_add_package_path (lua_State *L, - const gchar *package_path) -{ - luaL_checkstack (L, 3, ""); - - lua_getglobal (L, "package"); - lua_getfield (L, -1, "path"); - - if (!lua_isstring (L, -1)) - { - g_warning ("Invalid Lua package.path: %s", lua_tostring (L, -1)); - - /* Pop path and package */ - lua_pop (L, 2); - return FALSE; - } - - /* ";package_path/?.lua;package_path/?/init.lua" */ - lua_pushliteral (L, ";"); - lua_pushstring (L, package_path); - lua_pushliteral (L, G_DIR_SEPARATOR_S "?.lua;"); - lua_pushstring (L, package_path); - lua_pushliteral (L, G_DIR_SEPARATOR_S "?" G_DIR_SEPARATOR_S "init.lua"); - lua_concat (L, 5); - - if (strstr (lua_tostring (L, -2), lua_tostring (L, -1)) != NULL) - { - /* Pop new path and path */ - lua_pop (L, 2); - } - else - { - /* Update package.path */ - lua_concat (L, 2); - lua_setfield (L, -2, "path"); - } - - /* Pop package */ - lua_pop (L, 1); - return TRUE; -} - -static gboolean -_lua_has_package (lua_State *L, - const gchar *package_name) -{ - gboolean has_package; - - luaL_checkstack (L, 3, ""); - - lua_getglobal (L, "package"); - lua_getfield (L, -1, "loaded"); - lua_getfield (L, -1, package_name); - - has_package = !lua_isnil (L, -1); - - /* Pop package, loaded and package's table */ - lua_pop (L, 3); - return has_package; -} - -static gboolean -_lua_pushinstance (lua_State *L, - const gchar *namespace_, - const gchar *name, - GType gtype, - gpointer instance) -{ - luaL_checkstack (L, 3, ""); - - if (!peas_lua_utils_require (L, "lgi")) - return FALSE; - - lua_getfield (L, -1, namespace_); - lua_getfield (L, -1, name); - - /* Remove the namespace and lgi's module table */ - lua_replace (L, -2); - lua_replace (L, -2); - - lua_pushlightuserdata (L, instance); - lua_pushboolean (L, FALSE); - - /* new(addr[, already_own[, no_sink]]) */ - if (lua_pcall (L, 2, 1, 0) != 0) - { - g_warning ("Failed to create Lua object of type '%s': %s", - g_type_name (gtype), lua_tostring (L, -1)); - - /* Pop the error */ - lua_pop (L, 1); - return FALSE; - } - - /* Check that the Lua object was created correctly */ - lua_getfield (L, -1, "_native"); - g_assert (lua_islightuserdata (L, -1)); - g_assert (lua_touserdata (L, -1) == instance); - lua_pop (L, 1); - - return TRUE; -} - -static GType -_lua_get_gtype (lua_State *L, - int index) -{ - GType gtype = G_TYPE_INVALID; - - luaL_checkstack (L, 1, ""); - - lua_getfield (L, index, "_gtype"); - - if (lua_type (L, -1) == LUA_TLIGHTUSERDATA) - gtype = (GType) lua_touserdata (L, -1); - - /* Pop _gtype */ - lua_pop (L, 1); - return gtype; -} - -static GType -_lua_find_extension_type (lua_State *L, - PeasPluginInfo *info, - GType exten_type) -{ - GType found_type = G_TYPE_INVALID; - - luaL_checkstack (L, 3, ""); - - /* Get the module's table */ - lua_pushstring (L, info->filename); - lua_rawget (L, LUA_REGISTRYINDEX); - - /* Must always have a valid key */ - lua_pushnil (L); - while (lua_next (L, -2) != 0) - { - if (lua_istable (L, -1)) - { - found_type = _lua_get_gtype (L, -1); - - if (found_type != G_TYPE_INVALID) - { - if (!g_type_is_a (found_type, exten_type)) - { - found_type = G_TYPE_INVALID; - } - else - { - /* Pop value and key */ - lua_pop (L, 2); - break; - } - } - } - - /* Pop the value but keep the key for the next iteration */ - lua_pop (L, 1); - } - - /* Pop the module's table */ - lua_pop (L, 1); - return found_type; -} - static lua_State * thread_enter (PeasPluginLoaderLua *lua_loader, PeasPluginInfo *info) @@ -277,6 +111,33 @@ thread_leave (PeasPluginLoaderLua *lua_loader, priv->lgi_leave_func (priv->lgi_lock); } +static GType +find_lua_extension_type (lua_State *L, + PeasPluginInfo *info, + GType exten_type) +{ + luaL_checkstack (L, 2, ""); + lua_pushstring (L, info->filename); + lua_pushlightuserdata (L, GSIZE_TO_POINTER (exten_type)); + + if (peas_lua_internal_call (L, "find_extension_type", + 2, LUA_TLIGHTUSERDATA)) + { + GType extension_type; + + extension_type = (GType) lua_touserdata (L, -1); + lua_pop (L, 1); + + if (g_type_is_a (extension_type, exten_type)) + return extension_type; + + g_warning ("Found invalid extension type '%s' for '%s'", + g_type_name (extension_type), g_type_name (exten_type)); + } + + return G_TYPE_INVALID; +} + static gboolean peas_plugin_loader_lua_provides_extension (PeasPluginLoader *loader, PeasPluginInfo *info, @@ -284,14 +145,14 @@ peas_plugin_loader_lua_provides_extension (PeasPluginLoader *loader, { PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader); lua_State *L; - GType extension_type; + GType the_type; L = thread_enter (lua_loader, info); - extension_type = _lua_find_extension_type (L, info, exten_type); + the_type = find_lua_extension_type (L, info, exten_type); thread_leave (lua_loader, info, &L); - return extension_type != G_TYPE_INVALID; + return the_type != G_TYPE_INVALID; } static PeasExtension * @@ -308,16 +169,10 @@ peas_plugin_loader_lua_create_extension (PeasPluginLoader *loader, L = thread_enter (lua_loader, info); - the_type = _lua_find_extension_type (L, info, exten_type); + the_type = find_lua_extension_type (L, info, exten_type); if (the_type == G_TYPE_INVALID) goto out; - if (!g_type_is_a (the_type, exten_type)) - { - g_warn_if_fail (g_type_is_a (the_type, exten_type)); - goto out; - } - object = g_object_newv (the_type, n_parameters, parameters); if (object == NULL) goto out; @@ -328,29 +183,12 @@ peas_plugin_loader_lua_create_extension (PeasPluginLoader *loader, g_object_set_qdata (object, extension_type_quark (), GSIZE_TO_POINTER (exten_type)); - luaL_checkstack (L, 3, ""); - - if (!_lua_pushinstance (L, "GObject", "Object", the_type, object)) - { - g_clear_object (&object); - goto out; - } - - lua_getfield (L, -1, "priv"); - - if (!_lua_pushinstance (L, "Peas", "PluginInfo", - PEAS_TYPE_PLUGIN_INFO, info)) - { - g_clear_object (&object); - } - else - { - /* Set the plugin info as self.priv.plugin_info */ - lua_setfield (L, -2, "plugin_info"); - } + luaL_checkstack (L, 2, ""); + lua_pushlightuserdata (L, object); + lua_pushlightuserdata (L, info); - /* Pop priv and object */ - lua_pop (L, 2); + if (!peas_lua_internal_call (L, "setup_extension", 2, LUA_TNIL)) + g_clear_object (&object); out: @@ -364,53 +202,21 @@ peas_plugin_loader_lua_load (PeasPluginLoader *loader, { PeasPluginLoaderLua *lua_loader = PEAS_PLUGIN_LOADER_LUA (loader); lua_State *L; - gboolean success; + gboolean success = FALSE; L = thread_enter (lua_loader, info); - luaL_checkstack (L, 2, ""); - - /* Get the module's table */ + luaL_checkstack (L, 3, ""); lua_pushstring (L, info->filename); - lua_rawget (L, LUA_REGISTRYINDEX); + lua_pushstring (L, peas_plugin_info_get_module_dir (info)); + lua_pushstring (L, peas_plugin_info_get_module_name (info)); - if (!lua_isnil (L, -1)) - { - success = lua_istable (L, -1); - } - else + if (peas_lua_internal_call (L, "load", 3, LUA_TBOOLEAN)) { - const gchar *module_dir, *module_name; - - module_dir = peas_plugin_info_get_module_dir (info); - module_name = peas_plugin_info_get_module_name (info); - - /* Must push the key back onto the stack */ - lua_pushstring (L, info->filename); - - /* Push something that isn't a table */ - lua_pushboolean (L, FALSE); - - if (_lua_has_package (L, module_name)) - { - g_warning ("Error loading plugin '%s': " - "module name '%s' has already been used", - info->filename, module_name); - } - else if (_lua_add_package_path (L, module_dir) && - peas_lua_utils_require (L, module_name)) - { - /* Remove the boolean */ - lua_replace (L, -2); - } - - success = lua_istable (L, -1); - lua_rawset (L, LUA_REGISTRYINDEX); + success = lua_toboolean (L, -1); + lua_pop (L, 1); } - /* Pop the module's table */ - lua_pop (L, 1); - thread_leave (lua_loader, info, &L); return success; } @@ -433,9 +239,9 @@ peas_plugin_loader_lua_unload (PeasPluginLoader *loader, lua_pushnil (L); lua_rawset (L, LUA_REGISTRYINDEX); - priv->lgi_leave_func (priv->lgi_lock); - info->loader_data = NULL; + + priv->lgi_leave_func (priv->lgi_lock); } static void @@ -447,7 +253,7 @@ peas_plugin_loader_lua_garbage_collect (PeasPluginLoader *loader) priv->lgi_enter_func (priv->lgi_lock); - lua_gc (L, LUA_GCCOLLECT, 0); + peas_lua_internal_call (L, "garbage_collect", 0, LUA_TNIL); priv->lgi_leave_func (priv->lgi_lock); } @@ -515,6 +321,12 @@ peas_plugin_loader_lua_initialize (PeasPluginLoader *loader) /* Pop lgi's module table */ lua_pop (L, 1); + if (!peas_lua_internal_setup (L)) + { + /* Already warned */ + return FALSE; + } + /* Assert that no values were leaked to the stack */ g_assert_cmpint (lua_gettop (L), ==, 0); @@ -548,6 +360,7 @@ peas_plugin_loader_lua_finalize (GObject *object) if (priv->lgi_enter_func != NULL) priv->lgi_enter_func (priv->lgi_lock); + peas_lua_internal_shutdown (priv->L); g_clear_pointer (&priv->L, (GDestroyNotify) lua_close); G_OBJECT_CLASS (peas_plugin_loader_lua_parent_class)->finalize (object); |