140 lines
3.6 KiB
Go
140 lines
3.6 KiB
Go
package modules
|
|
|
|
import (
|
|
"embed"
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"Moonshark/functions"
|
|
|
|
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
|
|
)
|
|
|
|
//go:embed *.lua
|
|
var builtinModules embed.FS
|
|
|
|
// ModuleRegistry manages built-in modules and Go functions
|
|
type ModuleRegistry struct {
|
|
modules map[string]string
|
|
goFuncs map[string]luajit.GoFunction
|
|
}
|
|
|
|
// NewModuleRegistry creates a new module registry
|
|
func NewModuleRegistry() *ModuleRegistry {
|
|
mr := &ModuleRegistry{
|
|
modules: make(map[string]string),
|
|
goFuncs: functions.GetAll(),
|
|
}
|
|
|
|
return mr
|
|
}
|
|
|
|
// RegisterModule adds a module by name and source code
|
|
func (mr *ModuleRegistry) RegisterModule(name, source string) {
|
|
mr.modules[name] = source
|
|
}
|
|
|
|
// RegisterGoFunction adds a Go function that modules can use
|
|
func (mr *ModuleRegistry) RegisterGoFunction(name string, fn luajit.GoFunction) {
|
|
mr.goFuncs[name] = fn
|
|
}
|
|
|
|
// LoadEmbeddedModules loads all modules from the embedded filesystem
|
|
func (mr *ModuleRegistry) LoadEmbeddedModules() error {
|
|
entries, err := builtinModules.ReadDir(".")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read modules directory: %w", err)
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".lua") {
|
|
continue
|
|
}
|
|
|
|
moduleName := strings.TrimSuffix(entry.Name(), ".lua")
|
|
source, err := builtinModules.ReadFile(filepath.Join(".", entry.Name()))
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read module %s: %w", moduleName, err)
|
|
}
|
|
|
|
mr.RegisterModule(moduleName, string(source))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// InstallModules sets up the module system in the Lua state
|
|
func (mr *ModuleRegistry) InstallModules(state *luajit.State) error {
|
|
// Create moonshark global table
|
|
state.NewTable()
|
|
state.SetGlobal("moonshark")
|
|
|
|
// Install Go functions first
|
|
if err := mr.installGoFunctions(state); err != nil {
|
|
return fmt.Errorf("failed to install Go functions: %w", err)
|
|
}
|
|
|
|
// Register require function that checks our built-in modules first
|
|
err := state.RegisterGoFunction("require", func(s *luajit.State) int {
|
|
if err := s.CheckMinArgs(1); err != nil {
|
|
return s.PushError("require: %v", err)
|
|
}
|
|
|
|
moduleName, err := s.SafeToString(1)
|
|
if err != nil {
|
|
return s.PushError("require: module name must be a string")
|
|
}
|
|
|
|
// Check if it's a built-in module
|
|
if source, exists := mr.modules[moduleName]; exists {
|
|
// Execute the module and return its result
|
|
if err := s.LoadString(source); err != nil {
|
|
return s.PushError("require: failed to load module '%s': %v", moduleName, err)
|
|
}
|
|
|
|
if err := s.Call(0, 1); err != nil {
|
|
return s.PushError("require: failed to execute module '%s': %v", moduleName, err)
|
|
}
|
|
|
|
return 1 // Return the module's result
|
|
}
|
|
|
|
// Fall back to standard Lua require
|
|
s.GetGlobal("_require_original")
|
|
if s.IsFunction(-1) {
|
|
s.PushString(moduleName)
|
|
if err := s.Call(1, 1); err != nil {
|
|
return s.PushError("require: %v", err)
|
|
}
|
|
return 1
|
|
}
|
|
|
|
return s.PushError("require: module '%s' not found", moduleName)
|
|
})
|
|
|
|
return err
|
|
}
|
|
|
|
// installGoFunctions installs all registered Go functions into the Lua state
|
|
func (mr *ModuleRegistry) installGoFunctions(state *luajit.State) error {
|
|
// Install functions in moonshark namespace
|
|
state.GetGlobal("moonshark")
|
|
|
|
for name, fn := range mr.goFuncs {
|
|
if err := state.PushGoFunction(fn); err != nil {
|
|
return fmt.Errorf("failed to register Go function '%s': %w", name, err)
|
|
}
|
|
state.SetField(-2, name)
|
|
}
|
|
|
|
state.Pop(1) // Remove moonshark table
|
|
return nil
|
|
}
|
|
|
|
// BackupOriginalRequire saves the original require function
|
|
func BackupOriginalRequire(state *luajit.State) {
|
|
state.GetGlobal("require")
|
|
state.SetGlobal("_require_original")
|
|
}
|