rust_ts_json_compiler/syntax_tree/
syntax_tree.rs1use std::iter::Peekable;
2use std::vec;
3use thiserror::Error;
4
5use crate::lexer::Token;
6
7#[derive(Debug)]
8#[allow(dead_code)]
9pub enum ZodExpression {
10 Object(Box<Vec<(String, ZodExpression)>>),
11 Array(Box<ZodExpression>),
12 Literal(String),
13 Number,
14 UUID,
15 String,
16 Boolean,
17 Email,
18 Any,
19 Enum(Vec<String>),
20 Union(Vec<ZodExpression>),
21}
22
23#[derive(Error, Debug)]
24pub enum SyntaxError {
25 #[error("Expected token {0:?} found {1:?}")]
26 UnexpectedToken(Token, Token),
27
28 #[error("Invalid identifier {0:?}")]
29 InvalidIdentifier(String),
30
31 #[error("Unexpected end of a file")]
32 UnexpectedEndOfFile,
33
34 #[error("Unexpected token in enum {0:?}")]
35 UnexpectedTokenInEnum(Token),
36
37 #[error("Unexpected token in object body {0:?}")]
38 UnexpectedTokenInObjectBody(Token),
39}
40
41pub struct SyntaxTree {
42 tokens: Peekable<vec::IntoIter<Token>>,
43}
44
45impl SyntaxTree {
46 pub fn new(tokens: Peekable<vec::IntoIter<Token>>) -> SyntaxTree {
47 SyntaxTree { tokens }
48 }
49
50 pub fn parse(&mut self) -> Option<ZodExpression> {
51 match self.tokens.peek() {
52 Some(Token::Ident(ident)) => {
53 if ident == "z" {
54 match self.parse_zod() {
55 Result::Ok(zod) => Some(zod),
56 Err(_) => None,
57 }
58 } else {
59 None
60 }
61 }
62 _ => None,
63 }
64 }
65
66 fn parse_zod(&mut self) -> Result<ZodExpression, SyntaxError> {
67 self.next();
68 self.parse_dot()?;
69 let ident = match self.tokens.peek() {
70 Some(Token::Ident(ident)) => ident,
71 Some(_) => {
72 return Err(SyntaxError::UnexpectedToken(
73 self.tokens.next().unwrap(),
74 Token::Ident("".to_string()),
75 ))
76 }
77 None => return Err(SyntaxError::UnexpectedEndOfFile),
78 };
79
80 match ident.as_str() {
81 "object" => self.parse_zod_object_body(),
82 "array" => self.parse_zod_array(),
83 "literal" => self.parse_zod_literal(),
84 "number" => self.parse_zod_number(),
85 "enum" => self.parse_zod_enum(),
86 "string" => self.parse_zod_string(),
87 "boolean" => self.parse_zod_boolean(),
88 "any" => self.parse_zod_any(),
89 "union" => self.parse_zod_union(),
90 "coerce" => self.parse_zod(),
91 _ => Err(SyntaxError::InvalidIdentifier(ident.to_string())),
92 }
93 }
94
95 fn parse_zod_literal(&mut self) -> Result<ZodExpression, SyntaxError> {
96 self.next();
97 self.parse_left_round()?;
98 match self.next() {
99 Some(Token::Str(value)) => {
100 self.parse_right_round()?;
101 Ok(ZodExpression::Literal(value))
102 }
103 Some(token) => Err(SyntaxError::UnexpectedToken(
104 token,
105 Token::Str("\"\"".to_string()),
106 )),
107 None => Err(SyntaxError::UnexpectedEndOfFile),
108 }
109 }
110
111 fn parse_zod_union(&mut self) -> Result<ZodExpression, SyntaxError> {
112 self.next();
113 self.parse_left_round()?;
114 self.parse_left_square()?;
115
116 let mut arr = vec![];
117
118 loop {
119 match self.parse() {
120 Some(e) => arr.push(e),
121 None => break,
122 };
123
124 match self.next() {
125 Some(Token::RSquare) => break,
126 Some(Token::Comma) => continue,
127 Some(token) => return Err(SyntaxError::UnexpectedToken(token, Token::RSquare)),
128 None => return Err(SyntaxError::UnexpectedEndOfFile),
129 };
130 }
131 self.parse_right_round()?;
132 self.parse_to_end_of_scope();
133
134 Ok(ZodExpression::Union(arr))
135 }
136
137 fn parse_zod_enum(&mut self) -> Result<ZodExpression, SyntaxError> {
138 self.next();
139 self.parse_left_round()?;
140 self.parse_left_square()?;
141
142 let mut arr = vec![];
143
144 loop {
145 let token = self.next();
146 match token {
147 Some(Token::RSquare) => {
148 break;
149 }
150 Some(Token::Comma) => {
151 continue;
152 }
153 Some(Token::Str(ref str)) => {
154 arr.push(str.to_owned());
155 }
156 None => {
157 return Err(SyntaxError::UnexpectedEndOfFile);
158 }
159 Some(token) => {
160 return Err(SyntaxError::UnexpectedTokenInEnum(token));
161 }
162 }
163 }
164 self.parse_right_round()?;
165 self.parse_to_end_of_scope();
166
167 Ok(ZodExpression::Enum(arr))
168 }
169
170 fn parse_zod_any(&mut self) -> Result<ZodExpression, SyntaxError> {
171 self.next();
172 self.parse_left_round()?;
173 self.parse_right_round()?;
174
175 Ok(ZodExpression::Any)
176 }
177
178 fn parse_zod_boolean(&mut self) -> Result<ZodExpression, SyntaxError> {
179 self.next();
180 self.parse_left_round()?;
181 self.parse_right_round()?;
182
183 Ok(ZodExpression::Boolean)
184 }
185
186 fn parse_zod_array(&mut self) -> Result<ZodExpression, SyntaxError> {
187 self.next();
188 self.parse_left_round()?;
189 let exp = match self.parse() {
190 Some(e) => e,
191 None => return Err(SyntaxError::UnexpectedEndOfFile),
192 };
193 self.parse_to_end_of_scope();
194
195 Ok(ZodExpression::Array(Box::new(exp)))
196 }
197 fn parse_zod_number(&mut self) -> Result<ZodExpression, SyntaxError> {
198 self.next();
199 self.parse_left_round()?;
200 self.parse_right_round()?;
201 self.parse_to_end_of_scope();
202 Ok(ZodExpression::Number)
203 }
204
205 fn parse_zod_string(&mut self) -> Result<ZodExpression, SyntaxError> {
206 self.next();
207 self.parse_left_round()?;
208 self.parse_right_round()?;
209
210 loop {
211 if self.tokens.peek() != Some(&Token::Dot) {
212 break;
213 }
214
215 self.next();
216 let iden = match self.tokens.peek() {
217 Some(Token::Ident(ident)) => ident,
218 Some(_) => {
219 return Err(SyntaxError::UnexpectedToken(
220 self.next().unwrap(),
221 Token::Ident("".to_string()),
222 ))
223 }
224 None => return Err(SyntaxError::UnexpectedEndOfFile),
225 };
226 if iden == "email" {
227 self.parse_to_end_of_scope();
228 return Ok(ZodExpression::Email);
229 }
230 if iden == "uuid" {
231 self.parse_to_end_of_scope();
232 return Ok(ZodExpression::UUID);
233 }
234 }
235 self.parse_to_end_of_scope();
236 Ok(ZodExpression::String)
237 }
238
239 fn parse_to_end_of_scope(&mut self) {
240 while let Some(token) = self.tokens.peek() {
241 match token {
242 Token::Eof | Token::RSquare | Token::Comma | Token::RCurly => {
243 break;
244 }
245 _ => {
246 self.next();
247 continue;
248 }
249 }
250 }
251 }
252
253 fn parse_zod_object_body(&mut self) -> Result<ZodExpression, SyntaxError> {
254 self.next();
255 self.parse_left_round()?;
256 self.parse_left_curly()?;
257 let mut obj = vec![];
258
259 loop {
260 let token = self.next();
261 match token {
262 Some(Token::RCurly) => {
263 break;
264 }
265 Some(Token::RRound) => {
266 continue;
267 }
268 Some(Token::Comma) => {
269 continue;
270 }
271 Some(Token::Ident(ref ident)) => {
272 self.parse_colon()?;
273 let exp = match self.parse() {
274 Some(e) => e,
275 None => break,
276 };
277 obj.push((ident.to_owned(), exp));
278 }
279 Some(token) => {
280 return Err(SyntaxError::UnexpectedTokenInObjectBody(token));
281 }
282 None => {
283 return Err(SyntaxError::UnexpectedEndOfFile);
284 }
285 }
286 }
287 self.parse_right_round()?;
288
289 Ok(ZodExpression::Object(Box::new(obj)))
290 }
291
292 fn parse_left_round(&mut self) -> Result<(), SyntaxError> {
293 match self.next() {
294 Some(Token::LRound) => Ok(()),
295 Some(token) => Err(SyntaxError::UnexpectedToken(token, Token::LRound)),
296 None => Err(SyntaxError::UnexpectedEndOfFile),
297 }
298 }
299
300 fn parse_right_round(&mut self) -> Result<(), SyntaxError> {
301 match self.next() {
302 Some(Token::RRound) => Ok(()),
303 Some(token) => Err(SyntaxError::UnexpectedToken(token, Token::RRound)),
304 None => Err(SyntaxError::UnexpectedEndOfFile),
305 }
306 }
307
308 fn parse_left_curly(&mut self) -> Result<(), SyntaxError> {
309 match self.next() {
310 Some(Token::LCurly) => Ok(()),
311 Some(token) => Err(SyntaxError::UnexpectedToken(token, Token::LCurly)),
312 None => Err(SyntaxError::UnexpectedEndOfFile),
313 }
314 }
315
316 fn parse_colon(&mut self) -> Result<(), SyntaxError> {
317 match self.next() {
318 Some(Token::Colon) => Ok(()),
319 Some(token) => Err(SyntaxError::UnexpectedToken(token, Token::Colon)),
320 None => Err(SyntaxError::UnexpectedEndOfFile),
321 }
322 }
323
324 fn parse_left_square(&mut self) -> Result<(), SyntaxError> {
325 match self.next() {
326 Some(Token::LSquare) => Ok(()),
327 Some(token) => Err(SyntaxError::UnexpectedToken(token, Token::LSquare)),
328 None => Err(SyntaxError::UnexpectedEndOfFile),
329 }
330 }
331
332 fn parse_dot(&mut self) -> Result<(), SyntaxError> {
333 match self.next() {
334 Some(Token::Dot) => Ok(()),
335 Some(token) => Err(SyntaxError::UnexpectedToken(token, Token::Dot)),
336 None => Err(SyntaxError::UnexpectedEndOfFile),
337 }
338 }
339
340 fn next(&mut self) -> Option<Token> {
341 self.tokens.next()
342 }
343}