tech

[English] [Japanese]

21. import/provide

This time, I will explain LuneScript module management.

module

Module management in LuneScript is basically the same as in Lua.

Here are the differences from Lua:

  • Unless otherwise declared, each file is a module.
  • The file name extension is .lns, and the name without .lns is the module name.
  • init.lns is not supported.
  • File names of LuneScript built-in keywords (class, etc.) are not supported.

Just in case, I'll cover the common parts of LuneScript and Lua module management.

  • The package search path is controlled by the path information stored in package.path.
  • Module names are separated by . to represent subdirectories.
  • Does not support cross-reference modules.

For example, the file hoge/test.lns will have the module name hoge.test.

As you can see above, directory names and file names (other than extensions) cannot contain .

A LuneScript source becomes a single module without any special declaration.

For example, the following Test.lns is a module with function func.

// @lnsFront: ok
// Test.lns
fn func(): str, str {
   return __mod__, __func__;
}

However, the pub declaration is required to expose the information in the module to the outside world.

Specifically, you should declare pub like this:

// @lnsFront: ok
// Test.lns
pub fn func(): str, str {
   return __mod__, __func__;
}

This makes the func() function of this module available externally.

import

import declares the use of external modules.

Declare the import at the top of the module.

(2019/6/24) Support so that it can be declared inside a function.

To use the above Test.lns, do as follows.

// @lnsFront: skip
import Test;

print( Test.func() ); // @Test   Test.func

In the example above, Test.func() calls func() in the Test module.

Importing like this gives you access to symbols declared pub by the external module.

In addition, when importing work/Test.lns, it becomes as follows.

// @lnsFront: skip
import work.Test;

print( Test.func() ); // work.Test	Test.func

As you can see from the above example, to access the imported module, use the name after the last . of the module name. In the above example, work.Test is imported, so access it with the symbol Test.

In addition, when importing multiple modules, if the access name is the same (for example, when importing foo.bar and hoge.bar), please use as explained next.

import as

import as specifies the access name after import.

For example, if work.Test above is imported as foo, it will be as follows.

// @lnsFront: skip
import work.Test as foo;

print( foo.func() ); // work.Test	Test.func

require() a LuneScript transcompiled module from Lua

LuneScript is a Lua transcompiler. In other words, modules written in LuneScript can be used as require() from Lua.

In this case, the module written in LuneScript is always a table.

For example, the transcompiled Lua source of Test.lns above looks like this:

--work/Test.lns
local _moduleObj = {}
local __mod__ = 'work.Test'
if not _lune then
   _lune = {}
end
local function func(  )
   local __func__ = 'Test.func'

   return __mod__, __func__
end
_moduleObj.func = func
return _moduleObj

As you can see from the above source, if you require() this source from Lua, you will get _moduleObj.

On the other hand, Lua's require() can return any value. And sometimes this behavior is expected.

In other words, Lua modules transcompiled with LuneScript cannot be directly required and used from Lua that expects objects other than tables to be obtained.

The mechanism that enables compatibility with such Lua modules is provide .

provide

provide provides compatibility with existing Lua modules.

Avoid using it if you don't need compatibility with Lua modules.

Here is an example of provide :

// @lnsFront: ok
// Test.lns
pub fn func(): str, str {
   return __mod__, __func__;
}

provide func;

The above example gives function func() to provide .

This results in the following transcompiled result for this Test.lns module:

--work/Test.lns
local __mod__ = 'work.Test'
if not _lune then
   _lune = {}
end
local function func(  )
   local __func__ = 'Test.func'

   return __mod__, __func__
end
return func

As you can see above, require() this module from Lua and you get the function func .

By using provide in this way, you can generate modules that are compatible with existing Lua modules.

Note that provide can only be symbols. It is not possible to specify an immediate value.

summary

LuneScript is easy to create modules and compatible with existing Lua modules.

Next time, I will explain how to use existing Lua modules from LuneScript.