Skip to content

Commit

Permalink
fix: populate ... for required modules (#693)
Browse files Browse the repository at this point in the history
* fix: populate `...` for required modules

Fixes #689.

* adjust code to more closely match documented semantics

Instead of hardcoding the arguments within the loader, pass them
through the searcher, as specified by the documented behavior:

#689 (comment)

> quoted from https://www.lua.org/manual/5.4/manual.html#pdf-require
>
>> Once a loader is found, require calls the loader with two arguments:
>> modname and an extra value, a loader data, 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.)

Thanks @fperrad for the research!

* loader args: provide consistent behavior across Lua versions

This implements a compromise solution that allows Teal modules
to always get both arguments, even in Lua 5.1 based systems
(this should be harmless for modules which don't expect a second
argument there), without hardcoding `loader_data`, just in case
the user is on an environment that runs a patched `require` for
debug reasons or something.
  • Loading branch information
hishamhm committed Sep 5, 2023
1 parent 7aadbc2 commit e29e29b
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 11 deletions.
22 changes: 22 additions & 0 deletions spec/cli/run_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,28 @@ describe("tl run", function()
]], output)
end)

it("passes standard arguments to required chunks", function()
local dir_name = util.write_tmp_dir(finally, {
["ld.tl"] = [[
require("foo")
print("Done")
]],
["foo.tl"] = [[
print(...)
]]
})
local pd, output
util.do_in(dir_name, function()
pd = io.popen(util.tl_cmd("run", "ld.tl"), "r")
output = pd:read("*a")
end)
util.assert_popen_close(0, pd:close())
util.assert_line_by_line(util.os_path([[
foo ./foo.tl
Done
]]), output)
end)

describe("-l --require", function()
it("can require a module from the CLI like Lua", function()
local dir_name = util.write_tmp_dir(finally, {
Expand Down
10 changes: 5 additions & 5 deletions tl.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5487,14 +5487,14 @@ local function init_globals(lax)
}),
["loaders"] = a_type({
typename = "array",
elements = a_type({ typename = "function", args = TUPLE({ STRING }), rets = TUPLE({ ANY }) }),
elements = a_type({ typename = "function", args = TUPLE({ STRING }), rets = TUPLE({ ANY, ANY }) }),
}),
["loadlib"] = a_type({ typename = "function", args = TUPLE({ STRING, STRING }), rets = TUPLE({ FUNCTION }) }),
["path"] = STRING,
["preload"] = TABLE,
["searchers"] = a_type({
typename = "array",
elements = a_type({ typename = "function", args = TUPLE({ STRING }), rets = TUPLE({ ANY }) }),
elements = a_type({ typename = "function", args = TUPLE({ STRING }), rets = TUPLE({ ANY, ANY }) }),
}),
["searchpath"] = a_type({ typename = "function", args = TUPLE({ STRING, STRING, OPT(STRING), OPT(STRING) }), rets = TUPLE({ STRING, STRING }) }),
},
Expand Down Expand Up @@ -10824,11 +10824,11 @@ local function tl_package_loader(module_name)
local code = assert(tl.pretty_print_ast(program, env.gen_target, true))
local chunk, err = load(code, "@" .. found_filename, "t")
if chunk then
return function()
local ret = chunk()
return function(modname, loader_data)
local ret = chunk(modname, loader_data)
package.loaded[module_name] = ret
return ret
end
end, found_filename
else
error("Internal Compiler Error: Teal generator produced invalid Lua. Please report a bug at https://github.com/teal-language/tl\n\n" .. err)
end
Expand Down
15 changes: 9 additions & 6 deletions tl.tl
Original file line number Diff line number Diff line change
Expand Up @@ -5487,14 +5487,14 @@ local function init_globals(lax: boolean): {string:Variable}, {string:Type}
},
["loaders"] = a_type {
typename = "array",
elements = a_type { typename = "function", args = TUPLE { STRING }, rets = TUPLE { ANY } }
elements = a_type { typename = "function", args = TUPLE { STRING }, rets = TUPLE { ANY, ANY } }
},
["loadlib"] = a_type { typename = "function", args = TUPLE { STRING, STRING }, rets = TUPLE { FUNCTION } },
["path"] = STRING,
["preload"] = TABLE,
["searchers"] = a_type {
typename = "array",
elements = a_type { typename = "function", args = TUPLE { STRING }, rets = TUPLE { ANY } }
elements = a_type { typename = "function", args = TUPLE { STRING }, rets = TUPLE { ANY, ANY } }
},
["searchpath"] = a_type { typename = "function", args = TUPLE { STRING, STRING, OPT(STRING), OPT(STRING) }, rets = TUPLE { STRING, STRING } },
},
Expand Down Expand Up @@ -10791,7 +10791,7 @@ tl.gen = function(input: string, env: Env): string, Result
return code, result
end

local function tl_package_loader(module_name: string): any
local function tl_package_loader(module_name: string): any, any
local found_filename, fd, tried = tl.search_module(module_name, false)
if found_filename then
local input = read_full_file(fd)
Expand Down Expand Up @@ -10824,11 +10824,14 @@ local function tl_package_loader(module_name: string): any
local code = assert(tl.pretty_print_ast(program, env.gen_target, true))
local chunk, err = load(code, "@" .. found_filename, "t")
if chunk then
return function(): any
local ret = chunk()
return function(modname: string, loader_data: string): any
if loader_data == nil then
loader_data = found_filename
end
local ret = chunk(modname, loader_data)
package.loaded[module_name] = ret
return ret
end
end, found_filename
else
error("Internal Compiler Error: Teal generator produced invalid Lua. Please report a bug at https://github.com/teal-language/tl\n\n" .. err)
end
Expand Down

0 comments on commit e29e29b

Please sign in to comment.