github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/array.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 buildArrayMT() {
    13  	mt := tables.NewTableSize(0, 7)
    14  
    15  	mt.Set(object.TM_METATABLE, object.True)
    16  	mt.Set(object.TM_NAME, object.String("ARRAY*"))
    17  	mt.Set(object.TM_TOSTRING, object.GoFunction(atostring))
    18  
    19  	mt.Set(object.TM_INDEX, object.GoFunction(aindex))
    20  	mt.Set(object.TM_LEN, object.GoFunction(alength))
    21  	mt.Set(object.TM_PAIRS, object.GoFunction(apairs))
    22  
    23  	mt.Set(object.TM_EQ, cmp(func(x, y reflect.Value) bool { return aeq(x, y) }, toArray))
    24  
    25  	arrayMT = mt
    26  }
    27  
    28  func toArray(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) {
    29  	val, err := toValue(ap, n, "ARRAY*")
    30  	if err != nil {
    31  		return reflect.Value{}, err
    32  	}
    33  	if val.Kind() != reflect.Array {
    34  		return reflect.Value{}, ap.TypeError(n, "ARRAY*")
    35  	}
    36  	return val, nil
    37  }
    38  
    39  func atostring(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    40  	ap := fnutil.NewArgParser(th, args)
    41  
    42  	a, err := toArray(ap, 0)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	return []object.Value{object.String(fmt.Sprintf("go array[%d]", a.Len()))}, nil
    48  }
    49  
    50  func alength(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    51  	ap := fnutil.NewArgParser(th, args)
    52  
    53  	a, err := toArray(ap, 0)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  
    58  	return []object.Value{object.Integer(a.Len())}, nil
    59  }
    60  
    61  func aeq(x, y reflect.Value) bool {
    62  	xlen := x.Len()
    63  	ylen := y.Len()
    64  
    65  	if xlen == ylen {
    66  		for i := 0; i < xlen; i++ {
    67  			if x.Index(i).Interface() != y.Index(i).Interface() {
    68  				return false
    69  			}
    70  		}
    71  		return true
    72  	}
    73  
    74  	return false
    75  }
    76  
    77  func aindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
    78  	ap := fnutil.NewArgParser(th, args)
    79  
    80  	a, err := toArray(ap, 0)
    81  	if err != err {
    82  		return nil, err
    83  	}
    84  
    85  	index, err := ap.ToGoInt(1)
    86  	if err != nil {
    87  		name, err := ap.ToGoString(1)
    88  		if err != nil {
    89  			return nil, err
    90  		}
    91  
    92  		if !isPublic(name) {
    93  			return nil, nil
    94  		}
    95  
    96  		method := a.MethodByName(name)
    97  
    98  		if !method.IsValid() {
    99  			if a.CanAddr() {
   100  				method = a.Addr().MethodByName(name)
   101  			} else {
   102  				self2 := reflect.New(a.Type())
   103  				self2.Elem().Set(a)
   104  				method = self2.MethodByName(name)
   105  			}
   106  
   107  			if !method.IsValid() {
   108  				return nil, nil
   109  			}
   110  		}
   111  
   112  		return []object.Value{valueOfReflect(method, false)}, nil
   113  	}
   114  
   115  	index--
   116  
   117  	if 0 <= index && index < a.Len() {
   118  		rval := a.Index(index)
   119  
   120  		return []object.Value{valueOfReflect(rval, false)}, nil
   121  	}
   122  
   123  	return nil, nil
   124  }
   125  
   126  func apairs(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   127  	ap := fnutil.NewArgParser(th, args)
   128  
   129  	_, err := toArray(ap, 0)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return []object.Value{object.GoFunction(anext), args[0], object.Integer(0)}, nil
   135  }
   136  
   137  func anext(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   138  	ap := fnutil.NewArgParser(th, args)
   139  
   140  	a, err := toArray(ap, 0)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  
   145  	index, err := ap.ToGoInt(1)
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	if index >= a.Len() {
   151  		return nil, nil
   152  	}
   153  
   154  	rval := a.Index(index)
   155  
   156  	index++
   157  
   158  	return []object.Value{object.Integer(index), valueOfReflect(rval, false)}, nil
   159  }
   160  
   161  func buildSliceMT() {
   162  	mt := tables.NewTableSize(0, 7)
   163  
   164  	mt.Set(object.TM_METATABLE, object.True)
   165  	mt.Set(object.TM_NAME, object.String("SLICE*"))
   166  	mt.Set(object.TM_TOSTRING, object.GoFunction(stostring))
   167  
   168  	mt.Set(object.TM_INDEX, object.GoFunction(sindex))
   169  	mt.Set(object.TM_NEWINDEX, object.GoFunction(snewindex))
   170  	mt.Set(object.TM_LEN, object.GoFunction(slength))
   171  	mt.Set(object.TM_PAIRS, object.GoFunction(spairs))
   172  
   173  	mt.Set(object.TM_EQ, cmp(func(x, y reflect.Value) bool { return x.Pointer() == y.Pointer() }, toSlice))
   174  
   175  	sliceMT = mt
   176  }
   177  
   178  func toSlice(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) {
   179  	val, err := toValue(ap, n, "SLICE*")
   180  	if err != nil {
   181  		return reflect.Value{}, err
   182  	}
   183  	if val.Kind() != reflect.Slice {
   184  		return reflect.Value{}, ap.TypeError(n, "SLICE*")
   185  	}
   186  	return val, nil
   187  }
   188  
   189  func stostring(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   190  	ap := fnutil.NewArgParser(th, args)
   191  
   192  	s, err := toSlice(ap, 0)
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  
   197  	return []object.Value{object.String(fmt.Sprintf("go slice (0x%x)", s.Pointer()))}, nil
   198  }
   199  
   200  func slength(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   201  	ap := fnutil.NewArgParser(th, args)
   202  
   203  	s, err := toSlice(ap, 0)
   204  	if err != nil {
   205  		return nil, err
   206  	}
   207  
   208  	return []object.Value{object.Integer(s.Len())}, nil
   209  }
   210  
   211  func sindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   212  	ap := fnutil.NewArgParser(th, args)
   213  
   214  	s, err := toSlice(ap, 0)
   215  	if err != err {
   216  		return nil, err
   217  	}
   218  
   219  	index, err := ap.ToGoInt(1)
   220  	if err != nil {
   221  		name, err := ap.ToGoString(1)
   222  		if err != nil {
   223  			return nil, err
   224  		}
   225  
   226  		if !isPublic(name) {
   227  			return nil, nil
   228  		}
   229  
   230  		method := s.MethodByName(name)
   231  
   232  		if !method.IsValid() {
   233  			if s.CanAddr() {
   234  				method = s.Addr().MethodByName(name)
   235  			} else {
   236  				self2 := reflect.New(s.Type())
   237  				self2.Elem().Set(s)
   238  				method = self2.MethodByName(name)
   239  			}
   240  
   241  			if !method.IsValid() {
   242  				return nil, nil
   243  			}
   244  		}
   245  
   246  		return []object.Value{valueOfReflect(method, false)}, nil
   247  	}
   248  
   249  	index--
   250  
   251  	if 0 <= index && index < s.Len() {
   252  		rval := s.Index(index)
   253  
   254  		return []object.Value{valueOfReflect(rval, false)}, nil
   255  	}
   256  
   257  	return nil, object.NewRuntimeError(fmt.Sprintf("invalid array index %d (out of bounds for %d-element array)", index, s.Len()))
   258  }
   259  
   260  func snewindex(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   261  	ap := fnutil.NewArgParser(th, args)
   262  
   263  	s, err := toSlice(ap, 0)
   264  	if err != err {
   265  		return nil, err
   266  	}
   267  
   268  	index, err := ap.ToGoInt(1)
   269  	if err != nil {
   270  		return nil, err
   271  	}
   272  
   273  	val, err := ap.ToValue(2)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	index--
   279  
   280  	if 0 <= index && index < s.Len() {
   281  		styp := s.Type()
   282  		vtyp := styp.Elem()
   283  
   284  		if rval := toReflectValue(vtyp, val); rval.IsValid() {
   285  			s.Index(index).Set(rval)
   286  
   287  			return nil, nil
   288  		}
   289  
   290  		return nil, object.NewRuntimeError(fmt.Sprintf("non-%s array index %q", vtyp, reflect.TypeOf(val)))
   291  	}
   292  
   293  	return nil, object.NewRuntimeError(fmt.Sprintf("invalid array index %d (out of bounds for %d-element array)", index, s.Len()))
   294  }
   295  
   296  func spairs(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   297  	ap := fnutil.NewArgParser(th, args)
   298  
   299  	_, err := toSlice(ap, 0)
   300  	if err != nil {
   301  		return nil, err
   302  	}
   303  
   304  	return []object.Value{object.GoFunction(snext), args[0], object.Integer(0)}, nil
   305  }
   306  
   307  func snext(th object.Thread, args ...object.Value) ([]object.Value, *object.RuntimeError) {
   308  	ap := fnutil.NewArgParser(th, args)
   309  
   310  	s, err := toSlice(ap, 0)
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	index, err := ap.ToGoInt(1)
   316  	if err != nil {
   317  		return nil, err
   318  	}
   319  
   320  	if index >= s.Len() {
   321  		return nil, nil
   322  	}
   323  
   324  	rval := s.Index(index)
   325  
   326  	index++
   327  
   328  	return []object.Value{object.Integer(index), valueOfReflect(rval, false)}, nil
   329  }