1mod atom;
2
3pub(crate) use self::atom::match_arm_list;
4pub(super) use self::atom::{literal, LITERAL_FIRST};
5use super::*;
6
7const EXPR_FIRST: TokenSet = LHS_FIRST;
8
9pub(super) fn expr(p: &mut Parser) -> BlockLike {
10    let r = Restrictions {
11        forbid_structs: false,
12        prefer_stmt: false,
13    };
14    expr_bp(p, r, 1)
15}
16
17pub(super) fn expr_stmt(p: &mut Parser) -> BlockLike {
18    let r = Restrictions {
19        forbid_structs: false,
20        prefer_stmt: true,
21    };
22    expr_bp(p, r, 1)
23}
24
25fn expr_no_struct(p: &mut Parser) {
26    let r = Restrictions {
27        forbid_structs: true,
28        prefer_stmt: false,
29    };
30    expr_bp(p, r, 1);
31}
32
33pub(crate) fn block(p: &mut Parser) {
39    if !p.at(L_CURLY) {
40        p.error("expected a block");
41        return;
42    }
43    let m = p.start();
44    p.bump();
45    while !p.at(EOF) && !p.at(R_CURLY) {
46        match p.current() {
47            LET_KW => let_stmt(p),
48            _ => {
49                let m = p.start();
52                match items::maybe_item(p, items::ItemFlavor::Mod) {
53                    items::MaybeItem::Item(kind) => {
54                        m.complete(p, kind);
55                    }
56                    items::MaybeItem::Modifiers => {
57                        m.abandon(p);
58                        p.error("expected an item");
59                    }
60                    items::MaybeItem::None => {
63                        let is_blocklike = expressions::expr_stmt(p) == BlockLike::Block;
64                        if p.at(R_CURLY) {
65                            m.abandon(p);
66                        } else {
67                            if is_blocklike {
68                                p.eat(SEMI);
69                            } else {
70                                p.expect(SEMI);
71                            }
72                            m.complete(p, EXPR_STMT);
73                        }
74                    }
75                }
76            }
77        }
78    }
79    p.expect(R_CURLY);
80    m.complete(p, BLOCK);
81
82    fn let_stmt(p: &mut Parser) {
90        assert!(p.at(LET_KW));
91        let m = p.start();
92        p.bump();
93        patterns::pattern(p);
94        if p.at(COLON) {
95            types::ascription(p);
96        }
97        if p.eat(EQ) {
98            expressions::expr(p);
99        }
100        p.expect(SEMI);
101        m.complete(p, LET_STMT);
102    }
103}
104
105#[derive(Clone, Copy)]
106struct Restrictions {
107    forbid_structs: bool,
108    prefer_stmt: bool,
109}
110
111enum Op {
112    Simple,
113    Composite(SyntaxKind, u8),
114}
115
116fn current_op(p: &Parser) -> (u8, Op) {
117    if let Some(t) = p.next3() {
118        match t {
119            (L_ANGLE, L_ANGLE, EQ) => return (1, Op::Composite(SHLEQ, 3)),
120            (R_ANGLE, R_ANGLE, EQ) => return (1, Op::Composite(SHREQ, 3)),
121            _ => (),
122        }
123    }
124
125    if let Some(t) = p.next2() {
126        match t {
127            (PLUS, EQ) => return (1, Op::Composite(PLUSEQ, 2)),
128            (MINUS, EQ) => return (1, Op::Composite(MINUSEQ, 2)),
129            (STAR, EQ) => return (1, Op::Composite(STAREQ, 2)),
130            (SLASH, EQ) => return (1, Op::Composite(SLASHEQ, 2)),
131            (PIPE, EQ) => return (1, Op::Composite(PIPEEQ, 2)),
132            (AMP, EQ) => return (1, Op::Composite(AMPEQ, 2)),
133            (CARET, EQ) => return (1, Op::Composite(CARETEQ, 2)),
134            (PIPE, PIPE) => return (3, Op::Composite(PIPEPIPE, 2)),
135            (AMP, AMP) => return (4, Op::Composite(AMPAMP, 2)),
136            (L_ANGLE, EQ) => return (5, Op::Composite(LTEQ, 2)),
137            (R_ANGLE, EQ) => return (5, Op::Composite(GTEQ, 2)),
138            (L_ANGLE, L_ANGLE) => return (9, Op::Composite(SHL, 2)),
139            (R_ANGLE, R_ANGLE) => return (9, Op::Composite(SHR, 2)),
140            _ => (),
141        }
142    }
143
144    let bp = match p.current() {
145        EQ => 1,
146        DOTDOT => 2,
147        EQEQ | NEQ | L_ANGLE | R_ANGLE => 5,
148        PIPE => 6,
149        CARET => 7,
150        AMP => 8,
151        MINUS | PLUS => 10,
152        STAR | SLASH | PERCENT => 11,
153        _ => 0,
154    };
155    (bp, Op::Simple)
156}
157
158fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> BlockLike {
160    let mut lhs = match lhs(p, r) {
161        Some(lhs) => {
162            if r.prefer_stmt && is_block(lhs.kind()) {
168                return BlockLike::Block;
169            }
170            lhs
171        }
172        None => return BlockLike::NotBlock,
173    };
174
175    loop {
176        let is_range = p.current() == DOTDOT;
177        let (op_bp, op) = current_op(p);
178        if op_bp < bp {
179            break;
180        }
181        let m = lhs.precede(p);
182        match op {
183            Op::Simple => p.bump(),
184            Op::Composite(kind, n) => {
185                p.bump_compound(kind, n);
186            }
187        }
188        expr_bp(p, r, op_bp + 1);
189        lhs = m.complete(p, if is_range { RANGE_EXPR } else { BIN_EXPR });
190    }
191    BlockLike::NotBlock
192}
193
194fn is_block(kind: SyntaxKind) -> bool {
205    match kind {
206        IF_EXPR | WHILE_EXPR | FOR_EXPR | LOOP_EXPR | MATCH_EXPR | BLOCK_EXPR => true,
207        _ => false,
208    }
209}
210
211const LHS_FIRST: TokenSet = token_set_union![
212    token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
213    atom::ATOM_EXPR_FIRST,
214];
215
216fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
217    let m;
218    let kind = match p.current() {
219        AMP => {
225            m = p.start();
226            p.bump();
227            p.eat(MUT_KW);
228            REF_EXPR
229        }
230        STAR | EXCL | MINUS => {
237            m = p.start();
238            p.bump();
239            PREFIX_EXPR
240        }
241        DOTDOT => {
244            m = p.start();
245            p.bump();
246            if p.at_ts(EXPR_FIRST) {
247                expr_bp(p, r, 2);
248            }
249            return Some(m.complete(p, RANGE_EXPR));
250        }
251        _ => {
252            let lhs = atom::atom_expr(p, r)?;
253            return Some(postfix_expr(p, r, lhs));
254        }
255    };
256    expr_bp(p, r, 255);
257    Some(m.complete(p, kind))
258}
259
260fn postfix_expr(p: &mut Parser, r: Restrictions, mut lhs: CompletedMarker) -> CompletedMarker {
261    let mut allow_calls = !r.prefer_stmt || !is_block(lhs.kind());
262    loop {
263        lhs = match p.current() {
264            L_PAREN if allow_calls => call_expr(p, lhs),
273            L_BRACK if allow_calls => index_expr(p, lhs),
274            DOT if p.nth(1) == IDENT => {
275                if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
276                    method_call_expr(p, lhs)
277                } else {
278                    field_expr(p, lhs)
279                }
280            }
281            DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
282            DOTDOT if !EXPR_FIRST.contains(p.nth(1)) => {
285                let m = lhs.precede(p);
286                p.bump();
287                m.complete(p, RANGE_EXPR)
288            }
289            QUESTION => try_expr(p, lhs),
290            AS_KW => cast_expr(p, lhs),
291            _ => break,
292        };
293        allow_calls = true
294    }
295    lhs
296}
297
298fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
304    assert!(p.at(L_PAREN));
305    let m = lhs.precede(p);
306    arg_list(p);
307    m.complete(p, CALL_EXPR)
308}
309
310fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
315    assert!(p.at(L_BRACK));
316    let m = lhs.precede(p);
317    p.bump();
318    expr(p);
319    p.expect(R_BRACK);
320    m.complete(p, INDEX_EXPR)
321}
322
323fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
329    assert!(p.at(DOT) && p.nth(1) == IDENT && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON));
330    let m = lhs.precede(p);
331    p.bump();
332    name_ref(p);
333    type_args::opt_type_arg_list(p, true);
334    if p.at(L_PAREN) {
335        arg_list(p);
336    }
337    m.complete(p, METHOD_CALL_EXPR)
338}
339
340fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
346    assert!(p.at(DOT) && (p.nth(1) == IDENT || p.nth(1) == INT_NUMBER));
347    let m = lhs.precede(p);
348    p.bump();
349    if p.at(IDENT) {
350        name_ref(p)
351    } else {
352        p.bump()
353    }
354    m.complete(p, FIELD_EXPR)
355}
356
357fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
362    assert!(p.at(QUESTION));
363    let m = lhs.precede(p);
364    p.bump();
365    m.complete(p, TRY_EXPR)
366}
367
368fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
373    assert!(p.at(AS_KW));
374    let m = lhs.precede(p);
375    p.bump();
376    types::type_(p);
377    m.complete(p, CAST_EXPR)
378}
379
380fn arg_list(p: &mut Parser) {
381    assert!(p.at(L_PAREN));
382    let m = p.start();
383    p.bump();
384    while !p.at(R_PAREN) && !p.at(EOF) {
385        if !p.at_ts(EXPR_FIRST) {
386            p.error("expected expression");
387            break;
388        }
389        expr(p);
390        if !p.at(R_PAREN) && !p.expect(COMMA) {
391            break;
392        }
393    }
394    p.eat(R_PAREN);
395    m.complete(p, ARG_LIST);
396}
397
398fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
406    assert!(paths::is_path_start(p) || p.at(L_ANGLE));
407    let m = p.start();
408    paths::expr_path(p);
409    match p.current() {
410        L_CURLY if !r.forbid_structs => {
411            named_field_list(p);
412            m.complete(p, STRUCT_LIT)
413        }
414        EXCL => {
415            items::macro_call_after_excl(p);
416            m.complete(p, MACRO_CALL)
417        }
418        _ => m.complete(p, PATH_EXPR),
419    }
420}
421
422pub(crate) fn named_field_list(p: &mut Parser) {
429    assert!(p.at(L_CURLY));
430    let m = p.start();
431    p.bump();
432    while !p.at(EOF) && !p.at(R_CURLY) {
433        match p.current() {
434            IDENT => {
435                let m = p.start();
436                name_ref(p);
437                if p.eat(COLON) {
438                    expr(p);
439                }
440                m.complete(p, NAMED_FIELD);
441            }
442            DOTDOT => {
443                p.bump();
444                expr(p);
445            }
446            L_CURLY => error_block(p, "expected a field"),
447            _ => p.err_and_bump("expected identifier"),
448        }
449        if !p.at(R_CURLY) {
450            p.expect(COMMA);
451        }
452    }
453    p.expect(R_CURLY);
454    m.complete(p, NAMED_FIELD_LIST);
455}