| author | |
| committer | |
| log | 723c70fd438a6e9221155ff632a9974e30a7fe14 |
| tree | 30d71ad27dabc8d2238990d5f8ba2c5831f8a521 |
| parent | 04e8a5e42b58f1fdeb749caf22a1c998344b3ba8 |
9 files changed, 161 insertions(+), 165 deletions(-)
doc/langref.html.in+67-10| ... | @@ -1894,20 +1894,77 @@ const B = error{Two}; | ... | @@ -1894,20 +1894,77 @@ const B = error{Two}; |
| 1894 | </div> | 1894 | </div> |
| 1895 | {#header_close#} | 1895 | {#header_close#} |
| 1896 | {#header_open|Precedence#} | 1896 | {#header_open|Precedence#} |
| 1897 | <p> | ||
| 1898 | Zig features partial operator precedence: not every operator has a defined precedence with | ||
| 1899 | every other operator. Mixing operators with ambiguous precedence is prohibited and parentheses | ||
| 1900 | are mandatory. Consequently, valid code is typically auto-descriptive; when reading and | ||
| 1901 | writing Zig code, there are very few precedence rules you'll need to remember. | ||
| 1902 | </p> | ||
| 1903 | |||
| 1904 | {#code|operator_precedence.zig#} | ||
| 1905 | |||
| 1906 | {#code|ambiguous_precedence_orelse.zig#} | ||
| 1907 | |||
| 1908 | <p> | ||
| 1909 | Simplified operator precedence tables are provided below, each tailored to a general group of | ||
| 1910 | operators. For all of the groups shown below, the operators that have higher precedence are | ||
| 1911 | the same, and themselves have the following precedence table: | ||
| 1912 | </p> | ||
| 1913 | |||
| 1897 | <pre>{#syntax#}x() x[] x.y x.* x.? | 1914 | <pre>{#syntax#}x() x[] x.y x.* x.? |
| 1898 | a!b | 1915 | a!b |
| 1899 | x{} | 1916 | x{} |
| 1900 | !x -x -%x ~x &x ?x try | 1917 | !x -x -%x ~x &x ?x try{#endsyntax#}</pre> |
| 1901 | * / % *% *| || | 1918 | |
| 1902 | + - ++ +% -% +| -| | 1919 | <p> |
| 1903 | << >> <<| | 1920 | For the tables below, the operators that have ambiguous precedence or semantic errors with the |
| 1904 | & ^ | orelse catch | 1921 | given operators have been omitted, as have operators with higher precedence. |
| 1905 | == != < > <= >= | 1922 | The operators colored <span style="color: #C54675;">red</span> and |
| 1906 | and | 1923 | <span style="color: #419AFF;">blue</span> have ambiguous precedence with the other operators |
| 1907 | or | 1924 | on the same line. Those colored <span style="color: #C54675;">red</span> also have ambiguous |
| 1908 | = *= *%= *|= /= %= += +%= +|= -= -%= -|= <<= <<|= >>= &= ^= |={#endsyntax#}</pre> | 1925 | precedence with themselves (they cannot be chained). |
| 1909 | {#header_close#} | 1926 | </p> |
| 1927 | |||
| 1928 | <p> | ||
| 1929 | For arithmetic operators: | ||
| 1930 | </p> | ||
| 1931 | |||
| 1932 | <pre><code>* / *% *| <span style="color: #C54675;">%</span> | ||
| 1933 | + - +% -% +| -| | ||
| 1934 | <span style="color: #C54675;">== != &lt; > &lt;= >=</span> | ||
| 1935 | <span style="color: #419AFF;">and or</span></code></pre> | ||
| 1936 | |||
| 1937 | <p> | ||
| 1938 | For bitwise operators: | ||
| 1939 | </p> | ||
| 1940 | |||
| 1941 | <pre><code><span style="color: #C54675;">&lt;&lt; &lt;&lt;| >></span> <span style="color: #419AFF;">& ^ |</span> | ||
| 1942 | <span style="color: #C54675;">== != &lt; > &lt;= >=</span> | ||
| 1943 | <span style="color: #419AFF;">and or</span></code></pre> | ||
| 1944 | |||
| 1945 | <p> | ||
| 1946 | For null and error recovery operators: | ||
| 1947 | </p> | ||
| 1948 | |||
| 1949 | <pre><code><span style="color: #419AFF;">catch orelse</span></code></pre> | ||
| 1950 | |||
| 1951 | <p> | ||
| 1952 | For error set operators: | ||
| 1953 | </p> | ||
| 1910 | 1954 | ||
| 1955 | <pre>{#syntax#}||{#endsyntax#}</pre> | ||
| 1956 | |||
| 1957 | <p> | ||
| 1958 | For array concatenation operators: | ||
| 1959 | </p> | ||
| 1960 | |||
| 1961 | <pre>{#syntax#}++{#endsyntax#}</pre> | ||
| 1962 | |||
| 1963 | <p> | ||
| 1964 | The full precedence rules can be found in the {#link|Grammar#}, which also includes an {#link|Operator Precedence Flowchart#}. | ||
| 1965 | </p> | ||
| 1966 | |||
| 1967 | {#header_close#} | ||
| 1911 | {#header_close#} | 1968 | {#header_close#} |
| 1912 | 1969 | ||
| 1913 | {#header_open|Arrays#} | 1970 | {#header_open|Arrays#} |
doc/langref/ambiguous_precedence_mul_bitand.zig deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | test "ambiguous precedence" { | ||
| 2 | const x: u8 = 1; | ||
| 3 | const y: u8 = 2; | ||
| 4 | const z: u8 = 3; | ||
| 5 | |||
| 6 | // 1. Could be multiplication by a masked value: (x&y) *% z | ||
| 7 | // 2. Or masking the result of multiplication: x & (y*%z) | ||
| 8 | _ = x & y *% z; | ||
| 9 | } | ||
| 10 | |||
| 11 | // obj=ambiguous operator precedence with operators ... & ... *% ...; use parentheses to disambiguate | ||
| \ No newline at end of file | |||
doc/langref/ambiguous_precedence_orelse.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | test "ambiguous precedence" { | ||
| 2 | const x: ?bool = true; | ||
| 3 | const y: bool = false; | ||
| 4 | const z: bool = false; | ||
| 5 | |||
| 6 | // The following expression is always considered ambiguous, | ||
| 7 | // and, in this particular case, `(x orelse y) == z` would | ||
| 8 | // produce a different result than `x orelse (y == z)`. | ||
| 9 | _ = x orelse y == z; | ||
| 10 | } | ||
| 11 | |||
| 12 | // obj=ambiguous operator precedence with operators ... orelse ... == ...; use parentheses to disambiguate | ||
doc/langref/ambiguous_precedence_orelse_ne.zig deleted-18| ... | @@ -1,18 +0,0 @@ | ||
| 1 | fn makeBool(x: u32) ?bool { | ||
| 2 | if (x == 0) return false; | ||
| 3 | if (x == 1) return true; | ||
| 4 | return null; | ||
| 5 | } | ||
| 6 | |||
| 7 | test "ambiguous precedence" { | ||
| 8 | const x: ?u32 = 0; | ||
| 9 | const y: u8 = 0; | ||
| 10 | const z: u8 = 0; | ||
| 11 | |||
| 12 | // Without parentheses the compiler cannot distinguish between two conflicting interpretations: | ||
| 13 | // 1. Compare on the value which may be recovered: (makeBool(x) orelse y) != z | ||
| 14 | // 2. Recover to the result of the comparison: makeBool(x) orelse (y != z) | ||
| 15 | _ = makeBool(x) orelse y != z; | ||
| 16 | } | ||
| 17 | |||
| 18 | // obj=ambiguous operator precedence with operators ... orelse ... != ...; use parentheses to disambiguate | ||
| \ No newline at end of file | |||
doc/langref/ambiguous_precedence_shift_sub.zig deleted-10| ... | @@ -1,10 +0,0 @@ | ||
| 1 | test "ambiguous precedence" { | ||
| 2 | const x: u64 = 1; | ||
| 3 | const y: u6 = 63; | ||
| 4 | |||
| 5 | // 1. Could mean shift then subtract: (x<<y) - 1 such as to generate a mask | ||
| 6 | // 2. Or to shift after the subtract: x << (y-1) such as selecting bits | ||
| 7 | _ = x << y - 1; | ||
| 8 | } | ||
| 9 | |||
| 10 | // obj=ambiguous operator precedence with operators ... << ... - ...; use parentheses to disambiguate | ||
| \ No newline at end of file | |||
doc/langref/chained_sibling_operators.zig deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | fn foo(x: anytype, y: anytype, z: anytype) void { | ||
| 2 | _ = x + y - z; | ||
| 3 | } | ||
| 4 | |||
| 5 | // syntax | ||
| \ No newline at end of file | |||
doc/langref/incremental_operator_precedence.zig deleted-87| ... | @@ -1,87 +0,0 @@ | ||
| 1 | const expectEqual = @import("std").testing.expectEqual; | ||
| 2 | const expect = @import("std").testing.expect; | ||
| 3 | |||
| 4 | test "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 | |||
doc/langref/nonchaining_sibling_operators.zig deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | fn foo(x: anytype, y: anytype, z: anytype) void { | ||
| 2 | _ = x << y << z; | ||
| 3 | } | ||
| 4 | |||
| 5 | // obj=repetition of non-chainable operators ... << ... << ...; use parentheses to disambiguate | ||
| \ No newline at end of file | |||
doc/langref/operator_precedence.zig+82-19| ... | @@ -1,23 +1,86 @@ | ... | @@ -1,23 +1,86 @@ |
| 1 | const assert = @import("std").debug.assert; | 1 | const std = @import("std"); |
| 2 | 2 | ||
| 3 | test "operator precedence" { | 3 | test "operator precedence" { |
| 4 | const x = 1; | 4 | // Arithmetic operators follow the conventional order of operations. |
| 5 | const y = 2; | 5 | { |
| 6 | const z = 3; | 6 | const a = 1 + 2 * 3 - 4 / 2; |
| 7 | 7 | const b = 1 + (2 * 3) - (4 / 2); | |
| 8 | assert(x + y * z == x + (y*z)); | 8 | try std.testing.expectEqual(a, b); |
| 9 | assert(x * y + z == (x*y) + z); | 9 | } |
| 10 | 10 | ||
| 11 | // Ambiguously related operators may exist in the same expression if they are not adjacent | 11 | // Remainder division is a special case. It still has a higher precedence than |
| 12 | assert(x*y + x%y == (x*y) + (x%y)); | 12 | // addition and subtraction, but it has ambiguous precedence with itself and |
| 13 | // Thus includes comparisons | 13 | // other multiplication/division operators. |
| 14 | assert(x & y != x + y); | 14 | { |
| 15 | 15 | const a = 1 + 2 % 3; | |
| 16 | // Or's and and's may be freely chained, but not with each other | 16 | const b = 1 + (2 % 3); |
| 17 | assert(false or x == y or x + y == z); | 17 | try std.testing.expectEqual(a, b); |
| 18 | assert(true and x != y and y != z); | 18 | |
| 19 | // The following line would be a compile error | 19 | // `1 % 2 % 3`, `1 % 2 / 3`, etc. would be a compile error, |
| 20 | // assert(false or x != y and y != z); | 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; | ||
| 21 | } | 84 | } |
| 22 | 85 | ||
| 23 | // test | ||
| \ No newline at end of file | |||
| 86 | // test | ||