Easier Lua development with the transcompiler LuneScript!!
Lua is a very compact language, yet a language with high potential.
I think it's safe to say that it is one of the easiest languages to use when it comes to programming.
However, although it is "easy to use as a language to be incorporated into a program", it is also true that there are various things to worry about when compared to modern languages.
On the other hand, functional evolution to bring Lua closer to the modern language may be a trade-off with one of the major features of Lua, which is "compactness".
Therefore, I would like to introduce a transcompiler LuneScript that can cover the parts of Lua that you are interested in without modifying Lua itself.
What is LuneScript
LuneScript is a language that covers the concerns of Lua as mentioned above, and is a transcompiler that can convert the code developed in LuneScript into Lua code.
LuneScript has the following characteristics.
- null safety.
- Since it is a statically typed language, simple mistakes can be found at compile time through type checking.
- Minimize the effort of type declaration by type inference.
- generics allows processing while preserving type information.
- Support class definition as language grammar.
- Supports pattern matching. (match)
- Faster load times with lazy loading.
- Conversion between structured and unstructured data. (Mapping)
- Macros can realize designs that do not rely on dynamic processing such as polymorphism.
- Detect missing initialization of variables
-
Error delegation of functions with the
!
operator - Transcompiling to Lua and go.
- Supports data representation compatible with JSON.
- Transcompiled Lua code can work independently without any external libraries.
- Transcompiled Lua code is output as it is written in LuneScript, so there is no performance degradation.
- Existing Lua external modules can be used from LuneScript.
-
LuneScript runs on Lua and does not require anything other than Lua standard modules, so it is easy to introduce.
- Transcompile time can be reduced to 1/20 by using the go version of LuneScript.
- Lua modules converted from LuneScript can be used from other Lua modules.
-
Supports Lua5.1 to 5.4.
- For Lua5.1 see:
- ./crosscompile
- LuneScript is developed by self-hosting.
- Supports code completion in emacs
-
support tag jumping with lnstags
- Supports automatic generation of glue code
- Learning cost is low because it is based on Lua and C syntax.
How to use LuneScript
LuneScript is developed on github.
<https://github.com/ifritJP/LuneScript>
Please refer to the following for the installation method.
-
Introduction
command
Installing LuneScript installs the lnsc command.
For information on how to use the lnsc command, please refer to the following article:
-
Hello world
Cross-compiling between Lua versions
LuneScript supports cross-compilation between versions of Lua. Please refer to the following article.
-
Cross-compiling between Lua versions
LuneScript specification
This section describes the specifications of LuneScript.
value and type
comment
Comments use C++ style. Single-line comment //
and multi-line comment /* */
can be specified.
// @lnsFront: skip
// 行末までコメント
/* ここから〜
ここまでコメント*/
operator
In principle, operators use the same ones as Lua.
Note that Lua5.3's // (truncated division) is a one-line comment in LuneScript.
In LuneScript, / between ints is automatically rounded down and divided.
Variable declaration
Please refer to the following article for LuneScript variables.
-
variable
General control statement
function declaration
For LuneScript functions, please refer to the following.
-
Functions
nilable
LuneScript is a nil-safe (NULL-safe) language.
Please refer to the following for nilable which realizes nil safety of LuneScript.
-
nilable edition
class
LuneScript supports classes for object-oriented programming.
Classes in LuneScript have the following constraints:
- Does not support multiple inheritance.
generics are not supported.-
All are overridable methods.
- You cannot suppress overrides.
-
A method with the same name with different arguments cannot be defined between inheritances.
- The only exception is that the constructor has the same name ( __init ).
Please refer to the following article.
-
Basic class
-
accessor edition
-
class inheritance
-
class advertise
-
Class override edition
-
Interface
prototype declaration
LuneScript parses the script from top to bottom.
Symbols referenced in scripts must be previously defined. For example, before declaring a variable of type TEST, the class TEST must be defined.
Also, to define classes that refer to each other, one of them must be prototyped.
The following is an example when ClassA and ClassB cross-reference each other.
// @lnsFront: ok
pub class Super {
}
pub proto class ClassB extend Super;
pub class ClassA {
let val: ClassB;
}
pub class ClassB extend Super{
let val: ClassA;
}
Declare proto as above.
The prototype declaration and the actual definition must declare the same things such as pub and extend.
Mapping
LuneScript class instances can be converted to and from Map objects.
This is called Mapping.
Please refer to the following for Mapping.
-
mapping edition
Generics
nil conditional operator
It supports the nil conditional operator as an easy way to handle nilable values.
-
nil conditional operator
build
Please refer to the following for how to build a project using LuneScript.
-
build
_lune.lua module
As mentioned above, files transcompiled to Lua with LuneScript can be executed as-is with the Lua command. At this time, no external module is required.
This indicates that you have included all the code necessary for processing within the transcompiled Lua code.
For example, if you transcompile the following processing code:
// @lnsFront: ok
fn func( val:int! ):int {
return 1 + unwrap val default 0;
}
The Lua code is much longer, like this:
--mini.lns
local _moduleObj = {}
local __mod__ = 'mini'
if not _ENV._lune then
_lune = {}
end
function _lune.unwrap( val )
if val == nil then
__luneScript:error( 'unwrap val is nil' )
end
return val
end
function _lune.unwrapDefault( val, defval )
if val == nil then
return defval
end
return val
end
local function func( val )
return 1 + _lune.unwrapDefault( val, 0)
end
return _moduleObj
Lines 4 to 18 are the processing required for unwrap. Note that this code is output to all Lua files.
Since this code itself is a common process, by specifying the -r option when transcompiling, you can require it as a separate module and combine common processes.
Specifically, specify the -r option as follows.
$ lua lune/base/base.lua -r src.lns save
With this -r option, the above code would be transformed into the following, much cleaner.
--mini.lns
local _moduleObj = {}
local __mod__ = 'mini'
_lune = require( "lune.base._lune" )
local function func( val )
return 1 + _lune.unwrapDefault( val, 0)
end
return _moduleObj
Note that require( "lune.base._lune" ) will be inserted, so you need to set this module so that it can be loaded. You don't need to be aware of this if the transcompiler operates in an environment, but you need to be careful when executing the converted Lua source in some other environment.
macro
LuneScript employs simple macros.
Significance of macro
Macros have some restrictions compared to ordinary functions. In addition, most of the processing that can be performed by macros can be realized by making full use of object orientation.
So what's the point of using macros?
That is, "the operation is statically determined by using macros".
If the same processing is implemented in an object-oriented manner, it becomes dynamic processing. On the other hand, if implemented by a macro, it becomes a static process.
What do you enjoy about this?
It's the same advantage statically typed languages have over dynamically typed languages.
Static analysis is possible by statically processing statically determined information.
For example, most object-oriented function overrides can be resolved statically through the use of macros. By using static function calls instead of dynamic function overrides, it becomes easier to follow the source code.
It is not good to use macros recklessly, but it is also not ideal to make dynamic processing such as function overriding easily.
Dynamic processing and macros need to be used properly.
macro definition
Please refer to the following article for macro definition.
-
Macro edition
supplement
Links to supplementary articles will be added here.
-
Introduction to Lua Transcompiler LuneScript 2
- Introducing subfile, module and nil conditional operators
- introduce2
-
Let's have more fun with Lua's transcompiler LuneScript's modern development environment
- Completion, syntax checking, subfile search
- completion
For articles not linked from this page, follow them from the sidebar.