github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/arith/arith.go (about) 1 package arith 2 3 import ( 4 "math" 5 6 "github.com/hirochachacha/plua/object" 7 ) 8 9 func Len(x object.Value) object.Value { 10 switch x := x.(type) { 11 case object.String: 12 return object.Integer(len(x)) 13 case object.Table: 14 return object.Integer(x.Len()) 15 default: 16 return nil 17 } 18 } 19 20 func Unm(x object.Value) object.Value { 21 if x, ok := x.(object.Integer); ok { 22 return -x 23 } 24 25 if x, ok := object.ToNumber(x); ok { 26 return -x 27 } 28 29 return nil 30 } 31 32 func Bnot(x object.Value) object.Value { 33 if x, ok := object.ToInteger(x); ok { 34 return ^x 35 } 36 37 return nil 38 } 39 40 func Not(x object.Value) object.Value { 41 return !object.ToBoolean(x) 42 } 43 44 func Equal(x, y object.Value) object.Value { 45 return object.Boolean(object.Equal(x, y)) 46 } 47 48 func NotEqual(x, y object.Value) object.Value { 49 return !object.Boolean(object.Equal(x, y)) 50 } 51 52 func ltIntNum(x object.Integer, y object.Number) bool { 53 if -1<<52 <= x && x <= 1<<52 { 54 return object.Number(x) < y 55 } 56 if y >= -object.Number(object.MinInteger) { 57 return true 58 } 59 if y > object.Number(object.MinInteger) { 60 return x < object.Integer(y) 61 } 62 return false 63 } 64 65 func leIntNum(x object.Integer, y object.Number) bool { 66 if -1<<52 <= x && x <= 1<<52 { 67 return object.Number(x) <= y 68 } 69 if y >= -object.Number(object.MinInteger) { 70 return true 71 } 72 if y >= object.Number(object.MinInteger) { 73 return x <= object.Integer(y) 74 } 75 return false 76 } 77 78 func LessThan(x, y object.Value) object.Value { 79 switch x := x.(type) { 80 case object.Integer: 81 switch y := y.(type) { 82 case object.Integer: 83 return object.Boolean(x < y) 84 case object.Number: 85 return object.Boolean(ltIntNum(x, y)) 86 } 87 case object.Number: 88 switch y := y.(type) { 89 case object.Integer: 90 if math.IsNaN(float64(x)) { 91 return object.False 92 } 93 return object.Boolean(!leIntNum(y, x)) 94 case object.Number: 95 return object.Boolean(x < y) 96 } 97 case object.String: 98 if y, ok := y.(object.String); ok { 99 return object.Boolean(x < y) 100 } 101 } 102 103 return nil 104 } 105 106 func LessThanOrEqualTo(x, y object.Value) object.Value { 107 switch x := x.(type) { 108 case object.Integer: 109 switch y := y.(type) { 110 case object.Integer: 111 return object.Boolean(x <= y) 112 case object.Number: 113 return object.Boolean(leIntNum(x, y)) 114 } 115 case object.Number: 116 switch y := y.(type) { 117 case object.Integer: 118 if math.IsNaN(float64(x)) { 119 return object.False 120 } 121 return object.Boolean(!ltIntNum(y, x)) 122 case object.Number: 123 return object.Boolean(x <= y) 124 } 125 case object.String: 126 if y, ok := y.(object.String); ok { 127 return object.Boolean(x <= y) 128 } 129 } 130 131 return nil 132 } 133 134 func Add(x, y object.Value) object.Value { 135 if x, ok := x.(object.Integer); ok { 136 if y, ok := y.(object.Integer); ok { 137 return x + y 138 } 139 } 140 141 if x, ok := object.ToNumber(x); ok { 142 if y, ok := object.ToNumber(y); ok { 143 return x + y 144 } 145 } 146 147 return nil 148 } 149 150 func Sub(x, y object.Value) object.Value { 151 if x, ok := x.(object.Integer); ok { 152 if y, ok := y.(object.Integer); ok { 153 return x - y 154 } 155 } 156 157 if x, ok := object.ToNumber(x); ok { 158 if y, ok := object.ToNumber(y); ok { 159 return x - y 160 } 161 } 162 163 return nil 164 } 165 166 func Mul(x, y object.Value) object.Value { 167 if x, ok := x.(object.Integer); ok { 168 if y, ok := y.(object.Integer); ok { 169 return x * y 170 } 171 } 172 173 if x, ok := object.ToNumber(x); ok { 174 if y, ok := object.ToNumber(y); ok { 175 return x * y 176 } 177 } 178 179 return nil 180 } 181 182 func Div(x, y object.Value) object.Value { 183 if x, ok := object.ToNumber(x); ok { 184 if y, ok := object.ToNumber(y); ok { 185 return x / y 186 } 187 } 188 189 return nil 190 } 191 192 func Idiv(x, y object.Value) (object.Value, bool) { 193 if x, ok := x.(object.Integer); ok { 194 if y, ok := y.(object.Integer); ok { 195 if y == 0 { 196 return nil, false 197 } 198 199 z := x / y 200 201 if (x^y) < 0 && x%y != 0 { 202 z-- 203 } 204 205 return z, true 206 } 207 } 208 209 if xf, ok := object.ToGoFloat64(x); ok { 210 if yf, ok := object.ToGoFloat64(y); ok { 211 zf, frac := math.Modf(xf / yf) 212 213 if math.Signbit(xf) != math.Signbit(yf) && frac != 0 { 214 zf-- 215 } 216 217 return object.Number(zf), true 218 } 219 } 220 221 return nil, true 222 } 223 224 func Mod(x, y object.Value) (object.Value, bool) { 225 if x, ok := x.(object.Integer); ok { 226 if y, ok := y.(object.Integer); ok { 227 if y == 0 { 228 return nil, false 229 } 230 231 if x == object.MinInteger && y == -1 { 232 return object.Integer(0), true 233 } 234 235 rem := x % y 236 237 if x^y < 0 && rem != 0 { 238 rem += y 239 } 240 241 return rem, true 242 } 243 } 244 245 if xf, ok := object.ToGoFloat64(x); ok { 246 if yf, ok := object.ToGoFloat64(y); ok { 247 rem := math.Mod(xf, yf) 248 249 if math.Signbit(xf) != math.Signbit(yf) && rem != 0 { 250 rem += yf 251 } 252 253 return object.Number(rem), true 254 } 255 } 256 257 return nil, true 258 } 259 260 func Pow(x, y object.Value) object.Value { 261 if x, ok := object.ToNumber(x); ok { 262 if y, ok := object.ToNumber(y); ok { 263 return object.Number(math.Pow(float64(x), float64(y))) 264 } 265 } 266 267 return nil 268 } 269 270 func Band(x, y object.Value) object.Value { 271 if x, ok := object.ToInteger(x); ok { 272 if y, ok := object.ToInteger(y); ok { 273 return x & y 274 } 275 } 276 277 return nil 278 } 279 280 func Bor(x, y object.Value) object.Value { 281 if x, ok := object.ToInteger(x); ok { 282 if y, ok := object.ToInteger(y); ok { 283 return x | y 284 } 285 } 286 287 return nil 288 } 289 290 func Bxor(x, y object.Value) object.Value { 291 if x, ok := object.ToInteger(x); ok { 292 if y, ok := object.ToInteger(y); ok { 293 return x ^ y 294 } 295 } 296 297 return nil 298 } 299 300 func Shl(x, y object.Value) object.Value { 301 if x, ok := object.ToInteger(x); ok { 302 if y, ok := object.ToInteger(y); ok { 303 if y < 0 { 304 return object.Integer(uint64(x) >> uint64(-y)) 305 } 306 307 return object.Integer(uint64(x) << uint64(y)) 308 } 309 } 310 311 return nil 312 } 313 314 func Shr(x, y object.Value) object.Value { 315 if x, ok := object.ToInteger(x); ok { 316 if y, ok := object.ToInteger(y); ok { 317 if y < 0 { 318 return object.Integer(uint64(x) << uint64(-y)) 319 } 320 321 return object.Integer(uint64(x) >> uint64(y)) 322 } 323 } 324 325 return nil 326 } 327 328 // not arithmetic though 329 func Concat(x, y object.Value) object.Value { 330 if x, ok := object.ToString(x); ok { 331 if y, ok := object.ToString(y); ok { 332 return x + y 333 } 334 } 335 336 return nil 337 }