cas_parser/parser/
keyword.rs

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