LuaJIT-to-Go/stack.go
Sky Johnson f4bfff470f massive rewrite
fix go func mallocs
add helper utils
2025-05-31 17:42:58 -05:00

120 lines
2.4 KiB
Go

package luajit
/*
#include <lua.h>
#include <lauxlib.h>
*/
import "C"
import (
"fmt"
"strings"
)
// LuaError represents an enhanced error from the Lua state
type LuaError struct {
Code int
Message string
File string
Line int
StackTrace string
Context string
}
func (e *LuaError) Error() string {
var parts []string
if e.File != "" && e.Line > 0 {
parts = append(parts, fmt.Sprintf("%s:%d", e.File, e.Line))
}
if e.Context != "" {
parts = append(parts, fmt.Sprintf("[%s]", e.Context))
}
parts = append(parts, e.Message)
if e.Code != 0 {
parts = append(parts, fmt.Sprintf("(code=%d)", e.Code))
}
result := strings.Join(parts, " ")
if e.StackTrace != "" {
result += "\n" + e.StackTrace
}
return result
}
// GetStackTrace returns the current Lua stack trace
func (s *State) GetStackTrace() string {
s.GetGlobal("debug")
if !s.IsTable(-1) {
s.Pop(1)
return "debug table not available"
}
s.GetField(-1, "traceback")
if !s.IsFunction(-1) {
s.Pop(2)
return "debug.traceback not available"
}
s.Call(0, 1)
trace := s.ToString(-1)
s.Pop(1)
return trace
}
// GetErrorInfo extracts detailed error information from the Lua stack
func (s *State) GetErrorInfo(context string) *LuaError {
if s.GetTop() == 0 {
return &LuaError{
Message: "unknown error (empty stack)",
Context: context,
}
}
message := s.ToString(-1)
// Parse file:line from common Lua error format
var file string
var line int
if colonPos := strings.Index(message, ":"); colonPos > 0 {
beforeColon := message[:colonPos]
afterColon := message[colonPos+1:]
if secondColonPos := strings.Index(afterColon, ":"); secondColonPos > 0 {
file = beforeColon
if n, err := fmt.Sscanf(afterColon[:secondColonPos], "%d", &line); n == 1 && err == nil {
message = strings.TrimSpace(afterColon[secondColonPos+1:])
}
}
}
stackTrace := s.GetStackTrace()
return &LuaError{
Message: message,
File: file,
Line: line,
StackTrace: stackTrace,
Context: context,
}
}
// CreateLuaError creates a LuaError with full context information
func (s *State) CreateLuaError(code int, context string) *LuaError {
err := s.GetErrorInfo(context)
err.Code = code
return err
}
// PushError pushes an error string and returns -1
func (s *State) PushError(format string, args ...any) int {
s.PushString(fmt.Sprintf(format, args...))
return -1
}