cas_parser/parser/
keyword.rs

1use crate::{
2    parser::{error::{kind, Error}, garbage::Garbage, Parser, Parse},
3    tokenizer::TokenKind,
4};
5use std::ops::Range;
6
7/// Generates a unit struct for each keyword, as well as a simple [`Parse`] implementation for each
8/// keyword. This enables the parser to use and request keywords as a type, which is much more
9/// ergonomic than using a string.
10macro_rules! keywords {
11    ($(($name:ident, $lexeme:tt))*) => {
12        $(
13            #[derive(Clone, Debug, PartialEq)]
14            pub struct $name<'source> {
15                pub lexeme: &'source str,
16                pub span: Range<usize>,
17            }
18
19            impl<'source> Parse<'source> for $name<'source> {
20                fn std_parse(
21                    input: &mut Parser<'source>,
22                    _: &mut Vec<Error>
23                ) -> Result<Self, Vec<Error>> {
24                    let token = input.next_token().map_err(|e| vec![e])?;
25
26                    if token.kind == TokenKind::Keyword {
27                        if token.lexeme != stringify!($lexeme) {
28                            // return Err(vec![Error::new(vec![token.span], kind::UnexpectedToken {
29                            //     expected: &[stringify!($lexeme)],
30                            //     found: token.kind,
31                            // })]);
32                            // TODO
33                            return Err(vec![Error::new(vec![token.span], kind::UnexpectedToken {
34                                expected: &[TokenKind::Keyword],
35                                found: token.kind,
36                            })]);
37                        }
38                        Ok(Self {
39                            lexeme: token.lexeme,
40                            span: token.span,
41                        })
42                    } else {
43                        Err(vec![Error::new(vec![token.span], kind::UnexpectedToken {
44                            expected: &[TokenKind::Keyword],
45                            found: token.kind,
46                        })])
47                    }
48                }
49            }
50
51            impl<'source> Garbage for $name<'source> {
52                fn garbage() -> Self {
53                    Self { lexeme: "", span: 0..0 }
54                }
55            }
56        )*
57    };
58}
59
60keywords!(
61    (If, if)
62    (Then, then)
63    (Else, else)
64    (Loop, loop)
65    (While, while)
66    (Break, break)
67    (Continue, continue)
68);