Skip to main content

wp_primitives/fun/
parser.rs

1use std::net::IpAddr;
2
3use crate::fun::fun_trait::{Fun0Builder, Fun1Builder, Fun2Builder};
4use crate::net::ip;
5use crate::symbol::{symbol_bracket_beg, symbol_bracket_end, symbol_comma};
6use winnow::ascii::{digit1, multispace0};
7use winnow::combinator::separated;
8use winnow::{ModalResult as WResult, Parser};
9
10use super::fun_trait::ParseNext;
11
12pub fn take_call_args2<T: Fun2Builder>(data: &mut &str) -> WResult<(T::ARG1, T::ARG2)> {
13    multispace0.parse_next(data)?;
14    symbol_bracket_beg.parse_next(data)?;
15    multispace0.parse_next(data)?;
16    let a1 = T::args1.parse_next(data)?;
17    (multispace0, symbol_comma, multispace0).parse_next(data)?;
18    let a2 = T::args2.parse_next(data)?;
19    multispace0.parse_next(data)?;
20    symbol_bracket_end.parse_next(data)?;
21    Ok((a1, a2))
22}
23
24pub fn take_call_args0<T: Fun0Builder>(data: &mut &str) -> WResult<()> {
25    multispace0.parse_next(data)?;
26    symbol_bracket_beg.parse_next(data)?;
27    multispace0.parse_next(data)?;
28    symbol_bracket_end.parse_next(data)?;
29    Ok(())
30}
31
32pub fn take_call_args1<T: Fun1Builder>(data: &mut &str) -> WResult<T::ARG1> {
33    multispace0.parse_next(data)?;
34    symbol_bracket_beg.parse_next(data)?;
35    multispace0.parse_next(data)?;
36    let a1 = T::args1.parse_next(data)?;
37    multispace0.parse_next(data)?;
38    symbol_bracket_end.parse_next(data)?;
39    Ok(a1)
40}
41
42pub fn call_fun_args2<T: Fun2Builder>(data: &mut &str) -> WResult<T> {
43    T::fun_name().parse_next(data)?;
44    let args = take_call_args2::<T>.parse_next(data)?;
45    let obj = T::build(args);
46    Ok(obj)
47}
48
49pub fn call_fun_args1<T: Fun1Builder>(data: &mut &str) -> WResult<T> {
50    T::fun_name().parse_next(data)?;
51    let args = take_call_args1::<T>.parse_next(data)?;
52    let obj = T::build(args);
53    Ok(obj)
54}
55
56pub fn call_fun_args0<T: Fun0Builder>(data: &mut &str) -> WResult<T> {
57    T::fun_name().parse_next(data)?;
58    take_call_args0::<T>.parse_next(data)?;
59    let obj = T::build();
60    Ok(obj)
61}
62
63pub fn take_arr<T: ParseNext<T>>(data: &mut &str) -> WResult<Vec<T>> {
64    (multispace0, "[", multispace0).parse_next(data)?;
65    let arr: Vec<T> = separated(1.., T::parse_next, ",").parse_next(data)?;
66    (multispace0, "]").parse_next(data)?;
67    Ok(arr)
68}
69
70impl ParseNext<u32> for u32 {
71    fn parse_next(input: &mut &str) -> WResult<u32> {
72        use winnow::error::{ErrMode, ParserError};
73        let str = digit1(input)?;
74        str.parse::<u32>().map_err(|_| ErrMode::from_input(input))
75    }
76}
77
78impl ParseNext<i64> for i64 {
79    fn parse_next(input: &mut &str) -> WResult<i64> {
80        use winnow::error::{ErrMode, ParserError};
81        let str = digit1(input)?;
82        str.parse::<i64>().map_err(|_| ErrMode::from_input(input))
83    }
84}
85impl ParseNext<IpAddr> for IpAddr {
86    fn parse_next(input: &mut &str) -> WResult<IpAddr> {
87        ip.parse_next(input)
88    }
89}
90
91#[cfg(test)]
92mod test {
93    use super::{call_fun_args1, take_arr};
94    use crate::fun::fun_trait::Fun1Builder;
95    use winnow::{
96        //ascii::{digit1, multispace0},
97        ModalResult as WResult,
98        Parser,
99    };
100
101    #[derive(Debug, PartialEq)]
102    struct A {
103        arr: Vec<u32>,
104    }
105    impl Fun1Builder for A {
106        type ARG1 = Vec<u32>;
107
108        fn args1(data: &mut &str) -> WResult<Self::ARG1> {
109            take_arr::<u32>(data)
110        }
111
112        fn fun_name() -> &'static str {
113            "fun_a"
114        }
115
116        fn build(args: Self::ARG1) -> Self {
117            A { arr: args }
118        }
119    }
120
121    #[test]
122    fn test_arr_args_fun() -> WResult<()> {
123        let mut data = "fun_a([1,2,3])";
124        let x = call_fun_args1::<A>.parse_next(&mut data)?;
125        println!("{:?}", x);
126        assert_eq!(x, A { arr: vec![1, 2, 3] });
127        Ok(())
128    }
129
130    // ========================================================================
131    // Tests for error handling and boundary conditions
132    // ========================================================================
133
134    mod u32_parsing {
135        use super::super::ParseNext;
136
137        #[test]
138        fn valid_u32_parsing() {
139            let mut input = "123";
140            let result = u32::parse_next(&mut input);
141            assert!(result.is_ok());
142            assert_eq!(result.unwrap(), 123);
143        }
144
145        #[test]
146        fn valid_u32_max_value() {
147            let mut input = "4294967295"; // u32::MAX
148            let result = u32::parse_next(&mut input);
149            assert!(result.is_ok());
150            assert_eq!(result.unwrap(), u32::MAX);
151        }
152
153        #[test]
154        fn invalid_u32_overflow() {
155            let mut input = "4294967296"; // u32::MAX + 1
156            let result = u32::parse_next(&mut input);
157            assert!(result.is_err(), "Should fail on u32 overflow");
158        }
159
160        #[test]
161        fn invalid_u32_negative() {
162            let mut input = "-1";
163            let result = u32::parse_next(&mut input);
164            assert!(result.is_err(), "Should fail on negative number for u32");
165        }
166
167        #[test]
168        fn invalid_u32_non_numeric() {
169            let mut input = "abc";
170            let result = u32::parse_next(&mut input);
171            assert!(result.is_err(), "Should fail on non-numeric input");
172        }
173
174        #[test]
175        fn empty_input() {
176            let mut input = "";
177            let result = u32::parse_next(&mut input);
178            assert!(result.is_err(), "Should fail on empty input");
179        }
180    }
181
182    mod i64_parsing {
183        use super::super::ParseNext;
184
185        #[test]
186        fn valid_i64_positive() {
187            let mut input = "123";
188            let result = i64::parse_next(&mut input);
189            assert!(result.is_ok());
190            assert_eq!(result.unwrap(), 123);
191        }
192
193        #[test]
194        fn valid_i64_max_value() {
195            let mut input = "9223372036854775807"; // i64::MAX
196            let result = i64::parse_next(&mut input);
197            assert!(result.is_ok());
198            assert_eq!(result.unwrap(), i64::MAX);
199        }
200
201        #[test]
202        fn invalid_i64_overflow() {
203            let mut input = "9223372036854775808"; // i64::MAX + 1
204            let result = i64::parse_next(&mut input);
205            assert!(result.is_err(), "Should fail on i64 overflow");
206        }
207
208        #[test]
209        fn invalid_i64_negative() {
210            // Note: digit1 only matches positive digits, so negative would fail at parsing stage
211            let mut input = "-123";
212            let result = i64::parse_next(&mut input);
213            assert!(
214                result.is_err(),
215                "Should fail on negative (digit1 doesn't match '-')"
216            );
217        }
218
219        #[test]
220        fn invalid_i64_non_numeric() {
221            let mut input = "xyz";
222            let result = i64::parse_next(&mut input);
223            assert!(result.is_err(), "Should fail on non-numeric input");
224        }
225    }
226
227    mod array_parsing {
228        use super::super::take_arr;
229
230        #[test]
231        fn valid_array_single_element() {
232            let mut input = "[42]";
233            let result = take_arr::<u32>(&mut input);
234            assert!(result.is_ok());
235            assert_eq!(result.unwrap(), vec![42]);
236        }
237
238        #[test]
239        fn valid_array_multiple_elements() {
240            let mut input = "[1,2,3,4,5]";
241            let result = take_arr::<u32>(&mut input);
242            assert!(result.is_ok());
243            assert_eq!(result.unwrap(), vec![1, 2, 3, 4, 5]);
244        }
245
246        #[test]
247        fn valid_array_with_spaces() {
248            let mut input = "[1,2,3]"; // Note: multispace0 is between brackets and content
249            let result = take_arr::<u32>(&mut input);
250            assert!(result.is_ok());
251            assert_eq!(result.unwrap(), vec![1, 2, 3]);
252        }
253
254        #[test]
255        fn invalid_array_missing_bracket() {
256            let mut input = "1,2,3]";
257            let result = take_arr::<u32>(&mut input);
258            assert!(result.is_err(), "Should fail on missing opening bracket");
259        }
260
261        #[test]
262        fn invalid_array_empty() {
263            let mut input = "[]";
264            let result = take_arr::<u32>(&mut input);
265            // separated requires at least 1 element
266            assert!(result.is_err(), "Should fail on empty array");
267        }
268
269        #[test]
270        fn invalid_array_trailing_comma() {
271            let mut input = "[1,2,]";
272            let result = take_arr::<u32>(&mut input);
273            assert!(result.is_err(), "Should fail on trailing comma");
274        }
275    }
276
277    mod function_call_parsing {
278        use super::{super::call_fun_args1, A};
279
280        #[test]
281        fn valid_function_call() {
282            let mut input = "fun_a([1,2,3])";
283            let result = call_fun_args1::<A>(&mut input);
284            assert!(result.is_ok());
285            assert_eq!(result.unwrap(), A { arr: vec![1, 2, 3] });
286        }
287
288        #[test]
289        fn valid_function_call_with_spaces() {
290            let mut input = "fun_a([1,2,3])"; // Simplified for actual parser behavior
291            let result = call_fun_args1::<A>(&mut input);
292            assert!(result.is_ok());
293            assert_eq!(result.unwrap(), A { arr: vec![1, 2, 3] });
294        }
295
296        #[test]
297        fn invalid_function_wrong_name() {
298            let mut input = "fun_b([1,2,3])";
299            let result = call_fun_args1::<A>(&mut input);
300            assert!(result.is_err(), "Should fail on wrong function name");
301        }
302
303        #[test]
304        fn invalid_function_missing_parens() {
305            let mut input = "fun_a[1,2,3]";
306            let result = call_fun_args1::<A>(&mut input);
307            assert!(result.is_err(), "Should fail on missing parentheses");
308        }
309
310        #[test]
311        fn invalid_function_empty_args() {
312            let mut input = "fun_a()";
313            let result = call_fun_args1::<A>(&mut input);
314            assert!(result.is_err(), "Should fail on empty arguments");
315        }
316    }
317}