123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- package lua
- /*
- #include <stdlib.h>
- #include "../clua/lua.h"
- #include "../clua/lualib.h"
- */
- import "C"
- import (
- "reflect"
- "sync"
- "unsafe"
- )
- // Type of allocation functions to use with NewStateAlloc
- type Alloc func(ptr unsafe.Pointer, osize uint, nsize uint) unsafe.Pointer
- // This is the type of go function that can be registered as lua functions
- type LuaGoFunction func(L *State) int
- // This is the type of a go function that can be used as a lua_Hook
- type HookFunction func(L *State)
- // The errorstring used by State.SetExecutionLimit
- const ExecutionQuantumExceeded = "Lua execution quantum exceeded"
- // Wrapper to keep cgo from complaining about incomplete ptr type
- //export State
- type State struct {
- // Wrapped lua_State object
- s *C.lua_State
- // index of this object inside the goStates array
- Index uintptr
- // Registry of go object that have been pushed to Lua VM
- registry []interface{}
- // Freelist for funcs indices, to allow for freeing
- freeIndices []uint
- // User self defined memory alloc func for the lua State
- allocfn *Alloc
- // User defined hook function
- hookFn HookFunction
- }
- var goStates map[uintptr]*State
- var goStatesMutex sync.Mutex
- func init() {
- goStates = make(map[uintptr]*State, 16)
- }
- func registerGoState(L *State) {
- goStatesMutex.Lock()
- defer goStatesMutex.Unlock()
- L.Index = uintptr(unsafe.Pointer(L))
- goStates[L.Index] = L
- }
- func unregisterGoState(L *State) {
- goStatesMutex.Lock()
- defer goStatesMutex.Unlock()
- delete(goStates, L.Index)
- }
- func getGoState(gostateindex uintptr) *State {
- goStatesMutex.Lock()
- defer goStatesMutex.Unlock()
- return goStates[gostateindex]
- }
- //export golua_callgofunction
- func golua_callgofunction(gostateindex uintptr, fid uint) int {
- L1 := getGoState(gostateindex)
- if fid < 0 {
- panic(&LuaError{0, "Requested execution of an unknown function", L1.StackTrace()})
- }
- f := L1.registry[fid].(LuaGoFunction)
- return f(L1)
- }
- //export golua_callgohook
- func golua_callgohook(gostateindex uintptr) {
- L1 := getGoState(gostateindex)
- if L1.hookFn != nil {
- L1.hookFn(L1)
- }
- }
- var typeOfBytes = reflect.TypeOf([]byte(nil))
- //export golua_interface_newindex_callback
- func golua_interface_newindex_callback(gostateindex uintptr, iid uint, field_name_cstr *C.char) int {
- L := getGoState(gostateindex)
- iface := L.registry[iid]
- ifacevalue := reflect.ValueOf(iface).Elem()
- field_name := C.GoString(field_name_cstr)
- fval := ifacevalue.FieldByName(field_name)
- if fval.Kind() == reflect.Ptr {
- fval = fval.Elem()
- }
- luatype := LuaValType(C.lua_type(L.s, 3))
- switch fval.Kind() {
- case reflect.Bool:
- if luatype == LUA_TBOOLEAN {
- fval.SetBool(int(C.lua_toboolean(L.s, 3)) != 0)
- return 1
- } else {
- L.PushString("Wrong assignment to field " + field_name)
- return -1
- }
- case reflect.Int:
- fallthrough
- case reflect.Int8:
- fallthrough
- case reflect.Int16:
- fallthrough
- case reflect.Int32:
- fallthrough
- case reflect.Int64:
- if luatype == LUA_TNUMBER {
- fval.SetInt(int64(luaToInteger(L.s, 3)))
- return 1
- } else {
- L.PushString("Wrong assignment to field " + field_name)
- return -1
- }
- case reflect.Uint:
- fallthrough
- case reflect.Uint8:
- fallthrough
- case reflect.Uint16:
- fallthrough
- case reflect.Uint32:
- fallthrough
- case reflect.Uint64:
- if luatype == LUA_TNUMBER {
- fval.SetUint(uint64(luaToInteger(L.s, 3)))
- return 1
- } else {
- L.PushString("Wrong assignment to field " + field_name)
- return -1
- }
- case reflect.String:
- if luatype == LUA_TSTRING {
- fval.SetString(C.GoString(C.lua_tolstring(L.s, 3, nil)))
- return 1
- } else {
- L.PushString("Wrong assignment to field " + field_name)
- return -1
- }
- case reflect.Float32:
- fallthrough
- case reflect.Float64:
- if luatype == LUA_TNUMBER {
- fval.SetFloat(float64(luaToNumber(L.s, 3)))
- return 1
- } else {
- L.PushString("Wrong assignment to field " + field_name)
- return -1
- }
- case reflect.Slice:
- if fval.Type() == typeOfBytes {
- if luatype == LUA_TSTRING {
- fval.SetBytes(L.ToBytes(3))
- return 1
- } else {
- L.PushString("Wrong assignment to field " + field_name)
- return -1
- }
- }
- }
- L.PushString("Unsupported type of field " + field_name + ": " + fval.Type().String())
- return -1
- }
- //export golua_interface_index_callback
- func golua_interface_index_callback(gostateindex uintptr, iid uint, field_name *C.char) int {
- L := getGoState(gostateindex)
- iface := L.registry[iid]
- ifacevalue := reflect.ValueOf(iface).Elem()
- fval := ifacevalue.FieldByName(C.GoString(field_name))
- if fval.Kind() == reflect.Ptr {
- fval = fval.Elem()
- }
- switch fval.Kind() {
- case reflect.Bool:
- L.PushBoolean(fval.Bool())
- return 1
- case reflect.Int:
- fallthrough
- case reflect.Int8:
- fallthrough
- case reflect.Int16:
- fallthrough
- case reflect.Int32:
- fallthrough
- case reflect.Int64:
- L.PushInteger(fval.Int())
- return 1
- case reflect.Uint:
- fallthrough
- case reflect.Uint8:
- fallthrough
- case reflect.Uint16:
- fallthrough
- case reflect.Uint32:
- fallthrough
- case reflect.Uint64:
- L.PushInteger(int64(fval.Uint()))
- return 1
- case reflect.String:
- L.PushString(fval.String())
- return 1
- case reflect.Float32:
- fallthrough
- case reflect.Float64:
- L.PushNumber(fval.Float())
- return 1
- case reflect.Slice:
- if fval.Type() == typeOfBytes {
- L.PushBytes(fval.Bytes())
- return 1
- }
- }
- L.PushString("Unsupported type of field: " + fval.Type().String())
- return -1
- }
- //export golua_gchook
- func golua_gchook(gostateindex uintptr, id uint) int {
- L1 := getGoState(gostateindex)
- L1.unregister(id)
- return 0
- }
- //export golua_callpanicfunction
- func golua_callpanicfunction(gostateindex uintptr, id uint) int {
- L1 := getGoState(gostateindex)
- f := L1.registry[id].(LuaGoFunction)
- return f(L1)
- }
- //export golua_idtointerface
- func golua_idtointerface(id uint) interface{} {
- return id
- }
- //export golua_cfunctiontointerface
- func golua_cfunctiontointerface(f *uintptr) interface{} {
- return f
- }
- //export golua_callallocf
- func golua_callallocf(fp uintptr, ptr uintptr, osize uint, nsize uint) uintptr {
- return uintptr((*((*Alloc)(unsafe.Pointer(fp))))(unsafe.Pointer(ptr), osize, nsize))
- }
- //export go_panic_msghandler
- func go_panic_msghandler(gostateindex uintptr, z *C.char) {
- L := getGoState(gostateindex)
- s := C.GoString(z)
- panic(&LuaError{LUA_ERRERR, s, L.StackTrace()})
- }
|