rust_ts_json_compiler/syntax_tree/
syntax_tree.rs

1use 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}