mirror of https://github.com/rusefi/lua.git
'require' returns where module was found
The function 'require' returns the *loader data* as a second result. For file searchers, this data is the path where they found the module.
This commit is contained in:
parent
2d3f095448
commit
ed2872cd3b
23
loadlib.c
23
loadlib.c
|
@ -576,9 +576,14 @@ static int searcher_Croot (lua_State *L) {
|
||||||
static int searcher_preload (lua_State *L) {
|
static int searcher_preload (lua_State *L) {
|
||||||
const char *name = luaL_checkstring(L, 1);
|
const char *name = luaL_checkstring(L, 1);
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
|
||||||
if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */
|
if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */
|
||||||
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
|
lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushliteral(L, ":preload:");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -620,17 +625,23 @@ static int ll_require (lua_State *L) {
|
||||||
/* else must load package */
|
/* else must load package */
|
||||||
lua_pop(L, 1); /* remove 'getfield' result */
|
lua_pop(L, 1); /* remove 'getfield' result */
|
||||||
findloader(L, name);
|
findloader(L, name);
|
||||||
lua_pushstring(L, name); /* pass name as argument to module loader */
|
lua_rotate(L, -2, 1); /* function <-> loader data */
|
||||||
lua_insert(L, -2); /* name is 1st argument (before search data) */
|
lua_pushvalue(L, 1); /* name is 1st argument to module loader */
|
||||||
|
lua_pushvalue(L, -3); /* loader data is 2nd argument */
|
||||||
|
/* stack: ...; loader data; loader function; mod. name; loader data */
|
||||||
lua_call(L, 2, 1); /* run loader to load module */
|
lua_call(L, 2, 1); /* run loader to load module */
|
||||||
|
/* stack: ...; loader data; result from loader */
|
||||||
if (!lua_isnil(L, -1)) /* non-nil return? */
|
if (!lua_isnil(L, -1)) /* non-nil return? */
|
||||||
lua_setfield(L, 2, name); /* LOADED[name] = returned value */
|
lua_setfield(L, 2, name); /* LOADED[name] = returned value */
|
||||||
|
else
|
||||||
|
lua_pop(L, 1); /* pop nil */
|
||||||
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
|
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
|
||||||
lua_pushboolean(L, 1); /* use true as result */
|
lua_pushboolean(L, 1); /* use true as result */
|
||||||
lua_pushvalue(L, -1); /* extra copy to be returned */
|
lua_copy(L, -1, -2); /* replace loader result */
|
||||||
lua_setfield(L, 2, name); /* LOADED[name] = true */
|
lua_setfield(L, 2, name); /* LOADED[name] = true */
|
||||||
}
|
}
|
||||||
return 1;
|
lua_rotate(L, -2, 1); /* loader data <-> module result */
|
||||||
|
return 2; /* return module result and loader data */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|
|
@ -271,8 +271,8 @@ static void fchecksize (LoadState *S, size_t size, const char *tname) {
|
||||||
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
|
#define checksize(S,t) fchecksize(S,sizeof(t),#t)
|
||||||
|
|
||||||
static void checkHeader (LoadState *S) {
|
static void checkHeader (LoadState *S) {
|
||||||
/* 1st char already checked */
|
/* skip 1st char (already read and checked) */
|
||||||
checkliteral(S, LUA_SIGNATURE + 1, "not a binary chunk");
|
checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
|
||||||
if (LoadInt(S) != LUAC_VERSION)
|
if (LoadInt(S) != LUAC_VERSION)
|
||||||
error(S, "version mismatch");
|
error(S, "version mismatch");
|
||||||
if (LoadByte(S) != LUAC_FORMAT)
|
if (LoadByte(S) != LUAC_FORMAT)
|
||||||
|
|
|
@ -6408,11 +6408,15 @@ The function starts by looking into the @Lid{package.loaded} table
|
||||||
to determine whether @id{modname} is already loaded.
|
to determine whether @id{modname} is already loaded.
|
||||||
If it is, then @id{require} returns the value stored
|
If it is, then @id{require} returns the value stored
|
||||||
at @T{package.loaded[modname]}.
|
at @T{package.loaded[modname]}.
|
||||||
|
(The absence of a second result in this case
|
||||||
|
signals that this call did not have to load the module.)
|
||||||
Otherwise, it tries to find a @emph{loader} for the module.
|
Otherwise, it tries to find a @emph{loader} for the module.
|
||||||
|
|
||||||
To find a loader,
|
To find a loader,
|
||||||
@id{require} is guided by the @Lid{package.searchers} sequence.
|
@id{require} is guided by the table @Lid{package.searchers}.
|
||||||
By changing this sequence,
|
Each item in this table is a search function,
|
||||||
|
that searches for the module in a particular way.
|
||||||
|
By changing this table,
|
||||||
we can change how @id{require} looks for a module.
|
we can change how @id{require} looks for a module.
|
||||||
The following explanation is based on the default configuration
|
The following explanation is based on the default configuration
|
||||||
for @Lid{package.searchers}.
|
for @Lid{package.searchers}.
|
||||||
|
@ -6429,9 +6433,14 @@ it tries an @emph{all-in-one} loader @seeF{package.searchers}.
|
||||||
|
|
||||||
Once a loader is found,
|
Once a loader is found,
|
||||||
@id{require} calls the loader with two arguments:
|
@id{require} calls the loader with two arguments:
|
||||||
@id{modname} and an extra value dependent on how it got the loader.
|
@id{modname} and an extra value,
|
||||||
(If the loader came from a file,
|
a @emph{loader data},
|
||||||
this extra value is the file name.)
|
also returned by the searcher.
|
||||||
|
The loader data can be any value useful to the module;
|
||||||
|
for the default searchers,
|
||||||
|
it indicates where the loader was found.
|
||||||
|
(For instance, if the loader came from a file,
|
||||||
|
this extra value is the file path.)
|
||||||
If the loader returns any non-nil value,
|
If the loader returns any non-nil value,
|
||||||
@id{require} assigns the returned value to @T{package.loaded[modname]}.
|
@id{require} assigns the returned value to @T{package.loaded[modname]}.
|
||||||
If the loader does not return a non-nil value and
|
If the loader does not return a non-nil value and
|
||||||
|
@ -6439,6 +6448,9 @@ has not assigned any value to @T{package.loaded[modname]},
|
||||||
then @id{require} assigns @Rw{true} to this entry.
|
then @id{require} assigns @Rw{true} to this entry.
|
||||||
In any case, @id{require} returns the
|
In any case, @id{require} returns the
|
||||||
final value of @T{package.loaded[modname]}.
|
final value of @T{package.loaded[modname]}.
|
||||||
|
Besides that value, @id{require} also returns as a second result
|
||||||
|
the loader data returned by the searcher,
|
||||||
|
which indicates how @id{require} found the module.
|
||||||
|
|
||||||
If there is any error loading or running the module,
|
If there is any error loading or running the module,
|
||||||
or if it cannot find any loader for the module,
|
or if it cannot find any loader for the module,
|
||||||
|
@ -6558,16 +6570,20 @@ table used by @Lid{require}.
|
||||||
|
|
||||||
@LibEntry{package.searchers|
|
@LibEntry{package.searchers|
|
||||||
|
|
||||||
A table used by @Lid{require} to control how to load modules.
|
A table used by @Lid{require} to control how to find modules.
|
||||||
|
|
||||||
Each entry in this table is a @def{searcher function}.
|
Each entry in this table is a @def{searcher function}.
|
||||||
When looking for a module,
|
When looking for a module,
|
||||||
@Lid{require} calls each of these searchers in ascending order,
|
@Lid{require} calls each of these searchers in ascending order,
|
||||||
with the module name (the argument given to @Lid{require}) as its
|
with the module name (the argument given to @Lid{require}) as its
|
||||||
sole argument.
|
sole argument.
|
||||||
The function can return another function (the module @def{loader})
|
If the searcher finds the module,
|
||||||
plus an extra value that will be passed to that loader,
|
it returns another function, the module @def{loader},
|
||||||
or a string explaining why it did not find that module
|
plus an extra value, a @emph{loader data},
|
||||||
|
that will be passed to that loader and
|
||||||
|
returned as a second result by @Lid{require}.
|
||||||
|
If it cannot find the module,
|
||||||
|
it returns a string explaining why
|
||||||
(or @nil if it has nothing to say).
|
(or @nil if it has nothing to say).
|
||||||
|
|
||||||
Lua initializes this table with four searcher functions.
|
Lua initializes this table with four searcher functions.
|
||||||
|
@ -6617,9 +6633,9 @@ into one single library,
|
||||||
with each submodule keeping its original open function.
|
with each submodule keeping its original open function.
|
||||||
|
|
||||||
All searchers except the first one (preload) return as the extra value
|
All searchers except the first one (preload) return as the extra value
|
||||||
the file name where the module was found,
|
the file path where the module was found,
|
||||||
as returned by @Lid{package.searchpath}.
|
as returned by @Lid{package.searchpath}.
|
||||||
The first searcher returns no extra value.
|
The first searcher always returns the string @St{:preload:}.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -122,12 +122,13 @@ local oldpath = package.path
|
||||||
|
|
||||||
package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR)
|
package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR)
|
||||||
|
|
||||||
local try = function (p, n, r)
|
local try = function (p, n, r, ext)
|
||||||
NAME = nil
|
NAME = nil
|
||||||
local rr = require(p)
|
local rr, x = require(p)
|
||||||
assert(NAME == n)
|
assert(NAME == n)
|
||||||
assert(REQUIRED == p)
|
assert(REQUIRED == p)
|
||||||
assert(rr == r)
|
assert(rr == r)
|
||||||
|
assert(ext == x)
|
||||||
end
|
end
|
||||||
|
|
||||||
a = require"names"
|
a = require"names"
|
||||||
|
@ -143,27 +144,27 @@ assert(package.searchpath("C", package.path) == D"C.lua")
|
||||||
assert(require"C" == 25)
|
assert(require"C" == 25)
|
||||||
assert(require"C" == 25)
|
assert(require"C" == 25)
|
||||||
AA = nil
|
AA = nil
|
||||||
try('B', 'B.lua', true)
|
try('B', 'B.lua', true, "libs/B.lua")
|
||||||
assert(package.loaded.B)
|
assert(package.loaded.B)
|
||||||
assert(require"B" == true)
|
assert(require"B" == true)
|
||||||
assert(package.loaded.A)
|
assert(package.loaded.A)
|
||||||
assert(require"C" == 25)
|
assert(require"C" == 25)
|
||||||
package.loaded.A = nil
|
package.loaded.A = nil
|
||||||
try('B', nil, true) -- should not reload package
|
try('B', nil, true, nil) -- should not reload package
|
||||||
try('A', 'A.lua', true)
|
try('A', 'A.lua', true, "libs/A.lua")
|
||||||
package.loaded.A = nil
|
package.loaded.A = nil
|
||||||
os.remove(D'A.lua')
|
os.remove(D'A.lua')
|
||||||
AA = {}
|
AA = {}
|
||||||
try('A', 'A.lc', AA) -- now must find second option
|
try('A', 'A.lc', AA, "libs/A.lc") -- now must find second option
|
||||||
assert(package.searchpath("A", package.path) == D"A.lc")
|
assert(package.searchpath("A", package.path) == D"A.lc")
|
||||||
assert(require("A") == AA)
|
assert(require("A") == AA)
|
||||||
AA = false
|
AA = false
|
||||||
try('K', 'L', false) -- default option
|
try('K', 'L', false, "libs/L") -- default option
|
||||||
try('K', 'L', false) -- default option (should reload it)
|
try('K', 'L', false, "libs/L") -- default option (should reload it)
|
||||||
assert(rawget(_G, "_REQUIREDNAME") == nil)
|
assert(rawget(_G, "_REQUIREDNAME") == nil)
|
||||||
|
|
||||||
AA = "x"
|
AA = "x"
|
||||||
try("X", "XXxX", AA)
|
try("X", "XXxX", AA, "libs/XXxX")
|
||||||
|
|
||||||
|
|
||||||
removefiles(files)
|
removefiles(files)
|
||||||
|
@ -183,14 +184,16 @@ files = {
|
||||||
createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n")
|
createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n")
|
||||||
AA = 0
|
AA = 0
|
||||||
|
|
||||||
local m = assert(require"P1")
|
local m, ext = assert(require"P1")
|
||||||
|
assert(ext == "libs/P1/init.lua")
|
||||||
assert(AA == 0 and m.AA == 10)
|
assert(AA == 0 and m.AA == 10)
|
||||||
assert(require"P1" == m)
|
assert(require"P1" == m)
|
||||||
assert(require"P1" == m)
|
assert(require"P1" == m)
|
||||||
|
|
||||||
assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua")
|
assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua")
|
||||||
m.xuxu = assert(require"P1.xuxu")
|
m.xuxu, ext = assert(require"P1.xuxu")
|
||||||
assert(AA == 0 and m.xuxu.AA == 20)
|
assert(AA == 0 and m.xuxu.AA == 20)
|
||||||
|
assert(ext == "libs/P1/xuxu.lua")
|
||||||
assert(require"P1.xuxu" == m.xuxu)
|
assert(require"P1.xuxu" == m.xuxu)
|
||||||
assert(require"P1.xuxu" == m.xuxu)
|
assert(require"P1.xuxu" == m.xuxu)
|
||||||
assert(require"P1" == m and m.AA == 10)
|
assert(require"P1" == m and m.AA == 10)
|
||||||
|
@ -267,15 +270,17 @@ else
|
||||||
|
|
||||||
-- test C modules with prefixes in names
|
-- test C modules with prefixes in names
|
||||||
package.cpath = DC"?"
|
package.cpath = DC"?"
|
||||||
local lib2 = require"lib2-v2"
|
local lib2, ext = require"lib2-v2"
|
||||||
|
assert(string.find(ext, "libs/lib2-v2", 1, true))
|
||||||
-- check correct access to global environment and correct
|
-- check correct access to global environment and correct
|
||||||
-- parameters
|
-- parameters
|
||||||
assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2")
|
assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2")
|
||||||
assert(lib2.id("x") == "x")
|
assert(lib2.id("x") == "x")
|
||||||
|
|
||||||
-- test C submodules
|
-- test C submodules
|
||||||
local fs = require"lib1.sub"
|
local fs, ext = require"lib1.sub"
|
||||||
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
|
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
|
||||||
|
assert(string.find(ext, "libs/lib1", 1, true))
|
||||||
assert(fs.id(45) == 45)
|
assert(fs.id(45) == 45)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -293,10 +298,10 @@ do
|
||||||
return _ENV
|
return _ENV
|
||||||
end
|
end
|
||||||
|
|
||||||
local pl = require"pl"
|
local pl, ext = require"pl"
|
||||||
assert(require"pl" == pl)
|
assert(require"pl" == pl)
|
||||||
assert(pl.xuxu(10) == 30)
|
assert(pl.xuxu(10) == 30)
|
||||||
assert(pl[1] == "pl" and pl[2] == nil)
|
assert(pl[1] == "pl" and pl[2] == ":preload:" and ext == ":preload:")
|
||||||
|
|
||||||
package = p
|
package = p
|
||||||
assert(type(package.path) == "string")
|
assert(type(package.path) == "string")
|
||||||
|
|
Loading…
Reference in New Issue