tech

[English] [Japanese]

02. Hello world

This time, it is an introduction of Hello world using LuneScript.

lnsc command

Installing LuneScript installs the lnsc command.

Use the lnsc command as follows:

$ lnsc src.lns exe

where src.lns is the path of the script created with LuneScript. exe is an option for lnsc and means to run the specified script.

Hello world

Now let's run the traditional Hello world using LuneScript.

Create a file hello.lns with the following contents:

// @lnsFront: ok
print( "Hello world." );

And then run the following command:

$ lnsc hello.lns exe

This should print "Hello world".

If it's just this, it's not interesting or anything, so I'll continue the story a little more.

First, modify hello.lns slightly as follows:

// @lnsFront: ok
let txt = "world";
print( "Hello %s." ( txt ) );

The result of this script is also Hello world..

Now try running the following command:

$ lnsc hello.lns lua

You should see the following output:

--hello.lns
local _moduleObj = {}
local __mod__ = 'hello'
if not _lune then
   _lune = {}
end
local txt = "world"
print( string.format( "Hello %s.", txt) )
return _moduleObj

This is the code converted from hello.lns to Lua.

It's kind of messy, but you can see that print( string.format( "Hello %s.", txt) ) is being output.

This shows that print( "Hello %s." ( txt ) ) written in LuneScript is expanded to print( string.format( "Hello %s.", txt) ) when transpiling to Lua.

Now run the following command:

$ lnsc hello.lns save

This created a hello.lua file. The content of the hello.lua file is the same as the Lua code we printed earlier.

Now run hello.lua with the following command:

$ lua5.3 hello.lua

Hello world. should have been printed. Code transcompiled to Lua is Lua code that does not depend on LuneScript.

The first lnsc hello.lns exe is a command that transcompiles a LuneScript script and executes it.

Next, lnsc hello.lns lua is a command that transcompiles the LuneScript script and outputs the Lua code to the standard output.

The last lnsc hello.lns save is a command that transcompiles the LuneScript script and saves the Lua code.

While using exe in this document, we will use the save command when checking the converted code.

Main function

You can handle command line options by defining a main function.

Please refer to the following.

../shebang_main

Error message

LuneScript requires the delimiter ;. An error will occur if ; is not put at the end as shown below.

// @lnsFront: error
print( "Hello world." )

At this time, the following error message is output.

mini.lns:1:23: error: EOF
lua5.3: ./lune/base/Util.lua:176: has error
stack traceback:
	[C]: in function 'error'
	./lune/base/Util.lua:176: in function 'lune.base.Util.err'
	./lune/base/TransUnit.lua:3465: in method 'error'
	./lune/base/TransUnit.lua:3538: in method 'getToken'
	./lune/base/TransUnit.lua:11641: in method 'analyzeStatement'
	./lune/base/TransUnit.lua:3710: in method 'analyzeStatementList'
	./lune/base/TransUnit.lua:5430: in function <./lune/base/TransUnit.lua:5393>
	(...tail calls...)
	./lune/base/front.lua:848: in method 'loadFileToLuaCode'
	./lune/base/front.lua:914: in method 'loadFile'
	./lune/base/front.lua:1066: in method 'loadModule'
	./lune/base/front.lua:1709: in method 'exec'
	./lune/base/front.lua:1744: in function 'lune.base.front.exec'
	lune/base/base.lua:1: in main chunk
	[C]: in ?

In this error output, the following messages indicate compilation errors.

mini.lns:1:23: error: EOF

This error indicates an unexpected EOF error at line 1, byte 23 of mini.lns.

Any other error output is an error internal to LuneScript. To suppress error output inside LuneScript, specify the following option (diag –nodebug).

$ lnsc hello.lns exe diag --nodebug
mini.lns:1:23: error: EOF
has error

The current version suppresses internal error output by default.

Specify the –debug option to enable internal error output.

runtime

It's a bit heavy for an article about Hello world, but I'll explain the runtime while looking at the output Lua code.

Code output from LuneScript to Lua will have the runtime necessary to make it work.

For example, converting the following LuneScript code to Lua:

// @lnsFront: ok
fn add( val:int! ):int {
   return 10 + unwrap val default 0;
}
print( add( 1 ) ); // 11
print( add( nil ) ); // 10

It will be as follows.

--mini.lns
local _moduleObj = {}
local __mod__ = 'mini'
local _lune = {}
if _lune1 then
   _lune = _lune1
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

if not _lune1 then
   _lune1 = _lune
end
local function add( val )

   return 10 + _lune.unwrapDefault( val, 0)
end

print( add( 1 ) )
print( add( nil ) )
return _moduleObj

You can see that there is a decent amount of runtime output. By the way, above local function add( val ) is the runtime.

The amount of runtime inserted depends on the source LuneScript code content. When I print the full runtime, it's about 10KB in size.

This runtime is emitted in all converted Lua code.

If you are concerned about the runtime code being injected into your Lua code, you can specify -r in the lnsc command line option to replace the runtime expansion with require as follows:

--mini.lns
local _moduleObj = {}
local __mod__ = 'mini'
local _lune = require( "lune.base._lune1" )
if not _lune1 then
   _lune1 = _lune
end
local function add( val )

   return 10 + _lune.unwrapDefault( val, 0)
end

print( add( 1 ) )
print( add( nil ) )
return _moduleObj

However, in this case, lune.base._lune1 will be required, so it is necessary to pass through the load path so that lune.base._lune1 can be loaded.

where 1 in _lune1 indicates the runtime version.

If the Lua version of LuneScript is running in an environment, you don't have to worry about it, but if you run only the converted Lua code in another environment, you need to be careful.

By specifying the --runtime mod option instead of the -r option,

--mini.lns
local _moduleObj = {}
local __mod__ = 'mini'
local _lune = require( "mod" )
if not _lune1 then
   _lune1 = _lune
end
local function add( val )

   return 10 + _lune.unwrapDefault( val, 0)
end

print( add( 1 ) )
print( add( nil ) )
return _moduleObj

Instead of loading lune.base._lune as above, you can switch to the specified mod module.

As LuneScript versions change, the LuneScript runtime may also change. If Lua modules converted with different versions of LuneScript are mixed, using the default lune.base._lune may not work properly.

To avoid this, use the –runtime option to prevent an unintended version of the runtime from being loaded.

By specifying -mklunemod path on the command line, a runtime module file will be generated in the specified path.

comment

The comments in LuneScript are // and /* */.

// treats all lines as comments, and /* */ treats multiple lines as comments.

Next time, I will explain the values handled by LuneScript.