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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
use crate::priv_prelude::*;

macro_rules! define_keyword (
    ($ty_name:ident, $keyword:literal) => {
        #[derive(Clone, Debug)]
        pub struct $ty_name {
            span: Span,
        }

        impl Spanned for $ty_name {
            fn span(&self) -> Span {
                self.span.clone()
            }
        }

        impl Peek for $ty_name {
            fn peek(peeker: Peeker<'_>) -> Option<$ty_name> {
                let ident = peeker.peek_ident().ok()?;
                if ident.as_str() == $keyword {
                    Some($ty_name { span: ident.span().clone() })
                } else {
                    None
                }
            }
        }

        impl Parse for $ty_name {
            fn parse(parser: &mut Parser) -> ParseResult<$ty_name> {
                match parser.take() {
                    Some(value) => Ok(value),
                    None => {
                        Err(parser.emit_error(ParseErrorKind::ExpectedKeyword { word: $keyword }))
                    },
                }
            }
        }
    };
);

define_keyword!(ScriptToken, "script");
define_keyword!(ContractToken, "contract");
define_keyword!(PredicateToken, "predicate");
define_keyword!(LibraryToken, "library");
define_keyword!(DepToken, "dep");
define_keyword!(PubToken, "pub");
define_keyword!(UseToken, "use");
define_keyword!(AsToken, "as");
define_keyword!(StructToken, "struct");
define_keyword!(EnumToken, "enum");
define_keyword!(SelfToken, "self");
define_keyword!(FnToken, "fn");
define_keyword!(TraitToken, "trait");
define_keyword!(ImplToken, "impl");
define_keyword!(ForToken, "for");
define_keyword!(AbiToken, "abi");
define_keyword!(ConstToken, "const");
define_keyword!(StorageToken, "storage");
define_keyword!(StrToken, "str");
define_keyword!(AsmToken, "asm");
define_keyword!(ReturnToken, "return");
define_keyword!(IfToken, "if");
define_keyword!(ElseToken, "else");
define_keyword!(MatchToken, "match");
define_keyword!(MutToken, "mut");
define_keyword!(LetToken, "let");
define_keyword!(WhileToken, "while");
define_keyword!(WhereToken, "where");
define_keyword!(RefToken, "ref");
define_keyword!(DerefToken, "deref");
define_keyword!(TrueToken, "true");
define_keyword!(FalseToken, "false");

macro_rules! define_token (
    ($ty_name:ident, $description:literal, [$($punct_kinds:ident),*], [$($not_followed_by:ident),*]) => {
        #[derive(Clone, Debug)]
        pub struct $ty_name {
            span: Span,
        }

        impl Spanned for  $ty_name {
            fn span(&self) -> Span {
                self.span.clone()
            }
        }

        impl $ty_name {
            pub fn ident(&self) -> Ident {
                Ident::new(self.span())
            }
        }

        impl From<$ty_name> for Ident {
            fn from(o: $ty_name) -> Ident {
                o.ident()
            }
        }

        impl Peek for $ty_name {
            fn peek(peeker: Peeker<'_>) -> Option<$ty_name> {
                let span = peeker.peek_punct_kinds(
                    &[$(PunctKind::$punct_kinds,)*],
                    &[$(PunctKind::$not_followed_by,)*],
                ).ok()?;
                Some($ty_name { span })
            }
        }

        impl Parse for $ty_name {
            fn parse(parser: &mut Parser) -> ParseResult<$ty_name> {
                match parser.take() {
                    Some(value) => Ok(value),
                    None => {
                        let kinds = vec![$(PunctKind::$punct_kinds,)*];
                        Err(parser.emit_error(ParseErrorKind::ExpectedPunct { kinds }))
                    },
                }
            }
        }
    };
);

define_token!(SemicolonToken, "a semicolon", [Semicolon], []);
define_token!(ForwardSlashToken, "a forward slash", [ForwardSlash], []);
define_token!(
    DoubleColonToken,
    "a double colon (::)",
    [Colon, Colon],
    [Colon]
);
define_token!(StarToken, "an asterisk (*)", [Star], []);
define_token!(CommaToken, "a comma", [Comma], []);
define_token!(ColonToken, "a colon", [Colon], [Colon]);
define_token!(
    RightArrowToken,
    "`->`",
    [Sub, GreaterThan],
    [GreaterThan, Equals]
);
define_token!(LessThanToken, "`<`", [LessThan], [LessThan, Equals]);
define_token!(
    GreaterThanToken,
    "`>`",
    [GreaterThan],
    [GreaterThan, Equals]
);
define_token!(OpenAngleBracketToken, "`<`", [LessThan], []);
define_token!(CloseAngleBracketToken, "`>`", [GreaterThan], []);
define_token!(TildeToken, "`~`", [Tilde], []);
define_token!(EqToken, "`=`", [Equals], [GreaterThan, Equals]);
define_token!(
    FatRightArrowToken,
    "`=>`",
    [Equals, GreaterThan],
    [GreaterThan, Equals]
);
define_token!(DotToken, "`.`", [Dot], []);
define_token!(BangToken, "`!`", [Bang], [Equals]);
define_token!(PercentToken, "`%`", [Percent], []);
define_token!(AddToken, "`+`", [Add], []);
define_token!(SubToken, "`-`", [Sub], []);
define_token!(
    ShrToken,
    "`>>`",
    [GreaterThan, GreaterThan],
    [GreaterThan, Equals]
);
define_token!(ShlToken, "`<<`", [LessThan, LessThan], [LessThan, Equals]);
define_token!(AmpersandToken, "`&`", [Ampersand], [Ampersand]);
define_token!(CaretToken, "`^`", [Caret], []);
define_token!(PipeToken, "`|`", [Pipe], [Pipe]);
define_token!(
    DoubleEqToken,
    "`==`",
    [Equals, Equals],
    [Equals, GreaterThan]
);
define_token!(BangEqToken, "`!=`", [Bang, Equals], [Equals, GreaterThan]);
define_token!(
    GreaterThanEqToken,
    "`>=`",
    [GreaterThan, Equals],
    [Equals, GreaterThan]
);
define_token!(
    LessThanEqToken,
    "`<=`",
    [LessThan, Equals],
    [Equals, GreaterThan]
);
define_token!(
    DoubleAmpersandToken,
    "`&&`",
    [Ampersand, Ampersand],
    [Ampersand]
);
define_token!(DoublePipeToken, "`||`", [Pipe, Pipe], [Pipe]);
define_token!(UnderscoreToken, "`_`", [Underscore], [Underscore]);
define_token!(HashToken, "`#`", [Sharp], []);