Skip to main content

wpl/parser/
wpl_pkg.rs

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}