Loulabelle 5203 Reference Manual

Freely available under the terms of the MIT license.


1 – Introduction

Loulabelle is a compiler (or transpiler), which translates programs written in Lua version 5.2 to JavaScript (ECMAScript 2015 ES6), and a runtime support library, which enables the execution of such translated programs in a JavaScript environment such as a Web browser or Node.js.

Programs compiled by Loulabelle can be used anywhere that JavaScript code can be used, for example as the scripts to control a Web page, or in a smaller role, as supporting scripts that interact with other scripts written in JavaScript.

This reference manual assumes the reader is familiar with Lua 5.2 and ECMAScript 2015 ES6. The manual is styled after the Lua reference manual, but discusses information specific to Loulabelle. As such, it happens to discuss implementation details before the larger points. Please feel free to skip ahead to section 4 and section 7 for a discussion about the interoperability of Lua and JavaScript programs.

Loulabelle is free software, and is provided as usual with no guarantees, as stated in its license. The implementation described in this manual is available at the Loulabelle official web site, www.spaceflint.com/loulabelle.

2 – Basic Concepts

This section describes the Loulabelle implementation of the basic concepts of the Lua language.

2.1 – Values and Types

Lua types boolean, number and string are implemented as the corresponding types in JavaScript. Note that strings in JavaScript are encoded in UNICODE, while most Lua implementations support 8-bit strings. Lua nil is implemented as JavaScript undefined.

The Lua table is implemented as the following JavaScript object.

{ luatable: true, array: [], hash: new Map(), metatable: undefined, id: undefined }
luatable is a truthy value that is used in type checks, array and hash are, respectively, Array and Map JavaScript objects for the array and hash parts of the table, metatable is an optional reference to a metatable, and finally, id is only assigned if the table is passed to the tostring function, which uses an incrementing counter to simulate a unique address value for each table.

The Lua function is implemented as a JavaScript generator function, which provides a mechanism to yield execution, and in turn, to emulate synchronous execution and Lua coroutines. Because generator functions are slower than normal JavaScript functions, Loulabelle also provides the function coroutine.fastcall to call Lua functions as normal JavaScript functions, which are faster but cannot yield or suspend.

The Lua coroutine is implemented as a JavaScript object, which contains the property luacoroutine that tracks the state of the coroutine, and also participates in type checks. Other properties in this object are id which was described above, generator which references the coroutine function, status which is the status string returned by the coroutine.status library function, stack which is an array that contains the Lua call stack, and protected, which indicates execution within a pcall or xpcall scope.

While the JavaScript objects representing the Lua table and coroutine have been briefly discussed, the reader is strongly advised to interact with these objects exclusively through the Loulabelle core library, which exposes a JavaScript API, discussed in section 4.

The Loulabelle library function type behaves the same and returns the same results as its Lua namesake.

Functions in Lua may return multiple values, and this is implemented in Loulabelle by always returning an array, even if the array has no elements (which would indicate the function did not return any result).

2.2 – Environments and the Global Environment

Loulabelle assigns a property named env in each JavaScript function object, and this property references the environment table for the function. Typically, this env property references the global environment table.

A reference to the Lua variable _ENV (either implicitly or explictly) in a function is translated a reference to a local variable in JavaScript (called env) which is assigned from the env property of the same function. Note that as in Lua 5.2, references to global variables, as well as to _G (the global table), are done through the implicit _ENV variable.

The library function load can bind a function to a custom environment:

local f2 = load(string.dump(f), nil, nil, custom_env_table)
This works the same in Loulabelle, but please note a few points:

After the Loulabelle compiler has been invoked on itself to produce a JavaScript version of the compiler, and that compiled version of the compiler is executing in a JavaScript environment, it can compile a function from Lua source code while specifying a custom environment:

local compiler = require "Loulabelle"
local func, err = compiler("filename.lua", "source code text", { env = custom_env_table })

As with Lua 5.2 environments, changing the value of _ENV or _G before calling a function will not have an effect on the function, which is bound to an environment when its containing chunk is loaded. But note that unlike in Lua 5.2, the debug library in Loulabelle does not provide a mechanism to override the value of the bound _ENV.

2.3 – Error Handling

Loulabelle provides error handling facilities in the functions error, pcall, xpcall and debug.traceback, all of which work the same as in Lua 5.2.

In terms of JavaScript, error handling is implemented via JavaScript try...catch statements, and the error function throws an error string, or some other error value, depending on the parameter passed to it.

For direct invocation of a Lua function from JavaScript code, the Loulabelle xpcall API function may be used instead of the unprotected call API function, or call can just be enclosed in a JavaScript try...catch block.

2.4 – Metatables and Metamethods

Loulabelle supports Lua metatables and metamethods, with two exceptions related to garbage collection:

These facilities are not supported because JavaScript does not provide callbacks from its garbage collector, and because WeakMap is not enumerable. For similar reasons, the collectgarbage Lua library function is not provided.

As in Lua 5.2, metamethods may yield (or suspend).

2.6 – Coroutines

Loulabelle fully supports Lua coroutines. Each thread of execution, including the first loaded chunk, occurs in the context of a coroutine. This coroutine context, or coroutine object, is a JavaScript object that is accessible in Lua as an object with type "thread".

In JavaScript, the coroutine object associated with the currently-executing thread is referenced by the property co in the global runtime object. Within this coroutine object, the property main is set to a boolean true for the thread of the first loaded chunk.

In Lua code, the same object reference is returned as an opaque value by the function coroutine.running, which also returns the main boolean flag as its second result.

As well as normal coroutines, created by coroutine.create, and wrapped coroutines, created by coroutine.wrap, Loulabelle supports two more types of coroutines.

Spawned coroutines, created by coroutine.spawn, are detached from the creating coroutine, and begin execution asynchronously and independently. They are scheduled via a call to JavaScript setTimeout with a zero timeout, and should not be started explicitly.

Callback coroutines, created by coroutine.jscallback, are normal JavaScript functions (not generator functions) that can be passed to JavaScript code, or attached to browser events. When the function is executed, it creates a temporary coroutine, calls a specified Lua function, and passes its first result on to the caller.

Coroutines in Loulabelle can yield, as in Lua, via a call to coroutine.yield but can also suspend, via a call to coroutine.suspend. A suspended coroutine does not pass control back to its calling coroutine. Instead it just suspends execution, presumably while waiting for some event to occur and cause it to resume execution. For example, the coroutine.sleep function suspends the current coroutine after installing a timeout callback which calls coroutine.resume.

3 – The Language

Loulabelle strives to implement the Lua language precisely according to the Lua 5.2 specification, however there are a few minor points of difference.

3.6 – The JavaScript Statement

The JavaScript statement lets Loulabelle programs directly embed JavaScript code. The syntax of the statement is:
JavaScript("stmt_string", arg1, ...argN)

where stmt_string is a quoted string constant containing JavaScript code, with these considerations:

The identifier JavaScript is not, strictly speaking, a reserved word. It has a special meaning only in the form of a function call statement.

Example JavaScript statement:

    local context = {}
    local callback_id
    JavaScript("$1=window.requestAnimationFrame($2)",
        callback_id,
        (coroutine.jscallback(
            ::update_stack_frame::
            JavaScript("console.log('in callback')")
            function(context, timestamp)
                context.timestamp = timestamp
            end, context)))
    context.callback_id = callback_id
This example illustrates a few important points.

3.7 – Type Annotations

To account for the dynamic types in Lua, and the metamethod mechanism, the Loulabelle compiler has to generate code that checks the actual types of objects at runtime. For example, the expression a + b, when types of the local variables a and b are not known, is translated to the following:

v3 = (typeof v1 === 'number' && typeof v2 === 'number' ? v1 + v2 : yield*$lua.add(v1, v2, true));

On the other hand, if the compiler knows for certain that a and b are numbers, then the generated code is shorter and faster: v3=(v1+v2);

Using type annotations to tell the compiler to assume a specific type for expressions and local variables, enables the compiler to make the optimizations described above, and skip some type checks when generating code.

The type annoations are:

These annotations can be used around expressions, in a form similar to a function call, to annotate the type of the expression, and can also be used as a statement, to assume the type of one or more local variables (separated by commas). For example:
local a = 4                     -- type of a is number
local b = x()                   -- type of b is not known
local c = 4 + assume_number(b)  -- type of c is number
local d = y()                   -- tpye of d is not known
assume_number(b, d)             -- types of b and d are now number
local e = c + b * b             -- type of e is number

4 – The Application Program Interface

This section describes interoperability between the JavaScript environment, and any Lua code compiled by Loulabelle into JavaScript. It also includes a description of various Loulabelle API functions that are can be invoked from JavaScript code.

All API functions and properties are contained in the global runtime object $lua.

A Lua function is compiled into the following JavaScript:

$lua.func(
        function* func() {
            // JavaScript code translated from Lua source code
        },
        $lua.env,                       // or func.env
        function(s){return eval(s)},    // or undefined
        'filename.lua',                 // or func.file
        1)                              // line number
    );

$lua.func is a small utility function which stores additional properties on the function object func which is passed as the first parameter. The following properties are stored:

Note that like in Lua, a Lua source file is compiled by Loulabelle into a chunk, which is effectively a single JavaScript function that contains all the translated statements from the Lua source file:

$lua.chunk( $lua.func ( ... ) );

JavaScript scripts compiled by Loulabelle from Lua can be loaded into a JavaScript environment (such as a Web browser or Node.js) the same way that any other JavaScript script is loaded. However, the Loulabelle core library must be loaded first, to set up the global runtime object and the Lua environment.

A very simple HTML page example may look like this:

<!DOCTYPE html>
<html><head>
<script type="text/javascript" src="core.js"></script>
<script type="text/javascript" src="main.js"></script>
</head><body></body></html>

Note in this example that core.js, the Loulabelle core library, is loaded and executed first. Only then, main.js, which would be the Loulabelle JavaScript translation of a Lua chunk, is loaded.

It is not valid to load more than one chunk in this way. Lua code should use the Lua require function to load additional chunks. However, compiled chunks can be modified to start with $lua.preload_chunk, instead of $lua.chunk, and this enables preloading chunks in advance. For more on this, refer to the discussion in section 6.3.

4.8 – Functions and Properties

All functions and properties listed below are contained in the global runtime object $lua. Almost all API functions are generator functions, which means they can be invoked using the yield* expression if invoked from a generator function:

JavaScript("yield*$L.tostring(123)")

If invoked from a normal function, the JavaScript function next should be used. For example,

var str = $lua.tostring(123).next().value
Here, the Loulabelle API generator function tostring is invoked (generated) with parameter 123, and iterated once via a call to next.

call

call (name, func, arg1, ...argN)

Calls the Lua function func, passing it a variable number of parameters specified in arg1 through argN. The first parameter name is the name of the called function, as it should appear in the Lua call stack entry created for the function, or if passed as undefined, inhibits the creation of a call stack entry.

As discussed in section 3, the last parameter is checked to see if it is an array, using Array.isArray. If the check succeeds, call assumes the last parameter is an array of multiple values, and unpacks those values as additional parameters for the function call.

When using call to call functions with non-Lua JavaScript objects, it is important to keep this multiple value rule in mind. Avoid passing a JavaScript array as the last parameter. Instead, pass at least one more parameter (even undefined).

The call function returns an array that contains the results returned from the Lua function.


error

error (msg, level)

Generates an error message. If msg is a string, level specifies which call stack entry to use for decorating the error message, where 0 means the current stack entry, 1 (the default) means the calling entry, and so on. A value of -1 means to not decorate the message.


traceback

traceback (msg, level)

Generates a formatted stack trace. The parameters are similar to the parameters for error, described above, except that a value of -1 for the level parameter is not valid.


type

type (v)
Returns the type name for the Lua value v as a string (not wrapped in an array). Generates an error if the value is not a valid Lua type.

table

table (vals, n1, n2)

Creates a Lua table using the values passed in the JavaScript array vals. This array specifies both key-value pairs, and sequential values. The key-value pairs must come first, followed by the sequential values. The array may be empty, if an empty table should be created.

The parameter n1, which must be an even number, and can be zero, specifies the number of key-value pairs in the array. The parameter n2 specifies the number of sequential values in the array.

Generates an error if a key in the key-value segment of the array is NaN or undefined. Otherwise the return value is a JavaScript object that represents a Lua table. This returned object is not wrapped in an array.

As discussed in section 3, the last parameter is checked to see if it is an array, using Array.isArray. If the check succeeds, table assumes the last parameter is an array of multiple values, and unpacks those values as additional sequential values.

When using table to create a table which references non-Lua JavaScript objects, it is important to keep this multiple value rule in mind. Avoid passing a JavaScript array as the last element in the vals array. Instead, pass at least one more parameter (even undefined).

Note in the example below that n1 is specified as 10, for the first five key-value pairs, and n2 is specified as 4 for the following four sequential values.

    var t = $lua.table([
        "a",   'val_a',
        "b",   'val_b',
        "c",   undefined,
        true,  'val_true',
        false, 'val_false',
        123,
        456,
        111,
        789
    ],10,4).next().value

len

len (v)

Returns the length of the Lua value v, which may be a string or a table. May invoke the __len metamethod for a table, and generates an error for an unsupported type. Returns the length as a number, not wrapped in an array.


get

get (tbl, key, name)

Extracts the value of the key key from the table tbl. The key should be any valid value that can index into a table. May invoke the __index metamethod. May generate an error, in which case, the name parameter, if provided, is used to decorate the error message. Returns the value directly, not wrapped in an array.


set

set (tbl, key, name, val)

Sets the value of the key key in the table tbl to value val. The key should be any valid value that can index into a table. May invoke the __newindex metamethod. May generate an error, in which case, the name parameter, if provided, is used to decorate the error message. This function does not return any results.


gmt

gmt (v, typeof_v, who)

If v is a table, returns the metatable associated with the table, without respecting the __metatable property. If v is not a table, returns the shared metatable for values of the type of v, which may be passed in the parameter typeof_v, or else will be determined from v itself. The parameter who, if provided, is used to decorate the generated error. The returned table reference is not wrapped in an array.


smt

smt (v, mt)

Assigns the metatable mt for table v, if v is a table, or the shared metatable for values of the type of v. Does not respect the __metatable property. This function does not return any results, and may generate an error.


tonumber

tonumber (s)

Parses the string s as a number according the Lua rules for a numeric constant presented in section 3.1 of the Lua reference manual. Returns a number, or undefined if the string cannot be converted to a number. The return value is not wrapped in an array.


tostring

tostring (v)

Converts the value v to a string, using a __tostring metamethod if available. Where Lua generally uses the memory address of an object in order to give tables and coroutines a unique string representation, Loulabelle uses an incrementing counter to produce a similar result.

Note that when converting a number, Lua uses sprintf("%.14g"), which produces results that may differ from JavaScript conversions, whether toString or toPrecision is used. As the Lua reference manual suggests, for complete control over the output, use string.format.


next

next (tbl, key)

Given a key key in table tbl, returns the next key. If key is undefined, returns the first key. Enumeration starts with the array part of the table, then switches to the hash part. The return value is not wrapped in an array.

The iterator for next is kept as part of the table being iterated, and will be invalidated if next is invoked for a key that does not match the current key in the iterator. Avoid multiple concurrent next loops on the same table.


xpcall

xpcall (msgh, func, args_array)

Calls func in a protected scope, passing it the arguments in the JavaScript array args_array. The parameter msgh specifies the message handler generator function to invoke in case of error, and can be specified as $lua.dflt_msgh if no message handler is needed, for a pcall-like behavior rather than xpcall-like behavior.

Returns an array where the first element is a boolean that indicates if the call succeeded without errors. If true, the array also contains the zero or more results returned from the called function. If false, the array contains the error message in the second element.


cocreate

cocreate (f)

Creates a coroutine object for the function f. The coroutine is initially suspended and must be resumed before it begins executing. This function returns an array containing a single element, the coroutine object.

The coroutine object has a method resume, a normal function (not a generator), which accepts a JavaScript array of arguments, and resumes execution of the coroutine, passing it those arguments. This method does not return a value: If the resumed coroutine yields, it will itself invoke the resume method on the coroutine being yielded to, passing it the values to yield, and then return control.


coresume

coresume (co, arg1, ...argN)

Resumes coroutine co, passing it a variable number of parameters specified in arg1 through argN. Returns an array containing the values yielded by or returned from the coroutine being resumed.


cosuspend

cosuspend ()

Suspends the current coroutine, which is the coroutine object referenced by $lua.co.

Unlike a Lua yield, a suspended coroutine does not automatically cause execution to resume in another coroutine. The suspend mechanism is designed to accomodate the asynchronous nature of JavaScript. Lua code may schedule some asynchronous JavaScript operation, such as an XMLHttpRequest, suspend itself, and have the asynchronous callback resume it. For example, JavaScript code embedded in a Lua function:

JavaScript("var co=$L.co")
JavaScript("setTimeout(co.resume,5000)")
JavaScript("yield*$L.cosuspend()")

The first line saves the current coroutine, because some other coroutine may be scheduled by the time the setTimeout callback fires. The second line sets up a five second timer with a callback that resumes the current coroutine. And the third line, which can only be executed in a generator function (such as a Lua function), suspends the current coroutine. If writing non-generator JavaScript code, the third line can be rewritten as: $lua.cosuspend().next()


cowrap

cowrap (func)

Creates a function that wraps and drives a coroutine. Returns an array containing a generator function in the first element, and a coroutine object in the second element. Each invocation of the generator function causes the coroutine to resume, passing it any parameters passed to the generator function.


require_lua

require_lua (url)

In the Web browser, creates a new SCRIPT element to asynchronously load a script. In a Web worker, or in Node.js, loads the script synchronously, using importScripts or require, respectively.

The loaded script is expected to have been compiled by Loulabelle such that it contains a single call to $lua.chunk which wraps all other code in the chunk, as discussed at the top of section 4.

Returns a (generator) function representing the loaded chunk. This returned function is not wrapped in an array.


require_js

require_js (url)

In the Web browser, creates a new SCRIPT element to asynchronously load a script. In a Web worker, or in Node.js, loads the script synchronously, using importScripts or require, respectively.

Unlike require_lua, this function is intended to load non-Lua JavaScript code. There is no return value, and the invoking code should check if the script loaded successfully.


require_css

require_css (url, media)

In the Web browser, creates a new LINK element to asynchronously load a CSS file. In a Web worker, or in Node.js, this functions does not do anything. The media parameter, which defaults to the string screen if omitted, is assigned to the media property of the created element.


fastcall

fastcall (f)

This normal, non-generator JavaScript function performs a dynamic, on-the-fly recompilation of the Loulabelle-translated generator function passed in f, into a normal, non-generator JavaScript function. The new function is stored into a property named fast in the supplied function f, and then the new function is returned, not wrapped in an array.

5 – The Auxiliary Library

This section describes parameter-checking utility functions in the Loulabelle API. These are useful when writing JavaScript code which needs to validate any parameters passed to it from Lua code.


error_arg

error_arg (num, msg)

Generates this error:

bad argument #(num) to 'function' (msg)

error_argtype

error_argtype (got, num, exp)

Generates this error:

bad argument #(num) to 'function' ((exp) expected, got (got))

error_argexp

error_argexp (num, check)

If num is smaller than check, generates this error:

bad argument #(num) to 'function' (value expected)

checkstring

checkstring (arg, num)

If the arg parameter is a string, returns it. If it is a number, converts the number to a string and returns it. Otherwise calls error_argtype with num. The return value is not wrapped in an array.


checknumber

checknumber (arg, num)

If the arg parameter is a number, returns it. If it is a string that can be converted using tonumber, converts the string to a number and returns it. Otherwise calls error_argtype with num. The return value is not wrapped in an array.


checktable

checktable (arg, num)

Returns nothing if arg is a Lua table. Otherwise calls error_argtype with num.


checkfunction

checkfunction (arg, num)

Returns nothing if arg is a Lua function. Otherwise calls error_argtype with num.


checkcoroutine

checkcoroutine (arg, num)

Returns nothing if arg is a Lua coroutine. Otherwise calls error_argtype with num.

6 – Standard Libraries

This sections describes the differences in the standard library in Loulabelle compares to Lua 5.2.

6.1 – Basic Functions

Not implemented: collectgarbage, dofile, loadfile.


load (func, source, mode, env)

Clones the Lua generator function passed in func as a new generator function which will use the environment table passed in the parameter env, which can be passed as _ENV or _G for the default environment. Ignores parameters source and mode. See also section 2.2.

The function is recompiled by calling JavaScript toString() on the input function, and compiling the resulting source code using the recompiler utility function assigned to the eval property of the original function, as discussed at the top of section 4. (But note that if the function references upvalues only through JavaScript statements, the eval property will not be set, and the converted function will not compile correctly.)


next (table [, index])

The iterator used to track calls to this function is associated with the table being iterator. Concurrent iteration over different indexes will impact performance by forcing the iterator to be repeatedly invalidated. Note that functionality will not be impacted in any way. See also the next API function in section 4.8. For example, try to avoid code like this:

k1 = next(t)            -- iterator advances to second element
while k1 do
    k2 = next(t)        -- iterator restarts at first element
    while k2 do
        k2 = next(t, k2)
    end
    k1 = next(t, k1)    -- iterator restarts, positions to k1
end

In this example, the outer and inner loop share the same internal iterator, which has to be repeatedly invalidated, restated and repositioned. Prefer to use the functions pairs and ipairs, which use dedicated iterators, and are not subject to this performance issue.


print (···)

Similar to Lua print, uses tostring on all input parameters to construct an output string. See there for considerations about number conversion.

If the global printwriter is a Lua function, it is called with this function with the output string. Otherwise, the default behavior is to call JavaScript console.log with the output string.

6.2 – Coroutine Manipulation

Coroutines in Loulabelle can suspend/resume in addition to a normal Lua resume/yield combination. This is discussed in more detail in section 2.6 and in the cosuspend API function.


coroutine.spawn (f, arg1, ...argN)

Creates a coroutine and schedules it for immediate execution via a call to JavaScript setTimeout with a zero timeout. Returns the new coroutine.

Note that JavaScript is a single-threaded environment, and only one thread of JavaScript executes at the same time. (For sake of simplicity, we ignore worker threads.)

This example illustrates cooperating multithreading using asynchronous coroutines:

local main = coroutine.running()
local f = function(three, four, six)
    print (three)
    coroutine.resume(main)
    print (four)
    coroutine.suspend()
    print (six)
end
print '#1'
local co = coroutine.spawn(f, '#3', '#4', '#6')
print '#2'
coroutine.suspend()
print '#5'
coroutine.resume(co)

The output is #1 #2 #3 #4 #5 #6. Note that spawn or resume do not immediately cause another thread to run. The currently-running thread (whichever one it is) must suspend itself before any other thread can run.


coroutine.suspend ()

Suspends the current coroutine. Unlike a Lua yield, a suspended coroutine does not automatically cause execution to resume in another coroutine. The suspend mechanism is designed to accomodate the asynchronous nature of JavaScript. Lua code may schedule some asynchronous JavaScript operation, such as an XMLHttpRequest, suspend itself, and have the asynchronous callback resume it. See also the cosuspend API function.

Note that some care should be taken when one coroutine may be resumed by more than one callback at the same time. For example, if the same suspended coroutine can be resumed either by a button click or an XMLHttpRequest callback, the coroutine may need some way to identify which callback caused it to resume.


coroutine.sleep (ms)

Suspends execution of the current coroutine for a duration of ms milliseconds, using the JavaScript setTimeout function.


coroutine.status (co)

The only difference from the standard Lua function of the same name is that this function may also return the status asyncwait which indicates the coroutine has suspended itself using coroutine.suspend or cosuspend. Note that a status of suspended, as in Lua, indicates the coroutine has not started running yet, or has called yield.


coroutine.wrap (f)

The only difference from the standard Lua function of the same name is that this function also returns the coroutine object as a second result.

coroutine.jscallback (func, arg1, ...argN)

Creates a callback coroutine, as discussed in section 2.6. and see also the example in section 3.6.

JavaScript callbacks are typically normal functions, whereas Loulabelle-translated Lua functions are generator functions. The jscallback function makes it simple to connect Lua functions to JavaScript callbacks, as shown in the example in section 3.6.

The returned function is normal JavaScript function (not generator functions) which acts as the callback wrapper. When this wrapper is called, it creates a temporary coroutine with the call stack at the point of the call to jscallback. Then the Lua function is called in the context of the temporary coroutine. The Lua function receives the parameters passed to jscallback as well as any parameters passed in the invocation of the callback wrapper.

The first result from the Lua function is returned to the caller of the callback wrapper. Note that if the Lua function yields or suspends, instead of returning, this also returns control to the callback wrapper, but in this case, nothing is returned to the caller of the callback wrapper.

Note that the temporary coroutine created for the duration of the callback is not subject to a pcall or xpcall protected scope that was established during the creation of the callback, i.e. when jscallback was called.


coroutine.jsconvert (jsobj, luatbl)

This function converts between Lua tables and JavaScript objects and vice versa. It is not directly related to coroutine management.

If jsobj is nil, the function recursively traverses the Lua table in luatbl and constructs a JavaScript object that contains all boolean, number and string values in the table, and any tables referenced by it. Values in any other type are ignored.

If jsobj is not nil, the function recursively traverses the JavaScript object and populates the Lua table luatbl with the properties from the JavaScript object.

This function may make non-Lua JavaScript objects accessible to the Lua caller of this function. Be advised that using Lua functions such as tostring or type on non-Lua objects may generate various forms of the error: unexpected type in getmetatable.


coroutine.mutex ()

Returns a mutex table object which can be used to synchronize between threads. The object provides the following methods:

All methods expect a single parameter, the mutex table object, and can be invoked using the Lua colon syntax for method calls.


coroutine.fastcall (func, arg1, ...argN)

Performs a dynamic, on-the-fly recompilation of the Lua function func, into a normal, non-generator JavaScript function. In many JavaScript engines, JavaScript generator functions do not enjoy the same JavaScript JIT compiler optimizations that are available to non-generator functions. The fastcall mechanism makes it possible to optimize specific Lua functions that require higher performance.

The converted, "fast" version of the function is cached for future invocations, by storing it in the fast property of the function object. Any function called by func will also be fastcall-converted and cached: This is done by converting any call to function fn with a call to function fn.fast instead. As discussed at the top of section 4, this fast property is initially a utility function that fastcall-converts the function, and overwrites the fast property with the converted function.

Note that functions converted by fastcall cannot use any asynchronous features that depend on generators, such as coroutines and require.

The fastcall recompiler works by calling JavaScript toString() on the input function. Then, under the assumption that the function was created by Loulabelle, rewrites yield* expressions as direct function calls. Finally, the converted function is recompiled using the recompiler utility function assigned to the eval property of the original function, as discussed at the top of section 4. (But note that if the function references upvalues only through JavaScript statements, the eval property will not be set, and the converted function will not compile correctly.)

6.3 – Modules

As in Lua, the require function is provided in the global environment. The package table provides only two fields: package.loaded which caches (or can be used to preload) modules, and package.Loulabelle which is the Loulabelle version number and set to 5203.


require (modname)

Invokes require_lua to load a script file from a relative URL that is composed of modname concatenated with the suffix .js.

The script is loaded and executed, and per the discussion in section 4 and in require_lua, the script is expected to contain a single call to $lua.chunk, which makes the loaded chunk accessible to Loulabelle.

The loaded chunk is then called, and its result is recorded in the package.loaded table, and returned to the caller.

A chunk may be preloaded in advance of a call to require, by replacing the call to $lua.chunk with a call to $lua.preload_chunk.

At the top of the compiled chunk, instead of:

$lua.chunk( $lua.func ( ... ) );

Change to:

$lua.preload_chunk('new_chunk_name', $lua.func ( ... ) );

Preloading can also be used to bundle several chunks into one file, and change chunk names. The Loulabelle compiler itself makes use of this technique; see the build.sh example in the Loulabelle compiler folder.

6.4 – String Manipulation

Strings in Loulabelle are JavaScript strings, encoded in UNICODE, while most Lua implementations support 8-bit strings.

string.format in Loulabelle supports only 20 digits of precision in the various floating point number formats, as opposed to 99 digits in Lua.

Patterns and Regular Expressions

Loulabelle does not support Lua patterns. Instead, the full JavaScript regular expression engine is available for use anywhere that a Lua pattern can be used. To use a regular expression string, wrap it in a call to string.regex. For example:

local pattern = string.regex("([A-Z])([a-z]*)")
local iterator = string.gmatch("Quick Brown Fox", pattern)
while true do
    local cap1, cap2 = iterator()
    if cap1 then print (cap1, cap2) else break end
end

If you limit the use of patterns and regular expressions to only those features common to both, then the following polyfill can be used in programs that have to run under Lua as well as Loulabelle.

string.regex = string.regex or function(s) return s end

string.dump (f)

Returns the input function f. This is merely intended to maintain compatibility with Lua code that uses the result of string.dump in a call to load, as in the example in section 2.2.


string.regex (s)

Records the regular expression s in the table of known regular expressions, for use by one of the pattern functions: string.find, string.match, string.gmatch, and string.gsub.


string.index (haystack, needle, init)

Searches for the string needle in string haystack, optionally starting at position init (default is 1). Returns the index of occurence, or nil if not found.

Unlike the init parameter to string.find, negative positions do not count back from the end of the string.

The search is done using the JavaScript function indexOf.


string.rindex (haystack, needle, init)

Searches backwards for the string needle in string haystack, optionally starting at position init (default is #haystack) and going back towards the beginning of the string. Returns the index of occurence, or nil if not found.

Unlike the init parameter to string.find, negative positions do not count back from the end of the string.

The search is done using the JavaScript function lastIndexOf.


string.startswith (string, prefix, index)

Checks if string, starting at position index (default to 1), starts with the sub-string #prefix.

The check is done using the JavaScript function startsWith.


string.endswith (string, suffix, length)

Checks if string, of length length (default to #string), ends with the sub-string #suffix.

The check is done using the JavaScript function endsWith.


string.trim (s)

Returns the string s with whitespace removed from both ends of the string.

Uses JavaScript function trim.


string.ltrim (s)

Returns the string s with whitespace removed from the left end of the string.

Uses JavaScript function trimLeft.


string.rtrim (s)

Returns the string s with whitespace removed from the right end of the string.

Uses JavaScript function trimRight.

6.9 – Operating System Facilities

Loulabelle provides only a few functions in the os library, and even those provide limited functionality.

os.clock ()

Returns a time value measured in seconds. Note that unlike the os.clock function in Lua, this is not CPU time. Uses performance.now() in the browser, and process.hrtime in Node.js.


os.date (format, time)

The only formats supported are "*t" to return the results in a table (in which the field isdst is always false), or "%c" (the default) to return a full date string. The format string may optionally start with '!' to select UTC time rather than local time.


os.time ([table])

If the field isdst in the table is true, the time zone difference from UTC is added to the result. This is not necessarily desired or correct.


os.setlocale (locale, category)

Sets the current locale for the string collator, which is initially set to a default JavaScript Intl.Collator object. Therefore category can only be specified as "all" or "collate", if not omitted. The locale is passed to the Intl.Collator constructor. This function does not return the current locale.

6.10 – The Debug Library

Loulabelle provides only a few functions in the debug library:

debug.getmetatable, debug.setmetatable, and debug.traceback.

7 – Loulabelle Compiler

7.1 – Command Line Compiler

The compiler is composed of several Lua modules that can be found in the compiler folder. To invoke the compiler, you may need to set the LUA_PATH environment variable to include the compiler folder.
export LOULABELLE=~/Loulabelle/compiler
export LUA_PATH=$LOULABELLE/?.lua
lua $LOULABELLE/main.lua [options] inputfile
The options are:

The source Lua program is read from inputfile if specified, otherwise from standard input. The compiled JavaScript program is written to standard output.

7.2 – The Compiled Compiler

The build.sh shell script in the compiler folder combines the various modules that make up the compiler into a single Loulabelle.js file. This compiled compiler can be preloaded into a web application:
<!DOCTYPE html>
<html><head>
<script type="text/javascript" src="core.js"></script>
<script type="text/javascript" src="Loulabelle.js"></script>
<script type="text/javascript" src="webapp.js"></script>
</head><body></body></html>

In this example, webapp.js is the compiled form of webapp.lua, which might contain the following Lua code:

local Loulabelle = require "Loulabelle"
local chunk_text = "print (_VERSION)"
local chunk_name = 'test.lua'
local func, err = Loulabelle(chunk_name, chunk_text, { env = _G, debug=true })
if not err then func() end
The third parameter to the compiler is a table of options:


Last update: May 2018