Download
Clone the source repository:
git clone https://github.com/lus-lang/microlua.git
cd microlua
You can also download a source archive from the repository host and unpack it locally. The build instructions below assume that the current directory is the MicroLua source tree.
Compile
MicroLua uses Meson and Ninja. A debug build allows libc in the core and is the usual build for development:
meson setup builddir
ninja -C builddir
A release build compiles the core static library in freestanding mode:
meson setup builddir-release --buildtype=release
ninja -C builddir-release
In release mode, the core library is compiled with freestanding flags. The command-line executable still uses libc for file and console I/O.
For embedded systems that should not carry the source parser, build a bytecode-only runtime:
meson setup build-bytecode -Dcompiler=false --buildtype=release
ninja -C build-bytecode
The bytecode-only library omits the lexer and parser. It accepts
precompiled MicroLua bytecode through MLuaLoadBytecode,
MLuaDoBytecode, MLuaLoadBuffer, or
MLuaDoBuffer.
Port Configuration
Port settings live in src/MLuaConfig.h. Use
-Dport=generic64, generic32,
cortex-m, or riscv32 for bundled presets,
or provide a board-specific header:
meson setup build-board -Dport_header=path/to/my_board_mlua.h
A port header can override pointer size, heap alignment, default stack and frame sizes, GC threshold, math hooks, and compiler support.
Build Outputs
builddir/mlua- The command-line interpreter and REPL.
builddir/libmicrolua.a- The embeddable MicroLua static library.
builddir-release/libmicrolua.a- The freestanding release static library.
build-bytecode/mlua- The bytecode-only command-line runner.
build-bytecode/libmicrolua.a- The embeddable bytecode-only static library without the lexer or parser.
Use
Command Line
./builddir/mlua script.lua
./builddir/mlua
./builddir/mlua -e 'print(1 + 2 * 3)'
./builddir/mlua -o chunk.mlu script.lua
./build-bytecode/mlua chunk.mlu
Running mlua with no file starts the interactive REPL.
The REPL evaluates one line as one chunk, so local variables do not
persist across lines. Put multi-line programs in a file.
Use -o on a compiler-enabled host build to create a
portable .mlu bytecode file. Bytecode has a versioned
header with an explicit endianness byte and fixed-width serialized
fields, so it can be moved across supported endian and pointer-size
targets with a compatible MicroLua bytecode version and numeric
format.
Options
| Option | Meaning |
|---|---|
-h, --help |
Show command-line help. |
-e EXPR, --eval EXPR |
Evaluate a source chunk supplied on the command line. Requires a compiler-enabled build. |
-i, --interactive |
Enter interactive mode. Requires a compiler-enabled build. |
-I FILE, --include FILE |
Include a file through the REPL's require support. Requires a compiler-enabled build. |
-d, --dump |
Print memory usage statistics. |
--memory-limit N |
Run with a heap limited to N bytes. |
--no-column |
Omit column information from debug output. |
-o FILE |
Compile a source file or -e chunk and write MicroLua bytecode to FILE. Requires a compiler-enabled build. |
-v, --version |
Print version information. |
Small Example
local total = 0
for i = 1, 10 do
total = total + i
end
print(total)
Embed MicroLua
Link your application with libmicrolua.a and include the
headers from src/. The core can run on a caller-provided
heap and does not require libc in the freestanding release build.
The embedder controls host integration. Output and module loading are available only when the embedder installs callbacks.
MLuaSetOutput- Installs the callback used by functions such as
printanderror. MLuaSetRequirer- Installs the callback used by
require.
Optional io, os, dofile, and
loadfile support lives in src/extensions/MLuaStdLib.c
and requires libc.
A common embedded workflow is to compile source on a development host
with mlua -o app.mlu app.lua, include the resulting bytes
in firmware or external storage, then call MLuaDoBytecode
or MLuaLoadBytecode on the target. A bytecode-only build
rejects source-only workflows such as -e, the REPL,
load, and loadfile.
Documentation
Language
MicroLua follows Lua syntax where that syntax fits its footprint.
Supported statements include local declarations, assignments,
function definitions, if, while,
repeat, numeric for, generic
for, do blocks, break, and
return.
Supported values include nil, booleans, numbers, strings,
tables, functions, C functions, and coroutines. Strings and source
files are UTF-8. Numeric literals keep the Lua 5.3 integer/float
distinction: math.type(1) is "integer" and
math.type(1.0) is "float".
Supported operators include arithmetic +, -,
*, /, %, exponentiation
^, length #, concatenation ..,
comparisons, and, or, and not.
Functions support lexical closures, upvalues, varargs, multiple return
values, and proper tail calls for plain return f(...)
style calls.
Tables
Tables have an array part and a hash part. Array keys must remain
contiguous: assigning a value past #t + 1 is a runtime
error because it would create a hole. Assigning nil past
the end is a no-op.
MicroLua does not have metatables. It provides table.forward
as a small table-delegation mechanism for lookup forwarding.
Base Globals
| Function | Arguments | Returns | Description |
|---|---|---|---|
assert | v: any [, message: string] | All original arguments, or raises an error. | Checks that v is not false or nil. If the check fails, raises message or "assertion failed!". |
error | message: string | Does not return. | Raises a runtime error using the string value of message, or "error" when no string is supplied. |
load | chunk: string [, chunkname: string [, mode: string [, env: any]]] | Compiled function, or nil, message. | Compiles a string chunk. MicroLua accepts the extra Lua-style parameters but only uses the chunk name. |
loadstring | chunk: string [, chunkname: string [, mode: string [, env: any]]] | Compiled function, or nil, message. | Alias of load. |
next | table: table [, key: any] | next_key, value, or nil. | Returns the next key and value after key. Pass nil or omit key to start iteration. |
pairs | table: table | iterator, table, nil. | Returns a generic-for iterator triple using next. |
ipairs | table: table | iterator, table, 0. | Returns a generic-for iterator triple over array indices starting at 1. |
pcall | func: function, ...: any | true, ... on success; false, message on error. | Calls func in protected mode with the remaining arguments. |
select | index: integer|string, ...: any | Selected values, a count, or no values. | If index is "#", returns the number of extra arguments. Otherwise returns arguments from the numeric index onward; negative indices count from the end. |
tonumber | value: number|string [, base: integer] | Number, or nil. | Converts numbers or numeric strings. Base conversion is supported for integer strings. |
tostring | value: any | String. | Converts a value to its string representation. |
type | value: any | String. | Returns the MicroLua type name. |
xpcall | func: function, handler: function | true, ... on success; false, handled_error on error. | Protected call that invokes handler with the error value when func fails. |
print | ...: any | No values. | Writes tab-separated values through the embedder output callback. Available when the embedder installs output support; the REPL does. |
require | name: string | Module result. | Loads a module through the embedder requirer callback. Available only when that callback is installed; the REPL installs one. |
unpack | table: table [, i: integer [, j: integer]] | Values table[i] through table[j]. | Global compatibility alias of table.unpack. |
math
| Function | Arguments | Returns | Description |
|---|---|---|---|
math.abs | x: number | Number. | Absolute value. |
math.acos | x: number | Number. | Arc cosine in radians. |
math.asin | x: number | Number. | Arc sine in radians. |
math.atan | y: number [, x: number] | Number. | Arc tangent. With two arguments, uses atan2(y, x). |
math.atan2 | y: number [, x: number] | Number. | Alias of math.atan in MicroLua. |
math.ceil | x: number | Number. | Smallest integer not less than x. |
math.cos | x: number | Number. | Cosine of x radians. |
math.cosh | x: number | Number. | Hyperbolic cosine. |
math.deg | x: number | Number. | Converts radians to degrees. |
math.exp | x: number | Number. | Returns e raised to x. |
math.floor | x: number | Number. | Largest integer not greater than x. |
math.fmod | x: number, y: number | Number. | C-style floating remainder of x / y. |
math.frexp | x: number | mantissa, exponent. | Splits x into a normalized fraction and exponent. |
math.ldexp | mantissa: number, exponent: integer | Number. | Returns mantissa * 2^exponent. |
math.log | x: number [, base: number] | Number. | Natural logarithm, or logarithm in the supplied base. |
math.log10 | x: number | Number. | Base-10 logarithm. |
math.max | ...: number | Number, or nil when called without arguments. | Maximum numeric argument. |
math.min | ...: number | Number, or nil when called without arguments. | Minimum numeric argument. |
math.mod | x: number, y: number | Number. | Alias of math.fmod. |
math.modf | x: number | integer_part, fractional_part. | Splits a number into integer and fractional parts. |
math.pow | x: number, y: number | Number. | Returns x raised to y. |
math.rad | x: number | Number. | Converts degrees to radians. |
math.random | [m: integer [, n: integer]] | Number or integer. | With no arguments, returns a float in [0, 1). With one argument, returns an integer in [1, m]. With two, returns an integer in [m, n]. |
math.randomseed | seed: integer | No values. | Seeds MicroLua's xorshift64 pseudo-random generator. Seed zero is changed to one. |
math.sin | x: number | Number. | Sine of x radians. |
math.sinh | x: number | Number. | Hyperbolic sine. |
math.sqrt | x: number | Number. | Square root. |
math.tan | x: number | Number. | Tangent of x radians. |
math.tanh | x: number | Number. | Hyperbolic tangent. |
math.tointeger | x: number | Integer, or nil. | Returns x as an integer if it is exactly representable as a MicroLua integer. |
math.type | x: any | "integer", "float", or nil. | Reports whether a number is stored as an integer or float. |
math.ult | a: integer, b: integer | Boolean. | Unsigned less-than comparison of two integer values. |
Available constants:
pi, huge, maxinteger, and
mininteger.
string
string.len, string.sub,
string.byte, string.char, and
string.reverse operate on codepoints. Pattern matching is
byte-based, and case conversion is ASCII-only.
| Function | Arguments | Returns | Description |
|---|---|---|---|
string.byte | s: string [, i: integer [, j: integer]] | Codepoints from i through j. | Returns UTF-8 codepoints at codepoint positions. Negative indices count from the end. |
string.char | ...: integer | String. | Encodes up to 256 numeric codepoints as UTF-8. |
string.dump | func: function | Bytecode string, or nil, message. | Serializes a Lua closure in MicroLua bytecode format. C functions cannot be dumped. |
string.find | s: string, pattern: string [, init: integer [, plain: boolean]] | start, end [, captures...], or nil. | Finds a byte-position match. With plain truthy, searches for literal text. Otherwise uses MicroLua patterns. |
string.format | format: string, ...: any | String. | Formats values into a bounded buffer using MicroLua's formatter. |
string.len | s: string | Integer. | Returns the number of UTF-8 codepoints. |
string.lower | s: string | String. | ASCII-only lowercase conversion. Non-ASCII bytes are preserved. |
string.match | s: string, pattern: string [, init: integer] | Captures, whole match, or nil. | Matches a MicroLua pattern. Captures are returned when present; otherwise the matched substring is returned. |
string.pack | format: string, ...: integer|string | Binary string. | Packs values using supported format codes: b, B, h, H, i, I, l, L, n, N, cN, z, and ignored endian markers. |
string.packsize | format: string | Integer, or nil, message. | Returns the static packed size for fixed-size formats. Variable-length s and z formats return nil, message. |
string.rep | s: string, n: integer | String. | Repeats s n times. Non-positive counts return an empty string. |
string.reverse | s: string | String. | Reverses the sequence of UTF-8 codepoints. |
string.sub | s: string [, i: integer [, j: integer]] | String. | Returns a codepoint-indexed substring. Negative indices count from the end. |
string.unpack | format: string, data: string [, pos: integer] | Unpacked values followed by next position. | Unpacks values from data starting at 1-based byte position pos. |
string.upper | s: string | String. | ASCII-only uppercase conversion. Non-ASCII bytes are preserved. |
Supported pattern features include anchors ^ and
$, classes such as %a, %d,
%s, %w, %l, %u,
%p, %c, and %x, character
sets, captures, and the *, +,
-, and ? quantifiers.
table
| Function | Arguments | Returns | Description |
|---|---|---|---|
table.concat | table: table [, sep: string [, i: integer [, j: integer]]] | String. | Concatenates array entries from i through j, placing sep between entries. |
table.forward | table: table, forward: table|nil | No values. | Sets MicroLua's table lookup forwarding target. This is the small substitute for metatable __index. |
table.insert | table: table, value: any or table: table, pos: integer, value: any | No values. | Inserts at the end or at pos. Positions outside 1..#table+1 are errors because they would create holes. |
table.maxn | table: table | Number. | Returns the largest positive numeric key present in the table, or zero for non-tables/no numeric keys. |
table.pack | ...: any | Table. | Returns a table containing the arguments at integer keys and an n field with the argument count. |
table.remove | table: table [, pos: integer] | Removed value, or nil. | Removes and returns the entry at pos, defaulting to the last array entry, then shifts later entries down. |
table.sort | table: table [, comp: function] | No values. | Sorts the array part in place. comp(a, b), when supplied, should return true when a comes before b. |
table.unpack | table: table [, i: integer [, j: integer]] | Values table[i] through table[j]. | Returns array entries from i through j. Negative or zero starts are clamped to one; inverted ranges return no values. |
table.pack and table.unpack follow the
Lua 5.2 naming. unpack is also available as a global
compatibility alias.
coroutine
| Function | Arguments | Returns | Description |
|---|---|---|---|
coroutine.close | co: coroutine | true, or false, message. | Closes a suspended or dead coroutine and drops its saved state. Closing a running coroutine is an error. |
coroutine.create | func: function | Coroutine. | Creates a suspended coroutine that will run func. |
coroutine.isyieldable | No arguments. | Boolean. | Returns true inside a coroutine when not crossing a C-call boundary. |
coroutine.resume | co: coroutine, ...: any | true, ... on success/yield; false, message on error. | Starts or resumes co, passing the remaining arguments into the coroutine. |
coroutine.running | No arguments. | co, false inside a coroutine; nil, true on the main thread. | Reports the currently running coroutine and whether execution is on the main thread. |
coroutine.status | co: coroutine | String. | Returns "suspended", "running", "normal", or "dead". |
coroutine.yield | ...: any | Resume arguments when the coroutine is resumed again. | Suspends the current coroutine and transfers the arguments to its resumer. |
Coroutines can yield from nested Lua calls. Yielding across a C-call boundary is an error.
Optional io and os
These are not part of the freestanding core. They are available in the
REPL build through src/extensions/MLuaStdLib.c.
| Function | Arguments | Returns | Description |
|---|---|---|---|
io.close | file: file | Boolean. | Closes a file handle created by io.open. |
io.lines | file: file | iterator, file, nil. | Returns an iterator triple that reads lines from a file handle. |
io.open | path: string [, mode: string] | File handle, or nil, message. | Opens a file with the supplied C fopen mode, defaulting to read mode. |
io.read | [format: string] | Read value, or no value at EOF. | Reads from standard input. Supported formats include line, *l, *L, *n, and *a. |
io.write | ...: any | No values. | Writes values to standard output. |
file:read | [format: string] | Read value, or no value at EOF. | Reads from an opened file handle using the same formats as io.read. |
file:write | ...: any | The file handle. | Writes values to the file and returns the handle for chaining. |
file:close | self: file | Boolean. | Closes the file handle. |
file:lines | self: file | iterator, file, nil. | Returns an iterator triple over lines in the file. |
os.clock | No arguments. | Number. | Returns CPU time in seconds according to the host C library. |
os.date | [format: string] | String or table. | Formats the current local time. "*t" returns a table with date/time fields. |
os.exit | [code: integer] | Does not return. | Terminates the host process with the integer exit code, or zero. |
os.getenv | name: string | String, or nil. | Returns the value of an environment variable. |
os.time | No arguments. | Number. | Returns the current time as a host timestamp. |
dofile | path: string | All chunk return values. | Loads and executes a file. |
loadfile | path: string | Compiled function, or nil, message. | Loads and compiles a file without executing it. |
Limitations
- MicroLua is not a drop-in replacement for every Lua program.
- C functions are light C functions and do not have upvalues.
- Function environments are not supported;
setfenvandgetfenvare absent. collectgarbageis absent.- Metatables are absent;
setmetatable,getmetatable,rawequal,rawget, andrawsetare absent. coroutine.wrapis absent.string.gsubandstring.gmatchare absent.- The package library,
LUA_PATH, andLUA_CPATHbehavior are absent. - Table arrays reject holes by design.
- Integer arithmetic uses MicroLua's 32-bit integer behavior.
Tests and Benchmarks
Run all tests in a debug build:
meson test -C builddir
Run the freestanding release suite, including the libc-free symbol guard:
meson test -C builddir-release
Run only interpreter, smoke, guard, CLI, or security suites:
meson test -C builddir --suite interpreter
meson test -C builddir --suite smoke
meson test -C builddir --suite bytecode
meson test -C builddir --suite guard
meson test -C builddir --suite cli
meson test -C builddir --suite security
Compare MicroLua against a local Lua 5.5 binary:
python3 bench/bench.py
python3 bench/bench.py --quick
The benchmark checks byte-identical output before reporting timing, native heap, and binary-size results. It skips cleanly when Lua 5.5 is not available.
Compatibility Reference
MicroLua intentionally selects a small subset and a few later additions from Lua. For background on standard Lua behavior, see the official manuals at lua.org/manual. This page documents only the features implemented by MicroLua.