// 执行lua脚本字符串 func (L *State) Dostring(str string) (ok bool) { cs := C.CString(str) defer C.free(unsafe.Pointer(cs)) if C.luaL_loadstring(L.s, cs) == 0 { return C.lua_pcall(L.s, 0, C.LUA_MULTRET, 0) == 0 } return false }
// 执行lua脚本 func (L *State) Dofile(fname string) (ok bool) { fn := C.CString(fname) defer C.free(unsafe.Pointer(fn)) if C.luaL_loadfile(L.s, fn) == 0 { return C.lua_pcall(L.s, 0, C.LUA_MULTRET, 0) == 0 } return false }
// Peval evaluates a piece of lua code. no panic when error occur. func (l *Lua) Peval(code string, envs ...interface{}) (returns []interface{}, err error) { defer C.lua_settop(l.State, 0) C.push_errfunc(l.State) curTop := C.lua_gettop(l.State) // parse cCode := C.CString(code) defer C.free(unsafe.Pointer(cCode)) if ret := C.luaL_loadstring(l.State, cCode); ret != 0 { // load error return nil, fmt.Errorf("LOAD ERROR: %s", C.GoString(C.lua_tolstring(l.State, -1, nil))) } // env if len(envs) > 0 { if len(envs)%2 != 0 { return nil, fmt.Errorf("number of arguments not match") } C.lua_createtable(l.State, 0, 0) for i := 0; i < len(envs); i += 2 { name, ok := envs[i].(string) if !ok { return nil, fmt.Errorf("name must be string, not %v", envs[i]) } C.lua_pushstring(l.State, cstr(name)) err := l.pushGoValue(envs[i+1], name) if err != nil { return nil, err } C.lua_rawset(l.State, -3) } // set env C.set_eval_env(l.State) } // call l.err = nil if ret := C.lua_pcall(l.State, 0, C.LUA_MULTRET, -2); ret != 0 { // error occured return nil, fmt.Errorf("CALL ERROR: %s", C.GoString(C.lua_tolstring(l.State, -1, nil))) } else if l.err != nil { // error raise by invokeGoFunc return nil, l.err } else { // return values nReturn := C.lua_gettop(l.State) - curTop returns = make([]interface{}, int(nReturn)) for i := C.int(0); i < nReturn; i++ { value, err := l.toGoValue(-1-i, interfaceType) if err != nil { return nil, err } if value != nil { returns[int(nReturn-1-i)] = value.Interface() } else { returns[int(nReturn-1-i)] = nil } } } return }
// Calls a function in protected mode. // // Both nargs and nresults have the same meaning as in Call. If there are // no errors during the call, Pcall behaves exactly like Call. However, // if there is any error, Pcall catches it, pushes a single value on the // stack (the error message), and returns an error code. Like Call, Pcall // always removes the function and its arguments from the stack. // // If errfunc is 0, then the error message returned on the stack is exactly // the original error message. Otherwise, errfunc is the stack index of // an error handler function. (In the current implementation, this index // cannot be a pseudo-index.) In case of runtime errors, this function // will be called with the error message and its return value will be the // message returned on the stack by Pcall. // // Typically, the error handler function is used to add more debug // information to the error message, such as a stack traceback. Such // information cannot be gathered after the return of Pcall, since by then // the stack has unwound. func (this *State) Pcall(nargs, nresults, errfunc int) error { defer func() { if r := recover(); r != nil { fmt.Println(r.(string)) } }() r := int(C.lua_pcall(this.luastate, C.int(nargs), C.int(nresults), C.int(errfunc))) return this.geterror(r) }
// Executes an aggregation over the iterator. func (e *ExecutionEngine) Aggregate() (interface{}, error) { functionName := C.CString("sky_aggregate") defer C.free(unsafe.Pointer(functionName)) C.lua_getfield(e.state, -10002, functionName) C.lua_pushlightuserdata(e.state, unsafe.Pointer(e.cursor)) rc := C.lua_pcall(e.state, 1, 1, 0) if rc != 0 { luaErrString := C.GoString(C.lua_tolstring(e.state, -1, nil)) fmt.Println(e.FullAnnotatedSource()) return nil, fmt.Errorf("skyd.ExecutionEngine: Unable to aggregate: %s", luaErrString) } return e.decodeResult() }
// Initializes the Lua context and compiles the source code. func (e *ExecutionEngine) init() error { if e.state != nil { return nil } // Initialize the state and open the libraries. e.state = C.luaL_newstate() if e.state == nil { return errors.New("Unable to initialize Lua context.") } C.luaL_openlibs(e.state) // Generate the header file. err := e.generateHeader() if err != nil { e.Destroy() return err } // Compile the script. e.fullSource = fmt.Sprintf("%v\n%v", e.header, e.source) source := C.CString(e.fullSource) defer C.free(unsafe.Pointer(source)) ret := C.luaL_loadstring(e.state, source) if ret != 0 { defer e.Destroy() errstring := C.GoString(C.lua_tolstring(e.state, -1, nil)) return fmt.Errorf("skyd.ExecutionEngine: Syntax Error: %v", errstring) } // Run script once to initialize. ret = C.lua_pcall(e.state, 0, 0, 0) if ret != 0 { defer e.Destroy() errstring := C.GoString(C.lua_tolstring(e.state, -1, nil)) return fmt.Errorf("skyd.ExecutionEngine: Init Error: %v", errstring) } // Setup cursor. err = e.initCursor() if err != nil { e.Destroy() return err } return nil }
// Pcall calls a lua function. no panic func (l *Lua) Pcall(fullname string, args ...interface{}) (returns []interface{}, err error) { C.push_errfunc(l.State) curTop := C.lua_gettop(l.State) // get function path := strings.Split(fullname, ".") for i, name := range path { if i == 0 { C.lua_getfield(l.State, C.LUA_GLOBALSINDEX, cstr(name)) } else { if C.lua_type(l.State, -1) != C.LUA_TTABLE { return nil, fmt.Errorf("%s is not a function", fullname) } C.lua_pushstring(l.State, cstr(name)) C.lua_gettable(l.State, -2) C.lua_remove(l.State, -2) // remove table } } if C.lua_type(l.State, -1) != C.LUA_TFUNCTION { return nil, fmt.Errorf("%s is not a function", fullname) } // args for _, arg := range args { l.pushGoValue(arg, "") } // call l.err = nil if ret := C.lua_pcall(l.State, C.int(len(args)), C.LUA_MULTRET, C.int(-(len(args))-2)); ret != 0 { // error occured return nil, fmt.Errorf("CALL ERROR: %s", C.GoString(C.lua_tolstring(l.State, -1, nil))) } else if l.err != nil { // error raise by invokeGoFunc return nil, l.err } else { // return values nReturn := C.lua_gettop(l.State) - curTop returns = make([]interface{}, int(nReturn)) for i := C.int(0); i < nReturn; i++ { value, err := l.toGoValue(-1-i, interfaceType) if err != nil { return nil, err } returns[int(nReturn-1-i)] = value.Interface() } } return }
func callLuaFuncUtil(state State, inv []reflect.Value, nout int) ([]interface{}, error) { L := state.L bottom := int(C.lua_gettop(L)) var result []interface{} var nluaout C.int var nin C.int if nout >= 0 { nluaout = C.int(nout) result = make([]interface{}, 0, nout) } else { nluaout = C.LUA_MULTRET result = make([]interface{}, 0, 1) } if inv != nil { for _, iarg := range inv { state.goToLuaValue(iarg) } nin = C.int(len(inv)) } else { nin = 0 } ret := int(C.lua_pcall(L, nin, nluaout, 0)) if ret != 0 { err := stringFromLua(L, -1) C.lua_settop(L, -2) return result, errors.New(err) } top := int(C.lua_gettop(L)) for i := bottom; i <= top; i++ { value, _ := state.luaToGoValue(i, nil) if value.IsValid() { result = append(result, value.Interface()) } else { result = append(result, nil) } } rnout := C.int(top + 1 - bottom) C.lua_settop(L, -rnout-1) return result, nil }
// Executes an merge over the iterator. func (e *ExecutionEngine) Merge(results interface{}, data interface{}) (interface{}, error) { functionName := C.CString("sky_merge") defer C.free(unsafe.Pointer(functionName)) C.lua_getfield(e.state, -10002, functionName) err := e.encodeArgument(results) if err != nil { return results, err } err = e.encodeArgument(data) if err != nil { return results, err } rc := C.lua_pcall(e.state, 2, 1, 0) if rc != 0 { luaErrString := C.GoString(C.lua_tolstring(e.state, -1, nil)) fmt.Println(e.FullAnnotatedSource()) return results, fmt.Errorf("skyd.ExecutionEngine: Unable to merge: %s", luaErrString) } return e.decodeResult() }
// Initializes the cursor used by the script. func (e *ExecutionEngine) initCursor() error { // Create the cursor. minPropertyId, maxPropertyId := e.propertyFile.NextIdentifiers() e.cursor = C.sky_cursor_new((C.int32_t)(minPropertyId), (C.int32_t)(maxPropertyId)) e.cursor.context = unsafe.Pointer(e) C.executionEngine_setNextObjectFunc(unsafe.Pointer(e.cursor)) // Initialize the cursor from within Lua. functionName := C.CString("sky_init_cursor") defer C.free(unsafe.Pointer(functionName)) C.lua_getfield(e.state, -10002, functionName) C.lua_pushlightuserdata(e.state, unsafe.Pointer(e.cursor)) //fmt.Printf("%s\n\n", e.FullAnnotatedSource()) rc := C.lua_pcall(e.state, 1, 0, 0) if rc != 0 { luaErrString := C.GoString(C.lua_tolstring(e.state, -1, nil)) return fmt.Errorf("Unable to init cursor: %s", luaErrString) } return nil }
func (L *State) pcall(nargs, nresults, errfunc int) int { return int(C.lua_pcall(L.s, C.int(nargs), C.int(nresults), C.int(errfunc))) }
// Calls a function in protected mode. // // Both nargs and nresults have the same meaning as in Call. If there are // no errors during the call, Pcall behaves exactly like Call. However, // if there is any error, Pcall catches it, pushes a single value on the // stack (the error message), and returns an error code. Like Call, Pcall // always removes the function and its arguments from the stack. // // If errfunc is 0, then the error message returned on the stack is exactly // the original error message. Otherwise, errfunc is the stack index of // an error handler function. (In the current implementation, this index // cannot be a pseudo-index.) In case of runtime errors, this function // will be called with the error message and its return value will be the // message returned on the stack by Pcall. // // Typically, the error handler function is used to add more debug // information to the error message, such as a stack traceback. Such // information cannot be gathered after the return of Pcall, since by then // the stack has unwound. func (s *State) Pcall(nargs, nresults, errfunc int) error { r := int(C.lua_pcall(s.l, C.int(nargs), C.int(nresults), C.int(errfunc))) return numtoerror(r) }
func Pcall(s *State, nargs, nres, errf int) int { return int(C.lua_pcall((*C.lua_State)(s), C.int(nargs), C.int(nres), C.int(errf))) }