LuaJIT-to-Go/types.go
2025-03-29 09:08:02 -05:00

153 lines
2.9 KiB
Go

package luajit
/*
#include <lua.h>
*/
import "C"
import (
"fmt"
"strconv"
)
// LuaType represents Lua value types
type LuaType int
const (
// These constants match lua.h's LUA_T* values
TypeNone LuaType = -1
TypeNil LuaType = 0
TypeBoolean LuaType = 1
TypeLightUserData LuaType = 2
TypeNumber LuaType = 3
TypeString LuaType = 4
TypeTable LuaType = 5
TypeFunction LuaType = 6
TypeUserData LuaType = 7
TypeThread LuaType = 8
)
// String returns the string representation of the Lua type
func (t LuaType) String() string {
switch t {
case TypeNone:
return "none"
case TypeNil:
return "nil"
case TypeBoolean:
return "boolean"
case TypeLightUserData:
return "lightuserdata"
case TypeNumber:
return "number"
case TypeString:
return "string"
case TypeTable:
return "table"
case TypeFunction:
return "function"
case TypeUserData:
return "userdata"
case TypeThread:
return "thread"
default:
return "unknown"
}
}
// ConvertValue converts a value to the requested type with proper type conversion
func ConvertValue[T any](value any) (T, bool) {
var zero T
// Handle nil case
if value == nil {
return zero, false
}
// Try direct type assertion first
if result, ok := value.(T); ok {
return result, true
}
// Type-specific conversions
switch any(zero).(type) {
case string:
switch v := value.(type) {
case float64:
return any(fmt.Sprintf("%g", v)).(T), true
case int:
return any(strconv.Itoa(v)).(T), true
case bool:
if v {
return any("true").(T), true
}
return any("false").(T), true
}
case int:
switch v := value.(type) {
case float64:
return any(int(v)).(T), true
case string:
if i, err := strconv.Atoi(v); err == nil {
return any(i).(T), true
}
case bool:
if v {
return any(1).(T), true
}
return any(0).(T), true
}
case float64:
switch v := value.(type) {
case int:
return any(float64(v)).(T), true
case string:
if f, err := strconv.ParseFloat(v, 64); err == nil {
return any(f).(T), true
}
case bool:
if v {
return any(1.0).(T), true
}
return any(0.0).(T), true
}
case bool:
switch v := value.(type) {
case string:
switch v {
case "true", "yes", "1":
return any(true).(T), true
case "false", "no", "0":
return any(false).(T), true
}
case int:
return any(v != 0).(T), true
case float64:
return any(v != 0).(T), true
}
}
return zero, false
}
// GetTypedValue gets a value from the state with type conversion
func GetTypedValue[T any](s *State, index int) (T, bool) {
var zero T
// Get the value as any type
value, err := s.ToValue(index)
if err != nil {
return zero, false
}
// Convert it to the requested type
return ConvertValue[T](value)
}
// GetGlobalTyped gets a global variable with type conversion
func GetGlobalTyped[T any](s *State, name string) (T, bool) {
s.GetGlobal(name)
defer s.Pop(1)
return GetTypedValue[T](s, -1)
}