1use super::wpl_anno::ann_fun;
2use crate::ast::{WplPackage, WplRule};
3use crate::parser::{MergeTags, utils, wpl_rule};
4use smol_str::SmolStr;
5use winnow::ascii::{multispace0, multispace1};
6use winnow::combinator::{alt, cut_err, delimited, opt, repeat};
7use winnow::error::{ContextError, StrContext};
8use winnow::token::literal;
9use wp_primitives::Parser;
10use wp_primitives::WResult;
11use wp_primitives::symbol::{ctx_desc, ctx_label, ctx_literal};
12
13pub fn wpl_pkg_body2(input: &mut &str) -> WResult<Vec<WplRule>> {
14 let mut rules = Vec::new();
15 loop {
16 wpl_rule::wpl_rule
17 .context(StrContext::Expected("rule <name> {...}".into()))
18 .map(|x| rules.push(x))
19 .parse_next(input)?;
20 if !utils::is_next(alt(("rule", "#[")), input) {
21 break;
22 }
23 }
24 Ok(rules)
25}
26
27pub fn wpl_pkg_body<'a, 'b>(
28 package: &'b mut WplPackage,
29) -> impl Parser<&'a str, (), ContextError> + 'b {
30 move |input: &mut &'a str| {
31 use winnow::error::{ContextError, ErrMode};
32 delimited(
33 multispace0,
34 repeat(
35 1..,
36 wpl_rule::wpl_rule
37 .context(StrContext::Expected("rule <name> {...}".into()))
38 .map(|x| package.rules.push_back(x)),
39 ),
40 multispace0,
41 )
42 .parse_next(input)
43 .map_err(|e| match e {
44 ErrMode::Backtrack(e) | ErrMode::Cut(e) => e,
45 ErrMode::Incomplete(_) => ContextError::default(),
46 })
47 }
48}
49
50#[allow(clippy::field_reassign_with_default)]
51pub fn wpl_package(input: &mut &str) -> WResult<WplPackage> {
52 let mut package = WplPackage::default();
53 opt(ann_fun).map(|t| package.tags = t).parse_next(input)?;
54 package.name = (
55 multispace0,
56 literal("package"),
57 multispace1,
58 utils::take_key,
59 )
60 .context(ctx_label("wpl keyword"))
61 .context(ctx_literal("package <name> "))
62 .context(ctx_desc("<<< package <pkg_name> {...}"))
63 .map(|x| SmolStr::from(x.3))
64 .parse_next(input)?;
65
66 let rules = delimited(
67 (multispace0, literal("{"), multispace0),
68 cut_err(wpl_pkg_body2).context(ctx_desc("{ rule ... }")),
69 (multispace0, literal("}"), multispace0),
70 )
71 .parse_next(input)?;
72
73 package.append(rules);
74 package.merge_tags(&None);
75 Ok(package)
76}