aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-04-17 14:57:29 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-04-17 14:57:29 -0300
commited2872cd3bf6d352f36bbd34529738a60b0b51eb (patch)
treea4476cca4a43deeb8eaa0d52f0f02b15acc0db09
parent2d3f09544895b422eeecf89e0d108da8b8fcdfca (diff)
downloadlua-ed2872cd3bf6d352f36bbd34529738a60b0b51eb.tar.gz
lua-ed2872cd3bf6d352f36bbd34529738a60b0b51eb.tar.bz2
lua-ed2872cd3bf6d352f36bbd34529738a60b0b51eb.zip
'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.
-rw-r--r--loadlib.c23
-rw-r--r--lundump.c4
-rw-r--r--manual/manual.of38
-rw-r--r--testes/attrib.lua35
4 files changed, 66 insertions, 34 deletions
diff --git a/loadlib.c b/loadlib.c
index a6ce30d4..4cf9aec3 100644
--- a/loadlib.c
+++ b/loadlib.c
@@ -576,9 +576,14 @@ static int searcher_Croot (lua_State *L) {
576static int searcher_preload (lua_State *L) { 576static int searcher_preload (lua_State *L) {
577 const char *name = luaL_checkstring(L, 1); 577 const char *name = luaL_checkstring(L, 1);
578 lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 578 lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);
579 if (lua_getfield(L, -1, name) == LUA_TNIL) /* not found? */ 579 if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */
580 lua_pushfstring(L, "\n\tno field package.preload['%s']", name); 580 lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
581 return 1; 581 return 1;
582 }
583 else {
584 lua_pushliteral(L, ":preload:");
585 return 2;
586 }
582} 587}
583 588
584 589
@@ -620,17 +625,23 @@ static int ll_require (lua_State *L) {
620 /* else must load package */ 625 /* else must load package */
621 lua_pop(L, 1); /* remove 'getfield' result */ 626 lua_pop(L, 1); /* remove 'getfield' result */
622 findloader(L, name); 627 findloader(L, name);
623 lua_pushstring(L, name); /* pass name as argument to module loader */ 628 lua_rotate(L, -2, 1); /* function <-> loader data */
624 lua_insert(L, -2); /* name is 1st argument (before search data) */ 629 lua_pushvalue(L, 1); /* name is 1st argument to module loader */
630 lua_pushvalue(L, -3); /* loader data is 2nd argument */
631 /* stack: ...; loader data; loader function; mod. name; loader data */
625 lua_call(L, 2, 1); /* run loader to load module */ 632 lua_call(L, 2, 1); /* run loader to load module */
633 /* stack: ...; loader data; result from loader */
626 if (!lua_isnil(L, -1)) /* non-nil return? */ 634 if (!lua_isnil(L, -1)) /* non-nil return? */
627 lua_setfield(L, 2, name); /* LOADED[name] = returned value */ 635 lua_setfield(L, 2, name); /* LOADED[name] = returned value */
636 else
637 lua_pop(L, 1); /* pop nil */
628 if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ 638 if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */
629 lua_pushboolean(L, 1); /* use true as result */ 639 lua_pushboolean(L, 1); /* use true as result */
630 lua_pushvalue(L, -1); /* extra copy to be returned */ 640 lua_copy(L, -1, -2); /* replace loader result */
631 lua_setfield(L, 2, name); /* LOADED[name] = true */ 641 lua_setfield(L, 2, name); /* LOADED[name] = true */
632 } 642 }
633 return 1; 643 lua_rotate(L, -2, 1); /* loader data <-> module result */
644 return 2; /* return module result and loader data */
634} 645}
635 646
636/* }====================================================== */ 647/* }====================================================== */
diff --git a/lundump.c b/lundump.c
index a6004933..c1cff9e1 100644
--- a/lundump.c
+++ b/lundump.c
@@ -271,8 +271,8 @@ static void fchecksize (LoadState *S, size_t size, const char *tname) {
271#define checksize(S,t) fchecksize(S,sizeof(t),#t) 271#define checksize(S,t) fchecksize(S,sizeof(t),#t)
272 272
273static void checkHeader (LoadState *S) { 273static void checkHeader (LoadState *S) {
274 /* 1st char already checked */ 274 /* skip 1st char (already read and checked) */
275 checkliteral(S, LUA_SIGNATURE + 1, "not a binary chunk"); 275 checkliteral(S, &LUA_SIGNATURE[1], "not a binary chunk");
276 if (LoadInt(S) != LUAC_VERSION) 276 if (LoadInt(S) != LUAC_VERSION)
277 error(S, "version mismatch"); 277 error(S, "version mismatch");
278 if (LoadByte(S) != LUAC_FORMAT) 278 if (LoadByte(S) != LUAC_FORMAT)
diff --git a/manual/manual.of b/manual/manual.of
index fea6922e..24ac45ae 100644
--- a/manual/manual.of
+++ b/manual/manual.of
@@ -6408,11 +6408,15 @@ The function starts by looking into the @Lid{package.loaded} table
6408to determine whether @id{modname} is already loaded. 6408to determine whether @id{modname} is already loaded.
6409If it is, then @id{require} returns the value stored 6409If it is, then @id{require} returns the value stored
6410at @T{package.loaded[modname]}. 6410at @T{package.loaded[modname]}.
6411(The absence of a second result in this case
6412signals that this call did not have to load the module.)
6411Otherwise, it tries to find a @emph{loader} for the module. 6413Otherwise, it tries to find a @emph{loader} for the module.
6412 6414
6413To find a loader, 6415To find a loader,
6414@id{require} is guided by the @Lid{package.searchers} sequence. 6416@id{require} is guided by the table @Lid{package.searchers}.
6415By changing this sequence, 6417Each item in this table is a search function,
6418that searches for the module in a particular way.
6419By changing this table,
6416we can change how @id{require} looks for a module. 6420we can change how @id{require} looks for a module.
6417The following explanation is based on the default configuration 6421The following explanation is based on the default configuration
6418for @Lid{package.searchers}. 6422for @Lid{package.searchers}.
@@ -6429,9 +6433,14 @@ it tries an @emph{all-in-one} loader @seeF{package.searchers}.
6429 6433
6430Once a loader is found, 6434Once a loader is found,
6431@id{require} calls the loader with two arguments: 6435@id{require} calls the loader with two arguments:
6432@id{modname} and an extra value dependent on how it got the loader. 6436@id{modname} and an extra value,
6433(If the loader came from a file, 6437a @emph{loader data},
6434this extra value is the file name.) 6438also returned by the searcher.
6439The loader data can be any value useful to the module;
6440for the default searchers,
6441it indicates where the loader was found.
6442(For instance, if the loader came from a file,
6443this extra value is the file path.)
6435If the loader returns any non-nil value, 6444If the loader returns any non-nil value,
6436@id{require} assigns the returned value to @T{package.loaded[modname]}. 6445@id{require} assigns the returned value to @T{package.loaded[modname]}.
6437If the loader does not return a non-nil value and 6446If the loader does not return a non-nil value and
@@ -6439,6 +6448,9 @@ has not assigned any value to @T{package.loaded[modname]},
6439then @id{require} assigns @Rw{true} to this entry. 6448then @id{require} assigns @Rw{true} to this entry.
6440In any case, @id{require} returns the 6449In any case, @id{require} returns the
6441final value of @T{package.loaded[modname]}. 6450final value of @T{package.loaded[modname]}.
6451Besides that value, @id{require} also returns as a second result
6452the loader data returned by the searcher,
6453which indicates how @id{require} found the module.
6442 6454
6443If there is any error loading or running the module, 6455If there is any error loading or running the module,
6444or if it cannot find any loader for the module, 6456or if it cannot find any loader for the module,
@@ -6558,16 +6570,20 @@ table used by @Lid{require}.
6558 6570
6559@LibEntry{package.searchers| 6571@LibEntry{package.searchers|
6560 6572
6561A table used by @Lid{require} to control how to load modules. 6573A table used by @Lid{require} to control how to find modules.
6562 6574
6563Each entry in this table is a @def{searcher function}. 6575Each entry in this table is a @def{searcher function}.
6564When looking for a module, 6576When looking for a module,
6565@Lid{require} calls each of these searchers in ascending order, 6577@Lid{require} calls each of these searchers in ascending order,
6566with the module name (the argument given to @Lid{require}) as its 6578with the module name (the argument given to @Lid{require}) as its
6567sole argument. 6579sole argument.
6568The function can return another function (the module @def{loader}) 6580If the searcher finds the module,
6569plus an extra value that will be passed to that loader, 6581it returns another function, the module @def{loader},
6570or a string explaining why it did not find that module 6582plus an extra value, a @emph{loader data},
6583that will be passed to that loader and
6584returned as a second result by @Lid{require}.
6585If it cannot find the module,
6586it returns a string explaining why
6571(or @nil if it has nothing to say). 6587(or @nil if it has nothing to say).
6572 6588
6573Lua initializes this table with four searcher functions. 6589Lua initializes this table with four searcher functions.
@@ -6617,9 +6633,9 @@ into one single library,
6617with each submodule keeping its original open function. 6633with each submodule keeping its original open function.
6618 6634
6619All searchers except the first one (preload) return as the extra value 6635All searchers except the first one (preload) return as the extra value
6620the file name where the module was found, 6636the file path where the module was found,
6621as returned by @Lid{package.searchpath}. 6637as returned by @Lid{package.searchpath}.
6622The first searcher returns no extra value. 6638The first searcher always returns the string @St{:preload:}.
6623 6639
6624} 6640}
6625 6641
diff --git a/testes/attrib.lua b/testes/attrib.lua
index dcafd634..4adb42e0 100644
--- a/testes/attrib.lua
+++ b/testes/attrib.lua
@@ -122,12 +122,13 @@ local oldpath = package.path
122 122
123package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR) 123package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR)
124 124
125local try = function (p, n, r) 125local try = function (p, n, r, ext)
126 NAME = nil 126 NAME = nil
127 local rr = require(p) 127 local rr, x = require(p)
128 assert(NAME == n) 128 assert(NAME == n)
129 assert(REQUIRED == p) 129 assert(REQUIRED == p)
130 assert(rr == r) 130 assert(rr == r)
131 assert(ext == x)
131end 132end
132 133
133a = require"names" 134a = require"names"
@@ -143,27 +144,27 @@ assert(package.searchpath("C", package.path) == D"C.lua")
143assert(require"C" == 25) 144assert(require"C" == 25)
144assert(require"C" == 25) 145assert(require"C" == 25)
145AA = nil 146AA = nil
146try('B', 'B.lua', true) 147try('B', 'B.lua', true, "libs/B.lua")
147assert(package.loaded.B) 148assert(package.loaded.B)
148assert(require"B" == true) 149assert(require"B" == true)
149assert(package.loaded.A) 150assert(package.loaded.A)
150assert(require"C" == 25) 151assert(require"C" == 25)
151package.loaded.A = nil 152package.loaded.A = nil
152try('B', nil, true) -- should not reload package 153try('B', nil, true, nil) -- should not reload package
153try('A', 'A.lua', true) 154try('A', 'A.lua', true, "libs/A.lua")
154package.loaded.A = nil 155package.loaded.A = nil
155os.remove(D'A.lua') 156os.remove(D'A.lua')
156AA = {} 157AA = {}
157try('A', 'A.lc', AA) -- now must find second option 158try('A', 'A.lc', AA, "libs/A.lc") -- now must find second option
158assert(package.searchpath("A", package.path) == D"A.lc") 159assert(package.searchpath("A", package.path) == D"A.lc")
159assert(require("A") == AA) 160assert(require("A") == AA)
160AA = false 161AA = false
161try('K', 'L', false) -- default option 162try('K', 'L', false, "libs/L") -- default option
162try('K', 'L', false) -- default option (should reload it) 163try('K', 'L', false, "libs/L") -- default option (should reload it)
163assert(rawget(_G, "_REQUIREDNAME") == nil) 164assert(rawget(_G, "_REQUIREDNAME") == nil)
164 165
165AA = "x" 166AA = "x"
166try("X", "XXxX", AA) 167try("X", "XXxX", AA, "libs/XXxX")
167 168
168 169
169removefiles(files) 170removefiles(files)
@@ -183,14 +184,16 @@ files = {
183createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n") 184createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n")
184AA = 0 185AA = 0
185 186
186local m = assert(require"P1") 187local m, ext = assert(require"P1")
188assert(ext == "libs/P1/init.lua")
187assert(AA == 0 and m.AA == 10) 189assert(AA == 0 and m.AA == 10)
188assert(require"P1" == m) 190assert(require"P1" == m)
189assert(require"P1" == m) 191assert(require"P1" == m)
190 192
191assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua") 193assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua")
192m.xuxu = assert(require"P1.xuxu") 194m.xuxu, ext = assert(require"P1.xuxu")
193assert(AA == 0 and m.xuxu.AA == 20) 195assert(AA == 0 and m.xuxu.AA == 20)
196assert(ext == "libs/P1/xuxu.lua")
194assert(require"P1.xuxu" == m.xuxu) 197assert(require"P1.xuxu" == m.xuxu)
195assert(require"P1.xuxu" == m.xuxu) 198assert(require"P1.xuxu" == m.xuxu)
196assert(require"P1" == m and m.AA == 10) 199assert(require"P1" == m and m.AA == 10)
@@ -267,15 +270,17 @@ else
267 270
268 -- test C modules with prefixes in names 271 -- test C modules with prefixes in names
269 package.cpath = DC"?" 272 package.cpath = DC"?"
270 local lib2 = require"lib2-v2" 273 local lib2, ext = require"lib2-v2"
274 assert(string.find(ext, "libs/lib2-v2", 1, true))
271 -- check correct access to global environment and correct 275 -- check correct access to global environment and correct
272 -- parameters 276 -- parameters
273 assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2") 277 assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2")
274 assert(lib2.id("x") == "x") 278 assert(lib2.id("x") == "x")
275 279
276 -- test C submodules 280 -- test C submodules
277 local fs = require"lib1.sub" 281 local fs, ext = require"lib1.sub"
278 assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") 282 assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
283 assert(string.find(ext, "libs/lib1", 1, true))
279 assert(fs.id(45) == 45) 284 assert(fs.id(45) == 45)
280end 285end
281 286
@@ -293,10 +298,10 @@ do
293 return _ENV 298 return _ENV
294 end 299 end
295 300
296 local pl = require"pl" 301 local pl, ext = require"pl"
297 assert(require"pl" == pl) 302 assert(require"pl" == pl)
298 assert(pl.xuxu(10) == 30) 303 assert(pl.xuxu(10) == 30)
299 assert(pl[1] == "pl" and pl[2] == nil) 304 assert(pl[1] == "pl" and pl[2] == ":preload:" and ext == ":preload:")
300 305
301 package = p 306 package = p
302 assert(type(package.path) == "string") 307 assert(type(package.path) == "string")