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 = "named-choice")]
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
21#[cfg(feature = "named-choice")]
22use crate::attribute::string::parse_string;
23use crate::{
24    attribute::{optional::parse_optional, parse_attribute, r#type::parse_type, Attribute},
25    util::ws,
26    Entry, KconfigInput,
27};
28
29use super::parse_entry;
30
31/// 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.
32///
33/// 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.
34///
35/// 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.
36#[derive(Debug, Clone, Default, PartialEq)]
37#[cfg_attr(feature = "hash", derive(Hash))]
38#[cfg_attr(feature = "serialize", derive(Serialize))]
39#[cfg_attr(feature = "deserialize", derive(Deserialize))]
40pub struct Choice {
41    /// Only possible in the named_choice Kconfig format
42    #[cfg(feature = "named-choice")]
43    pub name: Option<String>,
44    pub options: Vec<Attribute>,
45    pub entries: Vec<Entry>,
46}
47
48fn parse_choice_attributes(input: KconfigInput) -> IResult<KconfigInput, Vec<Attribute>> {
49    ws(many0(alt((
50        parse_attribute,
51        parse_type,
52        map(ws(parse_optional), |_| Attribute::Optional),
53    ))))
54    .parse(input)
55}
56
57fn parse_choice_simple(input: KconfigInput) -> IResult<KconfigInput, Choice> {
58    map(
59        delimited(
60            tag("choice"),
61            pair(parse_choice_attributes, many0(ws(parse_entry))),
62            ws(tag("endchoice")),
63        ),
64        |(options, entries)| {
65            #[cfg(feature = "named-choice")]
66            return Choice {
67                options,
68                entries,
69                name: None,
70            };
71            #[cfg(not(feature = "named-choice"))]
72            return Choice { options, entries };
73        },
74    )
75    .parse(input)
76}
77
78pub fn parse_choice(input: KconfigInput) -> IResult<KconfigInput, Choice> {
79    alt((
80        parse_choice_simple,
81        #[cfg(feature = "named-choice")]
82        parse_named_choice,
83    ))
84    .parse(input)
85}
86
87#[cfg(feature = "named-choice")]
88pub fn parse_named_choice(input: KconfigInput) -> IResult<KconfigInput, Choice> {
89    map(
90        delimited(
91            tag("choice"),
92            (
93                ws(parse_choice_name),
94                parse_choice_attributes,
95                many0(ws(parse_entry)),
96            ),
97            ws(tag("endchoice")),
98        ),
99        |(name, options, entries)| Choice {
100            options,
101            entries,
102            name: Some(name),
103        },
104    )
105    .parse(input)
106}
107
108#[cfg(feature = "named-choice")]
109pub fn parse_choice_name(input: KconfigInput) -> IResult<KconfigInput, String> {
110    alt((
111        map(
112            recognize(ws(many1(alt((alphanumeric1, recognize(one_of("._"))))))),
113            |c: KconfigInput| c.trim().to_string(),
114        ),
115        parse_string,
116    ))
117    .parse(input)
118}