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