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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#[macro_export]
macro_rules! binary_left_associative {
    ($self:ident, $Kinds: expr, $SubOp: ident) => {{
        let start = $self.cur_token.start;
        let mut node = $self.$SubOp();

        while $Kinds.contains(&$self.cur_token.kind) {
            let current_token = $self.cur_token.clone();

            $self.eat(current_token.kind);

            let right = $self.$SubOp();
            node = $self.binary_expression(start, node, right, current_token.kind);
        }

        node
    }};

    ($self:ident, $SubOp: ident, [$($Kinds: expr),+], [$($EatOrNot: expr),+], [$($SubKind: expr),+]) => {{
        let start = $self.cur_token.start;
        let mut node = $self.$SubOp();

        $(
            while $Kinds.contains(&$self.cur_token.kind) {

                if $EatOrNot {
                    $self.eat($self.cur_token.kind);
                }

                let operator = if $SubKind != TokenKind::Unexpected {
                    $SubKind
                } else {
                    $self.cur_token.kind
                };

                let right = $self.$SubOp();
                node = $self.binary_expression(start, node, right, operator);
            }
        )+

        node
    }};
}

#[macro_export]
macro_rules! member_left_associative {
    ($self:ident, $Kinds: expr, $SubOp: ident) => {{
        let start = $self.cur_token.start;
        let (mut node, _) = $self.$SubOp();

        while $Kinds.contains(&$self.cur_token.kind) {
            let current_token = $self.cur_token.clone();

            $self.eat(current_token.kind);

            let (right, is_expr) = $self.$SubOp();
            node = $self.member_expression(start, node, right, is_expr);
        }

        node
    }};
}

#[macro_export]
macro_rules! word_right_associative {
    ($self:ident, $Kind: pat, $SubOp: ident, $SelfOp: ident, $WordFn: ident) => {{
        let start = $self.cur_token.start;
        match $self.cur_kind() {
            $Kind => {
                $self.advance();

                let argument = $self.$SelfOp();
                return $self.$WordFn(start, argument);
            }

            _ => {
                return $self.$SubOp();
            }
        }
    }};
}

#[macro_export]
macro_rules! binary_right_associative {
    ($self:ident,  $SubOp: ident, $Kinds: expr) => {{
        let start = $self.cur_token.start;
        let mut node = $self.$SubOp();

        while $Kinds.contains(&$self.cur_token.kind) {
            let current_token = $self.cur_token.clone();

            $self.eat(current_token.kind);

            let right = $self.expr();
            node = $self.binary_expression(start, node, right, current_token.kind);
        }

        node
    }};
}