Skip to content

aixiasang/pylua

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PyLua

Lua 5.3 virtual machine implemented in pure Python. No C dependencies.

Full pipeline: Lua source → lexer → compiler → bytecode → VM.

Quick Start

Run Lua from CLI

python -m pylua hello.lua

Run Lua from Python

from pylua import run_string

print(run_string('print("hello")'))
# hello

Examples

Basic

from pylua import run_string, LuaVM, LuaError

# arithmetic
run_string('print(2 ^ 10)')          # 1024.0
run_string('print(7 // 2, 7 % 2)')   # 3	1

# string
run_string('print("hello" .. " " .. "world")')  # hello world
run_string('print(string.format("%05d", 42))')   # 00042
run_string('print(string.rep("ab", 3, "-"))')    # ab-ab-ab

Table & Iteration

from pylua import run_string

run_string('''
local t = {10, 20, 30, x="hello"}
for i, v in ipairs(t) do
    print(i, v)
end
''')
-- 1	10
-- 2	20
-- 3	30

run_string('''
local t = {5, 3, 1, 4, 2}
table.sort(t)
print(table.concat(t, ", "))
''')
-- 1, 2, 3, 4, 5

Closure & Upvalue

from pylua import run_string

run_string('''
local function counter(start)
    local n = start
    return function()
        n = n + 1
        return n
    end
end

local c = counter(0)
print(c(), c(), c())   -- 1	2	3
''')

Metatable & OOP

from pylua import run_string

run_string('''
local Vec = {}
Vec.__index = Vec

function Vec.new(x, y)
    return setmetatable({x=x, y=y}, Vec)
end

function Vec:len()
    return math.sqrt(self.x^2 + self.y^2)
end

Vec.__add = function(a, b)
    return Vec.new(a.x + b.x, a.y + b.y)
end

Vec.__tostring = function(v)
    return "(" .. v.x .. ", " .. v.y .. ")"
end

local a = Vec.new(3, 4)
local b = Vec.new(1, 2)
print(tostring(a + b))   -- (4, 6)
print(a:len())           -- 5.0
''')

Coroutine

from pylua import run_string

run_string('''
local function fib()
    local a, b = 0, 1
    while true do
        coroutine.yield(a)
        a, b = b, a + b
    end
end

local co = coroutine.wrap(fib)
local out = {}
for i = 1, 10 do out[i] = co() end
print(table.concat(out, " "))
''')
-- 0 1 1 2 3 5 8 13 21 34

Pattern Matching

from pylua import run_string

run_string('''
local s = "2023-12-25"
local y, m, d = string.match(s, "(%d+)-(%d+)-(%d+)")
print(y, m, d)   -- 2023	12	25

local words = {}
for w in string.gmatch("hello world foo bar", "%a+") do
    words[#words+1] = w
end
print(table.concat(words, ", "))  -- hello, world, foo, bar

print(string.gsub("hello world", "(%w+)", string.upper))
-- HELLO WORLD	2
''')

Error Handling

from pylua import run_string

run_string('''
local ok, err = pcall(function()
    error("something went wrong")
end)
print(ok, err)
-- false	input:3: something went wrong

local ok2, msg = xpcall(
    function() error("oops") end,
    function(e) return "caught: " .. e end
)
print(ok2, msg)
-- false	caught: input:9: oops
''')

Persistent VM

from pylua import LuaVM, LuaError

vm = LuaVM()

# state persists across calls
vm.run_string('x = 42')
vm.run_string('print(x + 1)')  # 43

# read Lua globals from Python
print(vm.globals.rawget("x"))   # 42

# error handling
try:
    vm.run_string('error("boom")')
except LuaError as e:
    print(f"caught: {e}")

Run Lua File

from pylua import run_file

output = run_file("script.lua")
print(output)

Supported Features

Types: nil, boolean, integer, float, string, table, function, coroutine

Operators: + - * / // % ^ & | ~ << >> == ~= < > <= >= and or not .. #

Control: if/elseif/else, while, repeat/until, for (numeric & generic), break, goto/label

Functions: closures, upvalues, varargs (...), multiple returns, tail calls

Tables: array + hash, constructors {}, metatables (20 metamethods)

Stdlib: string, table, math, io, os, coroutine

Pattern matching: find, match, gmatch, gsub with full Lua pattern syntax

Coroutines: create, resume, yield, wrap, status

Testing

pytest tests/ -v

57 tests: 34 Lua files verified against lua53 reference output + 23 Python API tests.

Structure

pylua/
  __init__.py       Public API: LuaVM, run_string, run_file
  __main__.py       CLI: python -m pylua file.lua
  __type.py         Types, opcodes, constants
  __lexer.py        Lexer
  __compiler.py     Lua source → bytecode
  __dump.py         Bytecode writer
  __undump.py       Bytecode reader
  __vm.py           Virtual machine
  __stdlib.py       Standard library
tests/
  lua/              34 Lua test cases
  __test_compiler.py
  __test_api.py

About

Lua 5.3 virtual machine implemented in pure Python. No C dependencies.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors