Write `expr` as the receiver of a `[…]` subscript. An unparenthesized `Identifier(["map"])` reparses as `Token::Keyword(MAP)` followed by `[`, which dispatches to `parse_map` (the map-literal grammar) instead of a regular subscript. Parenthesize identifiers whose last component is a context-sensitive keyword so the round trip stays an identifier subscript.
(f: &mut AstFormatter<W>, expr: &Expr<T>)
| 906 | /// regular subscript. Parenthesize identifiers whose last component is a |
| 907 | /// context-sensitive keyword so the round trip stays an identifier subscript. |
| 908 | fn write_subscript_receiver<W: fmt::Write, T: AstInfo>(f: &mut AstFormatter<W>, expr: &Expr<T>) { |
| 909 | let needs_parens = match expr { |
| 910 | // A bare keyword identifier (`map`, `list`, …) dispatches to the |
| 911 | // map/list-literal grammar before `[`, so it needs parens even though |
| 912 | // identifiers are otherwise safe receivers. |
| 913 | Expr::Identifier(idents) => idents |
| 914 | .last() |
| 915 | .and_then(|id| id.as_keyword()) |
| 916 | .map(|kw| kw.is_context_sensitive_keyword()) |
| 917 | .unwrap_or(false), |
| 918 | // Self-delimiting primaries, the bracketed collections, and the postfix |
| 919 | // forms that end in an identifier or `)` are safe: a following `[…]` |
| 920 | // attaches to the whole receiver as a fresh subscript. |
| 921 | Expr::QualifiedWildcard(_) |
| 922 | | Expr::Parameter(_) |
| 923 | | Expr::Value(_) |
| 924 | | Expr::Function(_) |
| 925 | | Expr::HomogenizingFunction { .. } |
| 926 | | Expr::NullIf { .. } |
| 927 | | Expr::Nested(_) |
| 928 | | Expr::Subquery(_) |
| 929 | | Expr::Exists(_) |
| 930 | | Expr::Case { .. } |
| 931 | | Expr::Row { .. } |
| 932 | | Expr::Array(_) |
| 933 | | Expr::ArraySubquery(_) |
| 934 | | Expr::List(_) |
| 935 | | Expr::ListSubquery(_) |
| 936 | | Expr::Map(_) |
| 937 | | Expr::MapSubquery(_) |
| 938 | | Expr::FieldAccess { .. } |
| 939 | | Expr::WildcardAccess(_) |
| 940 | | Expr::Collate { .. } => false, |
| 941 | // `Cast`: the type parser swallows a following `[…]` as an array suffix |
| 942 | // (`a::int4[1]` is `a` cast to `int4[]`, not a subscript of `a::int4`). |
| 943 | // `Subscript`: consecutive `[…]` flatten into one node (`a[1][2]` is a |
| 944 | // single subscript), so a nested subscript receiver must be parenthesized |
| 945 | // to stay nested. Everything else (operators, `IS`/`LIKE`/… constructs) |
| 946 | // binds looser than `[` and would re-associate, so parenthesize by default. |
| 947 | _ => true, |
| 948 | }; |
| 949 | if needs_parens { |
| 950 | f.write_str("("); |
| 951 | f.write_node(expr); |
| 952 | f.write_str(")"); |
| 953 | } else { |
| 954 | f.write_node(expr); |
| 955 | } |
| 956 | } |
| 957 | |
| 958 | impl<T: AstInfo> Expr<T> { |
| 959 | pub fn null() -> Expr<T> { |
no test coverage detected