LuaJIT-to-Go/stack.go

109 lines
2.6 KiB
Go

package luajit
/*
#include <lua.h>
#include <lauxlib.h>
*/
import "C"
import "fmt"
// LuaError represents an error from the Lua state
type LuaError struct {
Code int
Message string
}
func (e *LuaError) Error() string {
return fmt.Sprintf("lua error (code=%d): %s", e.Code, e.Message)
}
// Stack management constants from lua.h
const (
LUA_MINSTACK = 20 // Minimum Lua stack size
LUA_MAXSTACK = 1000000 // Maximum Lua stack size
LUA_REGISTRYINDEX = -10000 // Pseudo-index for the Lua registry
LUA_GLOBALSINDEX = -10002 // Pseudo-index for globals table
)
// checkStack ensures there is enough space on the Lua stack
func (s *State) checkStack(n int) error {
if C.lua_checkstack(s.L, C.int(n)) == 0 {
return fmt.Errorf("stack overflow (cannot allocate %d slots)", n)
}
return nil
}
// safeCall wraps a potentially dangerous C call with stack checking
func (s *State) safeCall(f func() C.int) error {
// Save current stack size
top := s.GetTop()
// Ensure we have enough stack space (minimum 20 slots as per Lua standard)
if err := s.checkStack(LUA_MINSTACK); err != nil {
return err
}
// Make the call
status := f()
// Check for errors
if status != 0 {
err := &LuaError{
Code: int(status),
Message: s.ToString(-1),
}
s.Pop(1) // Remove error message
return err
}
// For lua_pcall, the function and arguments are popped before results are pushed
// So we don't consider it an underflow if the new top is less than the original
if status == 0 && s.GetType(-1) == TypeFunction {
// If we still have a function on the stack, restore original size
s.SetTop(top)
}
return nil
}
// stackGuard wraps a function with stack checking
func stackGuard[T any](s *State, f func() (T, error)) (T, error) {
// Save current stack size
top := s.GetTop()
defer func() {
// Only restore if stack is larger than original
if s.GetTop() > top {
s.SetTop(top)
}
}()
// Run the protected function
return f()
}
// stackGuardValue executes a function with stack protection
func stackGuardValue[T any](s *State, f func() (T, error)) (T, error) {
return stackGuard(s, f)
}
// stackGuardErr executes a function that only returns an error with stack protection
func stackGuardErr(s *State, f func() error) error {
// Save current stack size
top := s.GetTop()
defer func() {
// Only restore if stack is larger than original
if s.GetTop() > top {
s.SetTop(top)
}
}()
// Run the protected function
return f()
}
// getStackTrace returns the current Lua stack trace
func (s *State) getStackTrace() string {
// Same implementation...
return ""
}