Parsing support for if expressions. (#2883)

We model `if a then b else` as a prefix operator for parsing precedence purposes. The rule that a statement starting with `if` is never an `if` expression is handled implicitly because the statement parser never invokes the expression parser for a statement starting with `if`.

This exposed a bug in our diagnosis of the whitespace rule for prefix operators, which was incorrectly being applied to non-symbolic operators in some cases, and was producing a bogus second diagnostic in some cases, which is also fixed here.
This commit is contained in:
Richard Smith
2023-06-09 16:41:10 -07:00
committed by GitHub
parent 4e1adcf4c7
commit 2c45cb3be8
18 changed files with 400 additions and 22 deletions
+10 -5
View File
@@ -37,6 +37,8 @@ enum PrecedenceLevel : int8_t {
Relational,
LogicalAnd,
LogicalOr,
// Conditional.
If,
// Assignment.
SimpleAssignment,
CompoundAssignment,
@@ -62,11 +64,11 @@ struct OperatorPriorityTable {
MarkHigherThan({TypePostfix}, {Type});
MarkHigherThan(
{Modulo, Additive, BitwiseAnd, BitwiseOr, BitwiseXor, BitShift, Type},
{SimpleAssignment, CompoundAssignment, Relational});
{Relational});
MarkHigherThan({Relational, LogicalPrefix}, {LogicalAnd, LogicalOr});
MarkHigherThan(
{SimpleAssignment, CompoundAssignment, LogicalAnd, LogicalOr},
{Lowest});
MarkHigherThan({LogicalAnd, LogicalOr}, {If});
MarkHigherThan({If}, {SimpleAssignment, CompoundAssignment});
MarkHigherThan({SimpleAssignment, CompoundAssignment}, {Lowest});
// Compute the transitive closure of the above relationships: if we parse
// `a $ b @ c` as `(a $ b) @ c` and parse `b @ c % d` as `(b @ c) % d`,
@@ -137,7 +139,7 @@ struct OperatorPriorityTable {
// Ambiguous would mean it's an error. LeftFirst is meaningless. For now we
// allow all prefix operators to be repeated.
for (PrecedenceLevel prefix :
{TermPrefix, NumericPrefix, BitwisePrefix, LogicalPrefix}) {
{TermPrefix, NumericPrefix, BitwisePrefix, LogicalPrefix, If}) {
table[prefix][prefix] = OperatorPriority::RightFirst;
}
@@ -210,6 +212,9 @@ auto PrecedenceGroup::ForLeading(TokenKind kind)
case TokenKind::Tilde:
return PrecedenceGroup(BitwisePrefix);
case TokenKind::If:
return PrecedenceGroup(If);
default:
return std::nullopt;
}