Skip to content
Snippets Groups Projects
user avatar
Alexander Turenko authored
This commit starts a series, which refactors built-in module
registration mechanisms. The series aims several goals:

* Offer a standard tarantool specific way to register a built-in module.
  It allows to change the registration process for all built-in modules
  at once.
* Make the API of such functions simple and clean.
* Eliminate known problems of the existing approach to register built-in
  modules.

This particular commit offers the new `luaT_newmodule()` function. It
replaces `luaL_register()` and `luaL_register_module()` to some extent.

Here I also start a practice to use `luaL_setfuncs()` instead of
`luaL_register(L, NULL, funcs)` for readability purposes. The function
is part of Lua 5.2 ([documentation][1]), but it is implemented in
LuaJIT.

Let's look on examples below.

## How it works now

First of all, consider the [documentation][2] about the
`luaL_register()` function. Then look on the examples.

```c
luaL_register(L, "foo.bar", funcs);
```

Creates a table `package.loaded['foo.bar']` and `_G.foo.bar` (if neither
of them exists), fill it with the functions and pushes it to the stack.

What is not ok:

* Pollutes `_G`.
* `package.loaded` is written flat, but `_G` is written deeply.
* No control over (un)intended module rewritting.

It also worth to note that we can't change this function, because it is
part of the Lua API. So we need another function for our registration
process in order to implement #7774.

Another usage of the function makes it even more confusing:

```c
luaL_register(L, NULL, funcs);
```

Does it create a table, fill it with the functions and push it to the
stack? No.

Unlike other usages, it fills a table on the top of the stack with the
functions and leaves it on the stack. And it actually has no relation to
module registration.

There is tarantool specific function `luaL_register_module()`, which
looks as an attempt to solve some of the problems.

```c
luaL_register_module(L, "foo.bar", funcs);
```

It doesn't touch `_G` and, surprisingly, changes how a module is written
to `package.loaded`.

The call creates a table (or finds it) in `package.loaded.foo.bar`,
fills it with the functions and pushes to the stack. *This* function
writes `package.loaded` deeply.

It leaves us with `luaL_register()` for assigning `_G.foo.bar` (with
pollution of `package.loaded`). It leaves us with `luaL_register()` for
setting functions into a table on the stack (with confusing name in this
context and confusing contract). And we has no a function to just assign
`package.loaded[modname]` without the deep tables creation and with
appropriate checks.

## How it will work

```c
luaT_newmodule(L, "foo.bar", funcs);
```

Create a table, set it to `package.loaded['foo.bar']` and push into the
stack. Assert that the table doesn't exist.

```c
luaL_setfuncs(L, funcs, 0);
```

Add functions into a table on top of the stack.

```c
luaL_findtable(L, LUA_GLOBALSINDEX, "foo.bar", 0);
luaL_setfuncs(L, funcs, 0);
```

Find/create a table `_G.foo.bar` and add functions to it.

Next commits will adopt built-in modules to follow this practice.

[1]: https://www.lua.org/manual/5.2/manual.html#luaL_setfuncs
[2]: https://www.lua.org/manual/5.1/manual.html#luaL_register

Part of #7774

NO_DOC=user visible behavior is unchanged, pure refactoring change
NO_TEST=see NO_DOC
NO_CHANGELOG=see NO_DOC
e3cf5a5d
History
Name Last commit Last update