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  }