From 0e1a3e59bed9b8328d9ee98a0bd0b2cb10bbe229 Mon Sep 17 00:00:00 2001 From: terminaldweller Date: Fri, 31 May 2024 17:36:10 -0400 Subject: initial support for lua, WIP --- plugins.go | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 plugins.go (limited to 'plugins.go') diff --git a/plugins.go b/plugins.go new file mode 100644 index 0000000..d64f65b --- /dev/null +++ b/plugins.go @@ -0,0 +1,179 @@ +package main + +import ( + "fmt" + "log" + "os" + "reflect" + + lua "github.com/yuin/gopher-lua" +) + +func registerStrucAsLuaMetaTable[T any]( + luaState *lua.LState, + checkStruct func(luaState *lua.LState) *T, + structType T, + metaTableName string, +) { + metaTable := luaState.NewTypeMetatable(metaTableName) + + luaState.SetGlobal(metaTableName, metaTable) + + luaState.SetField( + metaTable, + "new", + luaState.NewFunction( + newStructFunctionFactory(structType, metaTableName), + ), + ) + + var zero [0]T + + luaState.SetField( + metaTable, + "__index", + luaState.SetFuncs( + luaState.NewTable(), + luaTableGenFactory(reflect.TypeOf(zero), + checkStruct, + ), + ), + ) +} + +func newStructFunctionFactory[T any](structType T, metaTableName string) func(*lua.LState) int { + return func(luaState *lua.LState) int { + structInstance := &structType + ud := luaState.NewUserData() + ud.Value = structInstance + luaState.SetMetatable(ud, luaState.GetTypeMetatable(metaTableName)) + luaState.Push(ud) + + return 1 + } +} + +func checkStruct[T any](luaState *lua.LState) *T { + userData := luaState.CheckUserData(1) + if v, ok := userData.Value.(*T); ok { + return v + } + + luaState.ArgError(1, "got wrong struct") + + return nil +} + +func getterSetterFactory[T any]( + fieldName string, + fieldType reflect.Type, + checkStruct func(luaState *lua.LState) *T, +) func(*lua.LState) int { + return func(luaState *lua.LState) int { + genericStruct := checkStruct(luaState) + + structValue := reflect.ValueOf(genericStruct).Elem() + + fieldValue := structValue.FieldByName(fieldName) + + if luaState.GetTop() == 2 { //nolint: mnd,gomnd + switch fieldType.Kind() { + case reflect.String: + fieldValue.SetString(luaState.CheckString(2)) //nolint: mnd,gomnd + case reflect.Float64: + fieldValue.SetFloat(float64(luaState.CheckNumber(2))) //nolint: mnd,gomnd + case reflect.Float32: + fieldValue.SetFloat(float64(luaState.CheckNumber(2))) //nolint: mnd,gomnd + case reflect.Int8: + fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd + case reflect.Int16: + fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd + case reflect.Int: + fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd + case reflect.Int32: + fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd + case reflect.Int64: + fieldValue.SetInt(int64(luaState.CheckInt(2))) //nolint: mnd,gomnd + case reflect.Bool: + fieldValue.SetBool(luaState.CheckBool(2)) //nolint: mnd,gomnd + default: + log.Print("unsupported type") + } + + return 0 + } + + switch fieldType.Kind() { + case reflect.String: + luaState.Push(lua.LString(fieldValue.Interface().(string))) + case reflect.Float64: + luaState.Push(lua.LNumber(fieldValue.Interface().(float64))) + case reflect.Float32: + luaState.Push(lua.LNumber(fieldValue.Float())) + case reflect.Int8: + luaState.Push(lua.LNumber(fieldValue.Int())) + case reflect.Int16: + luaState.Push(lua.LNumber(fieldValue.Int())) + case reflect.Int: + luaState.Push(lua.LNumber(fieldValue.Int())) + case reflect.Int32: + luaState.Push(lua.LNumber(fieldValue.Int())) + case reflect.Int64: + luaState.Push(lua.LNumber(fieldValue.Int())) + case reflect.Bool: + luaState.Push(lua.LBool(fieldValue.Bool())) + default: + log.Print("unsupported type") + } + + return 1 + } +} + +func luaTableGenFactory[T any]( + structType reflect.Type, + checkStructType func(luaState *lua.LState) *T) map[string]lua.LGFunction { + tableMethods := make(map[string]lua.LGFunction) + + for _, field := range reflect.VisibleFields(structType) { + tableMethods[field.Name] = getterSetterFactory(field.Name, field.Type, checkStructType) + } + + return tableMethods +} + +func RegisterCustomLuaTypes(luaState *lua.LState) { + registerStrucAsLuaMetaTable(luaState, checkStruct, TomlConfig{}, "toml_config") + registerStrucAsLuaMetaTable(luaState, checkStruct, CustomCommand{}, "custom_command") +} + +func returnAllPlugins(pluginPath string) ([]string, error) { + pluginList := make([]string, 0) + + files, err := os.ReadDir(pluginPath) + if err != nil { + return pluginList, fmt.Errorf("Error reading plugins directory: %v", err) + } + + for _, file := range files { + pluginList = append(pluginList, file.Name()) + } + + return pluginList, nil +} + +func LoadAllPlugins(appConfig *TomlConfig) { + luaState := lua.NewState() + defer luaState.Close() + + RegisterCustomLuaTypes(luaState) + + allPlugins, err := returnAllPlugins(appConfig.PluginPath) + if err != nil { + luaState.Close() + + log.Fatal(err) //nolint: gocritic + } + + log.Println(allPlugins) +} -- cgit v1.2.3