Skip to main content

thrift_analyzer/analyzer/
macros.rs

1/// Parses a header.
2#[macro_export]
3macro_rules! parse_header {
4    ($self:ident, $headers:ident, $($kind:ident => $parse_fn:ident),* $(,)?) => {
5        match $self.peek_next_token().kind {
6            $(
7                TokenKind::$kind => {
8                    if let Some(node) = $self.$parse_fn() {
9                        $headers.push(Rc::new(HeaderNode::$kind(node)));
10                    } else {
11                        $self.recover_to_next_line();
12                    }
13                }
14            )*
15            _ => break,
16        }
17    };
18}
19
20/// Parses a definition.
21#[macro_export]
22macro_rules! parse_definition {
23    ($self:ident, $definitions:ident, $($kind:ident => $parse_fn:ident),* $(,)?) => {
24        let next_token = $self.peek_next_token();
25
26        match next_token.kind {
27            $(
28                TokenKind::$kind => {
29                    if let Some(node) = $self.$parse_fn() {
30                        $definitions.push(Rc::new(DefinitionNode::$kind(node)));
31                    } else {
32                        $self.recover_to_next_definition();
33                    }
34                }
35            )*
36            TokenKind::Eof => break,
37            _ => {
38                $self.add_error(
39                    format!("Unexpected token: {}", next_token.kind),
40                    next_token.range(),
41                );
42                $self.eat_next_token();
43                $self.recover_to_next_definition();
44            }
45        }
46    };
47}
48
49/// Extracts the value of a token.
50#[macro_export]
51macro_rules! extract_token_value {
52    ($self:expr, $token:expr, $value_type:ident, $kind:expr) => {
53        if let TokenKind::$value_type(value) = $token.kind {
54            value
55        } else {
56            $self.add_error(
57                format!("Expected {}, but got {}", $kind, $token.kind),
58                $token.range(),
59            );
60            return None;
61        }
62    };
63}
64
65/// Expects a token kind.
66#[macro_export]
67macro_rules! expect_token {
68    ($self:expr, $kind:ident, $expected_str:expr) => {
69        let token = $self.next_token();
70        if token.kind != TokenKind::$kind {
71            $self.add_error(
72                format!("Expected {}, but got {}", $expected_str, token.kind),
73                token.range(),
74            );
75            return None;
76        }
77    };
78}
79
80/// Expects a token.
81#[macro_export]
82macro_rules! expect {
83    ($self:expr, $expected:expr, $expected_str:expr) => {
84        let token = $self.next_token();
85        if token.kind != $expected {
86            $self.add_error(
87                format!("Expected {}, but got {}", $expected_str, token.kind),
88                token.range(),
89            );
90            return None;
91        }
92    };
93}
94
95/// Optional list separator.
96#[macro_export]
97macro_rules! opt_list_separator {
98    ($self:expr) => {
99        let token = $self.peek_next_token();
100        if token.is_line_separator() {
101            $self.eat_next_token();
102        }
103    };
104}
105
106/// Breaks if the next token is the expected kind or EOF.
107#[macro_export]
108macro_rules! break_opt_token_or_eof {
109    ($self:expr, $kind:ident) => {
110        let next_token = $self.peek_next_token();
111        if next_token.kind == TokenKind::$kind {
112            $self.eat_next_token();
113            break;
114        }
115        if next_token.is_eof() {
116            $self.add_error("Unexpected end of file".to_string(), next_token.range());
117            break;
118        }
119    };
120}