diff --git a/vm.go b/vm.go index c25a090..415f986 100644 --- a/vm.go +++ b/vm.go @@ -8,7 +8,11 @@ package lua import ( + "fmt" luaCompile "github.com/yuin/gopher-lua" + "github.com/yuin/gopher-lua/ast" + "github.com/yuin/gopher-lua/parse" + "strings" "sync" ) @@ -16,19 +20,57 @@ var ( VMInstance *VM ) -func InitVM(poolSize int) { +// InitVM 初始化lua虚拟机 +func InitVM(poolSize int, preComplierScript map[string]string) error { if poolSize <= 0 { poolSize = 32 } VMInstance = &VM{ - l: &sync.RWMutex{}, - pool: make([]*luaCompile.LState, 0), + l: &sync.RWMutex{}, + scriptLock: &sync.RWMutex{}, + pool: make([]*luaCompile.LState, 0), + preComplierScript: make(map[string]*luaCompile.FunctionProto), } + for scriptID, scriptContent := range preComplierScript { + if err := VMInstance.AddScript(scriptID, scriptContent); nil != err { + return err + } + } + return nil } type VM struct { - l *sync.RWMutex - pool []*luaCompile.LState + l *sync.RWMutex + scriptLock *sync.RWMutex + pool []*luaCompile.LState // lua虚拟机实例池 + preComplierScript map[string]*luaCompile.FunctionProto // 预编译的脚本内容 +} + +// AddScript 脚本编译 +func (v *VM) AddScript(scriptID string, script string) error { + v.scriptLock.Lock() + defer v.scriptLock.Unlock() + var ( + err error + chunk []ast.Stmt + proto *luaCompile.FunctionProto + ) + + if chunk, err = parse.Parse(strings.NewReader(script), scriptID); nil != err { + return err + } + if proto, err = luaCompile.Compile(chunk, scriptID); nil != err { + return err + } + v.preComplierScript[scriptID] = proto + return nil +} + +// RemoveScript 删除一个已编译的脚本 +func (v *VM) RemoveScript(scriptID string) { + v.scriptLock.Lock() + defer v.scriptLock.Unlock() + delete(v.preComplierScript, scriptID) } // GetVm 获取一个VM实例 @@ -59,6 +101,29 @@ func (v *VM) Shutdown() { } } +// RunPreCompileScript 执行预编译过的脚本 +func (v *VM) RunPreCompileScript(scriptID string) (*luaCompile.LState, error) { + var ( + err error + proto *luaCompile.FunctionProto + exists bool + ) + v.scriptLock.Lock() + if proto, exists = v.preComplierScript[scriptID]; !exists { + v.scriptLock.Unlock() + return nil, fmt.Errorf("preComplier script %s not found", scriptID) + } + v.scriptLock.Unlock() + l := v.GetVm() + lFunc := l.NewFunctionFromProto(proto) + l.Push(lFunc) + if err = l.PCall(0, luaCompile.MultRet, nil); nil != err { + v.Close(l) + return nil, err + } + return l, nil +} + // Run 运行脚本 // // Author : go_developer@163.com<白茶清欢>