github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/ptr.go (about) 1 package reflect 2 3 import ( 4 "fmt" 5 "reflect" 6 7 "github.com/hirochachacha/plua/internal/tables" 8 "github.com/hirochachacha/plua/object" 9 "github.com/hirochachacha/plua/object/fnutil" 10 ) 11 12 func buildPtrMT() { 13 mt := tables.NewTableSize(0, 5) 14 15 mt.Set(object.TM_METATABLE, object.True) 16 mt.Set(object.TM_NAME, object.String("PTR*")) 17 mt.Set(object.TM_TOSTRING, object.GoFunction(ptostring)) 18 19 mt.Set(object.TM_INDEX, object.GoFunction(pindex)) 20 mt.Set(object.TM_NEWINDEX, object.GoFunction(pnewindex)) 21 22 mt.Set(object.TM_EQ, cmp(func(x, y reflect.Value) bool { return x.Pointer() == y.Pointer() }, toPtr)) 23 24 ptrMT = mt 25 } 26 27 func toPtr(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) { 28 val, err := toValue(ap, n, "PTR*") 29 if err != nil { 30 return reflect.Value{}, err 31 } 32 if val.Kind() != reflect.Ptr { 33 return reflect.Value{}, ap.TypeError(n, "PTR*") 34 } 35 return val, nil 36 } 37 38 func ptostring(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 39 ap := fnutil.NewArgParser(th, args) 40 41 p, err := toPtr(ap, 0) 42 if err != nil { 43 return nil, err 44 } 45 46 return []object.Value{object.String(fmt.Sprintf("go pointer (0x%x)", p.Pointer()))}, nil 47 } 48 49 func pindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 50 ap := fnutil.NewArgParser(th, args) 51 52 p, err := toPtr(ap, 0) 53 if err != nil { 54 return nil, err 55 } 56 57 name, err := ap.ToGoString(1) 58 if err != nil { 59 return nil, err 60 } 61 62 if !isPublic(name) { 63 return nil, nil 64 } 65 66 method := p.MethodByName(name) 67 68 if !method.IsValid() { 69 elem := p.Elem() 70 71 method = elem.MethodByName(name) 72 73 if !method.IsValid() { 74 if elem.Kind() == reflect.Struct { 75 field := elem.FieldByName(name) 76 if field.IsValid() { 77 return []object.Value{valueOfReflect(field, false)}, nil 78 } 79 } 80 return nil, nil 81 } 82 } 83 84 return []object.Value{valueOfReflect(method, false)}, nil 85 } 86 87 func pnewindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 88 ap := fnutil.NewArgParser(th, args) 89 90 p, err := toPtr(ap, 0) 91 if err != nil { 92 return nil, err 93 } 94 95 name, err := ap.ToGoString(1) 96 if err != nil { 97 return nil, err 98 } 99 100 val, err := ap.ToValue(2) 101 if err != nil { 102 return nil, err 103 } 104 105 if !isPublic(name) { 106 return nil, object.NewRuntimeError(fmt.Sprintf("%s is not public method or field", name)) 107 } 108 109 elem := p.Elem() 110 if elem.Kind() == reflect.Struct { 111 field := elem.FieldByName(name) 112 if field.IsValid() { 113 if field.Kind() == reflect.Ptr { 114 field = field.Elem() 115 } 116 117 if rval := toReflectValue(field.Type(), val); rval.IsValid() { 118 field.Set(rval) 119 120 return nil, nil 121 } 122 123 return nil, object.NewRuntimeError(fmt.Sprintf("cannot use %v (type %s) as type %s in field assignment", val, reflect.TypeOf(val), field.Type())) 124 } 125 } 126 127 return nil, object.NewRuntimeError(fmt.Sprintf("type %s has no field or method %s", p.Type(), name)) 128 }