scyllax_parser/
reserved.rs

1use crate::common::eof;
2use nom::{
3    branch::alt,
4    bytes::complete::{tag, tag_no_case},
5    combinator::{map, peek},
6    sequence::terminated,
7    IResult,
8};
9
10/// A reserved keyword in CQL
11#[derive(Debug, PartialEq)]
12pub enum ReservedKeyword {
13    Add,
14    Aggregate,
15    Allow,
16    Alter,
17    And,
18    Any,
19    Apply,
20    Asc,
21    Authorize,
22    Batch,
23    Begin,
24    By,
25    ColumnFamily,
26    Create,
27    Delete,
28    Desc,
29    Drop,
30    EachQuorum,
31    Entries,
32    From,
33    Full,
34    Grant,
35    If,
36    In,
37    Index,
38    Inet,
39    Infinity,
40    Insert,
41    Into,
42    Keyspace,
43    Keyspaces,
44    Limit,
45    LocalOne,
46    LocalQuorum,
47    Materialized,
48    Modify,
49    Nan,
50    NoRecursive,
51    Not,
52    Of,
53    On,
54    One,
55    Order,
56    Partition,
57    Password,
58    Per,
59    Primary,
60    Quorum,
61    Rename,
62    Revoke,
63    Schema,
64    Select,
65    Set,
66    Table,
67    Time,
68    Three,
69    To,
70    Token,
71    Truncate,
72    Two,
73    Unlogged,
74    Update,
75    Use,
76    Using,
77    Values,
78    View,
79    Where,
80    With,
81    WriteTime,
82}
83
84macro_rules! impl_keyword_parser {
85    ($keyword:literal, $enum_member:ident) => {
86        map(
87            terminated(tag_no_case($keyword), keyword_follow_char),
88            |_| ReservedKeyword::$enum_member,
89        )
90    };
91}
92
93fn keywords_alpha(input: &str) -> IResult<&str, ReservedKeyword> {
94    alt((
95        impl_keyword_parser!("ADD", Add),
96        impl_keyword_parser!("AGGREGATE", Aggregate),
97        impl_keyword_parser!("ALLOW", Allow),
98        impl_keyword_parser!("ALTER", Alter),
99        impl_keyword_parser!("AND", And),
100        impl_keyword_parser!("ANY", Any),
101        impl_keyword_parser!("APPLY", Apply),
102        impl_keyword_parser!("ASC", Asc),
103        impl_keyword_parser!("AUTHORIZE", Authorize),
104        impl_keyword_parser!("BATCH", Batch),
105        impl_keyword_parser!("BEGIN", Begin),
106        impl_keyword_parser!("BY", By),
107        impl_keyword_parser!("COLUMNFAMILY", ColumnFamily),
108        impl_keyword_parser!("CREATE", Create),
109        impl_keyword_parser!("DELETE", Delete),
110        impl_keyword_parser!("DESC", Desc),
111        impl_keyword_parser!("DROP", Drop),
112        impl_keyword_parser!("EACH_QUORUM", EachQuorum),
113        impl_keyword_parser!("ENTRIES", Entries),
114        impl_keyword_parser!("FROM", From),
115    ))(input)
116}
117
118fn keywords_bravo(input: &str) -> IResult<&str, ReservedKeyword> {
119    alt((
120        impl_keyword_parser!("FULL", Full),
121        impl_keyword_parser!("GRANT", Grant),
122        impl_keyword_parser!("IF", If),
123        impl_keyword_parser!("IN", In),
124        impl_keyword_parser!("INDEX", Index),
125        impl_keyword_parser!("INET", Inet),
126        impl_keyword_parser!("INFINITY", Infinity),
127        impl_keyword_parser!("INSERT", Insert),
128        impl_keyword_parser!("INTO", Into),
129        impl_keyword_parser!("KEYSPACE", Keyspace),
130        impl_keyword_parser!("KEYSPACES", Keyspaces),
131        impl_keyword_parser!("LIMIT", Limit),
132        impl_keyword_parser!("LOCAL_ONE", LocalOne),
133        impl_keyword_parser!("LOCAL_QUORUM", LocalQuorum),
134        impl_keyword_parser!("MATERIALIZED", Materialized),
135        impl_keyword_parser!("MODIFY", Modify),
136        impl_keyword_parser!("NAN", Nan),
137        impl_keyword_parser!("NORECURSIVE", NoRecursive),
138        impl_keyword_parser!("NOT", Not),
139        impl_keyword_parser!("OF", Of),
140        impl_keyword_parser!("ON", On),
141    ))(input)
142}
143
144fn keywords_charlie(input: &str) -> IResult<&str, ReservedKeyword> {
145    alt((
146        impl_keyword_parser!("ONE", One),
147        impl_keyword_parser!("ORDER", Order),
148        impl_keyword_parser!("PARTITION", Partition),
149        impl_keyword_parser!("PASSWORD", Password),
150        impl_keyword_parser!("PER", Per),
151        impl_keyword_parser!("PRIMARY", Primary),
152        impl_keyword_parser!("QUORUM", Quorum),
153        impl_keyword_parser!("RENAME", Rename),
154        impl_keyword_parser!("REVOKE", Revoke),
155        impl_keyword_parser!("SCHEMA", Schema),
156        impl_keyword_parser!("SELECT", Select),
157        impl_keyword_parser!("SET", Set),
158        impl_keyword_parser!("TABLE", Table),
159        impl_keyword_parser!("TIME", Time),
160        impl_keyword_parser!("THREE", Three),
161        impl_keyword_parser!("TO", To),
162        impl_keyword_parser!("TOKEN", Token),
163        impl_keyword_parser!("TRUNCATE", Truncate),
164        impl_keyword_parser!("TWO", Two),
165        impl_keyword_parser!("UNLOGGED", Unlogged),
166        impl_keyword_parser!("UPDATE", Update),
167    ))(input)
168}
169
170fn keywords_delta(input: &str) -> IResult<&str, ReservedKeyword> {
171    alt((
172        impl_keyword_parser!("USE", Use),
173        impl_keyword_parser!("USING", Using),
174        impl_keyword_parser!("VALUES", Values),
175        impl_keyword_parser!("VIEW", View),
176        impl_keyword_parser!("WHERE", Where),
177        impl_keyword_parser!("WITH", With),
178    ))(input)
179}
180
181/// A reserved keyword
182pub fn parse_cql_keyword(input: &str) -> IResult<&str, ReservedKeyword> {
183    alt((
184        keywords_alpha,
185        keywords_bravo,
186        keywords_charlie,
187        keywords_delta,
188    ))(input)
189}
190
191/// A parser that will throw an error if the input matches a keyword
192/// This parser will be used for named variables to prevent collisions with keywords
193pub fn fail_if_keyword(input: &str) -> IResult<&str, ReservedKeyword> {
194    // if the input matches a keyword, return an error
195    // otherwise, return the input
196    alt((
197        keywords_alpha,
198        keywords_bravo,
199        keywords_charlie,
200        keywords_delta,
201    ))(input)
202}
203
204fn keyword_follow_char(i: &str) -> IResult<&str, &str> {
205    peek(alt((
206        tag(" "),
207        tag("\n"),
208        tag(";"),
209        tag("("),
210        tag(")"),
211        tag("\t"),
212        tag(","),
213        tag("="),
214        eof,
215    )))(i)
216}
217
218#[cfg(test)]
219mod test {
220    use super::*;
221
222    #[test]
223    fn test_parse_cql_keyword() {
224        assert_eq!(parse_cql_keyword("ADD"), Ok(("", ReservedKeyword::Add)));
225        assert_eq!(parse_cql_keyword("ADD "), Ok((" ", ReservedKeyword::Add)));
226        assert_eq!(parse_cql_keyword("ADD;"), Ok((";", ReservedKeyword::Add)));
227        assert_eq!(parse_cql_keyword("ADD\n"), Ok(("\n", ReservedKeyword::Add)));
228        assert_eq!(parse_cql_keyword("ADD("), Ok(("(", ReservedKeyword::Add)));
229        assert_eq!(parse_cql_keyword("ADD)"), Ok((")", ReservedKeyword::Add)));
230        assert_eq!(parse_cql_keyword("ADD\t"), Ok(("\t", ReservedKeyword::Add)));
231        assert_eq!(parse_cql_keyword("ADD,"), Ok((",", ReservedKeyword::Add)));
232        assert_eq!(parse_cql_keyword("ADD="), Ok(("=", ReservedKeyword::Add)));
233    }
234
235    #[test]
236    fn test_fail_parse_cql_keyword() {
237        assert!(parse_cql_keyword("my_variable").is_err());
238    }
239}