github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/comp.go (about)

     1  package runtime
     2  
     3  import "fmt"
     4  
     5  // RawEqual returns two values.  The second one is true if raw equality makes
     6  // sense for x and y.  The first one returns whether x and y are raw equal.
     7  func RawEqual(x, y Value) (bool, bool) {
     8  	if x.Equals(y) {
     9  		return true, true
    10  	}
    11  	switch x.NumberType() {
    12  	case IntType:
    13  		if fy, ok := y.TryFloat(); ok {
    14  			return equalIntAndFloat(x.AsInt(), fy), true
    15  		}
    16  	case FloatType:
    17  		if ny, ok := y.TryInt(); ok {
    18  			return equalIntAndFloat(ny, x.AsFloat()), true
    19  		}
    20  	}
    21  	return false, false
    22  }
    23  
    24  // isZero returns true if x is a number and is equal to 0.
    25  func isZero(x Value) bool {
    26  	switch x.iface.(type) {
    27  	case int64:
    28  		return x.AsInt() == 0
    29  	case float64:
    30  		return x.AsFloat() == 0
    31  	}
    32  	return false
    33  }
    34  
    35  // isPositive returns true if x is a number and is > 0.
    36  func isPositive(x Value) bool {
    37  	switch x.iface.(type) {
    38  	case int64:
    39  		return x.AsInt() > 0
    40  	case float64:
    41  		return x.AsFloat() > 0
    42  	}
    43  	return false
    44  }
    45  
    46  func numIsLessThan(x, y Value) bool {
    47  	switch x.iface.(type) {
    48  	case int64:
    49  		switch y.iface.(type) {
    50  		case int64:
    51  			return x.AsInt() < y.AsInt()
    52  		case float64:
    53  			return ltIntAndFloat(x.AsInt(), y.AsFloat())
    54  		}
    55  	case float64:
    56  		switch y.iface.(type) {
    57  		case int64:
    58  			return ltFloatAndInt(x.AsFloat(), y.AsInt())
    59  		case float64:
    60  			return x.AsFloat() < y.AsFloat()
    61  		}
    62  	}
    63  	return false
    64  }
    65  
    66  func isLessThan(x, y Value) (bool, bool) {
    67  	switch x.iface.(type) {
    68  	case int64:
    69  		switch y.iface.(type) {
    70  		case int64:
    71  			return x.AsInt() < y.AsInt(), true
    72  		case float64:
    73  			return ltIntAndFloat(x.AsInt(), y.AsFloat()), true
    74  		}
    75  	case float64:
    76  		switch y.iface.(type) {
    77  		case int64:
    78  			return ltFloatAndInt(x.AsFloat(), y.AsInt()), true
    79  		case float64:
    80  			return x.AsFloat() < y.AsFloat(), true
    81  		}
    82  	}
    83  	return false, false
    84  }
    85  
    86  func equalIntAndFloat(n int64, f float64) bool {
    87  	nf := int64(f)
    88  	return float64(nf) == f && nf == n
    89  }
    90  
    91  func eq(t *Thread, x, y Value) (bool, error) {
    92  	if res, ok := RawEqual(x, y); ok {
    93  		return res, nil
    94  	}
    95  	if _, ok := x.TryTable(); ok {
    96  		if _, ok := y.TryTable(); !ok {
    97  			return false, nil
    98  		}
    99  	} else if _, ok := x.TryUserData(); ok {
   100  		if _, ok := y.TryUserData(); !ok {
   101  			return false, nil
   102  		}
   103  	} else {
   104  		return false, nil
   105  	}
   106  	res, err, ok := metabin(t, "__eq", x, y)
   107  	if ok {
   108  		return Truth(res), err
   109  	}
   110  	return false, nil
   111  }
   112  
   113  // Lt returns whether x < y is true (and an error if it's not possible to
   114  // compare them).
   115  func Lt(t *Thread, x, y Value) (bool, error) {
   116  	lt, ok := isLessThan(x, y)
   117  	if ok {
   118  		return lt, nil
   119  	}
   120  	if sx, ok := x.TryString(); ok {
   121  		if sy, ok := y.TryString(); ok {
   122  			return sx < sy, nil
   123  		}
   124  	}
   125  	res, err, ok := metabin(t, "__lt", x, y)
   126  	if ok {
   127  		return Truth(res), err
   128  	}
   129  	return false, compareError(x, y)
   130  }
   131  
   132  func ltIntAndFloat(n int64, f float64) bool {
   133  	nf := int64(f)
   134  	if float64(nf) == f {
   135  		return n < nf
   136  	}
   137  	return float64(n) < f
   138  }
   139  
   140  func ltFloatAndInt(f float64, n int64) bool {
   141  	nf := int64(f)
   142  	if float64(nf) == f {
   143  		return nf < n
   144  	}
   145  	return f < float64(n)
   146  }
   147  
   148  func leIntAndFloat(n int64, f float64) bool {
   149  	nf := int64(f)
   150  	if float64(nf) == f {
   151  		return n <= nf
   152  	}
   153  	return float64(n) <= f
   154  }
   155  
   156  func leFloatAndInt(f float64, n int64) bool {
   157  	nf := int64(f)
   158  	if float64(nf) == f {
   159  		return nf <= n
   160  	}
   161  	return f <= float64(n)
   162  }
   163  
   164  func le(t *Thread, x, y Value) (bool, error) {
   165  	switch x.NumberType() {
   166  	case IntType:
   167  		switch y.NumberType() {
   168  		case IntType:
   169  			return x.AsInt() <= y.AsInt(), nil
   170  		case FloatType:
   171  			return leIntAndFloat(x.AsInt(), y.AsFloat()), nil
   172  		}
   173  	case FloatType:
   174  		switch y.NumberType() {
   175  		case IntType:
   176  			return leFloatAndInt(x.AsFloat(), y.AsInt()), nil
   177  		case FloatType:
   178  			return x.AsFloat() <= y.AsFloat(), nil
   179  		}
   180  	}
   181  	if sx, ok := x.TryString(); ok {
   182  		if sy, ok := y.TryString(); ok {
   183  			return sx <= sy, nil
   184  		}
   185  	}
   186  	res, err, ok := metabin(t, "__le", x, y)
   187  	if ok {
   188  		return Truth(res), err
   189  	}
   190  	return false, compareError(x, y)
   191  }
   192  
   193  func compareError(x, y Value) error {
   194  	return fmt.Errorf("attempt to compare a %s value with a %s value", x.CustomTypeName(), y.CustomTypeName())
   195  }