131 lines
2.6 KiB
Go
131 lines
2.6 KiB
Go
|
package luar
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
|
||
|
"github.com/yuin/gopher-lua"
|
||
|
)
|
||
|
|
||
|
func checkPtr(L *lua.LState, idx int) reflect.Value {
|
||
|
ud := L.CheckUserData(idx)
|
||
|
ref := reflect.ValueOf(ud.Value)
|
||
|
if ref.Kind() != reflect.Ptr {
|
||
|
L.ArgError(idx, "expecting ptr")
|
||
|
}
|
||
|
return ref
|
||
|
}
|
||
|
|
||
|
func ptrIndex(L *lua.LState) int {
|
||
|
ref := checkPtr(L, 1)
|
||
|
deref := ref.Elem()
|
||
|
if deref.Kind() != reflect.Struct {
|
||
|
L.RaiseError("cannot index non-struct pointer")
|
||
|
}
|
||
|
refType := ref.Type()
|
||
|
|
||
|
// Check for method
|
||
|
key := L.OptString(2, "")
|
||
|
exKey := getExportedName(key)
|
||
|
if key != "" {
|
||
|
if method, ok := refType.MethodByName(exKey); ok {
|
||
|
L.Push(New(L, method.Func.Interface()))
|
||
|
return 1
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Check for field
|
||
|
if field := deref.FieldByName(exKey); field.IsValid() {
|
||
|
if !field.CanInterface() {
|
||
|
L.RaiseError("cannot interface field " + exKey)
|
||
|
}
|
||
|
if val := New(L, field.Interface()); val != nil {
|
||
|
L.Push(val)
|
||
|
return 1
|
||
|
}
|
||
|
L.RaiseError("could not convert field " + exKey)
|
||
|
}
|
||
|
|
||
|
if ret := metaFunction(L, luarIndexFunc, ref); ret >= 0 {
|
||
|
return ret
|
||
|
}
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func ptrNewIndex(L *lua.LState) int {
|
||
|
ref := checkPtr(L, 1)
|
||
|
deref := ref.Elem()
|
||
|
|
||
|
if deref.Kind() != reflect.Struct {
|
||
|
L.RaiseError("cannot new index non-struct pointer")
|
||
|
}
|
||
|
|
||
|
key := L.OptString(2, "")
|
||
|
value := L.CheckAny(3)
|
||
|
|
||
|
if key == "" {
|
||
|
if ret := metaFunction(L, luarNewIndexFunc, ref); ret >= 0 {
|
||
|
return ret
|
||
|
}
|
||
|
L.TypeError(2, lua.LTString)
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
exKey := getExportedName(key)
|
||
|
|
||
|
field := deref.FieldByName(exKey)
|
||
|
if !field.IsValid() {
|
||
|
if ret := metaFunction(L, luarNewIndexFunc, ref); ret >= 0 {
|
||
|
return ret
|
||
|
}
|
||
|
L.ArgError(2, "unknown field "+exKey)
|
||
|
}
|
||
|
if !field.CanSet() {
|
||
|
L.ArgError(2, "cannot set field "+exKey)
|
||
|
}
|
||
|
field.Set(lValueToReflect(value, field.Type()))
|
||
|
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func ptrPow(L *lua.LState) int {
|
||
|
ref := checkPtr(L, 1)
|
||
|
val := L.CheckAny(2)
|
||
|
|
||
|
if ref.IsNil() {
|
||
|
L.RaiseError("cannot dereference nil pointer")
|
||
|
}
|
||
|
elem := ref.Elem()
|
||
|
if !elem.CanSet() {
|
||
|
L.RaiseError("unable to set pointer value")
|
||
|
}
|
||
|
value := lValueToReflect(val, elem.Type())
|
||
|
elem.Set(value)
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
func ptrCall(L *lua.LState) int {
|
||
|
ref := checkPtr(L, 1)
|
||
|
if ret := metaFunction(L, luarCallFunc, ref); ret >= 0 {
|
||
|
return ret
|
||
|
}
|
||
|
L.RaiseError("attempt to call a non-function object")
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func ptrUnm(L *lua.LState) int {
|
||
|
ref := checkPtr(L, 1)
|
||
|
elem := ref.Elem()
|
||
|
if !elem.CanInterface() {
|
||
|
L.RaiseError("cannot interface pointer type " + elem.String())
|
||
|
}
|
||
|
L.Push(New(L, elem.Interface()))
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
func ptrEq(L *lua.LState) int {
|
||
|
ptr1 := checkPtr(L, 1)
|
||
|
ptr2 := checkPtr(L, 2)
|
||
|
L.Push(lua.LBool(ptr1 == ptr2))
|
||
|
return 1
|
||
|
}
|