A lightweight Swift wrapper for Lua with optional extensions for scientific computing, data formats, and visualization.
LuaSwift embeds the Lua scripting language in iOS and macOS applications. The core wrapper is lightweight and dependency-free, bundling the complete Lua source for App Store compliance. Optional extensions add scientific computing, data formats, and visualization capabilities.
- iOS 15.0+ / macOS 12.0+
- Swift 5.9+
- Xcode 15.0+
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/ChrisGVE/LuaSwift.git", from: "1.4.0")
]Or in Xcode: File → Add Package Dependencies → Enter the repository URL.
Full API reference and module documentation: docs/index.md
Quick links: Core API · Value Servers · Callbacks · Modules
import LuaSwift
// Create sandboxed engine (default: Lua 5.4)
let engine = try LuaEngine()
// Evaluate Lua code
let result = try engine.evaluate("return 1 + 2")
print(result.numberValue!) // 3.0
// Expose Swift data to Lua
class AppData: LuaValueServer {
let namespace = "App"
func resolve(path: [String]) -> LuaValue {
path.first == "version" ? .string("1.0") : .nil
}
}
engine.register(server: AppData())
let version = try engine.evaluate("return App.version")// Install all modules
ModuleRegistry.installModules(in: engine)
// Extend standard library with LuaSwift enhancements
try engine.run("luaswift.extend_stdlib()")
// Use from Lua
try engine.run("""
-- Standard library extensions work seamlessly
local s = string.capitalize("hello world") -- "Hello world"
local keys = table.keys({a=1, b=2}) -- {"a", "b"}
-- Math submodules are available
local m = math.linalg.matrix({{1, 2}, {3, 4}})
local z = math.complex.new(3, 4)
local v = math.geo.vec3(1, 2, 3)
-- Data parsing
local data = json.decode('{"x": 1, "y": 2}')
-- Arrays (standalone module)
local a = array.zeros({3, 3})
""")LuaSwift bundles Lua 5.1.5, 5.2.4, 5.3.6, 5.4.7, and 5.5.0. Default is 5.4.
LUASWIFT_LUA_VERSION=55 swift build # Lua 5.5
LUASWIFT_LUA_VERSION=51 swift build # Lua 5.1| Version | Env Value | Notes |
|---|---|---|
| 5.4.7 | 54 (default) |
Recommended for new projects |
| 5.5.0 | 55 |
Latest, experimental features |
| 5.3.6 | 53 |
Integer subtype support |
| 5.2.4 | 52 |
Goto, bit32 library |
| 5.1.5 | 51 |
Maximum compatibility |
These modules extend Lua's built-in libraries. After calling luaswift.extend_stdlib(), their functions are available directly on string, table, and utf8.
| Module | Extends | Key Functions |
|---|---|---|
| stringx | string |
capitalize, trim, split, join, startswith, endswith, replace |
| tablex | table |
keys, values, map, filter, reduce, merge, deepcopy |
| utf8x | utf8 |
sub, reverse, upper, lower, width (CJK-aware) |
| compat | - | Lua version compatibility (bit32, unpack, loadstring) |
luaswift.extend_stdlib()
-- Now available on standard libraries
string.trim(" hello ") -- "hello"
table.keys({a=1, b=2}) -- {"a", "b"}
utf8.sub("日本語", 1, 2) -- "日本"| Module | Global | Description |
|---|---|---|
| json | json |
JSON encode/decode with null handling |
| yaml | yaml |
YAML with multi-document support |
| toml | toml |
TOML configuration parsing |
After luaswift.extend_stdlib(), all math modules are available under the math namespace:
| Submodule | Access | Description |
|---|---|---|
| Base extensions | math.* |
Extended functions: sign, round, factorial, gamma |
| Linear Algebra | math.linalg |
Matrices, SVD, eigenvalues (BLAS/LAPACK) |
| Complex Numbers | math.complex |
Complex arithmetic and functions |
| Geometry | math.geo |
2D/3D vectors, quaternions, transforms |
| Special Functions | math.special |
Bessel, gamma, erf, elliptic integrals |
| Statistics | math.stats |
Mean, median, variance, percentile |
| Distributions | math.distributions |
Normal, t, chi2, F, gamma, beta distributions |
| Optimization | math.optimize |
Minimization, root finding, curve fitting |
| Integration | math.integrate |
Numerical integration, ODE solvers |
| Interpolation | math.interpolate |
Splines, PCHIP, Akima |
| Clustering | math.cluster |
K-means, hierarchical, DBSCAN |
| Spatial | math.spatial |
KDTree, Voronoi, Delaunay |
| Regression | math.regress |
OLS, WLS, GLS, GLM, ARIMA |
| Series | math.series |
Taylor polynomials, summation, products |
| Expressions | math.eval |
Expression parsing, LaTeX support |
| Constants | math.constants |
Physical constants, unit conversions |
| Number Theory | math.numtheory |
Primes, factorization, totient |
luaswift.extend_stdlib()
-- All under math namespace
local m = math.linalg.matrix({{1, 2}, {3, 4}})
local z = math.complex.new(3, 4)
local v = math.geo.vec3(1, 2, 3)
local g = math.special.gamma(5) -- 24
local c = math.constants.c -- speed of light
local avg = math.stats.mean({1, 2, 3, 4, 5})N-dimensional arrays with broadcasting and element-wise operations. Standalone module, not under math.
| Module | Global | Description |
|---|---|---|
| array | array |
N-dimensional arrays with broadcasting |
local a = array.zeros({3, 3})
local b = array.linspace(0, 1, 100)
local c = a + 1 -- broadcasting| Module | Global | Description |
|---|---|---|
| plot | plot |
Retained-mode plotting (includes SVG generation) |
local fig = plot.figure()
local ax = fig:subplot(1, 1, 1)
ax:plot({1, 2, 3}, {1, 4, 9})
local svg_string = fig:render()| Module | Global | Description |
|---|---|---|
| regex | regex |
ICU regular expressions |
| Module | Global | Description |
|---|---|---|
| types | types |
Type detection, conversion, and inspection |
| debug | dbg |
Structured logging with levels (debug, info, warn, error) |
| serialize | serialize |
Table serialization and deserialization |
| svg | svg |
Standalone SVG document generation |
These modules require explicit installation and configuration.
| Module | Global | Description |
|---|---|---|
| iox | iox |
Sandboxed file I/O within configured directories |
| http | http |
HTTP client for network requests |
// File I/O: Configure which directories Lua can access
IOModule.setAllowedDirectories([documentsPath, cachePath], for: engine)
ModuleRegistry.installIOModule(in: engine)
// HTTP: Enable network requests
ModuleRegistry.installHTTPModule(in: engine)The iox module restricts file operations to explicitly allowed directories—Lua scripts cannot access files outside these paths. This replaces Lua's standard io library (which is removed in sandboxed mode) with a secure alternative.
LuaSwift can optionally include three companion Swift packages that provide enhanced implementations for specific module groups. These packages are developed as independent Swift libraries that can also be used directly without Lua.
| Package | Environment Variable | Description |
|---|---|---|
| NumericSwift | LUASWIFT_INCLUDE_NUMERICSWIFT |
Complex numbers, statistics, geometry, special functions |
| ArraySwift | LUASWIFT_INCLUDE_ARRAYSWIFT |
N-dimensional arrays with broadcasting |
| PlotSwift | LUASWIFT_INCLUDE_PLOTSWIFT |
Matplotlib-inspired plotting with SVG output |
By default, all optional packages are included. To exclude packages and reduce binary size or dependencies:
# Exclude specific packages
LUASWIFT_INCLUDE_PLOTSWIFT=0 swift build # No PlotSwift
LUASWIFT_INCLUDE_ARRAYSWIFT=0 swift build # No ArraySwift
LUASWIFT_INCLUDE_NUMERICSWIFT=0 swift build # No NumericSwift
# Exclude multiple packages
LUASWIFT_INCLUDE_PLOTSWIFT=0 LUASWIFT_INCLUDE_ARRAYSWIFT=0 swift build
# Minimal build (core wrapper only)
LUASWIFT_INCLUDE_PLOTSWIFT=0 LUASWIFT_INCLUDE_ARRAYSWIFT=0 LUASWIFT_INCLUDE_NUMERICSWIFT=0 swift buildNumericSwift powers these Lua modules:
math.complex- Complex number arithmeticmath.geo- 2D/3D vectors and transformsmath.stats/math.distributions- Statistics and probability distributionsmath.special- Special mathematical functions (Bessel, gamma, erf, elliptic)math.numtheory- Number theory (primes, factorization)math.linalg- Linear algebra (BLAS/LAPACK via Accelerate)math.regress- Regression analysis (OLS, WLS, GLM, ARIMA)math.optimize- Minimization, root finding, curve fittingmath.integrate- Numerical integration, ODE solversmath.interpolate- Splines, PCHIP, Akima interpolationmath.cluster- K-means, hierarchical, DBSCANmath.spatial- KDTree, Voronoi, Delaunaymath.series- Taylor polynomials, summation
ArraySwift powers:
array- N-dimensional arrays with NumPy-like semantics
PlotSwift powers:
plot- Figure/axes plotting systemsvg- SVG document generation
When a package is excluded, its corresponding Lua modules are unavailable at runtime. Attempting to use them will result in a clear error message.
For Xcode projects, set environment variables in your scheme:
- Product → Scheme → Edit Scheme
- Select "Run" in the left sidebar
- Click "Arguments" tab
- Add environment variables under "Environment Variables"
- Binary size: Each package adds to the final binary; exclude what you don't need
- Build time: Fewer dependencies means faster builds
- Platform support: Some packages may have platform-specific requirements
- App Store size: iOS apps benefit from smaller binaries
Swift Package Manager does not have a native "optional dependency" feature like some package managers. LuaSwift uses environment variables at build time combined with conditional compilation (#if directives) to achieve optional dependencies.
For consumers who want fine-grained control, there are two approaches:
- Environment variables (current, Swift 5.9+): Set
LUASWIFT_INCLUDE_*=0before building - SPM Traits (Swift 6.1+): A newer feature that provides trait-based conditional dependencies
The environment variable approach is used for maximum compatibility. Future versions may adopt SPM Traits when Swift 6.1+ becomes the minimum supported version.
At runtime, install only the modules you need:
let engine = try LuaEngine()
// Install specific modules
ModuleRegistry.installJSONModule(in: engine)
ModuleRegistry.installStringXModule(in: engine)
ModuleRegistry.installMathModule(in: engine)
// Or install all compiled modules
ModuleRegistry.installModules(in: engine)// Default: sandboxed, Lua 5.4, no memory limit
let engine = try LuaEngine()
// Custom configuration
let config = LuaEngineConfiguration(
sandboxed: true, // Remove dangerous functions
packagePath: "/path/to/lua", // Custom require() path
memoryLimit: 50_000_000 // 50 MB limit for Swift modules (array, linalg, etc.)
)
let engine = try LuaEngine(configuration: config)
// Unrestricted (use with caution)
let engine = try LuaEngine(configuration: .unrestricted)Sandboxing removes: os.execute, os.exit, io.*, debug.*, loadfile, dofile, load
LuaSwift is designed to be App Store compliant per Apple's App Store Review Guidelines 2.5.2.
- Bundled interpreter: Lua source compiled into app (no code download)
- No JIT: Standard interpreter only, not LuaJIT
- Sandboxing: Dangerous functions disabled by default
The default sandboxed mode provides defense-in-depth:
| Disabled | Reason |
|---|---|
os.execute, os.exit |
System command execution |
io.* library |
File system access |
debug.* library |
Runtime introspection |
loadfile, dofile, load |
External code loading |
package.loadlib |
Dynamic library loading |
require('io'), require('debug') |
Library restoration bypass |
packagePath Security: Never set
packagePathto a writable directory (Documents, Caches, tmp) when running user-provided scripts. This would allow downloaded Lua code to be executed viarequire(), violating App Store guidelines.
// SAFE: Read-only bundle resources
let config = LuaEngineConfiguration(
sandboxed: true,
packagePath: Bundle.main.resourcePath! + "/Lua"
)
// UNSAFE: Writable directory - don't do this with untrusted scripts
let config = LuaEngineConfiguration(
sandboxed: true,
packagePath: documentsDirectory // Dangerous!
)Before submitting to the App Store, verify:
- Use sandboxed mode (default) for any user-provided scripts
- If using
packagePath, ensure it points only to read-only directories - Validate all inputs to Swift callbacks registered with Lua
- If using IOModule, restrict
allowedDirectoriesto app-controlled paths - Consider implementing script execution timeouts for untrusted code
- Don't combine HTTP + IO modules with
packagePathfor untrusted scripts
See the Sandboxing Guide for detailed security information.
MIT License. See LICENSE for details.
Lua is also MIT licensed. See https://www.lua.org/license.html
LuaSwift's scientific computing modules are inspired by excellent open-source libraries:
- NumPy - N-dimensional array design and broadcasting semantics
- SciPy - Optimization, integration, interpolation, and special functions
- statsmodels - Statistical modeling and regression analysis
- matplotlib - Plotting API design
- Penlight - String and table utility patterns
Required Dependencies:
- Lua - The Lua programming language (bundled)
- Yams - YAML parsing for Swift
- TOMLKit - TOML parsing for Swift
Optional Dependencies:
- NumericSwift - Complex numbers, statistics, geometry
- ArraySwift - N-dimensional arrays
- PlotSwift - Plotting and SVG generation
