Skip to content

Commit cc09e54

Browse files
committed
com.livecode.bitwise: Refactor bit shifts.
Require people to specify "left" or "right", and force the shift count to be positive.
1 parent 6cd069d commit cc09e54

File tree

4 files changed

+62
-22
lines changed

4 files changed

+62
-22
lines changed

libscript/src/bitwise.mlc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public foreign handler MCBitwiseEvalBitwiseOr(in Left as LCInt, in Right as LCIn
2727
public foreign handler MCBitwiseEvalBitwiseNot(in Operand as LCInt, out Value as LCInt) as undefined binds to "<builtin>"
2828
public foreign handler MCBitwiseEvalBitwiseXor(in Left as LCInt, in Right as LCInt, out Value as LCInt) as undefined binds to "<builtin>"
2929

30-
public foreign handler MCBitwiseEvalBitwiseShift(in Target as LCInt, in IsRight as CBool, in Shift as LCInt, out Value as LCInt) as undefined binds to "<builtin>"
30+
public foreign handler MCBitwiseEvalBitwiseShift(in Target as LCInt, in IsRight as CBool, in Shift as LCUInt, out Value as LCInt) as undefined binds to "<builtin>"
3131

3232
--
3333

@@ -140,16 +140,16 @@ Returns: The result of bit-shifting <Operand> by <Shift> places.
140140

141141
Example:
142142
variable tVar
143-
put 7 shifted by 2 bitwise into tVar -- tVar contains 28
143+
put 7 shifted left by 2 bitwise into tVar -- tVar contains 28
144144

145145
Description:
146-
Shifts the bits of <Operand> left or right. If neither direction is specified, then shifts left. Shifting the bits of <Operand> left by x is equivalent to multiplying by 2^x. Shifting by a negative value is equivalent to shifting by its absolute value in the opposite direction.
146+
Shifts the bits of <Operand> left or right. Shifting the bits of <Operand> left by x is equivalent to multiplying by 2^x.
147147

148148
Tags: Bitwise operations
149149
*/
150150

151151
syntax BitwiseShift is postfix operator with precedence 1
152-
<Operand: Expression> "shifted" ("left" <IsRight=false> | "right" <IsRight=true> | <IsRight=false>) "by" <Shift: Expression> "bitwise"
152+
<Operand: Expression> "shifted" ("left" <IsRight=false> | "right" <IsRight=true>) "by" <Shift: Expression> "bitwise"
153153
begin
154154
MCBitwiseEvalBitwiseShift(Operand, IsRight, Shift, output)
155155
end syntax

libscript/src/module-bitwise.cpp

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,32 @@ extern "C" MC_DLLEXPORT void MCBitwiseEvalBitwiseNot(integer_t p_operand, intege
3636
r_output = ~((int32_t)p_operand);
3737
}
3838

39-
extern "C" MC_DLLEXPORT void MCBitwiseEvalBitwiseShift(integer_t p_operand, bool p_is_right, integer_t p_shift, integer_t& r_output)
39+
extern "C" MC_DLLEXPORT void MCBitwiseEvalBitwiseShift(integer_t p_operand, bool p_is_right, uinteger_t p_shift, integer_t& r_output)
4040
{
41-
/* Ensure that the shift amount is always positive */
42-
if (p_shift < 0)
43-
{
44-
/* Overflow check (why would anyone do this?) */
45-
if (INTEGER_MIN == p_shift)
46-
++p_shift;
47-
48-
p_shift = -p_shift;
49-
p_is_right = !p_is_right;
50-
}
51-
52-
/* Shifting integer_t by more than 31 bits is undefined */
53-
integer_t t_max_shift = (sizeof(integer_t) << 3) - 1;
41+
/* Maximum shift amount for which the C operator is defined */
42+
uinteger_t t_max_shift = (sizeof(integer_t) << 3) - 1;
5443
p_shift = MCMin (p_shift, t_max_shift);
5544

45+
integer_t t_shifted;
5646
if (p_is_right)
57-
r_output = p_operand >> p_shift;
47+
{
48+
/* It's okay to shift right by any amount */
49+
t_shifted = p_operand >> p_shift;
50+
}
5851
else
59-
r_output = p_operand << p_shift;
52+
{
53+
t_shifted = p_operand << p_shift;
54+
55+
/* Overflow check */
56+
if (p_operand != t_shifted >> p_shift)
57+
{
58+
MCErrorCreateAndThrow (kMCGenericErrorTypeInfo, "reason",
59+
MCSTR("overflow in bitwise operation"), nil);
60+
return;
61+
}
62+
}
63+
64+
r_output = t_shifted;
6065
}
6166

6267
////////////////////////////////////////////////////////////////////////////////////////////////////

tests/lcb/stdlib/bitwise.lcb

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ along with LiveCode. If not see <http://www.gnu.org/licenses/>. */
1717

1818
module com.livecode.bitwise.tests
1919

20+
use com.livecode.__INTERNAL._testlib
2021
use com.livecode.bitwise
2122

2223
public handler TestAnd()
@@ -35,8 +36,42 @@ public handler TestNot()
3536
test "not" when bitwise not -5 is 4
3637
end handler
3738

39+
handler TestShift_OverflowPositive()
40+
return 5 shifted left by 29 bitwise
41+
end handler
42+
handler TestShift_OverflowNegative()
43+
return -5 shifted left by 29 bitwise
44+
end handler
3845
public handler TestShift()
39-
test "shift" when 7 shifted by 2 bitwise is 28
46+
-- 0…00101 → 0…01010
47+
test "shift left (+ve)" when 5 shifted left by 1 bitwise is 10
48+
-- 1…11011 → 1…10110
49+
test "shift left (-ve)" when -5 shifted left by 1 bitwise is -10
50+
-- 0…00000 → 0…00000
51+
test "shift left (0)" when 0 shifted left by 1 bitwise is 0
52+
53+
-- 0…00101 → 0…00010
54+
test "shift right (+ve)" when 5 shifted right by 1 bitwise is 2
55+
-- 1…11011 → 1…11101
56+
test "shift right (-ve)" when -5 shifted right by 1 bitwise is -3
57+
-- 0…00000 → 0…00000
58+
test "shift right (0)" when 0 shifted right by 1 bitwise is 0
59+
60+
-- Shift right by any amount is permitted
61+
test "shift right (+ve, big)" when 5 shifted right by 255 bitwise is 0
62+
test "shift right (-ve, big)" when -5 shifted right by 255 bitwise is -1
63+
test "shift right (0, big)" when 0 shifted right by 255 bitwise is 0
64+
65+
-- Shift left is only permitted if no overflow occurs
66+
-- 0…00101 → 01010…0
67+
test "shift left (+ve, limit)" when 5 shifted left by 28 bitwise is 1342177280
68+
-- 1…11011 → 10110…0
69+
test "shift left (-ve, limit)" when -5 shifted left by 28 bitwise is -1342177280
70+
-- 1…11111 → 10000…0
71+
test "shift left (-ve, edge)" when -1 shifted left by 31 bitwise is -2147483648
72+
73+
MCUnitTestHandlerThrows(TestShift_OverflowPositive, "shift left (+ve, overflow")
74+
MCUnitTestHandlerThrows(TestShift_OverflowNegative, "shift left (-ve, overflow")
4075
end handler
4176

4277
end module

toolchain/lc-compile/test.mlc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ public handler testBitwise(inout xResults as List)
498498
put bitwise not 5 into tVar
499499
testLog("Bitwise", "BitwiseNot", tVar is - 6, xResults)
500500

501-
put 7 shifted by 2 bitwise into tVar
501+
put 7 shifted left by 2 bitwise into tVar
502502
testLog("Bitwise", "BitwiseShift", tVar is 28, xResults)
503503

504504
end handler

0 commit comments

Comments
 (0)