mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 18:51:11 +01:00
Add precedence rules for assignment operators to the precedence diagram. (#3083)
Also indicate what can appear within parentheses. This is intended to be a clarification, not a design change. Note that while we previously described the operand of `++` or `--` as being simply an expression, the operand can never be anything other than the kinds of expression the diagram now shows due to the expression category rules added in #2006. Fixes #3079.
This commit is contained in:
@@ -85,6 +85,9 @@ graph BT
|
||||
complement["^x"]
|
||||
click complement "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/bitwise.md"
|
||||
|
||||
incDec["++x;<br>--x;"]
|
||||
click incDec "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/assignment.md"
|
||||
|
||||
unary((" "))
|
||||
|
||||
as["x as T"]
|
||||
@@ -136,7 +139,12 @@ graph BT
|
||||
if>"if x then y else z"]
|
||||
click if "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/expressions/if.md"
|
||||
|
||||
expressionEnd["x;"]
|
||||
insideParens["(...)"]
|
||||
|
||||
assignment["x = y;<br>x $= y;"]
|
||||
click assignment "https://github.com/carbon-language/carbon-lang/blob/trunk/docs/design/assignment.md"
|
||||
|
||||
expressionStatement["x;"]
|
||||
|
||||
top --> parens & braces & unqualifiedName
|
||||
|
||||
@@ -146,8 +154,7 @@ graph BT
|
||||
|
||||
memberAccess --> top
|
||||
pointer --> memberAccess
|
||||
negation --> pointer
|
||||
complement --> pointer
|
||||
negation & complement & incDec --> pointer
|
||||
unary --> negation & complement
|
||||
%% Use a longer arrow here to put `not` next to `and` and `or`.
|
||||
not -------> memberAccess
|
||||
@@ -157,7 +164,8 @@ graph BT
|
||||
logicalOperand --> comparison & not
|
||||
and & or --> logicalOperand
|
||||
logicalExpression --> and & or
|
||||
if & expressionEnd --> logicalExpression
|
||||
if & expressionStatement --> logicalExpression
|
||||
insideParens & assignment --> if
|
||||
```
|
||||
|
||||
The diagram's attributes are:
|
||||
|
||||
@@ -17,6 +17,7 @@ enum PrecedenceLevel : int8_t {
|
||||
// Terms.
|
||||
TermPrefix,
|
||||
// Numeric.
|
||||
IncrementDecrement,
|
||||
NumericPrefix,
|
||||
Modulo,
|
||||
Multiplicative,
|
||||
@@ -53,7 +54,8 @@ struct OperatorPriorityTable {
|
||||
// Start with a list of <higher precedence>, <lower precedence>
|
||||
// relationships.
|
||||
MarkHigherThan({Highest}, {TermPrefix, LogicalPrefix});
|
||||
MarkHigherThan({TermPrefix}, {NumericPrefix, BitwisePrefix});
|
||||
MarkHigherThan({TermPrefix},
|
||||
{NumericPrefix, BitwisePrefix, IncrementDecrement});
|
||||
MarkHigherThan({NumericPrefix, BitwisePrefix},
|
||||
{As, Multiplicative, Modulo, BitwiseAnd, BitwiseOr,
|
||||
BitwiseXor, BitShift});
|
||||
@@ -64,7 +66,7 @@ struct OperatorPriorityTable {
|
||||
MarkHigherThan({Relational, LogicalPrefix}, {LogicalAnd, LogicalOr});
|
||||
MarkHigherThan({LogicalAnd, LogicalOr}, {If});
|
||||
MarkHigherThan({If}, {Assignment});
|
||||
MarkHigherThan({Assignment}, {Lowest});
|
||||
MarkHigherThan({Assignment, IncrementDecrement}, {Lowest});
|
||||
|
||||
// Types are mostly a separate precedence graph.
|
||||
MarkHigherThan({Highest}, {TypePrefix});
|
||||
@@ -208,7 +210,7 @@ auto PrecedenceGroup::ForLeading(TokenKind kind)
|
||||
|
||||
case TokenKind::MinusMinus:
|
||||
case TokenKind::PlusPlus:
|
||||
return PrecedenceGroup(Assignment);
|
||||
return PrecedenceGroup(IncrementDecrement);
|
||||
|
||||
case TokenKind::Caret:
|
||||
return PrecedenceGroup(BitwisePrefix);
|
||||
|
||||
@@ -23,6 +23,10 @@ fn F() {
|
||||
// CHECK:STDERR: a + ++a;
|
||||
// CHECK:STDERR: ^
|
||||
a + ++a;
|
||||
// CHECK:STDERR: fail_precedence_assign.carbon:[[@LINE+3]]:5: Parentheses are required around this unary `if` operator.
|
||||
// CHECK:STDERR: ++if c then a else b;
|
||||
// CHECK:STDERR: ^
|
||||
++if c then a else b;
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: [
|
||||
@@ -56,6 +60,14 @@ fn F() {
|
||||
// CHECK:STDOUT: {kind: 'PrefixOperator', text: '++', subtree_size: 2},
|
||||
// CHECK:STDOUT: {kind: 'InfixOperator', text: '+', subtree_size: 4},
|
||||
// CHECK:STDOUT: {kind: 'ExpressionStatement', text: ';', subtree_size: 5},
|
||||
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 31},
|
||||
// CHECK:STDOUT: {kind: 'NameExpression', text: 'c'},
|
||||
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
|
||||
// CHECK:STDOUT: {kind: 'NameExpression', text: 'a'},
|
||||
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 2},
|
||||
// CHECK:STDOUT: {kind: 'NameExpression', text: 'b'},
|
||||
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else', subtree_size: 6},
|
||||
// CHECK:STDOUT: {kind: 'PrefixOperator', text: '++', subtree_size: 7},
|
||||
// CHECK:STDOUT: {kind: 'ExpressionStatement', text: ';', subtree_size: 8},
|
||||
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 39},
|
||||
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
|
||||
// CHECK:STDOUT: ]
|
||||
|
||||
@@ -9,9 +9,8 @@ fn F(c: bool) {
|
||||
var b: i32;
|
||||
var p: i32*;
|
||||
*p = if c then 1 else 2;
|
||||
// These are valid to _parse_ even though rejected semantically.
|
||||
// This is valid to _parse_ even though rejected semantically.
|
||||
(if c then a else b) += if c then 1 else 2;
|
||||
++if c then a else b;
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: [
|
||||
@@ -65,14 +64,6 @@ fn F(c: bool) {
|
||||
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else', subtree_size: 6},
|
||||
// CHECK:STDOUT: {kind: 'InfixOperator', text: '+=', subtree_size: 15},
|
||||
// CHECK:STDOUT: {kind: 'ExpressionStatement', text: ';', subtree_size: 16},
|
||||
// CHECK:STDOUT: {kind: 'NameExpression', text: 'c'},
|
||||
// CHECK:STDOUT: {kind: 'IfExpressionIf', text: 'if', subtree_size: 2},
|
||||
// CHECK:STDOUT: {kind: 'NameExpression', text: 'a'},
|
||||
// CHECK:STDOUT: {kind: 'IfExpressionThen', text: 'then', subtree_size: 2},
|
||||
// CHECK:STDOUT: {kind: 'NameExpression', text: 'b'},
|
||||
// CHECK:STDOUT: {kind: 'IfExpressionElse', text: 'else', subtree_size: 6},
|
||||
// CHECK:STDOUT: {kind: 'PrefixOperator', text: '++', subtree_size: 7},
|
||||
// CHECK:STDOUT: {kind: 'ExpressionStatement', text: ';', subtree_size: 8},
|
||||
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 59},
|
||||
// CHECK:STDOUT: {kind: 'FunctionDefinition', text: '}', subtree_size: 51},
|
||||
// CHECK:STDOUT: {kind: 'FileEnd', text: ''},
|
||||
// CHECK:STDOUT: ]
|
||||
|
||||
Reference in New Issue
Block a user