Package Exports
- lua-vm
- lua-vm/dist/index.js
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (lua-vm) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
LUA VM: lua interpreter in TypeScript
LuaVM is a safe, sandboxed Lua interpreter implemented in TypeScript. It is designed to be easily embedded in TypeScript/JavaScript applications or web environments (also referred to as host systems).
The virtual machine executes Lua code without any ability to access or affect the host environment. There are no escape hatches: Lua code cannot invoke arbitrary host functions or manipulate memory outside the VM. There is no DOM access.
Design Philosophy
The host system controls the entire lifecycle of Lua code execution. A typical usage pattern looks like this:
- Initialize the VM
- Create a new VM instance.
- Set up the initial memory state (e.g., define global variables or register host-provided functions).
- Execute Lua Code
- Provide a Lua source string.
- Set an upper limit on the number of instructions to guard against infinite loops.
- Access Results
- After execution, inspect return values or query the VM’s memory state (e.g., read variable values).
Architecture
At its core, LuaVM consists of a pure interpreter that operates on an abstract syntax tree (AST) generated from Lua code. It uses a plain TypeScript map to store runtime variables.
- The interpreter is fully isolated from the host environment.
- It does not access the DOM, browser APIs, or any external resources.
- The interpreter is wrapped by a higher-level VM layer that simplifies integration into host applications.
This strict separation ensures safe and predictable behavior in embedded contexts like browsers, games, or Node.js scripts.
Features
- Set variables in the Lua VM before execution.
- Read variables after execution completes.
- Provide external (TypeScript/JavaScript) functions callable from Lua.
- Enforce a configurable instruction limit to prevent infinite loops (10k is the default).
- Optionally include a subset of standard Lua library functions.
- Supported Types: nil, boolean, number, string, function, and table.
- All LuaVM values are TypeScript-wrapped primitives; behavior is aligned with JS semantics.
Limitations
- Unsupported Features:
- userdata, thread, and coroutines
- Metatables
- Closures
- Attributes
Concept
VMBuilder: Creating a Virtual Machine
The VMBuilder
class is the entry point for constructing a Lua VM instance.
- Create a basic VM:
const vm = new VMBuilder().build();
- Create a VM with a subset of Lua standard library functions:
const vm = new VMBuilder().withStdLib().build();
- Limit running time:
const vm = new VMBuilder().withRunCredit(10).withStdLib().build();
A VM instance created via VMBuilder
acts as a container for execution threads. These threads are not concurrent or parallel (LuaVM does not support real multithreading); instead, they represent independent memory contexts. This design allows you to run multiple isolated Lua programs using a single VM instance.
VM-Level Variable Management
- Set a global variable available to all threads:This variable will be visible in all threads created from this VM.
vm.setLuaVar(StringValue.from("varName"), NumberValue.from(42));
Note: If you assign a
TableValue
, it is passed by reference. This allows threads to communicate via shared tables. If isolation is required, consider setting variables at the thread level instead.
One-Off Execution
- Execute Lua code in a temporary thread and get the result:This is a shortcut that internally creates a thread, executes the code, and returns the result.
const result = vm.executeOnce("return 1 + 2");
Threads: Isolated Execution Contexts
- Create a new thread:
const thread = vm.newThread();
A thread is an isolated environment with its own memory. It is not a system thread or a parallel task. All Lua variables for this execution context reside within the thread’s memory.
Set a thread-specific variable:
thread.setLuaVar(StringValue.from("varName"), NumberValue.from(100));
Execute Lua code in a thread:
const result = thread.execute("return 45*10");
- Threads retain memory between executions.
- You can call
execute(...)
multiple times with different code snippets. - The host system can inspect or modify memory using
getLuaVar
andsetLuaVar
between executions.
Accessing Execution Results
An execution result provides information about the outcome of Lua code:
if (result.hasReturnValue()) {
const values = result.returnValueAsList(); // A TypeScript array (0-based index)
}
- Access global variables after execution:
const message = result.globalVar("message");
Working with LuaVM Types
All values exchanged between the host system and the VM must use LuaVM types, which are lightweight wrappers around TypeScript primitives:
NilValue
BooleanValue
NumberValue
StringValue
TableValue
FunctionValue
ExtFunction
(for host-defined functions)
🧪 Example: Creating Lua-compatible values
const count = NumberValue.from(42);
console.log(count.number); // 42
Function Support in LuaVM
LuaVM supports functions as first-class values, with two distinct types representing them:
FunctionValue
Represents a function defined within the Lua code itself.
- This type is created internally by the VM when Lua code declares a function.
- In most cases, the host system should not need to create or manipulate
FunctionValue
instances directly.
ExtFunction
Represents an external (host-defined) function exposed to the Lua runtime.
- Use this type to inject TypeScript/JavaScript functions into the Lua environment.
- These functions can be used to extend the capabilities of Lua code, for example to interact with APIs, custom logic, or host-specific resources.
Coding Examples
Explore the following files and directories for usage patterns and integration ideas:
General VM usage (setting/getting variables, error handling):
tests/vm.test.tsUsing external (host-provided) functions:
tests/vmfun.test.tsWriting custom external functions:
src/stdlib/*Embedding LuaVM in a web page:
demo.html
📦 Installation
As an NPM Package (for Node.js/TypeScript projects):
npm install lua-vm
import {
VMBuilder,
Value,
NumberValue,
StringValue,
ExtFunction } from 'lua-vm';
function add(args: Value[]): Value[] {
const a = args[0] as NumberValue;
const b = args[1] as NumberValue;
return [NumberValue.from(a.number + b.number)];
}
const lua = `
a = 2
return a*b, add(a, b)
`;
const vm = new VMBuilder().build();
vm.setLuaVar(StringValue.from("b"), NumberValue.from(3));
vm.setLuaVar(StringValue.from("add"), ExtFunction.of(add));
const result = vm.executeOnce(lua);
const resultAsList = result.returnValueAsList();
const r1 = (resultAsList[0] as NumberValue).number;
const r2 = (resultAsList[1] as NumberValue).number;
console.log(r1);
console.log(r2);
As a JavaScript Library (for use in web apps):
- Download the latest
lua-vm.js
from GitHub Releases. - OR build it from source:
npm run buildjs
- See demo.html for an example of integration in a browser environment.
STDLIB
The StdLib is a curated subset of Lua’s standard library, reimplemented as ExtFunctions in TypeScript.
These functions are designed to be safe and sandboxed—they do not access the host environment (no DOM, no browser APIs, no external side effects).
As a reminder, LuaVM types are lightweight wrappers around native TypeScript types. Many functions in the StdLib are simply proxy calls to underlying TypeScript implementations, adapted to work seamlessly with LuaVM’s type system and execution model.
Feel free to browse the src/stdlib directory for examples and inspiration for building your own ExtFunctions.
License
MIT