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

     1  package runtime
     2  
     3  import "fmt"
     4  
     5  func band(t *Thread, x, y Value) (Value, error) {
     6  	ix, okx := ToIntNoString(x)
     7  	iy, oky := ToIntNoString(y)
     8  	if okx && oky {
     9  		return IntValue(ix & iy), nil
    10  	}
    11  	res, err, ok := metabin(t, "__band", x, y)
    12  	if ok {
    13  		return res, err
    14  	}
    15  	return NilValue, binaryBitwiseError("and", x, y, okx, oky)
    16  }
    17  
    18  func bor(t *Thread, x, y Value) (Value, error) {
    19  	ix, okx := ToIntNoString(x)
    20  	iy, oky := ToIntNoString(y)
    21  	if okx && oky {
    22  		return IntValue(ix | iy), nil
    23  	}
    24  	res, err, ok := metabin(t, "__bor", x, y)
    25  	if ok {
    26  		return res, err
    27  	}
    28  	return NilValue, binaryBitwiseError("or", x, y, okx, oky)
    29  }
    30  
    31  func bxor(t *Thread, x, y Value) (Value, error) {
    32  	ix, okx := ToIntNoString(x)
    33  	iy, oky := ToIntNoString(y)
    34  	if okx && oky {
    35  		return IntValue(ix ^ iy), nil
    36  	}
    37  	res, err, ok := metabin(t, "__bxor", x, y)
    38  	if ok {
    39  		return res, err
    40  	}
    41  	return NilValue, binaryBitwiseError("xor", x, y, okx, oky)
    42  }
    43  
    44  func shl(t *Thread, x, y Value) (Value, error) {
    45  	ix, okx := ToIntNoString(x)
    46  	iy, oky := ToIntNoString(y)
    47  
    48  	// We turn the value into an uint64 before shifting so that it's a logical
    49  	// shift, not arithmetic.
    50  	if okx && oky {
    51  		if iy < 0 {
    52  			return IntValue(int64(uint64(ix) >> uint64(-iy))), nil
    53  		}
    54  		return IntValue(int64(uint64(ix) << uint64(iy))), nil
    55  	}
    56  	res, err, ok := metabin(t, "__shl", x, y)
    57  	if ok {
    58  		return res, err
    59  	}
    60  	return NilValue, binaryBitwiseError("shl", x, y, okx, oky)
    61  }
    62  
    63  func shr(t *Thread, x, y Value) (Value, error) {
    64  	ix, okx := ToIntNoString(x)
    65  	iy, oky := ToIntNoString(y)
    66  
    67  	// We turn the value into an uint64 before shifting so that it's a logical
    68  	// shift, not arithmetic.
    69  	if okx && oky {
    70  		if iy < 0 {
    71  			return IntValue(int64(uint64(ix) << uint64(-iy))), nil
    72  		}
    73  		return IntValue(int64(uint64(ix) >> uint64(iy))), nil
    74  	}
    75  	res, err, ok := metabin(t, "__shr", x, y)
    76  	if ok {
    77  		return res, err
    78  	}
    79  	return NilValue, binaryBitwiseError("shr", x, y, okx, oky)
    80  }
    81  
    82  func bnot(t *Thread, x Value) (Value, error) {
    83  	ix, okx := ToIntNoString(x)
    84  	if okx {
    85  		return IntValue(^ix), nil
    86  	}
    87  	res, err, ok := metaun(t, "__bnot", x)
    88  	if ok {
    89  		return res, err
    90  	}
    91  	return NilValue, binaryBitwiseError("not", x, x, false, true)
    92  }
    93  
    94  func binaryBitwiseError(op string, x, y Value, okx, oky bool) error {
    95  	var wrongVal Value
    96  	switch {
    97  	case oky:
    98  		wrongVal = x
    99  	case okx:
   100  		wrongVal = y
   101  	case x.Type() != FloatType:
   102  		wrongVal = x
   103  	case y.Type() != FloatType:
   104  		wrongVal = y
   105  	default:
   106  		// Both x, and y are floats
   107  		wrongVal = x
   108  	}
   109  	if wrongVal.Type() == FloatType {
   110  		return fmt.Errorf("number has no integer representation")
   111  	}
   112  	return fmt.Errorf("attempt to perform bitwise %s on a %s value", op, wrongVal.CustomTypeName())
   113  }