Skip to main content

nom_kconfig/entry/
choice.rs

1use nom::{
2    branch::alt,
3    bytes::complete::tag,
4    combinator::map,
5    multi::many0,
6    sequence::{delimited, pair},
7    IResult, Parser,
8};
9
10#[cfg(feature = "coreboot")]
11use nom::{
12    character::complete::{alphanumeric1, one_of},
13    combinator::recognize,
14    multi::many1,
15};
16#[cfg(feature = "deserialize")]
17use serde::Deserialize;
18#[cfg(feature = "serialize")]
19use serde::Serialize;
20
21use crate::{
22    attribute::{optional::parse_optional, parse_attribute, r#type::parse_type, Attribute},
23    util::ws,
24    Entry, KconfigInput,
25};
26
27use super::parse_entry;
28
29/// This defines a choice group and accepts any of the above attributes as options. A choice can only be of type bool or tristate. If no type is specified for a choice, its type will be determined by the type of the first choice element in the group or remain unknown if none of the choice elements have a type specified, as well.
30///
31/// While a boolean choice only allows a single config entry to be selected, a tristate choice also allows any number of config entries to be set to 'm'. This can be used if multiple drivers for a single hardware exists and only a single driver can be compiled/loaded into the kernel, but all drivers can be compiled as modules.
32///
33/// A choice accepts another option "optional", which allows to set the choice to 'n' and no entry needs to be selected. If no [symbol](crate::symbol::Symbol) is associated with a choice, then you can not have multiple definitions of that choice. If a [symbol](crate::symbol::Symbol) is associated to the choice, then you may define the same choice (i.e. with the same entries) in another place.
34#[derive(Debug, Clone, Default, PartialEq)]
35#[cfg_attr(feature = "hash", derive(Hash))]
36#[cfg_attr(feature = "serialize", derive(Serialize))]
37#[cfg_attr(feature = "deserialize", derive(Deserialize))]
38pub struct Choice {
39    /// Only possible in the coreboot Kconfig format
40    #[cfg(feature = "coreboot")]
41    pub name: Option<String>,
42    pub options: Vec<Attribute>,
43    pub entries: Vec<Entry>,
44}
45
46fn parse_choice_attributes(input: KconfigInput) -> IResult<KconfigInput, Vec<Attribute>> {
47    ws(many0(alt((
48        parse_attribute,
49        parse_type,
50        map(ws(parse_optional), |_| Attribute::Optional),
51    ))))
52    .parse(input)
53}
54
55#[cfg(feature = "coreboot")]
56pub fn parse_choice_for_coreboot(input: KconfigInput) -> IResult<KconfigInput, Choice> {
57    map(
58        delimited(
59            tag("choice"),
60            (
61                map(
62                    recognize(ws(many1(alt((alphanumeric1, recognize(one_of("._"))))))),
63                    |c: KconfigInput| c.trim().to_string(),
64                ),
65                parse_choice_attributes,
66                many0(ws(parse_entry)),
67            ),
68            ws(tag("endchoice")),
69        ),
70        |(name, options, entries)| Choice {
71            options,
72            entries,
73            name: Some(name),
74        },
75    )
76    .parse(input)
77}
78
79fn parse_choice_simple(input: KconfigInput) -> IResult<KconfigInput, Choice> {
80    map(
81        delimited(
82            tag("choice"),
83            pair(parse_choice_attributes, many0(ws(parse_entry))),
84            ws(tag("endchoice")),
85        ),
86        |(options, entries)| {
87            #[cfg(feature = "coreboot")]
88            return Choice {
89                options,
90                entries,
91                name: None,
92            };
93            #[cfg(not(feature = "coreboot"))]
94            return Choice { options, entries };
95        },
96    )
97    .parse(input)
98}
99
100pub fn parse_choice(input: KconfigInput) -> IResult<KconfigInput, Choice> {
101    alt((
102        parse_choice_simple,
103        #[cfg(feature = "coreboot")]
104        parse_choice_for_coreboot,
105    ))
106    .parse(input)
107}