improve error reporting
This commit is contained in:
parent
2bdf7cfd4a
commit
6a2eb9df63
66
bytecode.go
66
bytecode.go
@ -7,46 +7,46 @@ package luajit
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const unsigned char *buf;
|
const unsigned char *buf;
|
||||||
size_t size;
|
size_t size;
|
||||||
const char *name;
|
const char *name;
|
||||||
} BytecodeReader;
|
} BytecodeReader;
|
||||||
|
|
||||||
const char *bytecode_reader(lua_State *L, void *ud, size_t *size) {
|
const char *bytecode_reader(lua_State *L, void *ud, size_t *size) {
|
||||||
BytecodeReader *r = (BytecodeReader *)ud;
|
BytecodeReader *r = (BytecodeReader *)ud;
|
||||||
(void)L; // unused
|
(void)L; // unused
|
||||||
if (r->size == 0) return NULL;
|
if (r->size == 0) return NULL;
|
||||||
*size = r->size;
|
*size = r->size;
|
||||||
r->size = 0; // Only read once
|
r->size = 0; // Only read once
|
||||||
return (const char *)r->buf;
|
return (const char *)r->buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int load_bytecode(lua_State *L, const unsigned char *buf, size_t len, const char *name) {
|
int load_bytecode(lua_State *L, const unsigned char *buf, size_t len, const char *name) {
|
||||||
BytecodeReader reader = {buf, len, name};
|
BytecodeReader reader = {buf, len, name};
|
||||||
return lua_load(L, bytecode_reader, &reader, name);
|
return lua_load(L, bytecode_reader, &reader, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct bytecode dumping without intermediate buffer - more efficient
|
// Direct bytecode dumping without intermediate buffer - more efficient
|
||||||
int direct_bytecode_writer(lua_State *L, const void *p, size_t sz, void *ud) {
|
int direct_bytecode_writer(lua_State *L, const void *p, size_t sz, void *ud) {
|
||||||
void **data = (void **)ud;
|
void **data = (void **)ud;
|
||||||
size_t current_size = (size_t)data[1];
|
size_t current_size = (size_t)data[1];
|
||||||
void *newbuf = realloc(data[0], current_size + sz);
|
void *newbuf = realloc(data[0], current_size + sz);
|
||||||
if (newbuf == NULL) return 1;
|
if (newbuf == NULL) return 1;
|
||||||
|
|
||||||
memcpy((unsigned char*)newbuf + current_size, p, sz);
|
memcpy((unsigned char*)newbuf + current_size, p, sz);
|
||||||
data[0] = newbuf;
|
data[0] = newbuf;
|
||||||
data[1] = (void*)(current_size + sz);
|
data[1] = (void*)(current_size + sz);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combined load and run bytecode in a single call
|
// Combined load and run bytecode in a single call
|
||||||
int load_and_run_bytecode(lua_State *L, const unsigned char *buf, size_t len,
|
int load_and_run_bytecode(lua_State *L, const unsigned char *buf, size_t len,
|
||||||
const char *name, int nresults) {
|
const char *name, int nresults) {
|
||||||
BytecodeReader reader = {buf, len, name};
|
BytecodeReader reader = {buf, len, name};
|
||||||
int status = lua_load(L, bytecode_reader, &reader, name);
|
int status = lua_load(L, bytecode_reader, &reader, name);
|
||||||
if (status != 0) return status;
|
if (status != 0) return status;
|
||||||
|
|
||||||
return lua_pcall(L, 0, nresults, 0);
|
return lua_pcall(L, 0, nresults, 0);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
@ -102,10 +102,7 @@ func (s *State) LoadBytecode(bytecode []byte, name string) error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), fmt.Sprintf("LoadBytecode(%s)", name))
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -123,10 +120,7 @@ func (s *State) RunBytecode() error {
|
|||||||
func (s *State) RunBytecodeWithResults(nresults int) error {
|
func (s *State) RunBytecodeWithResults(nresults int) error {
|
||||||
status := C.lua_pcall(s.L, 0, C.int(nresults), 0)
|
status := C.lua_pcall(s.L, 0, C.int(nresults), 0)
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), fmt.Sprintf("RunBytecode(nresults=%d)", nresults))
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -152,10 +146,7 @@ func (s *State) LoadAndRunBytecode(bytecode []byte, name string) error {
|
|||||||
)
|
)
|
||||||
|
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), fmt.Sprintf("LoadAndRunBytecode(%s)", name))
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -182,10 +173,7 @@ func (s *State) LoadAndRunBytecodeWithResults(bytecode []byte, name string, nres
|
|||||||
)
|
)
|
||||||
|
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), fmt.Sprintf("LoadAndRunBytecodeWithResults(%s, nresults=%d)", name, nresults))
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
86
stack.go
86
stack.go
@ -5,16 +5,45 @@ package luajit
|
|||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// LuaError represents an error from the Lua state
|
// LuaError represents an enhanced error from the Lua state
|
||||||
type LuaError struct {
|
type LuaError struct {
|
||||||
Code int
|
Code int
|
||||||
Message string
|
Message string
|
||||||
|
File string
|
||||||
|
Line int
|
||||||
|
StackTrace string
|
||||||
|
Context string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *LuaError) Error() string {
|
func (e *LuaError) Error() string {
|
||||||
return fmt.Sprintf("lua error (code=%d): %s", e.Code, e.Message)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stack management constants from lua.h
|
// Stack management constants from lua.h
|
||||||
@ -45,3 +74,50 @@ func (s *State) GetStackTrace() string {
|
|||||||
|
|
||||||
return trace
|
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 {
|
||||||
|
// Strip the file:line part from message for cleaner display
|
||||||
|
message = strings.TrimSpace(afterColon[secondColonPos+1:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get stack trace
|
||||||
|
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
|
||||||
|
}
|
||||||
|
56
wrapper.go
56
wrapper.go
@ -13,25 +13,25 @@ package luajit
|
|||||||
|
|
||||||
// Direct execution helpers to minimize CGO transitions
|
// Direct execution helpers to minimize CGO transitions
|
||||||
static int do_string(lua_State *L, const char *s) {
|
static int do_string(lua_State *L, const char *s) {
|
||||||
int status = luaL_loadstring(L, s);
|
int status = luaL_loadstring(L, s);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
status = lua_pcall(L, 0, 0, 0);
|
status = lua_pcall(L, 0, 0, 0);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_file(lua_State *L, const char *filename) {
|
static int do_file(lua_State *L, const char *filename) {
|
||||||
int status = luaL_loadfile(L, filename);
|
int status = luaL_loadfile(L, filename);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
status = lua_pcall(L, 0, 0, 0);
|
status = lua_pcall(L, 0, 0, 0);
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int execute_with_results(lua_State *L, const char *code, int store_results) {
|
static int execute_with_results(lua_State *L, const char *code, int store_results) {
|
||||||
int status = luaL_loadstring(L, code);
|
int status = luaL_loadstring(L, code);
|
||||||
if (status != 0) return status;
|
if (status != 0) return status;
|
||||||
return lua_pcall(L, 0, store_results ? LUA_MULTRET : 0, 0);
|
return lua_pcall(L, 0, store_results ? LUA_MULTRET : 0, 0);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
@ -342,10 +342,7 @@ func (s *State) LoadString(code string) error {
|
|||||||
|
|
||||||
status := C.luaL_loadstring(s.L, ccode)
|
status := C.luaL_loadstring(s.L, ccode)
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), "LoadString")
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -359,10 +356,7 @@ func (s *State) LoadFile(filename string) error {
|
|||||||
|
|
||||||
status := C.luaL_loadfile(s.L, cfilename)
|
status := C.luaL_loadfile(s.L, cfilename)
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), fmt.Sprintf("LoadFile(%s)", filename))
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -373,10 +367,7 @@ func (s *State) LoadFile(filename string) error {
|
|||||||
func (s *State) Call(nargs, nresults int) error {
|
func (s *State) Call(nargs, nresults int) error {
|
||||||
status := C.lua_pcall(s.L, C.int(nargs), C.int(nresults), 0)
|
status := C.lua_pcall(s.L, C.int(nargs), C.int(nresults), 0)
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), fmt.Sprintf("Call(%d,%d)", nargs, nresults))
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -390,10 +381,7 @@ func (s *State) DoString(code string) error {
|
|||||||
|
|
||||||
status := C.do_string(s.L, ccode)
|
status := C.do_string(s.L, ccode)
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), "DoString")
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -407,10 +395,7 @@ func (s *State) DoFile(filename string) error {
|
|||||||
|
|
||||||
status := C.do_file(s.L, cfilename)
|
status := C.do_file(s.L, cfilename)
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), fmt.Sprintf("DoFile(%s)", filename))
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -426,10 +411,7 @@ func (s *State) Execute(code string) (int, error) {
|
|||||||
|
|
||||||
status := C.execute_with_results(s.L, ccode, 1) // store_results=true
|
status := C.execute_with_results(s.L, ccode, 1) // store_results=true
|
||||||
if status != 0 {
|
if status != 0 {
|
||||||
err := &LuaError{
|
err := s.CreateLuaError(int(status), "Execute")
|
||||||
Code: int(status),
|
|
||||||
Message: s.ToString(-1),
|
|
||||||
}
|
|
||||||
s.Pop(1) // Remove error message
|
s.Pop(1) // Remove error message
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user