authorgravatar for gbell12907@gmail.comCMDRZero <gbell12907@gmail.com> 2026-08-08 22:59:41-05:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-22 12:21:43+02:00
log04e8a5e42b58f1fdeb749caf22a1c998344b3ba8
tree27df45c147ef52ea46763759a055a1067bcb1068
parent65924d31e4ed3234303d6c6ca72cf30cda0cbaa3

Update langref to perfer allowed operator mixing vs disallowed.


2 files changed, 123 insertions(+), 28 deletions(-)

doc/langref.html.in+36-28
...@@ -1907,35 +1907,7 @@ and...@@ -1907,35 +1907,7 @@ and
1907or1907or
1908= *= *%= *|= /= %= += +%= +|= -= -%= -|= <<= <<|= >>= &= ^= |={#endsyntax#}</pre>1908= *= *%= *|= /= %= += +%= +|= -= -%= -|= <<= <<|= >>= &= ^= |={#endsyntax#}</pre>
1909 {#header_close#}1909 {#header_close#}
1910 <p>
1911 However, understanding the full ambiguity rules are not necessary for reading or writing code. Instead, having an understanding of the unambiguous cases for the operators, you're using is more practical. To that end, some simplified versions, of the precedence table are provided below, tailored to understanding particular groups of operator groups. The operators that have ambiguous precedence with the given operators in question have been omitted, as have operators with higher precedence. The operators colored <span style="color: orange">orange</span> have ambiguous precedence with other operators on the same line.
1912
1913 For arithmetic and error set operators, the simplfied precedence table would look like this.
1914 </p>
1915
1916 <pre><code>* / *% *| || <span style="color: orange">%</span>
1917+ - ++ +% -% +| -|
1918== != &lt; > &lt;= >=
1919<span style="color: orange">and or</span>
1920= *= *%= *|= /= %= += +%= +|= -= -%= -|= &lt;&lt;= &lt;&lt;|= >>= &= ^= |=</code></pre>
1921
1922 <p>
1923 For bitwise operators, it would look like this:
1924 </p>
19251910
1926 <pre><code><span style="color: orange">&lt;&lt; &lt;&lt;| >> & ^ |</span>
1927== != &lt; > &lt;= >=
1928<span style="color: orange">and or</span>
1929= *= *%= *|= /= %= += +%= +|= -= -%= -|= &lt;&lt;= &lt;&lt;|= >>= &= ^= |=</code></pre>
1930
1931 <p>
1932 For null and error recovery, it would look like this:
1933 </p>
1934
1935 <pre><code><span style="color: orange">catch orelse</span>
1936= *= *%= *|= /= %= += +%= +|= -= -%= -|= &lt;&lt;= &lt;&lt;|= >>= &= ^= |=</code></pre>
1937
1938 {#header_close#}
1939 {#header_close#}1911 {#header_close#}
19401912
1941 {#header_open|Arrays#}1913 {#header_open|Arrays#}
...@@ -7909,6 +7881,42 @@ fn readU32Be() u32 {}...@@ -7909,6 +7881,42 @@ fn readU32Be() u32 {}
7909 {#header_open|Appendix#}7881 {#header_open|Appendix#}
7910 {#header_open|Grammar#}7882 {#header_open|Grammar#}
7911 {#grammar#}7883 {#grammar#}
7884 {#header_open|Operator Precedence Flowchart#}
7885 <p>
7886 To help understand the grammar, this flowchart is provided for the operator precedence.
7887 The bottom represents any location where an expression may occur and the topmost row represents
7888 a parenthesized expression. An operator will have a higher precedence (and therefore be the parent) to
7889 another node if it is strictly lower on the tree (having a directed path from one to another). This is inverted from classical precedence, but
7890 is closer to how a recursive descent parser views the grammar.
7891 </p>
7892 <pre><code>
7893 ┏━━━━━━━━━━━━━━━━━━━┓
7894 ┃(expr) ┃
7895 ┃x() x[] x.y x.* x.?┃
7896 ┃E!T ┃
7897 ┃x{} ┃
7898 ┃!x -x -%x ~x &x ?x ┃
7899 ┗━━━━━━━━━▲━━━━━━━━━┛
7900 ┌─────────────┬──────┴───────┬───────┬──┬──┬─┐
7901 │ │ │ │ │ │ │
7902 ┏━━━━━━┷━━━━━┓╭Non╌Chaining╮ ╭Non╌Chaining╮┏┷┓┏┷┓┏┷┓│
7903 ┃* *% *| / ||┃╎ % ╎ ╎ &lt;&lt; &lt;&lt;| >> ╎┃&┃┃^┃┃|┃│
7904 ┗━━━━━━▲━━━━━┛╰╌╌╌╌╌╌▲╌╌╌╌╌╯ ╰╌╌╌╌╌╌▲╌╌╌╌╌╯┗▲┛┗▲┛┗▲┛│
7905 ┏━━┷━━━━━━━━━━━━━┷━┓ ┌────┴───────┴──┴──┘ │
7906 ┃+ - +% -% +| -| ++┃ │ │
7907 ┗━━━━━━━━━━━▲━━━━━━┛ │ │
7908 ╭┴╌Non-Chaining╌┴╮ │
7909 ╎== != &lt; &lt;= >= >╎ │
7910 ╰╌╌╌▲╌╌╌╌▲╌╌╌╌╌╌╌╯ ┌──────┬─────┘
7911 ┏━┷━┓┏━┷━┓ ┏━━━┷━━┓┏━━┷━━┓
7912 ┃and┃┃or ┃ ┃orelse┃┃catch┃
7913 ┗━▲━┛┗━▲━┛ ┗━━━▲━━┛┗━━▲━━┛
7914 ╭╌╌┴╌╌╌╌┴╌╌╌╌╌╌╌╌╌╌╌╌╌╌┴╌╌╌╌╌╌┴╌╮
7915 ╎ Any expression location ╎
7916 ╰╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╯
7917
7918 </code></pre>
7919 {#header_close#}
7912 {#header_close#}7920 {#header_close#}
7913 {#header_open|Zen#}7921 {#header_open|Zen#}
7914 <ul>7922 <ul>
doc/langref/incremental_operator_precedence.zig created+87
...@@ -0,0 +1,87 @@
1const expectEqual = @import("std").testing.expectEqual;
2const expect = @import("std").testing.expect;
3
4test "Operator Precedence" {
5 // Arithmetic
6 // + and - can be freely mixed and are left associative
7 try expectEqual((2 + 3) + 4, 2 + 3 + 4);
8 try expectEqual((1 - 2) - 3, 1 - 2 - 3);
9
10 // Saturating and wrapping modifications to arithmetic operators act the same
11 const x: u8 = 255;
12 try expectEqual((x +% 2) -| 3, x +% 2 -| 3);
13 try expectEqual(0, x +% 2 -| 3);
14
15 // Since all associative operators are left associative, non-left-to-right evaluation must be forced with parenthesis
16 try expectEqual(255, x +% (2 -| 3));
17
18 // * and / can be freely mixed and bind tigher than any addition
19 try expectEqual((8 / 2) * 4, 8 / 2 * 4);
20 try expectEqual(1 + (2 * 3), 1 + 2 * 3);
21
22 // The Modulus is special in that it cannot be repeated without parenthesis
23 // The following line would be a compile error
24 // _ = x % 7 % 3;
25 // However it does bind tighter than addition
26 try expectEqual(1 + (x % 3), 1 + x % 3);
27
28 // Bitwise Operators
29 // &, |, and ^ can all be freely repeated, but not mixed without parenthesis
30 try expectEqual((x & 0xF) & 1, x & 0xF & 1);
31 try expectEqual((x | 0xF) | 1, x | 0xF | 1);
32 try expectEqual((x ^ 0xF) ^ 1, x ^ 0xF ^ 1);
33 // The following line would be a compile error
34 // _ = x & 0xF | 0xF0;
35
36 // Bitshifts <<, <<|, and >> cannot be repeated without parenthesis nor mixed with other bitwise operators
37 // The following lines would be compile errors
38 // _ = x >> 1 >> 2;
39 // _ = 1 << 16 | 1 << 8 | 1;
40 // Instead parentheses should be used
41 try expectEqual(63, (x >> 1) >> 2);
42 try expectEqual(0x10101, (1 << 16) | (1 << 8) | 1);
43
44 // Comparisons
45 // < > <= >= == != cannot be chained
46 // Binds lower than either bitwise operators or arithmetic operators
47 // which allows one on one side and one on the other
48 try expect(1 | 4 <= 1 + 4);
49 // equivilent to this code
50 try expect((1 | 4) <= (1 + 4));
51
52 // Boolean Operators
53 // `and` and `or` can be freely chained with themselves, shortcircuiting left to right
54 // they may not be mixed with each other without parenthesis
55 // bind looser than comparisons
56 const false_expr: bool = 7 < 2;
57 const true_expr: bool = 1 + 1 == 2;
58
59 try expect(false_expr or false_expr or true_expr);
60 try expect(7 < 2 or 7 < 2 or 1 + 1 == 2);
61 try expect(((7 < 2) or (7 < 2)) or (1 + 1 == 2));
62
63 try expect(true_expr and true_expr and true_expr);
64 try expect(1 + 1 == 2 and 1 + 1 == 2 and 1 + 1 == 2);
65 try expect(((1 + 1 == 2) and (1 + 1 == 2)) and (1 + 1 == 2));
66
67 // The following line would be a compile error
68 // _ = false_expr or true_expr and true_expr
69 // Instead parentheses should be used
70 try expect(false_expr or (true_expr and true_expr));
71
72 // Orelse and Catch
73 // Like Boolean Operators, may be chained with themselves, but not each other
74 // bind looser than prefix expressions
75 const some_null: ?u8 = null;
76 try expectEqual(2, some_null orelse some_null orelse 2);
77
78 const some_error: error{invalid}!u8 = error.invalid;
79 try expectEqual(3, some_error catch some_error catch 3);
80
81 // The following line would be a compile error
82 // _ = some_error catch some_null orelse 1;
83 // Instead parentheses should be used
84 try expectEqual(1, (some_error catch some_null) orelse 1);
85}
86
87// obj
\ No newline at end of file