1
1
//! Routines the parser and pretty-printer use to classify AST nodes.
2
2
3
+ use crate :: ast:: ExprKind :: * ;
3
4
use crate :: { ast, token:: Delimiter } ;
4
5
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
+
5
53
/// Does this expression require a semicolon to be treated as a statement?
6
54
///
7
55
/// 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,
10
58
///
11
59
/// ```ignore (illustrative)
12
60
/// if true {...} else {...}
@@ -15,56 +63,26 @@ use crate::{ast, token::Delimiter};
15
63
///
16
64
/// isn't parsed as `(if true {...} else {...} | x) | 5`.
17
65
///
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.
20
69
///
21
70
/// ```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
25
73
/// }
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).
32
74
///
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
44
76
/// ```
45
77
pub fn expr_requires_semi_to_be_stmt ( e : & ast:: Expr ) -> bool {
46
- use ast:: ExprKind :: * ;
47
-
48
78
match & e. kind {
49
- If ( ..)
50
- | Match ( ..)
51
- | Block ( ..)
52
- | While ( ..)
53
- | Loop ( ..)
54
- | ForLoop { .. }
55
- | TryBlock ( ..)
56
- | ConstBlock ( ..) => false ,
57
-
58
79
MacCall ( mac_call) => mac_call. args . delim != Delimiter :: Brace ,
59
-
60
- _ => true ,
80
+ _ => !expr_is_complete ( e) ,
61
81
}
62
82
}
63
83
64
84
/// If an expression ends with `}`, returns the innermost expression ending in the `}`
65
85
pub fn expr_trailing_brace ( mut expr : & ast:: Expr ) -> Option < & ast:: Expr > {
66
- use ast:: ExprKind :: * ;
67
-
68
86
loop {
69
87
match & expr. kind {
70
88
AddrOf ( _, _, e)
0 commit comments