|
1 | 1 | //! Routines the parser and pretty-printer use to classify AST nodes.
|
2 | 2 |
|
3 | 3 | use crate::ast::ExprKind::*;
|
4 |
| -use crate::{ast, token::Delimiter}; |
| 4 | +use crate::ast::{self, MatchKind}; |
| 5 | +use crate::token::Delimiter; |
5 | 6 |
|
6 | 7 | /// This classification determines whether various syntactic positions break out
|
7 | 8 | /// of parsing the current expression (true) or continue parsing more of the
|
@@ -81,6 +82,82 @@ pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
|
81 | 82 | }
|
82 | 83 | }
|
83 | 84 |
|
| 85 | +/// Returns whether the leftmost token of the given expression is the label of a |
| 86 | +/// labeled loop or block, such as in `'inner: loop { break 'inner 1 } + 1`. |
| 87 | +/// |
| 88 | +/// Such expressions are not allowed as the value of an unlabeled break. |
| 89 | +/// |
| 90 | +/// ```ignore (illustrative) |
| 91 | +/// 'outer: { |
| 92 | +/// break 'inner: loop { break 'inner 1 } + 1; // invalid syntax |
| 93 | +/// |
| 94 | +/// break 'outer 'inner: loop { break 'inner 1 } + 1; // okay |
| 95 | +/// |
| 96 | +/// break ('inner: loop { break 'inner 1 } + 1); // okay |
| 97 | +/// |
| 98 | +/// break ('inner: loop { break 'inner 1 }) + 1; // okay |
| 99 | +/// } |
| 100 | +/// ``` |
| 101 | +pub fn leading_labeled_expr(mut expr: &ast::Expr) -> bool { |
| 102 | + loop { |
| 103 | + match &expr.kind { |
| 104 | + Block(_, label) | ForLoop { label, .. } | Loop(_, label, _) | While(_, _, label) => { |
| 105 | + return label.is_some(); |
| 106 | + } |
| 107 | + |
| 108 | + Assign(e, _, _) |
| 109 | + | AssignOp(_, e, _) |
| 110 | + | Await(e, _) |
| 111 | + | Binary(_, e, _) |
| 112 | + | Call(e, _) |
| 113 | + | Cast(e, _) |
| 114 | + | Field(e, _) |
| 115 | + | Index(e, _, _) |
| 116 | + | Match(e, _, MatchKind::Postfix) |
| 117 | + | Range(Some(e), _, _) |
| 118 | + | Try(e) => { |
| 119 | + expr = e; |
| 120 | + } |
| 121 | + MethodCall(method_call) => { |
| 122 | + expr = &method_call.receiver; |
| 123 | + } |
| 124 | + |
| 125 | + AddrOf(..) |
| 126 | + | Array(..) |
| 127 | + | Become(..) |
| 128 | + | Break(..) |
| 129 | + | Closure(..) |
| 130 | + | ConstBlock(..) |
| 131 | + | Continue(..) |
| 132 | + | FormatArgs(..) |
| 133 | + | Gen(..) |
| 134 | + | If(..) |
| 135 | + | IncludedBytes(..) |
| 136 | + | InlineAsm(..) |
| 137 | + | Let(..) |
| 138 | + | Lit(..) |
| 139 | + | MacCall(..) |
| 140 | + | Match(_, _, MatchKind::Prefix) |
| 141 | + | OffsetOf(..) |
| 142 | + | Paren(..) |
| 143 | + | Path(..) |
| 144 | + | Range(None, _, _) |
| 145 | + | Repeat(..) |
| 146 | + | Ret(..) |
| 147 | + | Struct(..) |
| 148 | + | TryBlock(..) |
| 149 | + | Tup(..) |
| 150 | + | Type(..) |
| 151 | + | Unary(..) |
| 152 | + | Underscore |
| 153 | + | Yeet(..) |
| 154 | + | Yield(..) |
| 155 | + | Err(..) |
| 156 | + | Dummy => return false, |
| 157 | + } |
| 158 | + } |
| 159 | +} |
| 160 | + |
84 | 161 | pub enum TrailingBrace<'a> {
|
85 | 162 | /// Trailing brace in a macro call, like the one in `x as *const brace! {}`.
|
86 | 163 | /// We will suggest changing the macro call to a different delimiter.
|
|
0 commit comments