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 }