diff --git a/DOCS.md b/DOCS.md new file mode 100644 index 0000000..dbc815b --- /dev/null +++ b/DOCS.md @@ -0,0 +1,270 @@ +# LuaJIT Go Wrapper API Documentation + +## State Management + +### NewSafe() *State +Creates a new Lua state with stack safety enabled. +```go +L := luajit.NewSafe() +defer L.Close() +defer L.Cleanup() +``` + +### New() *State +Creates a new Lua state without stack safety checks. +```go +L := luajit.New() +defer L.Close() +defer L.Cleanup() +``` + +### Close() +Closes the Lua state and frees associated resources. +```go +L.Close() +``` + +### Cleanup() +Cleans up the function registry and other internal resources. +```go +L.Cleanup() +``` + +## Stack Operations + +### GetTop() int +Returns the index of the top element in the stack. +```go +top := L.GetTop() // 0 for empty stack +``` + +### Pop(n int) +Removes n elements from the stack. +```go +L.Pop(1) // Remove top element +L.Pop(2) // Remove top two elements +``` + +### Remove(index int) +Removes the element at the given index. +```go +L.Remove(-1) // Remove top element +L.Remove(1) // Remove first element +``` + +### checkStack(n int) error +Internal function that ensures there's enough space for n new elements. +```go +if err := L.checkStack(2); err != nil { + return err +} +``` + +## Type Checks + +### GetType(index int) LuaType +Returns the type of the value at the given index. +```go +if L.GetType(-1) == TypeString { + // Handle string +} +``` + +### IsFunction(index int) bool +### IsTable(index int) bool +### IsUserData(index int) bool +Type checking functions for specific Lua types. +```go +if L.IsTable(-1) { + table, err := L.ToTable(-1) +} +``` + +## Value Retrieval + +### ToString(index int) string +Converts the value at the given index to a string. +```go +str := L.ToString(-1) +``` + +### ToNumber(index int) float64 +Converts the value to a number. +```go +num := L.ToNumber(-1) +``` + +### ToBoolean(index int) bool +Converts the value to a boolean. +```go +bool := L.ToBoolean(-1) +``` + +### ToValue(index int) (interface{}, error) +Converts any Lua value to its Go equivalent. +```go +val, err := L.ToValue(-1) +if err != nil { + return err +} +``` + +### ToTable(index int) (map[string]interface{}, error) +Converts a Lua table to a Go map. +```go +table, err := L.ToTable(-1) +if err != nil { + return nil, err +} +``` + +## Value Pushing + +### PushNil() +### PushBoolean(b bool) +### PushNumber(n float64) +### PushString(str string) +Basic value pushing functions. +```go +L.PushString("hello") +L.PushNumber(42) +L.PushBoolean(true) +L.PushNil() +``` + +### PushValue(v interface{}) error +Pushes any Go value onto the stack. +```go +err := L.PushValue(myValue) +``` + +### PushTable(table map[string]interface{}) error +Pushes a Go map as a Lua table. +```go +data := map[string]interface{}{ + "key": "value", + "numbers": []float64{1, 2, 3}, +} +err := L.PushTable(data) +``` + +## Function Registration + +### RegisterGoFunction(name string, fn GoFunction) error +Registers a Go function that can be called from Lua. +```go +adder := func(s *State) int { + sum := s.ToNumber(1) + s.ToNumber(2) + s.PushNumber(sum) + return 1 +} +err := L.RegisterGoFunction("add", adder) +``` + +### UnregisterGoFunction(name string) +Removes a previously registered function. +```go +L.UnregisterGoFunction("add") +``` + +## Package Management + +### SetPackagePath(path string) error +Sets the Lua package.path variable. +```go +err := L.SetPackagePath("./?.lua;/usr/local/share/lua/5.1/?.lua") +``` + +### AddPackagePath(path string) error +Adds a path to the existing package.path. +```go +err := L.AddPackagePath("./modules/?.lua") +``` + +## Code Execution + +### DoString(str string) error +Executes a string of Lua code. +```go +err := L.DoString(` + local x = 40 + local y = 2 + result = x + y +`) +``` + +### DoFile(filename string) error +Executes a Lua file. +```go +err := L.DoFile("script.lua") +``` + +## Table Operations + +### GetField(index int, key string) +Gets a field from a table at the given index. +```go +L.GetField(-1, "name") // gets table.name +``` + +### SetField(index int, key string) +Sets a field in a table at the given index. +```go +L.PushString("value") +L.SetField(-2, "key") // table.key = "value" +``` + +### GetGlobal(name string) +Gets a global variable. +```go +L.GetGlobal("myGlobal") +``` + +### SetGlobal(name string) +Sets a global variable from the value at the top of the stack. +```go +L.PushNumber(42) +L.SetGlobal("answer") // answer = 42 +``` + +## Error Handling + +### LuaError +Error type containing both an error code and message. +```go +type LuaError struct { + Code int + Message string +} +``` + +### getStackTrace() string +Gets the current Lua stack trace. +```go +trace := L.getStackTrace() +fmt.Println(trace) +``` + +## Thread Safety Notes + +- The function registry is thread-safe +- Individual Lua states are not thread-safe +- Create separate states for concurrent operations +- Use the function registry to share functions between states + +## Memory Management + +Always pair state creation with cleanup: +```go +L := luajit.NewSafe() +defer L.Close() +defer L.Cleanup() +``` + +Stack management in unsafe mode requires manual attention: +```go +L := luajit.New() +L.PushString("hello") +// ... use the string +L.Pop(1) // Clean up when done +``` \ No newline at end of file diff --git a/README.md b/README.md index 06c7d49..8b00180 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,133 @@ -# LuaJIT-to-Go +# LuaJIT Go Wrapper -Go wrapper for LuaJIT. Uses amalgamated static libraries for LuaJIT 5.1. \ No newline at end of file +Hey there! This is a Go wrapper for LuaJIT that makes it easy to embed Lua in your Go applications. We've focused on making it both safe and fast, while keeping the API clean and intuitive. + +## What's This For? + +This wrapper lets you run Lua code from Go and easily pass data back and forth between the two languages. You might want this if you're: +- Adding scripting support to your application +- Building a game engine +- Creating a configuration system +- Writing an embedded rules engine +- Building test automation tools + +## Get Started + +First, grab the package: +```bash +go get git.sharkk.net/Sky/LuaJIT-to-Go +``` + +You'll need LuaJIT's development files, but don't worry - we include libraries for Windows and Linux in the vendor directory. + +Here's the simplest thing you can do: +```go +L := luajit.NewSafe() +defer L.Close() +defer L.Cleanup() + +err := L.DoString(`print("Hey from Lua!")`) +``` + +## Stack Safety: Choose Your Adventure + +One of the key decisions you'll make is whether to use stack-safe mode. Here's what that means: + +### Stack-Safe Mode (NewSafe()) +```go +L := luajit.NewSafe() +``` +Think of this as driving with guardrails. It's perfect when: +- You're new to Lua or embedding scripting languages +- You're writing a server or long-running application +- You want to handle untrusted Lua code +- You'd rather have slightly slower code than mysterious crashes + +The safe mode will: +- Prevent stack overflows +- Check types more thoroughly +- Clean up after messy Lua code +- Give you better error messages + +### Non-Stack-Safe Mode (New()) +```go +L := luajit.New() +``` +This is like taking off the training wheels. Use it when: +- You know exactly how your Lua code behaves +- You've profiled your application and need more speed +- You're doing lots of rapid, simple Lua calls +- You're writing performance-critical code + +The unsafe mode: +- Skips most safety checks +- Runs noticeably faster +- Gives you direct control over the stack +- Can crash spectacularly if you make a mistake + +Most applications should start with stack-safe mode and only switch to unsafe mode if profiling shows it's necessary. + +## Registering Go Functions + +Want to call Go code from Lua? Easy: +```go +// This function adds two numbers and returns the result +adder := func(s *luajit.State) int { + sum := s.ToNumber(1) + s.ToNumber(2) + s.PushNumber(sum) + return 1 // we're returning one value +} + +L.RegisterGoFunction("add", adder) +``` + +Now in Lua: +```lua +result = add(40, 2) -- result = 42 +``` + +## Working with Tables + +Lua tables are pretty powerful - they're like a mix of Go's maps and slices. We make it easy to work with them: + +```go +// Go → Lua +stuff := map[string]interface{}{ + "name": "Arthur Dent", + "age": 30, + "items": []float64{1, 2, 3}, +} +L.PushTable(stuff) + +// Lua → Go +L.GetGlobal("some_table") +result, err := L.ToTable(-1) +``` + +## Error Handling + +We try to give you useful errors instead of mysterious panics: +```go +if err := L.DoString("this isn't valid Lua!"); err != nil { + if luaErr, ok := err.(*luajit.LuaError); ok { + fmt.Printf("Oops: %s\n", luaErr.Message) + } +} +``` + +## A Few Tips + +- Always use those `defer L.Close()` and `defer L.Cleanup()` calls - they prevent memory leaks +- Each Lua state should stick to one goroutine +- For concurrent stuff, create multiple states +- You can share functions between states safely +- Keep an eye on your stack in unsafe mode - it won't clean up after itself +- Start with stack-safe mode and measure before optimizing + +## Need Help? + +Check out the tests in the repository - they're full of examples. If you're stuck, open an issue! We're here to help. + +## License + +MIT Licensed - do whatever you want with it! \ No newline at end of file diff --git a/generate.go b/generate.go deleted file mode 100644 index 2a62e30..0000000 --- a/generate.go +++ /dev/null @@ -1,6 +0,0 @@ -//go:build exclude - -package luajit - -//go:generate cp -r ../include ./include -//go:generate cp -r ../lib ./lib