nom_kconfig/entry/
menu.rs

1use nom::{
2    branch::alt,
3    bytes::complete::tag,
4    combinator::{cut, map},
5    multi::many0,
6    sequence::{pair, preceded, terminated},
7    IResult, Parser,
8};
9#[cfg(feature = "deserialize")]
10use serde::Deserialize;
11#[cfg(feature = "serialize")]
12use serde::Serialize;
13
14use crate::{
15    attribute::{
16        parse_depends_on, parse_prompt_value, parse_visible, visible::Visible, Attribute,
17        Expression,
18    },
19    util::ws,
20    KconfigInput,
21};
22
23use super::{parse_entry, Entry};
24
25/// This defines a menu block, see ["Menu structure"](https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html#menu-structure) for more information. The only possible options are dependencies and "visible" attributes.
26#[derive(Debug, Clone, Default, PartialEq)]
27#[cfg_attr(feature = "hash", derive(Hash))]
28#[cfg_attr(feature = "serialize", derive(Serialize))]
29#[cfg_attr(feature = "deserialize", derive(Deserialize))]
30pub struct Menu {
31    pub prompt: String,
32    #[cfg_attr(
33        any(feature = "serialize", feature = "deserialize"),
34        serde(skip_serializing_if = "Option::is_none")
35    )]
36    pub visible: Option<Visible>,
37    pub depends_on: Vec<Expression>,
38    pub entries: Vec<Entry>,
39}
40
41fn parse_menu_attributes(input: KconfigInput) -> IResult<KconfigInput, Vec<Attribute>> {
42    many0(alt((
43        ws(parse_depends_on),
44        map(ws(parse_visible), Attribute::Visible),
45    )))
46    .parse(input)
47}
48
49pub fn parse_menu(input: KconfigInput) -> IResult<KconfigInput, Menu> {
50    let (input, mut menu) = map(
51        preceded(
52            ws(tag("menu")),
53            pair(ws(parse_prompt_value), ws(parse_menu_attributes)),
54        ),
55        |(prompt, attributes)| {
56            let mut menu = Menu {
57                prompt: prompt.to_string(),
58                ..Default::default()
59            };
60            for attribute in attributes {
61                match attribute {
62                    Attribute::Visible(a) => menu.visible = Some(a),
63                    Attribute::DependsOn(a) => menu.depends_on.push(a),
64                    _ => (),
65                }
66            }
67            menu
68        },
69    )
70    .parse(input)?;
71
72    let (input, entries) =
73        cut(terminated(many0(ws(parse_entry)), ws(tag("endmenu")))).parse(input)?;
74    menu.entries = entries;
75    Ok((input, menu))
76}