| 1 | const std = @import("std"); |
| 2 | |
| 3 | test "operator precedence" { |
| 4 | // Arithmetic operators follow the conventional order of operations. |
| 5 | { |
| 6 | const a = 1 + 2 * 3 - 4 / 2; |
| 7 | const b = 1 + (2 * 3) - (4 / 2); |
| 8 | try std.testing.expectEqual(a, b); |
| 9 | } |
| 10 | |
| 11 | // Remainder division is a special case. It still has a higher precedence than |
| 12 | // addition and subtraction, but it has ambiguous precedence with itself and |
| 13 | // other multiplication/division operators. |
| 14 | { |
| 15 | const a = 1 + 2 % 3; |
| 16 | const b = 1 + (2 % 3); |
| 17 | try std.testing.expectEqual(a, b); |
| 18 | |
| 19 | // `1 % 2 % 3`, `1 % 2 / 3`, etc. would be a compile error, |
| 20 | // and parentheses would be required to disambiguate. |
| 21 | } |
| 22 | |
| 23 | // Bitwise operators have ambiguous precedence with other bitwise operators. |
| 24 | // However, non-shifting bitwise operators (&, |, ^) can be chained with themselves. |
| 25 | { |
| 26 | const a = 1 ^ 2 ^ 3; |
| 27 | const b = (1 ^ 2) ^ 3; |
| 28 | try std.testing.expectEqual(a, b); |
| 29 | |
| 30 | // `1 ^ 2 | 3`, `1 << 2 << 3`, etc. would be a compile error, |
| 31 | // and parentheses would be required to disambiguate. |
| 32 | |
| 33 | // To mix bitwise operators, parentheses must be used. |
| 34 | try std.testing.expectEqual(0x10101, (1 << 16) | (1 << 8) | 1); |
| 35 | } |
| 36 | |
| 37 | // Comparison operators have lower precedence than both arithmetic and bitwise |
| 38 | // operators. Comparisons cannot be chained. |
| 39 | { |
| 40 | const a = 1 | 4 <= 1 + 4; |
| 41 | const b = (1 | 4) <= (1 + 4); |
| 42 | try std.testing.expectEqual(a, b); |
| 43 | |
| 44 | // `1 == 2 >= 3`, etc. would be a compile error, |
| 45 | // and parentheses would be required to disambiguate. |
| 46 | } |
| 47 | |
| 48 | // Logical operators have lower precedence than comparison operators, |
| 49 | // and may only be chained homogeneously (`and` with `and`, but not |
| 50 | // with `or`, and vice versa). |
| 51 | { |
| 52 | const false_expr: bool = 7 < 2; |
| 53 | const true_expr: bool = 1 + 1 == 2; |
| 54 | |
| 55 | const a = false_expr or false_expr or true_expr; |
| 56 | const b = 7 < 2 or 7 < 2 or 1 + 1 == 2; |
| 57 | const c = ((7 < 2) or (7 < 2)) or (1 + 1 == 2); |
| 58 | try std.testing.expect(a and b and c); |
| 59 | |
| 60 | // `a or b and c`, etc. would be a compile error, |
| 61 | // and parentheses would be required to disambiguate. |
| 62 | } |
| 63 | |
| 64 | // `orelse` and `catch` may be chained with themselves, but not each other. |
| 65 | { |
| 66 | const some_null: ?u8 = null; |
| 67 | |
| 68 | const a = some_null orelse some_null orelse 2; |
| 69 | const b = (some_null orelse some_null) orelse 2; |
| 70 | try std.testing.expectEqual(a, b); |
| 71 | |
| 72 | // `a catch b orelse c`, etc. would be a compile error, |
| 73 | // and parentheses would be required to disambiguate. |
| 74 | |
| 75 | // Prefix operators like `try` have higher precedence than `orelse`/`catch`. |
| 76 | const c = try maybe() orelse 1; |
| 77 | const d = (try maybe()) orelse 1; |
| 78 | try std.testing.expectEqual(c, d); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | fn maybe() error{Fail}!?u8 { |
| 83 | return null; |
| 84 | } |
| 85 | |
| 86 | // test |