1use core::fmt;
4
5#[derive(Clone, Debug, Eq, PartialEq)]
7pub enum Token<'a> {
8 Static(&'a str),
10 QueryVar(&'a str),
12 DataVar(&'a str),
14}
15
16#[derive(Debug)]
18pub enum ParseError {
19 InvalidVariableName,
21 InvalidVariablePrefix,
23}
24
25impl<'a> Token<'a> {
26 pub fn is_static(&self) -> bool {
28 match self {
29 Self::Static(_) => true,
30 _ => false,
31 }
32 }
33
34 pub fn is_query_var(&self) -> bool {
36 match self {
37 Self::QueryVar(_) => true,
38 _ => false,
39 }
40 }
41
42 pub fn is_data_var(&self) -> bool {
44 match self {
45 Self::DataVar(_) => true,
46 _ => false,
47 }
48 }
49}
50
51fn parse_next(src: &str) -> Result<Option<(Token, &str)>, ParseError> {
52 let (tok, rest) = if let Ok((_, tok, rest)) = nl_parser::parse_token(src) {
53 (tok, rest)
54 } else {
55 return Ok(None);
56 };
57 if tok.contains('`') {
58 if !tok.ends_with('`') {
59 return Err(ParseError::InvalidVariableName);
60 } else if tok.starts_with("q`") {
61 let var = &tok[2..tok.len() - 1];
63 return Ok(Some((Token::QueryVar(var), rest)));
64 } else if tok.starts_with("d`") {
65 let var = &tok[2..tok.len() - 1];
67 return Ok(Some((Token::DataVar(var), rest)));
68 } else {
69 return Err(ParseError::InvalidVariablePrefix);
70 }
71 } else {
72 return Ok(Some((Token::Static(tok), rest)));
73 }
74}
75
76pub struct Parser<'a> {
78 src: &'a str,
79}
80
81impl<'a> Parser<'a> {
82 #[inline]
84 pub fn new(src: &'a str) -> Self {
85 Self { src }
86 }
87}
88
89impl<'a> Iterator for Parser<'a> {
90 type Item = Result<Token<'a>, ParseError>;
91 fn next(&mut self) -> Option<Self::Item> {
92 match parse_next(self.src) {
93 Ok(Some((tok, rest))) => {
94 self.src = rest;
95 Some(Ok(tok))
96 }
97 Ok(None) => None,
98 Err(err) => Some(Err(err)),
99 }
100 }
101}
102
103impl fmt::Display for ParseError {
104 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105 match self {
106 ParseError::InvalidVariablePrefix => f.write_str("invalid variable prefix"),
107 ParseError::InvalidVariableName => f.write_str("invalid variable name"),
108 }
109 }
110}
111
112#[inline]
114pub fn parse<'a>(string: &'a str) -> impl Iterator<Item = Result<Token<'a>, ParseError>> {
115 Parser::new(string)
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121 use alloc::vec;
122 use alloc::vec::Vec;
123
124 #[test]
125 fn test_parse_next() -> Result<(), ParseError> {
126 assert_eq!(parse_next("the")?, Some((Token::Static("the"), "")));
127 assert_eq!(
128 parse_next("the token")?,
129 Some((Token::Static("the"), "token"))
130 );
131 assert_eq!(
132 parse_next("q`variable`")?,
133 Some((Token::QueryVar("variable"), ""))
134 );
135 assert_eq!(
136 parse_next("q`variable` token")?,
137 Some((Token::QueryVar("variable"), "token"))
138 );
139 assert_eq!(
140 parse_next("d`variable`")?,
141 Some((Token::DataVar("variable"), ""))
142 );
143 assert_eq!(
144 parse_next("d`variable` token")?,
145 Some((Token::DataVar("variable"), "token"))
146 );
147 Ok(())
148 }
149
150 #[test]
151 fn test_parse() -> Result<(), ParseError> {
152 assert_eq!(
153 parse("the token string").collect::<Result<Vec<Token>, ParseError>>()?,
154 vec![
155 Token::Static("the"),
156 Token::Static("token"),
157 Token::Static("string")
158 ]
159 );
160 assert_eq!(
161 parse("the q`variable` token").collect::<Result<Vec<Token>, ParseError>>()?,
162 vec![
163 Token::Static("the"),
164 Token::QueryVar("variable"),
165 Token::Static("token")
166 ]
167 );
168 assert_eq!(
169 parse("the d`variable` token").collect::<Result<Vec<Token>, ParseError>>()?,
170 vec![
171 Token::Static("the"),
172 Token::DataVar("variable"),
173 Token::Static("token")
174 ]
175 );
176 Ok(())
177 }
178}