tech

[English] [Japanese]

82. Linking with Lua

LuneScript can execute Lua code.

This feature is preserved even after transpiling to the go language, but there are some caveats.

Be especially careful when combining asynchronous processing with lua code execution.

Luaval

As already explained in the link destination, the result of lua is managed by Luaval type.

../lua

This Luaval type data has the following restrictions.

The Lua VM executed when retrieving a certain Luaval type data dataA and the Lua VM executed when accessing that dataA must be the same Lua VM.

The behavior is undefined if this limit is not met.

If Luaval is not handled in asynchronous processing, the number of Lua VMs that are used is limited to one, so there is no need to be aware of which Lua VM is used.

Note that "access to Luaval type data" does not include assignment between variables. In other words, the following work = val is not "Access to Luaval type data", so you don't need to be aware of Lua VM.

// @lnsFront: ok
fn func( val:&Luaval<&List<int>> ) {
   let work = val;
}

Types of Lua VMs

There are two types of Lua VMs:

  • Lua VM running with __noasync
  • Lua VM running with __async

    • Lua VM for __async exists for each asynchronous thread

When running lua, you need to control which Lua VMs are accessed.

The lua access block provides this control.

block lua access

The types of lua access blocks are: Also, the lua access block to be used differs depending on whether the accessing function is __async or __noasync.

  • __luago

    • Used to access lua from __noasync functions
    • This accesses lua with the Lua VM for __noasync.
  • __luaLock

    • Used when accessing lua from __async functions
    • This is equivalent to the combination of __asyncLock and __luago.
  • __luaDepend

    • Used when accessing lua from __async functions
    • This is accessed by lua for the Lua VM associated with the currently running thread.
    • In other words, if the currently executing thread is __noasync, it will be accessed with the Lua VM for __noasync, and if the currently executing thread is __async, it will be accessed with the Lua VM for __async.

__luaDepend is tricky because the Lua VM used is determined at runtime.

sample

Below is a sample that runs the lua code.

// @lnsFront: ok
__luago {
   let code = ```
return { val1 = 10, val2 = 20 }
```;
   let loaded, err = _load( code, nil );
   when! loaded {
      if! let obj = loaded( ## ) {
         forsort val, key in obj@@Map<str,int> {
            print( key, val + 100 ); 
         }
      }
   } else {
      print( err );
   }
}

The lua code return { val1 = 10, val2 = 20 } assigned to the variable code is executed, and the resulting Map is enumerated and output using foreach.

At the top of this, we declare __luago .

Proper use of lua access block

As mentioned above, to access Lua from asynchronous processing, it is necessary to use __luaLock and __luaDepend of the lua access block properly.

However, you shouldn't use __luaDepend unless you're doing heavy Lua work asynchronously.

By limiting to __luago and __luaLock without using __luaDepend , the load processing in the Lua VM can be minimized, memory usage can be reduced, and as a result processing can be performed more efficiently than asynchronous execution.

Also, when using __luaDepend, you have to be careful with the lua VM used, getting it wrong can lead to undefined results at runtime.

To use __luaDepend, it is necessary to consider the advantages and disadvantages of asynchronous processing.

When to use __luaDepend

string.gmatch() needs lua access block to access lua.

At this time, the Luaval data handled by string.gmatch() is closed in the apply block, so using __luaDepend is more efficient and safer.

// @lnsFront: skip
   let mut list:List<str> = [];
   __luaDepend {
      apply token of string.gmatch( txt, pattern ) {
         list.insert( token );
      }
   }