Skip to content

Conversation

CMDRZero
Copy link

Implements a version of the operator precedence @thejoshwolfe described in #114.
All operators are broken into operator classes which can feature a "minor" version for intraclass relations.

Operator Classes

Arithmetic-0 consists of {* *% *| / ||}
Arithmetic-1 consists of {** %} and is not chainable (throwing a new error)
Arithmetic-2 consists of {+ - +% -% +| -| ++}
Bitwise-0 consists of {<< <<| >>}
Bitwise-1 consists of {&}
Bitwise-2 consists of {^}
Bitwise-3 consists of {|}
Coercion consists of {orelse catch}
Comparison consists of {== != < <= >= >} and is not chainable (throwing the old error)
Logical-0 consists of {and}
Logical-1 consists of {or}

Operator Class Major Relationships

arithmetic > coercion
bitwise > coercion
coercion > comparison > logical

Operator Class Minor Relationships

a0 == a1 > a2
b0 > b1 > b3
l0 > l1

Major relationships are defined in a table in Parse.Zig, while minor is defined in the comparison function.
The parser changes are limited to replacing precedence numbers with classes and delegating comparisons to the new comparison function which is configurable at compile-time. If two operators do not have a defined precedence relationship, the parser raises an error instructing the user to add disambiguating parentheses.

Rationale for the defined relationships

Arithmetic precedence is generally well-defined. The % and ** operators are not chainable, as constructs such as a % b % c and a ** b ** c result in ambiguous, confusing, or unintuitive code that should be reconsidered by the programmer.
Bitwise & and | are analogous to * and +, in all the languages I surveyed (C, (old Zig), Python, Java, Odin), bit shifts have higher precedence than other bitwise operators. Additionally, bit shifts precede |, as constructs like a << b | c are common in bit packing and is often expected behavior. ^ has no analogous arithmetic operation (except maybe +%), so for this reason its not defined in relation to those.
Symbolic operators coming before keyword operators is, in my opinion, intuitive, however I've lofted coercion operators above comparisons as it would never trigger below them and we do often see syntax like dict.get(item) orelse .default != .default
Finally, and and or are treated analogously to * and +, and are consistently defined across languages as having lower precedence than comparisons.

The most common source of code that needed to be updated was mixing + with << and mixing + with &; the relationship between arithmetic and bitwise operators is left undefined, since language conventions are inconsistent and programmer expectations may vary.

Fixes #114

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

require parentheses sometimes to disambiguate confusing operator precedence
1 participant