github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/func.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 buildFuncMT() { 13 mt := tables.NewTableSize(0, 5) 14 15 mt.Set(object.TM_METATABLE, object.True) 16 mt.Set(object.TM_NAME, object.String("FUNC*")) 17 mt.Set(object.TM_TOSTRING, object.GoFunction(functostring)) 18 mt.Set(object.TM_INDEX, index(toFunc)) 19 20 mt.Set(object.TM_CALL, object.GoFunction(call)) 21 22 mt.Set(object.TM_EQ, cmp(func(x, y reflect.Value) bool { return x.Pointer() == y.Pointer() }, toFunc)) 23 24 funcMT = mt 25 } 26 27 func toFunc(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) { 28 val, err := toValue(ap, n, "FUNC*") 29 if err != nil { 30 return reflect.Value{}, err 31 } 32 if val.Kind() != reflect.Func { 33 return reflect.Value{}, ap.TypeError(n, "INT*") 34 } 35 return val, nil 36 } 37 38 func functostring(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 39 ap := fnutil.NewArgParser(th, args) 40 41 f, err := toFunc(ap, 0) 42 if err != nil { 43 return nil, err 44 } 45 46 return []object.Value{object.String(fmt.Sprintf("go func (0x%x)", f.Pointer()))}, nil 47 } 48 49 func call(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) { 50 ap := fnutil.NewArgParser(th, args) 51 52 f, err := toFunc(ap, 0) 53 if err != nil { 54 return nil, err 55 } 56 57 styp := f.Type() 58 59 var numin int 60 if styp.IsVariadic() { 61 numin = styp.NumIn() - 1 62 if len(args)-1 > numin { 63 numin = len(args) - 1 64 } 65 } else { 66 numin = styp.NumIn() 67 } 68 69 rargs := make([]reflect.Value, numin) 70 71 if len(args)-1 >= len(rargs) { 72 for i := range rargs { 73 if rarg := toReflectValue(styp.In(i), args[1+i]); rarg.IsValid() { 74 rargs[i] = rarg 75 } else { 76 return nil, object.NewRuntimeError(fmt.Sprintf("mismatched types %s and %s", styp.In(i), reflect.TypeOf(args[1+i]))) 77 } 78 } 79 } else { 80 for i, arg := range args[1:] { 81 if rarg := toReflectValue(styp.In(i), arg); rarg.IsValid() { 82 rargs[i] = rarg 83 } else { 84 return nil, object.NewRuntimeError(fmt.Sprintf("mismatched types %s and %s", styp.In(i), reflect.TypeOf(arg))) 85 } 86 } 87 88 for i := len(args); i < len(rargs); i++ { 89 if rarg := toReflectValue(styp.In(i), nil); rarg.IsValid() { 90 rargs[i] = rarg 91 } else { 92 return nil, object.NewRuntimeError(fmt.Sprintf("mismatched types %s and %s", styp.In(i), reflect.TypeOf(nil))) 93 } 94 } 95 } 96 97 rrets := f.Call(rargs) 98 99 rets := make([]object.Value, len(rrets)) 100 for i, rret := range rrets { 101 rets[i] = valueOfReflect(rret, false) 102 } 103 104 return rets, nil 105 }