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  }