11//! Routines the parser and pretty-printer use to classify AST nodes.
22
3+ use crate :: ast:: ExprKind :: * ;
34use crate :: { ast, token:: Delimiter } ;
45
6+ /// This classification determines whether various syntactic positions break out
7+ /// of parsing the current expression (true) or continue parsing more of the
8+ /// same expression (false).
9+ ///
10+ /// For example, it's relevant in the parsing of match arms:
11+ ///
12+ /// ```ignore (illustrative)
13+ /// match ... {
14+ /// // Is this calling $e as a function, or is it the start of a new arm
15+ /// // with a tuple pattern?
16+ /// _ => $e (
17+ /// ^ )
18+ ///
19+ /// // Is this an Index operation, or new arm with a slice pattern?
20+ /// _ => $e [
21+ /// ^ ]
22+ ///
23+ /// // Is this a binary operator, or leading vert in a new arm? Same for
24+ /// // other punctuation which can either be a binary operator in
25+ /// // expression or unary operator in pattern, such as `&` and `-`.
26+ /// _ => $e |
27+ /// ^
28+ /// }
29+ /// ```
30+ ///
31+ /// If $e is something like `{}` or `if … {}`, then terminate the current
32+ /// arm and parse a new arm.
33+ ///
34+ /// If $e is something like `path::to` or `(…)`, continue parsing the same
35+ /// arm.
36+ ///
37+ /// *Almost* the same classification is used as an early bail-out for parsing
38+ /// statements. See `expr_requires_semi_to_be_stmt`.
39+ pub fn expr_is_complete ( e : & ast:: Expr ) -> bool {
40+ matches ! (
41+ e. kind,
42+ If ( ..)
43+ | Match ( ..)
44+ | Block ( ..)
45+ | While ( ..)
46+ | Loop ( ..)
47+ | ForLoop { .. }
48+ | TryBlock ( ..)
49+ | ConstBlock ( ..)
50+ )
51+ }
52+
553/// Does this expression require a semicolon to be treated as a statement?
654///
755/// The negation of this: "can this expression be used as a statement without a
8- /// semicolon" -- is used as an early bail-out in the parser so that, for
9- /// instance,
56+ /// semicolon" -- is used as an early bail-out when parsing statements so that,
57+ /// for instance,
1058///
1159/// ```ignore (illustrative)
1260/// if true {...} else {...}
@@ -15,56 +63,26 @@ use crate::{ast, token::Delimiter};
1563///
1664/// isn't parsed as `(if true {...} else {...} | x) | 5`.
1765///
18- /// Nearly the same early bail-out also occurs in the right-hand side of match
19- /// arms:
66+ /// Surprising special case: even though braced macro calls like `m! {}`
67+ /// normally do not introduce a boundary when found at the head of a match arm,
68+ /// they do terminate the parsing of a statement.
2069///
2170/// ```ignore (illustrative)
22- /// match i {
23- /// 0 => if true {...} else {...}
24- /// | x => {}
71+ /// match ... {
72+ /// _ => m! {} (), // macro that expands to a function, which is then called
2573/// }
26- /// ```
27- ///
28- /// Here the `|` is a leading vert in a second match arm. It is not a binary
29- /// operator with the If as its left operand. If the first arm were some other
30- /// expression for which `expr_requires_semi_to_be_stmt` returns true, then the
31- /// `|` on the next line would be a binary operator (leading to a parse error).
3274///
33- /// The statement case and the match-arm case are "nearly" the same early
34- /// bail-out because of 1 edge case. Macro calls with brace delimiter terminate
35- /// a statement without a semicolon, but do not terminate a match-arm without
36- /// comma.
37- ///
38- /// ```ignore (illustrative)
39- /// m! {} - 1; // two statements: a macro call followed by -1 literal
40- ///
41- /// match () {
42- /// _ => m! {} - 1, // binary subtraction operator
43- /// }
75+ /// let _ = { m! {} () }; // macro call followed by unit
4476/// ```
4577pub fn expr_requires_semi_to_be_stmt ( e : & ast:: Expr ) -> bool {
46- use ast:: ExprKind :: * ;
47-
4878 match & e. kind {
49- If ( ..)
50- | Match ( ..)
51- | Block ( ..)
52- | While ( ..)
53- | Loop ( ..)
54- | ForLoop { .. }
55- | TryBlock ( ..)
56- | ConstBlock ( ..) => false ,
57-
5879 MacCall ( mac_call) => mac_call. args . delim != Delimiter :: Brace ,
59-
60- _ => true ,
80+ _ => !expr_is_complete ( e) ,
6181 }
6282}
6383
6484/// If an expression ends with `}`, returns the innermost expression ending in the `}`
6585pub fn expr_trailing_brace ( mut expr : & ast:: Expr ) -> Option < & ast:: Expr > {
66- use ast:: ExprKind :: * ;
67-
6886 loop {
6987 match & expr. kind {
7088 AddrOf ( _, _, e)
0 commit comments