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  }