github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/object/reflect/int.go (about)

     1  package reflect
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/hirochachacha/plua/internal/limits"
     7  	"github.com/hirochachacha/plua/internal/tables"
     8  	"github.com/hirochachacha/plua/object"
     9  	"github.com/hirochachacha/plua/object/fnutil"
    10  )
    11  
    12  func buildIntMT() {
    13  	mt := tables.NewTableSize(0, 20)
    14  
    15  	mt.Set(object.TM_METATABLE, object.True)
    16  	mt.Set(object.TM_NAME, object.String("INT*"))
    17  	mt.Set(object.TM_TOSTRING, tostring(toInt))
    18  	mt.Set(object.TM_INDEX, index(toInt))
    19  
    20  	mt.Set(object.TM_EQ, cmp(func(x, y reflect.Value) bool { return x.Int() == y.Int() }, toInt))
    21  	mt.Set(object.TM_LT, cmp(func(x, y reflect.Value) bool { return x.Int() < y.Int() }, toInt))
    22  	mt.Set(object.TM_LE, cmp(func(x, y reflect.Value) bool { return x.Int() <= y.Int() }, toInt))
    23  
    24  	mt.Set(object.TM_UNM, unary(func(x reflect.Value) reflect.Value { return reflect.ValueOf(-x.Int()) }, toInt, mt))
    25  	mt.Set(object.TM_BNOT, unary(func(x reflect.Value) reflect.Value { return reflect.ValueOf(^x.Int()) }, toInt, mt))
    26  
    27  	mt.Set(object.TM_ADD, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    28  		return reflect.ValueOf(x.Int() + y.Int()), nil
    29  	}, toInt, mt))
    30  	mt.Set(object.TM_SUB, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    31  		return reflect.ValueOf(x.Int() - y.Int()), nil
    32  	}, toInt, mt))
    33  	mt.Set(object.TM_MUL, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    34  		return reflect.ValueOf(x.Int() * y.Int()), nil
    35  	}, toInt, mt))
    36  	mt.Set(object.TM_MOD, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    37  		z, err := imod(x.Int(), y.Int())
    38  		return reflect.ValueOf(z), err
    39  	}, toInt, mt))
    40  	mt.Set(object.TM_POW, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    41  		return reflect.ValueOf(ipow(x.Int(), y.Int())), nil
    42  	}, toInt, mt))
    43  	mt.Set(object.TM_DIV, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    44  		z, err := idiv(x.Int(), y.Int())
    45  		return reflect.ValueOf(z), err
    46  	}, toInt, mt))
    47  	mt.Set(object.TM_IDIV, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    48  		z, err := idiv(x.Int(), y.Int())
    49  		return reflect.ValueOf(z), err
    50  	}, toInt, mt))
    51  	mt.Set(object.TM_BAND, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    52  		return reflect.ValueOf(x.Int() & y.Int()), nil
    53  	}, toInt, mt))
    54  	mt.Set(object.TM_BOR, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    55  		return reflect.ValueOf(x.Int() | y.Int()), nil
    56  	}, toInt, mt))
    57  	mt.Set(object.TM_BXOR, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    58  		return reflect.ValueOf(x.Int() ^ y.Int()), nil
    59  	}, toInt, mt))
    60  	mt.Set(object.TM_SHL, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    61  		return reflect.ValueOf(ishl(x.Int(), y.Int())), nil
    62  	}, toInt, mt))
    63  	mt.Set(object.TM_SHR, binary(func(x, y reflect.Value) (reflect.Value, *object.RuntimeError) {
    64  		return reflect.ValueOf(ishr(x.Int(), y.Int())), nil
    65  	}, toInt, mt))
    66  
    67  	intMT = mt
    68  }
    69  
    70  func toInt(ap *fnutil.ArgParser, n int) (reflect.Value, *object.RuntimeError) {
    71  	if i64, err := ap.ToGoInt64(n); err == nil {
    72  		return reflect.ValueOf(i64), nil
    73  	}
    74  	val, err := toValue(ap, n, "INT*")
    75  	if err != nil {
    76  		return reflect.Value{}, err
    77  	}
    78  	switch val.Kind() {
    79  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    80  	default:
    81  		return reflect.Value{}, ap.TypeError(n, "INT*")
    82  	}
    83  	return val, nil
    84  }
    85  
    86  func ipow(x, y int64) int64 {
    87  	prod := int64(1)
    88  	for y != 0 {
    89  		if y&1 != 0 {
    90  			prod *= x
    91  		}
    92  		y >>= 1
    93  		x *= x
    94  	}
    95  	return prod
    96  }
    97  
    98  func ishl(x, y int64) int64 {
    99  	if y > 0 {
   100  		return x << uint64(y)
   101  	}
   102  	return x >> uint64(-y)
   103  }
   104  
   105  func ishr(x, y int64) int64 {
   106  	if y > 0 {
   107  		return x >> uint64(y)
   108  	}
   109  	return x << uint64(-y)
   110  }
   111  
   112  func imod(x, y int64) (int64, *object.RuntimeError) {
   113  	if y == 0 {
   114  		return 0, object.NewRuntimeError("integer divide by zero")
   115  	}
   116  
   117  	if x == limits.MinInt64 && y == -1 {
   118  		return 0, nil
   119  	}
   120  
   121  	rem := x % y
   122  
   123  	if rem < 0 {
   124  		rem += y
   125  	}
   126  
   127  	return rem, nil
   128  }
   129  
   130  func idiv(x, y int64) (int64, *object.RuntimeError) {
   131  	if y == 0 {
   132  		return 0, object.NewRuntimeError("integer divide by zero")
   133  	}
   134  
   135  	return x / y, nil
   136  }