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  }