1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//! Utilities for combining parsers.
use crate::{Parser, SyntaxKind};

/// This function does not eat trailing trivia
pub fn sequential<F>(p: &mut Parser, parse_function: F, delimiter: SyntaxKind)
where
    F: Fn(&mut Parser),
{
    parse_function(p);
    while p.eat_through_trivia(delimiter) {
        p.eat_trivia();
        parse_function(p);
    }
}

/// outer_node_kind: e.g. EXP
/// inner_node_kind: e.g., ORELSE_EXP
pub fn descend_once(
    p: &mut Parser,
    inner_node_kind: SyntaxKind,
    before: impl Fn(&mut Parser),
    continue_if: impl Fn(&mut Parser) -> bool,
    after: impl Fn(&mut Parser),
) {
    let inner_checkpoint = p.checkpoint();

    before(p);

    if continue_if(p) {
        let _ng_inner = p.start_node_at(inner_checkpoint, inner_node_kind);

        p.eat_trivia();
        after(p)
    }
}

/// outer_node_kind: e.g. EXP
/// inner_node_kind: e.g., ORELSE_EXP
///
/// NOTE: This folds all the `after` nodes into the same node in a flat structure.
/// To make them right-associate, use `precedence_climber_once` recursively
/// (i.e, with `after` set to the enclosing function.)
pub fn descend_flat(
    p: &mut Parser,
    inner_node_kind: SyntaxKind,
    before: impl Fn(&mut Parser),
    continue_if: impl Fn(&mut Parser) -> bool,
    after: impl Fn(&mut Parser),
) {
    let inner_checkpoint = p.checkpoint();

    before(p);

    if continue_if(p) {
        let _ng_inner = p.start_node_at(inner_checkpoint, inner_node_kind);

        p.eat_trivia();
        after(p);

        while continue_if(p) {
            p.eat_trivia();
            after(p);
        }
    }
}

/// outer_node_kind: e.g. EXP
/// inner_node_kind: e.g., ORELSE_EXP
///
/// This folds expressions right associatively.
/// It should be called recursively by putting the
/// calling function in the `caller` arg.
pub fn descend_right(
    p: &mut Parser,
    inner_node_kind: SyntaxKind,
    before: impl Fn(&mut Parser),
    continue_if: impl Fn(&mut Parser) -> bool,
    caller: impl Fn(&mut Parser),
) {
    descend_flat(p, inner_node_kind, before, continue_if, caller)
}