qcl/
ast_test.rs

1#[cfg(test)]
2mod test {
3    use crate::{
4        ast::Parser,
5        expr::Expr,
6        op::BinOp,
7        token::{Token, Tokenizer},
8    };
9
10    #[test]
11    fn basic() {
12        let tokens = vec![
13            Token::At,
14            Token::Id("req".to_string()),
15            Token::Dot,
16            Token::Id("user".to_string()),
17            Token::Dot,
18            Token::Id("age".to_string()),
19            Token::Gt,
20            Token::Int(18),
21        ];
22        let expr = Expr::Bin(
23            Box::new(Expr::At(vec![
24                Box::new(Expr::Val("req".into())),
25                Box::new(Expr::Val("user".into())),
26                Box::new(Expr::Val("age".into())),
27            ])),
28            BinOp::Gt,
29            Box::new(Expr::Val(18.into())),
30        );
31        let parsed = Parser::new(&tokens).parse().unwrap();
32        assert_eq!(parsed, expr);
33    }
34
35    #[test]
36    fn paren() {
37        let r = r#"
38        (
39            true
40            ||
41            false
42        )
43        "#;
44
45        let ts = Tokenizer::new(r).unwrap();
46        let parsed = Parser::new(&ts).parse().unwrap();
47        let expected = Expr::Paren(Box::new(Expr::Or(
48            Box::new(Expr::Val(true.into())),
49            Box::new(Expr::Val(false.into())),
50        )));
51        assert_eq!(parsed, expected);
52    }
53
54    #[test]
55    fn complex() {
56        let r = r#"
57        (
58            @time != 0 
59            ||
60            @col.pub == true
61        )
62        &&
63        @random > 0.5
64        "#;
65
66        let ts = Tokenizer::new(r).unwrap();
67        let parsed = Parser::new(&ts).parse().unwrap();
68        let expected = Expr::And(
69            Box::new(Expr::Paren(Box::new(Expr::Or(
70                Box::new(Expr::Bin(
71                    Box::new(Expr::At(vec![Box::new(Expr::Val("time".into()))])),
72                    BinOp::Ne,
73                    Box::new(Expr::Val(0.into())),
74                )),
75                Box::new(Expr::Bin(
76                    Box::new(Expr::At(vec![
77                        Box::new(Expr::Val("col".into())),
78                        Box::new(Expr::Val("pub".into())),
79                    ])),
80                    BinOp::Eq,
81                    Box::new(Expr::Val(true.into())),
82                )),
83            )))),
84            Box::new(Expr::Bin(
85                Box::new(Expr::At(vec![Box::new(Expr::Val("random".into()))])),
86                BinOp::Gt,
87                Box::new(Expr::Val(0.5.into())),
88            )),
89        );
90        assert_eq!(parsed, expected);
91    }
92
93    #[test]
94    fn access_str_int_str() {
95        let r = "@list.0.name";
96
97        let ts = Tokenizer::new(r).unwrap();
98        let parsed = Parser::new(&ts).parse().unwrap();
99        let expected = Expr::At(vec![
100            Box::new(Expr::Val("list".into())),
101            Box::new(Expr::Val(0.into())),
102            Box::new(Expr::Val("name".into())),
103        ]);
104        assert_eq!(parsed, expected);
105    }
106
107    #[test]
108    fn access_first_int_paths() {
109        let r = "@1.2";
110
111        let t = Tokenizer::new(r).unwrap();
112        let parsed = Parser::new(&t).parse();
113        assert!(parsed.is_err());
114    }
115
116    #[test]
117    fn empty_list() {
118        let r = "[]";
119
120        let ts = Tokenizer::new(r).unwrap();
121        let parsed = Parser::new(&ts).parse().unwrap();
122        let expected = Expr::List(vec![]);
123        assert_eq!(parsed, expected);
124    }
125
126    #[test]
127    fn simple_list() {
128        let r = "[1, 2, 3]";
129
130        let ts = Tokenizer::new(r).unwrap();
131        let parsed = Parser::new(&ts).parse().unwrap();
132        let expected = Expr::List(vec![
133            Box::new(Expr::Val(1.into())),
134            Box::new(Expr::Val(2.into())),
135            Box::new(Expr::Val(3.into())),
136        ]);
137        assert_eq!(parsed, expected);
138    }
139
140    #[test]
141    fn mixed_list() {
142        let r = r#"[1, "hello", true]"#;
143
144        let ts = Tokenizer::new(r).unwrap();
145        let parsed = Parser::new(&ts).parse().unwrap();
146        let expected = Expr::List(vec![
147            Box::new(Expr::Val(1.into())),
148            Box::new(Expr::Val("hello".into())),
149            Box::new(Expr::Val(true.into())),
150        ]);
151        assert_eq!(parsed, expected);
152    }
153
154    #[test]
155    fn list_with_expressions() {
156        let r = "[1 + 2, 3 * 4]";
157
158        let ts = Tokenizer::new(r).unwrap();
159        let parsed = Parser::new(&ts).parse().unwrap();
160        let expected = Expr::List(vec![
161            Box::new(Expr::Bin(
162                Box::new(Expr::Val(1.into())),
163                BinOp::Add,
164                Box::new(Expr::Val(2.into())),
165            )),
166            Box::new(Expr::Bin(
167                Box::new(Expr::Val(3.into())),
168                BinOp::Mul,
169                Box::new(Expr::Val(4.into())),
170            )),
171        ]);
172        assert_eq!(parsed, expected);
173    }
174
175    #[test]
176    fn nested_list() {
177        let r = "[[1, 2], [3, 4]]";
178
179        let ts = Tokenizer::new(r).unwrap();
180        let parsed = Parser::new(&ts).parse().unwrap();
181        let expected = Expr::List(vec![
182            Box::new(Expr::List(vec![
183                Box::new(Expr::Val(1.into())),
184                Box::new(Expr::Val(2.into())),
185            ])),
186            Box::new(Expr::List(vec![
187                Box::new(Expr::Val(3.into())),
188                Box::new(Expr::Val(4.into())),
189            ])),
190        ]);
191        assert_eq!(parsed, expected);
192    }
193
194    #[test]
195    fn list_with_trailing_comma() {
196        let r = "[1, 2, 3,]";
197
198        let ts = Tokenizer::new(r).unwrap();
199        let parsed = Parser::new(&ts).parse().unwrap();
200        let expected = Expr::List(vec![
201            Box::new(Expr::Val(1.into())),
202            Box::new(Expr::Val(2.into())),
203            Box::new(Expr::Val(3.into())),
204        ]);
205        assert_eq!(parsed, expected);
206    }
207
208    #[test]
209    fn empty_map() {
210        let r = "{}";
211
212        let ts = Tokenizer::new(r).unwrap();
213        let parsed = Parser::new(&ts).parse().unwrap();
214        let expected = Expr::Map(vec![]);
215        assert_eq!(parsed, expected);
216    }
217
218    #[test]
219    fn simple_map() {
220        let r = r#"{"name": "Alice", "age": 30}"#;
221
222        let ts = Tokenizer::new(r).unwrap();
223        let parsed = Parser::new(&ts).parse().unwrap();
224        let expected = Expr::Map(vec![
225            (
226                Box::new(Expr::Val("name".into())),
227                Box::new(Expr::Val("Alice".into())),
228            ),
229            (
230                Box::new(Expr::Val("age".into())),
231                Box::new(Expr::Val(30.into())),
232            ),
233        ]);
234        assert_eq!(parsed, expected);
235    }
236
237    #[test]
238    fn map_with_expressions() {
239        let r = r#"{"sum": 1 + 2, "product": 3 * 4}"#;
240
241        let ts = Tokenizer::new(r).unwrap();
242        let parsed = Parser::new(&ts).parse().unwrap();
243        let expected = Expr::Map(vec![
244            (
245                Box::new(Expr::Val("sum".into())),
246                Box::new(Expr::Bin(
247                    Box::new(Expr::Val(1.into())),
248                    BinOp::Add,
249                    Box::new(Expr::Val(2.into())),
250                )),
251            ),
252            (
253                Box::new(Expr::Val("product".into())),
254                Box::new(Expr::Bin(
255                    Box::new(Expr::Val(3.into())),
256                    BinOp::Mul,
257                    Box::new(Expr::Val(4.into())),
258                )),
259            ),
260        ]);
261        assert_eq!(parsed, expected);
262    }
263
264    #[test]
265    fn map_with_different_key_types() {
266        let r = r#"{42: "number", true: "bool", "key": "string"}"#;
267
268        let ts = Tokenizer::new(r).unwrap();
269        let parsed = Parser::new(&ts).parse().unwrap();
270        let expected = Expr::Map(vec![
271            (
272                Box::new(Expr::Val(42.into())),
273                Box::new(Expr::Val("number".into())),
274            ),
275            (
276                Box::new(Expr::Val(true.into())),
277                Box::new(Expr::Val("bool".into())),
278            ),
279            (
280                Box::new(Expr::Val("key".into())),
281                Box::new(Expr::Val("string".into())),
282            ),
283        ]);
284        assert_eq!(parsed, expected);
285    }
286
287    #[test]
288    fn nested_map() {
289        let r = r#"{"user": {"name": "Alice", "age": 30}}"#;
290
291        let ts = Tokenizer::new(r).unwrap();
292        let parsed = Parser::new(&ts).parse().unwrap();
293        let expected = Expr::Map(vec![(
294            Box::new(Expr::Val("user".into())),
295            Box::new(Expr::Map(vec![
296                (
297                    Box::new(Expr::Val("name".into())),
298                    Box::new(Expr::Val("Alice".into())),
299                ),
300                (
301                    Box::new(Expr::Val("age".into())),
302                    Box::new(Expr::Val(30.into())),
303                ),
304            ])),
305        )]);
306        assert_eq!(parsed, expected);
307    }
308
309    #[test]
310    fn map_with_trailing_comma() {
311        let r = r#"{"a": 1, "b": 2,}"#;
312
313        let ts = Tokenizer::new(r).unwrap();
314        let parsed = Parser::new(&ts).parse().unwrap();
315        let expected = Expr::Map(vec![
316            (
317                Box::new(Expr::Val("a".into())),
318                Box::new(Expr::Val(1.into())),
319            ),
320            (
321                Box::new(Expr::Val("b".into())),
322                Box::new(Expr::Val(2.into())),
323            ),
324        ]);
325        assert_eq!(parsed, expected);
326    }
327
328    #[test]
329    fn mixed_structures() {
330        let r = r#"[{"name": "Alice", "scores": [90, 85]}, {"name": "Bob", "scores": [88, 92]}]"#;
331
332        let ts = Tokenizer::new(r).unwrap();
333        let parsed = Parser::new(&ts).parse().unwrap();
334        let expected = Expr::List(vec![
335            Box::new(Expr::Map(vec![
336                (
337                    Box::new(Expr::Val("name".into())),
338                    Box::new(Expr::Val("Alice".into())),
339                ),
340                (
341                    Box::new(Expr::Val("scores".into())),
342                    Box::new(Expr::List(vec![
343                        Box::new(Expr::Val(90.into())),
344                        Box::new(Expr::Val(85.into())),
345                    ])),
346                ),
347            ])),
348            Box::new(Expr::Map(vec![
349                (
350                    Box::new(Expr::Val("name".into())),
351                    Box::new(Expr::Val("Bob".into())),
352                ),
353                (
354                    Box::new(Expr::Val("scores".into())),
355                    Box::new(Expr::List(vec![
356                        Box::new(Expr::Val(88.into())),
357                        Box::new(Expr::Val(92.into())),
358                    ])),
359                ),
360            ])),
361        ]);
362        assert_eq!(parsed, expected);
363    }
364
365    #[test]
366    fn context_access_in_literals() {
367        let r = r#"[@user.name, @user.age]"#;
368
369        let ts = Tokenizer::new(r).unwrap();
370        let parsed = Parser::new(&ts).parse().unwrap();
371        let expected = Expr::List(vec![
372            Box::new(Expr::At(vec![
373                Box::new(Expr::Val("user".into())),
374                Box::new(Expr::Val("name".into())),
375            ])),
376            Box::new(Expr::At(vec![
377                Box::new(Expr::Val("user".into())),
378                Box::new(Expr::Val("age".into())),
379            ])),
380        ]);
381        assert_eq!(parsed, expected);
382    }
383
384    #[test]
385    fn invalid_list_syntax() {
386        // Missing closing bracket
387        let r = "[1, 2, 3";
388        let ts = Tokenizer::new(r).unwrap();
389        let parsed = Parser::new(&ts).parse();
390        assert!(parsed.is_err());
391
392        // Invalid separator
393        let r = "[1; 2; 3]";
394        let ts = Tokenizer::new(r).unwrap();
395        let parsed = Parser::new(&ts).parse();
396        assert!(parsed.is_err());
397    }
398
399    #[test]
400    fn invalid_map_syntax() {
401        // Missing closing brace
402        let r = r#"{"key": "value""#;
403        let ts = Tokenizer::new(r).unwrap();
404        let parsed = Parser::new(&ts).parse();
405        assert!(parsed.is_err());
406
407        // Missing colon
408        let r = r#"{"key" "value"}"#;
409        let ts = Tokenizer::new(r).unwrap();
410        let parsed = Parser::new(&ts).parse();
411        assert!(parsed.is_err());
412
413        // Missing value
414        let r = r#"{"key":}"#;
415        let ts = Tokenizer::new(r).unwrap();
416        let parsed = Parser::new(&ts).parse();
417        assert!(parsed.is_err());
418    }
419}