1use crate::ast::WplExpress;
2use crate::parser::error::{WPLCodeErrorTrait, WplCodeResult};
3use crate::parser::utils::is_sep_next;
4use crate::parser::wpl_group::wpl_group;
5use crate::parser::wpl_rule;
6use winnow::ascii::multispace0;
7use winnow::combinator::{cut_err, delimited, opt};
8use winnow::token::literal;
9use wp_primitives::Parser;
10use wp_primitives::WResult;
11use wp_primitives::symbol::ctx_desc;
12
13use super::wpl_anno::ann_fun;
14pub fn wpl_express(input: &mut &str) -> WResult<WplExpress> {
17 let mut rule = WplExpress::default();
18 if let Some(mut pipe) = opt(wpl_rule::pip_proc).parse_next(input)? {
19 rule.pipe_process.append(&mut pipe);
20 }
21 loop {
22 wpl_group
23 .context(ctx_desc("group"))
24 .map(|x| rule.group.push(x))
25 .parse_next(input)?;
26 if !is_sep_next(input) {
27 break;
28 }
29 }
30 Ok(rule)
31}
32
33pub(crate) fn segment(input: &mut &str) -> WResult<WplExpress> {
34 let tags = opt(ann_fun).parse_next(input)?;
35 let mut define = delimited(
36 (multispace0, literal('{'), multispace0),
37 cut_err(wpl_express),
38 (multispace0, literal('}'), multispace0),
39 )
40 .parse_next(input)?;
41 define.tags = tags;
42 Ok(define)
43}
44
45pub fn source_segment(code: &str) -> WplCodeResult<WplExpress> {
46 segment
47 .parse(code)
48 .map_err(|e| WPLCodeErrorTrait::from_parse_err(e, code, "<segment>"))
49}
50
51#[cfg(test)]
65mod tests {
66 use smol_str::SmolStr;
67 use winnow::LocatingSlice;
68
69 use super::*;
70 use crate::ast::fld_fmt::WplFieldFmt;
71 use crate::ast::{WplField, WplPackage};
72 use crate::parser::error::WplCodeError;
73 use crate::parser::error::WplCodeReason;
74 use crate::parser::error::WplCodeResult;
75 use crate::parser::wpl_pkg::{wpl_package, wpl_pkg_body};
76 use crate::parser::wpl_rule::pip_proc;
77 use orion_error::UvsFrom;
78 use orion_error::compat_traits::ErrorOweBase;
79 use orion_error::testcase::TestAssert;
80 use wp_model_core::model::DataType;
81
82 #[test]
83 fn test_package() -> Result<(), WplCodeError> {
84 let input = r#" package test {
85 rule test { (digit<<,>>,digit,time_3339:recv_time,5*_) }
86 }
87 "#;
88
89 assert_eq!(
90 wpl_package
91 .parse(&LocatingSlice::new(input))
92 .owe(WplCodeReason::from_conf())?
93 .to_string(),
94 r#"package test {
95 rule test {
96 (
97 digit<<,>>,
98 digit,
99 time_3339:recv_time,
100 5*_
101 )
102 }
103}
104"#
105 );
106
107 let data = r#"
108 package test {
109 rule /service/for_test/wplab_1 {
110 (digit<<,>>,digit,time_3339:recv_time,5*_),
111 (digit:id,digit:len,time,sn,chars:dev_name,time,kv,sn,chars:dev_name,time,time,ip,kv,chars,kv,kv,chars,kv,kv,chars,chars,ip,chars,http/request<[,]>,http/agent")
112 }
113 }
114 "#;
115
116 assert_eq!(
117 wpl_package.parse(data).assert().to_string(),
118 r#"package test {
119 rule /service/for_test/wplab_1 {
120 (
121 digit<<,>>,
122 digit,
123 time_3339:recv_time,
124 5*_
125 ),
126 (
127 digit:id,
128 digit:len,
129 time,
130 sn,
131 chars:dev_name,
132 time,
133 kv,
134 sn,
135 chars:dev_name,
136 time,
137 time,
138 ip,
139 kv,
140 chars,
141 kv,
142 kv,
143 chars,
144 kv,
145 kv,
146 chars,
147 chars,
148 ip,
149 chars,
150 http/request<[,]>,
151 http/agent"
152 )
153 }
154}
155"#
156 );
157
158 let data = r#"
159 package test {
160 rule /service/for_test/wplab_1 {
161 (time_3339:recv_time,5*_)\!\|
162 }
163 rule /service/for_test/wplab_2 {
164 (time_3339:recv_time,5*_)
165 }
166 }
167 "#;
168
169 let result = wpl_package.parse(data).assert();
170 assert_eq!(
171 result.to_string(),
172 r#"package test {
173 rule /service/for_test/wplab_1 {
174 (
175 time_3339:recv_time,
176 5*_
177 )\!\|
178 }
179 rule /service/for_test/wplab_2 {
180 (
181 time_3339:recv_time,
182 5*_
183 )
184 }
185}
186"#
187 );
188 Ok(())
189 }
190 #[test]
191 fn test_parse_block2() {
192 let data = r#"(kv(digit@message_type),kv(chars@serial_num))\!\|"#;
193 let result = wpl_express.parse(data).assert();
194 assert_eq!(
195 result.to_string(),
196 r#" (
197 kv(digit@message_type),
198 kv(@serial_num)
199 )\!\|"#,
200 );
201 }
202
203 #[test]
204 fn test_parse_block() {
205 let data = "(kv(digit@message_type),chars<skyeye_abnormal {,|>,kv(chars@serial_num),kv(time@access_time),kv(@type),kv(ip@sip),kv(digit@sport),kv(ip@dip),kv(digit@dport),kv(chars@data),kv(digit@datalen),kv(chars@info),kv(chars@vendor_id),kv(ip@device_ip),chars<},|>)";
206 assert_eq!(
207 wpl_express.parse(data).assert().to_string(),
208 r#" (
209 kv(digit@message_type),
210 chars<skyeye_abnormal {,|>,
211 kv(@serial_num),
212 kv(time@access_time),
213 kv(@type),
214 kv(ip@sip),
215 kv(digit@sport),
216 kv(ip@dip),
217 kv(digit@dport),
218 kv(@data),
219 kv(digit@datalen),
220 kv(@info),
221 kv(@vendor_id),
222 kv(ip@device_ip),
223 chars<},|>
224 )"#,
225 );
226
227 let data = r#"(json(_@_origin,_@payload/packet_data))"#;
228 assert_eq!(
229 wpl_express.parse(data).assert().to_string(),
230 " (
231 json(_@_origin,_@payload/packet_data,)
232 )"
233 );
234 }
235
236 #[test]
237 fn test_pip_proc() {
238 assert_eq!(
239 pip_proc.parse_peek("|decode/base64|"),
240 Ok(("", vec![SmolStr::from("decode/base64")]))
241 );
242
243 assert_eq!(
244 pip_proc.parse_peek("|decode/hex|"),
245 Ok(("", vec![SmolStr::from("decode/hex")]))
246 );
247
248 assert_eq!(
249 pip_proc.parse_peek("|unquote/unescape|"),
250 Ok(("", vec![SmolStr::from("unquote/unescape")]))
251 );
252 assert_eq!(
253 pip_proc.parse_peek("|decode/base64|zip|"),
254 Ok((
255 "",
256 vec![SmolStr::from("decode/base64"), SmolStr::from("zip")]
257 ))
258 );
259 assert_eq!(
260 pip_proc.parse_peek("|decode/base64|zip |"),
261 Ok((
262 "",
263 vec![SmolStr::from("decode/base64"), SmolStr::from("zip")]
264 ))
265 );
266 assert_eq!(
267 pip_proc.parse_peek("| base64 |zip |"),
268 Ok(("", vec![SmolStr::from("base64"), SmolStr::from("zip")]))
269 );
270 assert_eq!(
271 pip_proc.parse_peek("| base |"),
272 Ok(("", vec![SmolStr::from("base")]))
273 );
274 assert_eq!(
275 pip_proc
276 .parse(&LocatingSlice::new("| !!!|"))
277 .err()
278 .unwrap()
279 .offset(),
280 2
281 );
282 assert_eq!(
283 pip_proc
284 .parse(&LocatingSlice::new("|"))
285 .err()
286 .unwrap()
287 .offset(),
288 1
289 );
290 assert_eq!(
291 pip_proc
292 .parse(&LocatingSlice::new("|2222 |34333| 444 "))
293 .err()
294 .unwrap()
295 .offset(),
296 20
297 );
298 }
299
300 #[test]
301 fn test_conf_map() -> WplCodeResult<()> {
302 let data = r#"(json(base64@a:x,@b:y))"#;
303 let conf = wpl_express.parse(data).assert();
304 let map = conf.group[0].fields[0].sub_fields.as_ref().unwrap();
305 let expect = WplField {
306 name: Some("x".into()),
307 meta_name: "base64".into(),
308 meta_type: DataType::Base64,
309 desc: "base64:x".to_string(),
310 fmt_conf: WplFieldFmt {
311 ..Default::default()
314 },
315 ..Default::default()
316 };
317 assert_eq!(map.get("a"), Some(&expect));
318 Ok(())
319 }
320
321 #[test]
322 fn test_conf_vec() {
323 let data = "(ip,ip)";
324 wpl_group.parse(data).assert();
325 wpl_group.parse("(http/method,ip)").assert();
326 wpl_group.parse("(*ip,ip:src)").assert();
327
328 let group = wpl_group.parse("(*ip,ip:src)[100]\\,").assert();
329 group
330 .fields
331 .iter()
332 .for_each(|x| assert_eq!(x.separator, None));
333 assert!(group.base_group_sep.is_some());
334
335 let data = "(chars<-[,]*>)";
336 let group = wpl_group.parse(data).assert();
337 assert_eq!(group.fields[0].fmt_conf.scope_beg, Some("-[".to_string()));
338 assert_eq!(group.fields[0].fmt_conf.scope_end, Some("]*".to_string()));
339
340 wpl_group.parse("(chars<http://,/>)").assert();
341 wpl_group.parse("(chars<http://,/>)").assert();
342 wpl_group.parse("\n(\nip,\nip\n)").assert();
343 }
344
345 #[test]
346 fn test_rules() -> WplCodeResult<()> {
347 let data = r#" rule wparse_1 { |decode/base64|zip|unquote/unescape|(digit,time) }"#;
348 wpl_pkg_body(&mut WplPackage::default())
349 .parse(data)
350 .assert();
351
352 let data = r#"
353 rule wparse_1 { |base64|zip|(digit,time) }
354
355 rule wparse_2 { |base64|zip|(digit,time) } "#;
356 let mut package = WplPackage::default();
357 wpl_pkg_body(&mut package).parse(data).assert();
358 assert_eq!(package.rules.len(), 2);
359 Ok(())
360 }
361
362 #[test]
386 fn test_package_annotation1() {
387 let data = r#"
388#[tag(t1:"id",t2:"sn"),copy_raw(hello:"ll")]
389package test {
390 rule /service/for_test/wplab_1 {
391 (digit<<,>>,digit,time_3339:recv_time2,5*_),
392 (digit:id,digit:len,time,sn,chars:dev_name,time,kv,sn,chars:dev_name,time,time,ip,kv,chars,kv,kv,chars,kv,kv,chars,chars,ip,chars,http/request<[,]>,http/agent")\,
393 }
394}
395 "#;
396
397 let expect = r#"#[tag(t1:"id", t2:"sn"), copy_raw(hello:"ll")]
398package test {
399 #[tag(t1:"id", t2:"sn"), copy_raw(hello:"ll")]
400 rule /service/for_test/wplab_1 {
401 (
402 digit<<,>>,
403 digit,
404 time_3339:recv_time2,
405 5*_
406 ),
407 (
408 digit:id,
409 digit:len,
410 time,
411 sn,
412 chars:dev_name,
413 time,
414 kv,
415 sn,
416 chars:dev_name,
417 time,
418 time,
419 ip,
420 kv,
421 chars,
422 kv,
423 kv,
424 chars,
425 kv,
426 kv,
427 chars,
428 chars,
429 ip,
430 chars,
431 http/request<[,]>,
432 http/agent"
433 )\,
434 }
435}
436"#;
437
438 let packages = wpl_package.parse(data).assert();
439 assert_eq!(packages.to_string(), expect);
440 }
441
442 #[test]
443 fn test_annotation2() {
444 let data = r#"
445#[tag(t1:"id",t2:"sn"),copy_raw(name:"ok")]
446package test {
447 #[tag(t1:"id",t3:"sn2"),copy_raw(name:"yes")]
448 rule /service/for_test/wplab_1 {
449 (digit<<,>>,digit,time_3339:recv_time2,5*_),
450 (digit:id,digit:len,time,sn,chars:dev_name,time,kv,sn,chars:dev_name,time,time,ip,kv,chars,kv,kv,chars,kv,kv,chars,chars,ip,chars,http/request<[,]>,http/agent")\,
451 }
452}
453 "#;
454
455 let expect = r#"#[tag(t1:"id", t2:"sn"), copy_raw(name:"ok")]
456package test {
457 #[tag(t1:"id", t2:"sn", t3:"sn2"), copy_raw(name:"yes")]
458 rule /service/for_test/wplab_1 {
459 (
460 digit<<,>>,
461 digit,
462 time_3339:recv_time2,
463 5*_
464 ),
465 (
466 digit:id,
467 digit:len,
468 time,
469 sn,
470 chars:dev_name,
471 time,
472 kv,
473 sn,
474 chars:dev_name,
475 time,
476 time,
477 ip,
478 kv,
479 chars,
480 kv,
481 kv,
482 chars,
483 kv,
484 kv,
485 chars,
486 chars,
487 ip,
488 chars,
489 http/request<[,]>,
490 http/agent"
491 )\,
492 }
493}
494"#;
495
496 let packages = wpl_package.parse(data).assert();
497 assert_eq!(packages.to_string(), expect);
498 }
499
500 #[test]
501 fn test_annotation3() {
502 let data = r#"
503#[tag(t1:"id")]
504package test {
505 #[tag(t1:"hello",t3:"sn2"),copy_raw(hello:"ll")]
506 rule /service/for_test/wplab_1 {
507 (digit<<,>>,digit,time_3339:recv_time2,5*_),
508 (digit:id,digit:len,time,sn,chars:dev_name,time,kv,sn,chars:dev_name,time,time,ip,kv,chars,kv,kv,chars,kv,kv,chars,chars,ip,chars,http/request<[,]>,http/agent")\,
509 }
510}
511 "#;
512
513 let expect = r#"#[tag(t1:"id")]
514package test {
515 #[tag(t1:"hello", t3:"sn2"), copy_raw(hello:"ll")]
516 rule /service/for_test/wplab_1 {
517 (
518 digit<<,>>,
519 digit,
520 time_3339:recv_time2,
521 5*_
522 ),
523 (
524 digit:id,
525 digit:len,
526 time,
527 sn,
528 chars:dev_name,
529 time,
530 kv,
531 sn,
532 chars:dev_name,
533 time,
534 time,
535 ip,
536 kv,
537 chars,
538 kv,
539 kv,
540 chars,
541 kv,
542 kv,
543 chars,
544 chars,
545 ip,
546 chars,
547 http/request<[,]>,
548 http/agent"
549 )\,
550 }
551}
552"#;
553
554 let packages = wpl_package.parse(data).assert();
555 assert_eq!(packages.to_string(), expect);
556 }
557}