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 }