github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/value.go (about) 1 package reflect 2 3 import ( 4 "fmt" 5 "reflect" 6 "unicode" 7 "unicode/utf8" 8 9 "github.com/hirochachacha/plua/object" 10 "github.com/hirochachacha/plua/object/fnutil" 11 ) 12 13 type toValuefn func(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) 14 15 func tostring(toValue toValuefn) object.GoFunction { 16 return func(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 17 ap := fnutil.NewArgParser(th, args) 18 19 self, err := toValue(ap, 0) 20 if err != nil { 21 return nil, err 22 } 23 24 return []object.Value{object.String(fmt.Sprintf("%v", self))}, nil 25 } 26 } 27 28 func index(toValue toValuefn) object.GoFunction { 29 return func(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 30 ap := fnutil.NewArgParser(th, args) 31 32 self, err := toValue(ap, 0) 33 if err != nil { 34 return nil, err 35 } 36 37 name, err := ap.ToGoString(1) 38 if err != nil { 39 return nil, err 40 } 41 42 if !isPublic(name) { 43 return nil, nil 44 } 45 46 method := self.MethodByName(name) 47 48 if !method.IsValid() { 49 if self.CanAddr() { 50 method = self.Addr().MethodByName(name) 51 } else { 52 self2 := reflect.New(self.Type()) 53 self2.Elem().Set(self) 54 method = self2.MethodByName(name) 55 } 56 57 if !method.IsValid() { 58 return nil, nil 59 } 60 } 61 62 return []object.Value{valueOfReflect(method, false)}, nil 63 } 64 } 65 66 func cmp(op func(x, y reflect.Value) bool, toValue toValuefn) object.GoFunction { 67 return func(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 68 ap := fnutil.NewArgParser(th, args) 69 70 x, err := toValue(ap, 0) 71 if err != nil { 72 return nil, err 73 } 74 75 y, err := toValue(ap, 1) 76 if err != nil { 77 return nil, err 78 } 79 80 return []object.Value{object.Boolean(op(x, y))}, nil 81 } 82 } 83 84 func unary(op func(x reflect.Value) reflect.Value, toValue toValuefn, mt object.Table) object.GoFunction { 85 return func(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 86 ap := fnutil.NewArgParser(th, args) 87 88 x, err := toValue(ap, 0) 89 if err != nil { 90 return nil, err 91 } 92 93 val := op(x) 94 95 ud := &object.Userdata{Value: val.Convert(x.Type()), Metatable: mt} 96 97 return []object.Value{ud}, nil 98 } 99 } 100 101 func binary(op func(x, y reflect.Value) (reflect.Value, *object.RuntimeError), toValue toValuefn, mt object.Table) object.GoFunction { 102 return func(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 103 ap := fnutil.NewArgParser(th, args) 104 105 x, err := toValue(ap, 0) 106 if err != nil { 107 return nil, err 108 } 109 110 y, err := toValue(ap, 1) 111 if err != nil { 112 return nil, err 113 } 114 115 val, err := op(x, y) 116 if err != nil { 117 return nil, err 118 } 119 120 ud := &object.Userdata{Value: val.Convert(x.Type()), Metatable: mt} 121 122 return []object.Value{ud}, nil 123 } 124 } 125 126 func isPublic(name string) bool { 127 r, _ := utf8.DecodeRuneInString(name) 128 129 return unicode.IsUpper(r) 130 } 131 132 func toValue(ap *fnutil.ArgParser, n int, tname string) (reflect.Value, *object.RuntimeError) { 133 ud, err := ap.ToFullUserdata(n) 134 if err != nil { 135 return reflect.Value{}, ap.TypeError(n, tname) 136 } 137 138 if ud.Metatable == nil || ud.Metatable.Get(object.TM_NAME) != object.String(tname) { 139 return reflect.Value{}, ap.TypeError(n, tname) 140 } 141 142 val, ok := ud.Value.(reflect.Value) 143 if !ok { 144 return reflect.Value{}, ap.TypeError(n, tname) 145 } 146 147 return val, nil 148 }